@hifullmoon/aicommit 1.5.1 → 2.0.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/.aicommit.config.example.json +30 -10
- package/CHANGELOG.md +17 -1
- package/README.md +43 -41
- package/README.zh-CN.md +68 -66
- package/SECURITY.md +1 -1
- package/docs/distribution.md +3 -38
- package/docs/privacy.md +8 -8
- package/docs/provider-presets.md +22 -9
- package/docs/troubleshooting.md +0 -1
- package/package.json +2 -3
- package/presets/provider-presets.json +48 -15
- package/schemas/aicommit-provider-presets.schema.json +24 -4
- package/src/cli.js +38 -7
- package/src/completion.js +4 -1
- package/src/config-command.js +7 -5
- package/src/config.js +198 -26
- package/src/doctor.js +5 -3
- package/src/main.js +29 -6
- package/src/provider-presets.js +43 -15
- package/src/setup.js +66 -37
- package/src/ui.js +66 -13
package/docs/distribution.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Distribution / 分发
|
|
2
2
|
|
|
3
|
-
AICommit
|
|
3
|
+
AICommit 仅通过 npm 发布。
|
|
4
4
|
|
|
5
|
-
AICommit is distributed through npm
|
|
5
|
+
AICommit is distributed exclusively through npm.
|
|
6
6
|
|
|
7
7
|
## npm
|
|
8
8
|
|
|
@@ -26,36 +26,10 @@ The release workflow uses npm Trusted Publishing without a long-lived `NPM_TOKEN
|
|
|
26
26
|
```bash
|
|
27
27
|
workdir=$(mktemp -d)
|
|
28
28
|
cd "$workdir"
|
|
29
|
-
npm install --package-lock-only @hifullmoon/aicommit@
|
|
29
|
+
npm install --package-lock-only @hifullmoon/aicommit@2.0.0
|
|
30
30
|
npm audit signatures
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
## Homebrew
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
# install / 安装
|
|
37
|
-
brew tap hi-fullmoon/aicommit https://github.com/hi-fullmoon/AICommit.git
|
|
38
|
-
brew install hi-fullmoon/aicommit/aicommit
|
|
39
|
-
|
|
40
|
-
# upgrade / 升级
|
|
41
|
-
brew update
|
|
42
|
-
brew upgrade hi-fullmoon/aicommit/aicommit
|
|
43
|
-
|
|
44
|
-
# uninstall / 卸载
|
|
45
|
-
brew uninstall aicommit
|
|
46
|
-
brew untap hi-fullmoon/aicommit
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Formula 依赖 Homebrew 的 Node package,使用 Homebrew 标准 npm 安装参数,并测试 `--version`、`--help` 与无凭据配置校验。每次 npm 发布完成后,release workflow 会从公开 registry 再执行一次真实安装测试。
|
|
50
|
-
|
|
51
|
-
The formula depends on Homebrew's Node package, uses Homebrew's standard npm installation arguments, and tests `--version`, `--help`, and credential-free configuration validation. After every npm publish, the release workflow performs a real install from the public registry.
|
|
52
|
-
|
|
53
|
-
## Integrity / 完整性
|
|
54
|
-
|
|
55
|
-
`Formula/aicommit.rb` 中的 `sha256` 必须与对应 npm tarball 一致。维护者发布前通过 `scripts/release-assets.mjs` 生成 formula,工作流发布前会再次比较生成结果与已提交文件。
|
|
56
|
-
|
|
57
|
-
The `sha256` in `Formula/aicommit.rb` must match the corresponding npm tarball. Maintainers generate the formula with `scripts/release-assets.mjs`, and the release workflow compares it again before publishing.
|
|
58
|
-
|
|
59
33
|
## Rollback / 回滚
|
|
60
34
|
|
|
61
35
|
npm 用户可以立即固定上一可用版本:
|
|
@@ -64,13 +38,4 @@ npm 用户可以立即固定上一可用版本:
|
|
|
64
38
|
npm install --global @hifullmoon/aicommit@<last-good-version>
|
|
65
39
|
```
|
|
66
40
|
|
|
67
|
-
Homebrew 用户可从旧 tag 取出 formula 并本地安装:
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
git clone https://github.com/hi-fullmoon/AICommit.git /tmp/aicommit-rollback
|
|
71
|
-
git -C /tmp/aicommit-rollback show v1.4.0:Formula/aicommit.rb > /tmp/aicommit.rb
|
|
72
|
-
brew uninstall aicommit
|
|
73
|
-
brew install --formula /tmp/aicommit.rb
|
|
74
|
-
```
|
|
75
|
-
|
|
76
41
|
已发布的 npm version 不应覆盖或复用。维护者应 deprecate 有问题的版本、恢复正确的 dist-tag,并发布修复 patch。完整流程见 [`RELEASING.md`](../RELEASING.md)。
|
package/docs/privacy.md
CHANGED
|
@@ -6,14 +6,14 @@ AICommit 是本地 CLI,不是托管中转服务。仓库数据从本地进程
|
|
|
6
6
|
|
|
7
7
|
## Trust boundaries / 信任边界
|
|
8
8
|
|
|
9
|
-
| Boundary / 边界
|
|
10
|
-
|
|
|
11
|
-
| Main CLI process / CLI 主进程
|
|
12
|
-
| Git subprocess / Git 子进程
|
|
13
|
-
| Provider endpoint / Provider 端点
|
|
14
|
-
| Extension child / 扩展子进程
|
|
15
|
-
| Local metrics file / 本地指标文件
|
|
16
|
-
| GitHub/npm
|
|
9
|
+
| Boundary / 边界 | Data visible there / 可见数据 | Default control / 默认控制 |
|
|
10
|
+
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| Main CLI process / CLI 主进程 | Selected Git metadata/diff, effective config, resolved provider credential / 选定 Git 元数据与 diff、有效配置、provider 凭据 | User config owns connection fields; project config is filtered / 连接字段归用户配置,项目配置受过滤 |
|
|
12
|
+
| Git subprocess / Git 子进程 | Requested status, diff, index/tree operations / 请求的 status、diff、index/tree 操作 | Explicit arguments, temporary indexes, fingerprints and recovery checkpoints / 显式参数、临时 index、指纹与恢复 checkpoint |
|
|
13
|
+
| Provider endpoint / Provider 端点 | Prompt, protected selected diff/context, model options, Bearer credential / prompt、保护后的选定 diff/context、模型选项、Bearer 凭据 | Remote HTTPS except loopback; preview/protection before send; bounded context / 远端仅 HTTPS;发送前预览/保护;上下文有预算 |
|
|
14
|
+
| Extension child / 扩展子进程 | Only the input for its declared interface / 仅声明接口所需输入 | Sanitized environment, no resolved credential, Node permission model, timeout/output bounds / 清理环境、不传凭据、Node 权限模型、超时/输出限制 |
|
|
15
|
+
| Local metrics file / 本地指标文件 | Duration, token totals, bounded result, edited/rewrite flags / 延迟、token 总量、结果类别、编辑/重写标记 | Local-only, owner permissions, retention cap, disable/clear controls / 仅本地、owner 权限、保留上限、可关闭/清除 |
|
|
16
|
+
| GitHub/npm during installation / 安装期 GitHub/npm | Package download metadata / package 下载元数据 | Version tag and npm Trusted Publishing provenance / 版本 tag 与 npm Trusted Publishing provenance |
|
|
17
17
|
|
|
18
18
|
## Provider request contents / Provider 请求内容
|
|
19
19
|
|
package/docs/provider-presets.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Provider presets / Provider 预设
|
|
2
2
|
|
|
3
|
-
Provider presets are versioned setup data, not request code. The stable adapters in `src/providers.js` own request/response behavior; `presets/provider-presets.json`
|
|
3
|
+
Provider presets are versioned setup data, not request code. The stable adapters in `src/providers.js` own request/response behavior; `presets/provider-presets.json` supplies a provider ID, display label, adapter ID, secure endpoint, a named model map, and the default model name. Each model supplies its API `modelId` and may include a label or bounded `extraBody` defaults. Adding another OpenAI-compatible service with the `custom` adapter does not change Git, interaction, or request orchestration code.
|
|
4
4
|
|
|
5
|
-
Provider preset 是带版本的 setup 数据,不是请求代码。`src/providers.js` 中的稳定 adapter 负责请求/响应行为;`presets/provider-presets.json`
|
|
5
|
+
Provider preset 是带版本的 setup 数据,不是请求代码。`src/providers.js` 中的稳定 adapter 负责请求/响应行为;`presets/provider-presets.json` 提供 provider ID、显示名称、adapter ID、安全 endpoint、命名模型表和默认模型名。每个模型提供 API `modelId`,也可提供显示名称或有界的 `extraBody` 默认值。使用 `custom` adapter 新增另一个 OpenAI-compatible 服务时,不需要修改 Git、交互或请求编排代码。
|
|
6
6
|
|
|
7
7
|
## Compatibility contract / 兼容契约
|
|
8
8
|
|
|
@@ -13,11 +13,11 @@ Every manifest declares:
|
|
|
13
13
|
```json
|
|
14
14
|
{
|
|
15
15
|
"kind": "aicommit-provider-presets",
|
|
16
|
-
"schemaVersion":
|
|
17
|
-
"version": "
|
|
16
|
+
"schemaVersion": 2,
|
|
17
|
+
"version": "2.0.0",
|
|
18
18
|
"compatibility": {
|
|
19
|
-
"coreMinimum": "1.
|
|
20
|
-
"coreMaximumExclusive": "
|
|
19
|
+
"coreMinimum": "1.5.1",
|
|
20
|
+
"coreMaximumExclusive": "3.0.0",
|
|
21
21
|
"adapterContract": 1
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -27,13 +27,15 @@ Every manifest declares:
|
|
|
27
27
|
- The core range is inclusive at `coreMinimum` and exclusive at `coreMaximumExclusive`.
|
|
28
28
|
- Core prerelease versions and build metadata follow SemVer; build metadata is ignored for precedence.
|
|
29
29
|
- `adapterContract` declares the request-adapter interface expected by every entry.
|
|
30
|
-
-
|
|
30
|
+
- Every provider declares a non-empty `models` map and a `defaultModel` that references one entry. Model names are setup aliases; `modelId` is sent to the API.
|
|
31
|
+
- The runtime rejects unknown fields, duplicate/reserved IDs, unsupported adapters, remote HTTP, credentials, model-level `model`/`messages` overrides, oversized data, incompatible versions, and symlinked files.
|
|
31
32
|
|
|
32
33
|
- `version` 标识可独立替换的 preset 数据版本。
|
|
33
34
|
- core 范围包含 `coreMinimum`,不包含 `coreMaximumExclusive`。
|
|
34
35
|
- Core 的预发布版本与构建元数据遵循 SemVer;构建元数据不参与优先级比较。
|
|
35
36
|
- `adapterContract` 声明每个条目所依赖的请求 adapter 接口。
|
|
36
|
-
-
|
|
37
|
+
- 每个 Provider 都声明非空 `models`,并通过 `defaultModel` 引用其中一项。模型名是 setup 使用的别名,`modelId` 才会发送给 API。
|
|
38
|
+
- 运行时拒绝未知字段、重复/保留 ID、不支持的 adapter、远程 HTTP、凭据、模型级 `model`/`messages` 覆盖、超限数据、不兼容版本和符号链接文件。
|
|
37
39
|
|
|
38
40
|
The published JSON Schema is [`schemas/aicommit-provider-presets.schema.json`](../schemas/aicommit-provider-presets.schema.json). Runtime validation is authoritative and adds semantic/security checks that JSON Schema alone cannot express.
|
|
39
41
|
|
|
@@ -91,7 +93,18 @@ Add one entry to a copied manifest, bump `version`, validate, and install it:
|
|
|
91
93
|
"label": "Acme Compatible",
|
|
92
94
|
"adapter": "custom",
|
|
93
95
|
"apiUrl": "https://api.acme.example/v1/chat/completions",
|
|
94
|
-
"
|
|
96
|
+
"defaultModel": "fast",
|
|
97
|
+
"models": {
|
|
98
|
+
"fast": {
|
|
99
|
+
"label": "Acme Chat",
|
|
100
|
+
"modelId": "acme-chat"
|
|
101
|
+
},
|
|
102
|
+
"quality": {
|
|
103
|
+
"label": "Acme Reasoner",
|
|
104
|
+
"modelId": "acme-reasoner",
|
|
105
|
+
"extraBody": { "reasoning": true }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
95
108
|
}
|
|
96
109
|
```
|
|
97
110
|
|
package/docs/troubleshooting.md
CHANGED
|
@@ -29,7 +29,6 @@ JSON 模式保证 stdout 只有一个机器对象,诊断进入 stderr。`error
|
|
|
29
29
|
| Preset install/rollback fails / preset 安装或回滚失败 | `config` / `2` | Schema/core range/adapter contract mismatch or no valid backup / schema、核心范围、adapter contract 不匹配或无备份 | `aicommit preset validate --file=...`; `aicommit preset show`; follow the compatibility guide |
|
|
30
30
|
| Extension requires Node 20+ / 扩展要求 Node 20+ | `config` / `2` | Node 18 intentionally has no executable-extension fallback / Node 18 有意不降级运行扩展 | Upgrade Node for extensions or remove user manifest entries; core CLI still supports Node 18 |
|
|
31
31
|
| Extension timeout or permission error / 扩展超时或权限错误 | warning or `response_format` | Extension exceeded its limit or tried denied filesystem/process access / 扩展超时或访问被拒资源 | Review the extension, keep it single-file, raise `extensions.timeoutMs` cautiously; validator failures are fail-closed |
|
|
32
|
-
| `brew install` checksum mismatch / Homebrew checksum 不一致 | Homebrew failure | Formula and registry tarball differ, stale tap, or tampered download / formula 与 tarball 不同、tap 过旧或下载被篡改 | `brew update`; compare `Formula/aicommit.rb` with the npm tarball; do not use `--force` to bypass integrity |
|
|
33
32
|
| npm provenance is absent or invalid / npm provenance 缺失或失败 | npm audit failure | Old npm CLI, non-trusted release, or wrong version / npm 过旧、非可信发布或版本错误 | Upgrade npm; run `npm audit signatures`; install only a version linked to the official workflow |
|
|
34
33
|
|
|
35
34
|
If a failure remains, capture `aicommit doctor --output=json`, Node/Git versions, the error category, and redacted config sources. Never attach a diff, commit message, config file, API key, reasoning trace, extension source containing secrets, or credential-helper output to a public issue.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hifullmoon/aicommit",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Safe, local-first AI commit message generator for Git workflows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,9 +29,8 @@
|
|
|
29
29
|
"coverage": "c8 node --test --test-concurrency=1",
|
|
30
30
|
"eval": "node eval/run.mjs",
|
|
31
31
|
"test:package": "node scripts/package-smoke.mjs",
|
|
32
|
-
"test:homebrew": "node scripts/homebrew-smoke.mjs",
|
|
33
32
|
"docs:terminal-demo": "node scripts/readme-terminal-demo.mjs",
|
|
34
|
-
"release:
|
|
33
|
+
"release:version": "node scripts/update-version.mjs",
|
|
35
34
|
"release:npm:check": "node scripts/verify-release.mjs && npm run ci && npm run test:package && npm pack --dry-run",
|
|
36
35
|
"ci": "npm run lint && npm run format:check && npm run eval && npm run coverage"
|
|
37
36
|
},
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"kind": "aicommit-provider-presets",
|
|
3
|
-
"schemaVersion":
|
|
4
|
-
"version": "
|
|
3
|
+
"schemaVersion": 2,
|
|
4
|
+
"version": "2.0.0",
|
|
5
5
|
"compatibility": {
|
|
6
|
-
"coreMinimum": "1.
|
|
7
|
-
"coreMaximumExclusive": "
|
|
6
|
+
"coreMinimum": "1.5.1",
|
|
7
|
+
"coreMaximumExclusive": "3.0.0",
|
|
8
8
|
"adapterContract": 1
|
|
9
9
|
},
|
|
10
10
|
"providers": [
|
|
@@ -13,33 +13,55 @@
|
|
|
13
13
|
"label": "OpenAI",
|
|
14
14
|
"adapter": "openai",
|
|
15
15
|
"apiUrl": "https://api.openai.com/v1/chat/completions",
|
|
16
|
-
"
|
|
16
|
+
"defaultModel": "gpt-4o",
|
|
17
|
+
"models": {
|
|
18
|
+
"gpt-4o": {
|
|
19
|
+
"label": "GPT-4o",
|
|
20
|
+
"modelId": "gpt-4o"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
17
23
|
},
|
|
18
24
|
{
|
|
19
25
|
"id": "deepseek",
|
|
20
26
|
"label": "DeepSeek",
|
|
21
27
|
"adapter": "deepseek",
|
|
22
28
|
"apiUrl": "https://api.deepseek.com/v1/chat/completions",
|
|
23
|
-
"
|
|
29
|
+
"defaultModel": "chat",
|
|
30
|
+
"models": {
|
|
31
|
+
"chat": {
|
|
32
|
+
"label": "DeepSeek Chat",
|
|
33
|
+
"modelId": "deepseek-v4-flash"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
24
36
|
},
|
|
25
37
|
{
|
|
26
38
|
"id": "openrouter",
|
|
27
39
|
"label": "OpenRouter",
|
|
28
40
|
"adapter": "openrouter",
|
|
29
41
|
"apiUrl": "https://openrouter.ai/api/v1/chat/completions",
|
|
30
|
-
"
|
|
42
|
+
"defaultModel": "default",
|
|
43
|
+
"models": {
|
|
44
|
+
"default": {
|
|
45
|
+
"modelId": "openai/gpt-4o-mini"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
31
48
|
},
|
|
32
49
|
{
|
|
33
50
|
"id": "minimax",
|
|
34
51
|
"label": "MiniMax",
|
|
35
52
|
"adapter": "minimax",
|
|
36
53
|
"apiUrl": "https://api.minimaxi.com/v1/chat/completions",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
"defaultModel": "default",
|
|
55
|
+
"models": {
|
|
56
|
+
"default": {
|
|
57
|
+
"modelId": "MiniMax-M3",
|
|
58
|
+
"extraBody": {
|
|
59
|
+
"thinking": {
|
|
60
|
+
"type": "disabled"
|
|
61
|
+
},
|
|
62
|
+
"reasoning_split": true
|
|
63
|
+
}
|
|
64
|
+
}
|
|
43
65
|
}
|
|
44
66
|
},
|
|
45
67
|
{
|
|
@@ -47,14 +69,25 @@
|
|
|
47
69
|
"label": "Kimi Code",
|
|
48
70
|
"adapter": "custom",
|
|
49
71
|
"apiUrl": "https://api.kimi.com/coding/v1/chat/completions",
|
|
50
|
-
"
|
|
72
|
+
"defaultModel": "default",
|
|
73
|
+
"models": {
|
|
74
|
+
"default": {
|
|
75
|
+
"modelId": "kimi-for-coding"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
51
78
|
},
|
|
52
79
|
{
|
|
53
80
|
"id": "ollama",
|
|
54
81
|
"label": "Ollama (local)",
|
|
55
82
|
"adapter": "ollama",
|
|
56
83
|
"apiUrl": "http://127.0.0.1:11434/api/chat",
|
|
57
|
-
"
|
|
84
|
+
"defaultModel": "qwen",
|
|
85
|
+
"models": {
|
|
86
|
+
"qwen": {
|
|
87
|
+
"label": "Qwen 3 8B",
|
|
88
|
+
"modelId": "qwen3:8b"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
58
91
|
}
|
|
59
92
|
]
|
|
60
93
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"required": ["kind", "schemaVersion", "version", "compatibility", "providers"],
|
|
8
8
|
"properties": {
|
|
9
9
|
"kind": { "const": "aicommit-provider-presets" },
|
|
10
|
-
"schemaVersion": { "const":
|
|
10
|
+
"schemaVersion": { "const": 2 },
|
|
11
11
|
"version": {
|
|
12
12
|
"type": "string",
|
|
13
13
|
"pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$"
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"items": {
|
|
36
36
|
"type": "object",
|
|
37
37
|
"additionalProperties": false,
|
|
38
|
-
"required": ["id", "label", "adapter", "apiUrl", "
|
|
38
|
+
"required": ["id", "label", "adapter", "apiUrl", "defaultModel", "models"],
|
|
39
39
|
"properties": {
|
|
40
40
|
"id": {
|
|
41
41
|
"type": "string",
|
|
@@ -47,8 +47,28 @@
|
|
|
47
47
|
"enum": ["openai", "openrouter", "deepseek", "minimax", "ollama", "custom"]
|
|
48
48
|
},
|
|
49
49
|
"apiUrl": { "type": "string", "minLength": 1, "maxLength": 2048 },
|
|
50
|
-
"
|
|
51
|
-
|
|
50
|
+
"defaultModel": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$"
|
|
53
|
+
},
|
|
54
|
+
"models": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"minProperties": 1,
|
|
57
|
+
"maxProperties": 100,
|
|
58
|
+
"propertyNames": {
|
|
59
|
+
"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$"
|
|
60
|
+
},
|
|
61
|
+
"additionalProperties": {
|
|
62
|
+
"type": "object",
|
|
63
|
+
"additionalProperties": false,
|
|
64
|
+
"required": ["modelId"],
|
|
65
|
+
"properties": {
|
|
66
|
+
"label": { "type": "string", "minLength": 1, "maxLength": 80 },
|
|
67
|
+
"modelId": { "type": "string", "minLength": 1, "maxLength": 256 },
|
|
68
|
+
"extraBody": { "type": "object" }
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
52
72
|
}
|
|
53
73
|
}
|
|
54
74
|
}
|
package/src/cli.js
CHANGED
|
@@ -45,6 +45,7 @@ function showHelp() {
|
|
|
45
45
|
-v, --version Show version number
|
|
46
46
|
-l, --lang=<zh|en> Commit message language (default: zh)
|
|
47
47
|
-p, --provider=<name> Use the named provider from config "providers"
|
|
48
|
+
-m, --model=<name> Use a named model from the selected provider
|
|
48
49
|
--split-hunks Experimental same-file hunk planning (default: off)
|
|
49
50
|
--scope=<scope> Scope for "split|split plan": staged, all
|
|
50
51
|
--file=<path> Split-plan artifact or commit-message file
|
|
@@ -72,7 +73,7 @@ function showHelp() {
|
|
|
72
73
|
aicommit stats Show local acceptance, quality, latency, and token trends
|
|
73
74
|
aicommit Commit changes in current directory (Chinese)
|
|
74
75
|
aicommit --lang=en Generate English commit message
|
|
75
|
-
aicommit -p deepseek
|
|
76
|
+
aicommit -p deepseek -m chat Select a configured provider and model
|
|
76
77
|
aicommit split Choose staged/all scope, then plan logical commits
|
|
77
78
|
aicommit split --scope=staged Split only the reviewed index snapshot
|
|
78
79
|
aicommit split --scope=all --yes Split the complete working tree non-interactively
|
|
@@ -109,6 +110,7 @@ function parsedDefaults(overrides = {}) {
|
|
|
109
110
|
targetPath: null,
|
|
110
111
|
cliLang: null,
|
|
111
112
|
cliProvider: null,
|
|
113
|
+
cliModel: null,
|
|
112
114
|
cliReasoning: null,
|
|
113
115
|
output: 'text',
|
|
114
116
|
debug: false,
|
|
@@ -228,6 +230,7 @@ export function parseArgs(args = process.argv.slice(2)) {
|
|
|
228
230
|
let targetPath = null;
|
|
229
231
|
let cliLang = null;
|
|
230
232
|
let cliProvider = null;
|
|
233
|
+
let cliModel = null;
|
|
231
234
|
let cliReasoning = null;
|
|
232
235
|
let output = 'text';
|
|
233
236
|
let debug = false;
|
|
@@ -387,6 +390,23 @@ export function parseArgs(args = process.argv.slice(2)) {
|
|
|
387
390
|
continue;
|
|
388
391
|
}
|
|
389
392
|
|
|
393
|
+
if (arg === '-m' || arg === '--model') {
|
|
394
|
+
cliModel = takeValue(args, i, arg, 'name');
|
|
395
|
+
i++;
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (arg.startsWith('--model=')) {
|
|
400
|
+
cliModel = arg.slice('--model='.length);
|
|
401
|
+
if (!cliModel) throw fail(ERROR_CATEGORIES.CONFIG, 'Missing value for --model.');
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (arg.startsWith('-m') && arg.length > 2) {
|
|
406
|
+
cliModel = arg.slice(2);
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
|
|
390
410
|
if (!arg.startsWith('-')) {
|
|
391
411
|
if (targetPath) {
|
|
392
412
|
throw fail(
|
|
@@ -439,7 +459,7 @@ export function parseArgs(args = process.argv.slice(2)) {
|
|
|
439
459
|
'split apply reads its scope from the plan; do not pass --scope or --split-hunks.',
|
|
440
460
|
);
|
|
441
461
|
}
|
|
442
|
-
if (cliProvider || cliLang || cliReasoning || dryRun) {
|
|
462
|
+
if (cliProvider || cliModel || cliLang || cliReasoning || dryRun) {
|
|
443
463
|
throw fail(
|
|
444
464
|
ERROR_CATEGORIES.CONFIG,
|
|
445
465
|
'split apply accepts only --file, --yes, --output, and --debug.',
|
|
@@ -451,6 +471,7 @@ export function parseArgs(args = process.argv.slice(2)) {
|
|
|
451
471
|
split ||
|
|
452
472
|
splitHunks ||
|
|
453
473
|
cliProvider ||
|
|
474
|
+
cliModel ||
|
|
454
475
|
cliLang ||
|
|
455
476
|
cliReasoning ||
|
|
456
477
|
dryRun
|
|
@@ -484,15 +505,23 @@ export function parseArgs(args = process.argv.slice(2)) {
|
|
|
484
505
|
) {
|
|
485
506
|
throw fail(
|
|
486
507
|
ERROR_CATEGORIES.CONFIG,
|
|
487
|
-
'config accepts only an optional path, --provider, --output, and --debug.',
|
|
508
|
+
'config accepts only an optional path, --provider, --model, --output, and --debug.',
|
|
488
509
|
);
|
|
489
510
|
}
|
|
490
|
-
if (configAction === 'path' && cliProvider) {
|
|
491
|
-
throw fail(ERROR_CATEGORIES.CONFIG, 'config path does not accept --provider.');
|
|
511
|
+
if (configAction === 'path' && (cliProvider || cliModel)) {
|
|
512
|
+
throw fail(ERROR_CATEGORIES.CONFIG, 'config path does not accept --provider or --model.');
|
|
492
513
|
}
|
|
493
514
|
if (
|
|
494
515
|
policyAction &&
|
|
495
|
-
(cliProvider ||
|
|
516
|
+
(cliProvider ||
|
|
517
|
+
cliModel ||
|
|
518
|
+
cliLang ||
|
|
519
|
+
cliReasoning ||
|
|
520
|
+
split ||
|
|
521
|
+
splitHunks ||
|
|
522
|
+
splitCommand ||
|
|
523
|
+
dryRun ||
|
|
524
|
+
yes)
|
|
496
525
|
) {
|
|
497
526
|
throw fail(
|
|
498
527
|
ERROR_CATEGORIES.CONFIG,
|
|
@@ -509,6 +538,7 @@ export function parseArgs(args = process.argv.slice(2)) {
|
|
|
509
538
|
presetAction &&
|
|
510
539
|
(targetPath ||
|
|
511
540
|
cliProvider ||
|
|
541
|
+
cliModel ||
|
|
512
542
|
cliLang ||
|
|
513
543
|
cliReasoning ||
|
|
514
544
|
split ||
|
|
@@ -534,7 +564,7 @@ export function parseArgs(args = process.argv.slice(2)) {
|
|
|
534
564
|
) {
|
|
535
565
|
throw fail(
|
|
536
566
|
ERROR_CATEGORIES.CONFIG,
|
|
537
|
-
'doctor accepts only --provider, --output, and --debug options.',
|
|
567
|
+
'doctor accepts only --provider, --model, --output, and --debug options.',
|
|
538
568
|
);
|
|
539
569
|
}
|
|
540
570
|
|
|
@@ -542,6 +572,7 @@ export function parseArgs(args = process.argv.slice(2)) {
|
|
|
542
572
|
targetPath,
|
|
543
573
|
cliLang,
|
|
544
574
|
cliProvider,
|
|
575
|
+
cliModel,
|
|
545
576
|
cliReasoning,
|
|
546
577
|
output,
|
|
547
578
|
debug,
|
package/src/completion.js
CHANGED
|
@@ -11,6 +11,7 @@ const TOP_LEVEL = [
|
|
|
11
11
|
'--version',
|
|
12
12
|
'--lang',
|
|
13
13
|
'--provider',
|
|
14
|
+
'--model',
|
|
14
15
|
'--split-hunks',
|
|
15
16
|
'--scope',
|
|
16
17
|
'--reasoning',
|
|
@@ -30,7 +31,7 @@ _aicommit() {
|
|
|
30
31
|
command="\${COMP_WORDS[1]}"
|
|
31
32
|
|
|
32
33
|
case "$command" in
|
|
33
|
-
config) COMPREPLY=( $(compgen -W "show validate path --provider --output --debug" -- "$cur") ); return ;;
|
|
34
|
+
config) COMPREPLY=( $(compgen -W "show validate path --provider --model --output --debug" -- "$cur") ); return ;;
|
|
34
35
|
policy) COMPREPLY=( $(compgen -W "template check --file --range --output --debug" -- "$cur") ); return ;;
|
|
35
36
|
preset) COMPREPLY=( $(compgen -W "show validate path install rollback --file --output --debug" -- "$cur") ); return ;;
|
|
36
37
|
completion) COMPREPLY=( $(compgen -W "bash zsh fish" -- "$cur") ); return ;;
|
|
@@ -66,6 +67,7 @@ _aicommit() {
|
|
|
66
67
|
'--version[show version]'
|
|
67
68
|
'--lang=[commit language]:language:(zh en)'
|
|
68
69
|
'--provider=[provider name]:provider:'
|
|
70
|
+
'--model=[model name]:model:'
|
|
69
71
|
'--split-hunks[experimental same-file hunk splitting]'
|
|
70
72
|
'--scope=[split scope]:scope:(staged all)'
|
|
71
73
|
'--file=[split plan or commit-message file]:path:_files'
|
|
@@ -115,6 +117,7 @@ complete -c aicommit -s h -l help -d 'Show help'
|
|
|
115
117
|
complete -c aicommit -s v -l version -d 'Show version'
|
|
116
118
|
complete -c aicommit -s l -l lang -x -a 'zh en' -d 'Commit language'
|
|
117
119
|
complete -c aicommit -s p -l provider -x -d 'Provider name'
|
|
120
|
+
complete -c aicommit -s m -l model -x -d 'Model name'
|
|
118
121
|
complete -c aicommit -l split-hunks -d 'Experimental same-file hunk splitting'
|
|
119
122
|
complete -c aicommit -l scope -x -a 'staged all' -d 'Split plan scope'
|
|
120
123
|
complete -c aicommit -l file -r -d 'Split plan file'
|
package/src/config-command.js
CHANGED
|
@@ -28,7 +28,10 @@ function printPaths(paths) {
|
|
|
28
28
|
);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export async function runConfigCommand(
|
|
31
|
+
export async function runConfigCommand(
|
|
32
|
+
action,
|
|
33
|
+
{ provider = null, model = null, machineOutput = false } = {},
|
|
34
|
+
) {
|
|
32
35
|
const projectRoot = getProjectRoot();
|
|
33
36
|
const paths = await inspectConfigPaths(projectRoot);
|
|
34
37
|
if (action === 'path') {
|
|
@@ -36,18 +39,17 @@ export async function runConfigCommand(action, { provider = null, machineOutput
|
|
|
36
39
|
return { exitReason: 'config_path', data: { projectRoot, paths } };
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
const loaded = await loadConfig(provider, { resolveCredentials: false });
|
|
42
|
+
const loaded = await loadConfig(provider, { model, resolveCredentials: false });
|
|
40
43
|
const data = {
|
|
41
44
|
projectRoot: loaded.projectRoot,
|
|
42
45
|
sources: loaded.loaded,
|
|
43
46
|
provider: loaded.providerName,
|
|
47
|
+
model: loaded.modelName,
|
|
44
48
|
paths,
|
|
45
49
|
};
|
|
46
50
|
if (action === 'validate') {
|
|
47
51
|
if (!machineOutput) {
|
|
48
|
-
console.log(
|
|
49
|
-
`Configuration valid${loaded.providerName ? ` for provider "${loaded.providerName}"` : ''}.`,
|
|
50
|
-
);
|
|
52
|
+
console.log(`Configuration valid for ${loaded.providerName}/${loaded.modelName}.`);
|
|
51
53
|
printPaths(paths);
|
|
52
54
|
}
|
|
53
55
|
return { exitReason: 'config_valid', data };
|