@hifullmoon/aicommit 1.4.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.
Files changed (57) hide show
  1. package/.aicommit.config.example.json +118 -0
  2. package/CHANGELOG.md +131 -0
  3. package/LICENSE +21 -0
  4. package/README.md +406 -0
  5. package/README.zh-CN.md +408 -0
  6. package/SECURITY.md +33 -0
  7. package/bin/aicommit.js +47 -0
  8. package/docs/distribution.md +104 -0
  9. package/docs/examples/aicommit-policy.yml +24 -0
  10. package/docs/examples/commit-msg +4 -0
  11. package/docs/examples/extension/aicommit-extension.json +9 -0
  12. package/docs/examples/extension/index.mjs +32 -0
  13. package/docs/extensions.md +93 -0
  14. package/docs/privacy.md +58 -0
  15. package/docs/provider-compatibility.md +37 -0
  16. package/docs/provider-presets.md +100 -0
  17. package/docs/team-policy.md +86 -0
  18. package/docs/troubleshooting.md +37 -0
  19. package/package.json +100 -0
  20. package/presets/provider-presets.json +60 -0
  21. package/schemas/aicommit-extension.schema.json +27 -0
  22. package/schemas/aicommit-output.schema.json +86 -0
  23. package/schemas/aicommit-provider-presets.schema.json +56 -0
  24. package/schemas/aicommit-split-checkpoint.schema.json +92 -0
  25. package/schemas/aicommit-split-plan.schema.json +108 -0
  26. package/schemas/aicommit-team-policy.schema.json +59 -0
  27. package/src/api.js +740 -0
  28. package/src/cli.js +558 -0
  29. package/src/completion.js +136 -0
  30. package/src/config-command.js +59 -0
  31. package/src/config.js +524 -0
  32. package/src/context.js +537 -0
  33. package/src/credentials.js +123 -0
  34. package/src/doctor.js +131 -0
  35. package/src/errors.js +96 -0
  36. package/src/extension-runner.mjs +36 -0
  37. package/src/extensions.js +426 -0
  38. package/src/generation-ui.js +53 -0
  39. package/src/git.js +458 -0
  40. package/src/main.js +768 -0
  41. package/src/metrics.js +375 -0
  42. package/src/output.js +87 -0
  43. package/src/policy-command.js +172 -0
  44. package/src/policy.js +421 -0
  45. package/src/preset-command.js +91 -0
  46. package/src/provider-presets.js +361 -0
  47. package/src/providers.js +306 -0
  48. package/src/setup.js +268 -0
  49. package/src/split-checkpoint.js +252 -0
  50. package/src/split-hunks.js +263 -0
  51. package/src/split-plan.js +339 -0
  52. package/src/split.js +2285 -0
  53. package/src/team-policy.js +95 -0
  54. package/src/trust.js +31 -0
  55. package/src/ui.js +488 -0
  56. package/src/utils.js +165 -0
  57. package/templates/.aicommit.policy.json +22 -0
@@ -0,0 +1,32 @@
1
+ export function contextProvider({ files }) {
2
+ const packages = [...new Set(files.map(({ path }) => path.split('/')[0]).filter(Boolean))];
3
+ return { text: `Changed top-level areas: ${packages.join(', ')}`, warnings: [] };
4
+ }
5
+
6
+ export function messageValidator({ message }) {
7
+ return {
8
+ issues: /(?:ACME|ticket)-\d+/i.test(message)
9
+ ? []
10
+ : [{ severity: 'warning', code: 'ticket', message: 'consider including a ticket id' }],
11
+ };
12
+ }
13
+
14
+ export function providerAdapter({ operation, config, request, response, reasoning }) {
15
+ if (operation === 'buildRequest') {
16
+ return {
17
+ model: config.modelId,
18
+ input: request.messages,
19
+ max_output_tokens: request.maxTokens,
20
+ };
21
+ }
22
+ if (operation === 'normalizeResponse') {
23
+ return {
24
+ content: response.output_text || '',
25
+ model: response.model,
26
+ usage: response.usage,
27
+ finishReason: response.status,
28
+ };
29
+ }
30
+ if (operation === 'reasoningForFollowUp') return { ...reasoning, mode: 'off' };
31
+ throw new Error(`Unsupported providerAdapter operation: ${operation}`);
32
+ }
@@ -0,0 +1,93 @@
1
+ # Extensions / 扩展
2
+
3
+ AICommit extension API v1 exposes three deliberately small interfaces without loading third-party code into the CLI process. Extensions are user-installed single-file ESM modules and are never enabled by repository config.
4
+
5
+ AICommit 扩展 API v1 提供三个刻意保持精简的接口,第三方代码不会加载到 CLI 主进程。扩展由用户以单文件 ESM 模块安装,仓库配置无权启用扩展。
6
+
7
+ ## Security model / 安全模型
8
+
9
+ - Every manifest must declare `"permissions": { "credentials": false }`; v1 rejects every other value.
10
+ - The extension process receives no AICommit API key, credential-helper result, `HOME`/`USERPROFILE` value, or inherited secret environment variable.
11
+ - On Node.js 20+, the child runs with Node's permission model and may read only the packaged runner and its own `.mjs` entry. File writes, child processes, workers, and unrelated reads are denied.
12
+ - Node.js 18 remains supported for core AICommit. Executable extensions fail clearly instead of running without isolation; use Node.js 20+ when extensions are enabled.
13
+ - A context provider receives bounded branch/file metadata, a validator receives the candidate and normalized policy, and an adapter receives non-secret provider settings plus the request/response value needed for its operation.
14
+ - Extensions can observe the data passed to their selected capability and may have network access, including access to services reachable from the machine. Node's permission model is defense in depth, not a substitute for reviewing third-party code. Keep the manifest and entry in a dedicated directory; imports and multi-file packages are intentionally outside v1.
15
+
16
+ - 每个清单必须声明 `"permissions": { "credentials": false }`,v1 会拒绝其他值。
17
+ - 扩展进程不会收到 AICommit API key、credential helper 结果、`HOME`/`USERPROFILE` 值或继承的秘密环境变量。
18
+ - 在 Node.js 20+ 上,子进程使用 Node 权限模型,只能读取随包发布的 runner 和自己的 `.mjs` 入口;文件写入、子进程、worker 与无关文件读取均被拒绝。
19
+ - Node.js 18 仍可运行 AICommit 核心;启用扩展时会明确失败,而不会在无隔离条件下降级执行。扩展场景请使用 Node.js 20+。
20
+ - context provider 只收到受限的分支/文件元数据,validator 收到候选消息和标准化 policy,adapter 只收到非敏感 provider 设置及当前操作需要的请求/响应值。
21
+ - 扩展能看到其接口明确收到的数据,也可能访问网络,包括本机可达的服务。Node 权限模型是纵深防御,不能替代第三方代码审查。请把清单和入口放进独立目录;v1 有意不支持 import 和多文件扩展包。
22
+
23
+ ## Manifest and configuration / 清单与配置
24
+
25
+ Copy the executable example in [`docs/examples/extension`](examples/extension), then add its absolute manifest path to the user config:
26
+
27
+ 复制 [`docs/examples/extension`](examples/extension) 中的可执行示例,再把清单绝对路径写入用户配置:
28
+
29
+ ```json
30
+ {
31
+ "extensions": {
32
+ "manifests": ["/Users/me/.aicommit/extensions/team-rules/aicommit-extension.json"],
33
+ "timeoutMs": 3000,
34
+ "maxContextChars": 2000
35
+ }
36
+ }
37
+ ```
38
+
39
+ ```json
40
+ {
41
+ "kind": "aicommit-extension",
42
+ "apiVersion": 1,
43
+ "id": "team-rules",
44
+ "version": "1.0.0",
45
+ "entry": "./index.mjs",
46
+ "capabilities": ["contextProvider", "messageValidator", "providerAdapter"],
47
+ "permissions": { "credentials": false }
48
+ }
49
+ ```
50
+
51
+ Validate the config shape without resolving credentials, then exercise the installed code through a dry run or doctor:
52
+
53
+ 先在不解析凭据的情况下校验配置结构,再通过 dry run 或 doctor 实际加载扩展:
54
+
55
+ ```bash
56
+ aicommit config validate
57
+ aicommit --dry-run
58
+ aicommit doctor
59
+ ```
60
+
61
+ The published JSON Schema is [`schemas/aicommit-extension.schema.json`](../schemas/aicommit-extension.schema.json).
62
+
63
+ ## Interface contract / 接口契约
64
+
65
+ All exports may be synchronous or asynchronous and must return JSON-serializable values.
66
+
67
+ 所有导出函数均可同步或异步执行,返回值必须可 JSON 序列化。
68
+
69
+ ```js
70
+ export function contextProvider({ repository, branch, files }) {
71
+ return { text: 'bounded context text', warnings: [] };
72
+ }
73
+
74
+ export function messageValidator({ message, policy }) {
75
+ return {
76
+ issues: [{ severity: 'error', code: 'ticket', message: 'ticket id required' }],
77
+ };
78
+ }
79
+
80
+ export function providerAdapter({ operation, config, request, response, reasoning }) {
81
+ if (operation === 'buildRequest') return { model: config.modelId, messages: request.messages };
82
+ if (operation === 'normalizeResponse') return { content: response.answer };
83
+ if (operation === 'reasoningForFollowUp') return { ...reasoning, mode: 'off' };
84
+ }
85
+ ```
86
+
87
+ To select the adapter, set `"providerType": "extension:team-rules"`. Core code still owns endpoint validation, timeout/retry, HTTP transport, and Bearer authorization. Adapter-produced credential-like request fields are rejected. Therefore a new body dialect can be added without modifying the core Git or interaction flow, while custom credential schemes remain intentionally unsupported by extension API v1.
88
+
89
+ 选择 adapter 时设置 `"providerType": "extension:team-rules"`。endpoint 校验、超时/重试、HTTP 传输和 Bearer 鉴权仍由核心负责。adapter 返回的疑似凭据字段会被拒绝。因此,新的请求/响应 body 方言无需修改核心 Git 或交互流程即可加入,而自定义鉴权方案在扩展 API v1 中暂不支持。
90
+
91
+ Validator errors participate in the same one-shot correction flow as built-in policy errors and fail closed if the extension crashes or returns malformed output. Context-provider failures become warnings so optional context cannot block a commit.
92
+
93
+ Validator 错误与内置 policy 错误共用一次纠正流程;扩展崩溃或返回格式错误时会 fail closed。Context provider 失败只产生 warning,避免可选上下文阻断提交。
@@ -0,0 +1,58 @@
1
+ # Privacy model / 隐私模型
2
+
3
+ AICommit is a local CLI, not a hosted relay. Repository data travels directly from the local process to the provider endpoint selected in the user-owned config. There is no telemetry upload implementation.
4
+
5
+ AICommit 是本地 CLI,不是托管中转服务。仓库数据从本地进程直接发送到用户配置选定的 provider endpoint;项目没有遥测上传实现。
6
+
7
+ ## Trust boundaries / 信任边界
8
+
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/Homebrew during installation / 安装期 GitHub/npm/Homebrew | Package/formula download metadata / 包与 formula 下载元数据 | Signed tag, Sigstore/GitHub provenance, npm provenance, SHA-256 formula pin / 签名 tag、构建证明、npm provenance、SHA-256 固定 |
17
+
18
+ ## Provider request contents / Provider 请求内容
19
+
20
+ A normal generation can send the system policy, requested language, selected changed paths/statuses, staged diff, bounded repository context, and provider/model controls. Split planning can additionally send tracked diffs and bounded previews of untracked regular files. Regeneration sends the previous message by default instead of the diff. Connection check sends only a fixed `OK` prompt.
21
+
22
+ 普通生成可能发送 system policy、语言、选定文件路径/状态、staged diff、受限仓库上下文及 provider/model 控制。Split planning 还可能发送 tracked diff 与未跟踪普通文件的受限预览。默认重写只发送上一条消息而不重发 diff。连通性检查只发送固定 `OK` prompt。
23
+
24
+ AICommit does not intentionally send unrelated files, historical commit bodies, local metric records, environment variables, its config file, Git credential-helper output, split checkpoint content, or model reasoning in machine output.
25
+
26
+ AICommit 不会主动发送无关文件、历史 commit body、本地指标、环境变量、配置文件、Git credential-helper 输出、split checkpoint 内容,也不会在机器输出中包含模型 reasoning。
27
+
28
+ ## Data minimization and sensitive content / 数据最小化与敏感内容
29
+
30
+ - Repository context and every diff category have explicit character/count ceilings and can be disabled.
31
+ - Lock files and configured generated artifacts are stubbed; oversized diffs/files are condensed.
32
+ - Common sensitive filenames, private keys, cloud access-key IDs, and credential-like assignments are omitted or redacted in the protected request.
33
+ - Repository text is encoded as untrusted JSON data under an authoritative system policy.
34
+ - Interactive users can explicitly send the original content after a warning. This is a deliberate override and should be rare.
35
+
36
+ - 仓库上下文与每类 diff 都有字符/数量上限,并可关闭。
37
+ - 锁文件与配置的生成物会被替换为占位;过大 diff/文件会被压缩。
38
+ - 常见敏感文件名、私钥、云访问 key ID 与疑似凭据赋值会在默认保护请求中省略或脱敏。
39
+ - 仓库文本作为不可信 JSON 数据编码,由权威 system policy 约束。
40
+ - 交互用户可在警告后明确发送原文;这是应谨慎使用的主动覆盖。
41
+
42
+ Detection, redaction, prompt boundaries, and the extension permission model are defense in depth, not proofs that arbitrary data or malicious code is safe. Extensions may access the network and can observe the candidate/context/response explicitly passed to their capability. Install only reviewed extensions and verify custom endpoints before sending private code.
43
+
44
+ 检测、脱敏、prompt 边界与扩展权限模型都是纵深防御,不能证明任意数据或恶意代码绝对安全。扩展可能访问网络,并能看到其 capability 明确收到的候选消息、上下文或响应。只安装已审查扩展,并在向自定义 endpoint 发送私有代码前核实其可信度。
45
+
46
+ ## Credentials and retention / 凭据与保留
47
+
48
+ Credential resolution order is environment variable → opted-in Git credential helper → literal user config → keyless loopback. Project config and team policy cannot select a credential source. The provider credential is used only by the core transport; extension API v1 always declares `credentials: false` and never receives the resolved value.
49
+
50
+ 凭据解析顺序为:环境变量 → 用户启用的 Git credential helper → 用户配置明文 → 无 key 的 loopback。项目配置和团队 policy 无权选择凭据来源。Provider 凭据只由核心传输层使用;扩展 API v1 固定声明 `credentials: false`,不会收到解析后的值。
51
+
52
+ Providers control their own server-side retention and training policies; AICommit cannot enforce them. Consult the selected provider's current terms. Locally, Git commits retain the accepted message, split checkpoints persist only code-free plan metadata until completion/recovery, and metrics retain at most the configured number of minimal records.
53
+
54
+ Provider 自行决定服务端保留与训练策略,AICommit 无法强制控制;请查阅所选 provider 的现行条款。本地 Git commit 会保留接受的消息;split checkpoint 在完成/恢复前只保存不含代码的计划元数据;metrics 最多保留配置数量的最小记录。
55
+
56
+ Use `aicommit config show`, `aicommit stats`, and `aicommit preset show` to inspect effective local state without revealing credentials. Use `aicommit stats clear` to permanently remove local metric history.
57
+
58
+ 使用 `aicommit config show`、`aicommit stats` 和 `aicommit preset show` 可在不显示凭据的情况下检查本地状态。使用 `aicommit stats clear` 可永久删除本地指标历史。
@@ -0,0 +1,37 @@
1
+ # Provider compatibility / Provider 兼容表
2
+
3
+ Provider presets choose setup defaults; adapters own request/response dialects; the core owns Git state, user interaction, HTTPS enforcement, retry, timeout, authorization, and machine output. Adding a compatible preset or an extension adapter does not modify the core Git/interaction flow.
4
+
5
+ Provider preset 只选择 setup 默认值;adapter 负责请求/响应方言;核心负责 Git 状态、用户交互、HTTPS、重试、超时、鉴权与机器输出。新增兼容 preset 或 extension adapter 无需修改核心 Git/交互流程。
6
+
7
+ | Provider / adapter | Endpoint and auth / 端点与鉴权 | Streaming / 流式 | Reasoning / 推理 | Token and usage mapping / token 与 usage | Notes / 说明 |
8
+ | ---------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
9
+ | OpenAI / `openai` | Official HTTPS Chat Completions; Bearer key / 官方 HTTPS;Bearer key | SSE | Native for recognized `o*`/`gpt-5*`; model-dependent otherwise / 已识别推理模型原生支持 | `max_completion_tokens` for reasoning models, otherwise `max_tokens`; OpenAI usage | Unsupported effort is rejected locally for known model generations / 已知模型不支持的 effort 会本地拒绝 |
10
+ | OpenRouter / `openrouter` | OpenRouter HTTPS; Bearer key; `X-Title: aicommit` | SSE | `reasoning.effort` | `max_tokens`; OpenAI-style usage | Model IDs commonly include vendor prefix / model 通常含厂商前缀 |
11
+ | DeepSeek / `deepseek` | DeepSeek HTTPS; Bearer key | SSE | `thinking.type` plus normalized effort / thinking 与归一 effort | `max_tokens`; compatible usage | `medium`/`xhigh` map to supported high behavior where required / 必要时映射为 high |
12
+ | MiniMax / `minimax` | MiniMax HTTPS; Bearer key | SSE | `reasoning_split` and thinking switch | `max_tokens`; compatible usage | Adapter removes conflicting switches before send / 发送前移除冲突开关 |
13
+ | Kimi Code / `custom` | Kimi Code OpenAI-compatible HTTPS; Bearer key / Kimi Code OpenAI 兼容 HTTPS | SSE | Server default; no vendor fields injected / 使用服务端默认值,不注入厂商字段 | `max_tokens`; OpenAI-style usage | Bundled preset uses `kimi-for-coding`; membership and Platform keys are distinct / 会员与开放平台 key 不通用 |
14
+ | Ollama native / `ollama` | Loopback `/api/chat` or `/api/generate`; normally keyless HTTP | Complete JSON in v1; native NDJSON streaming is not consumed / v1 使用完整 JSON | Native `think` boolean | `options.num_predict`; `prompt_eval_count` + `eval_count` | OpenAI-compatible `/v1/chat/completions` uses the compatible shape instead / `/v1` 使用兼容方言 |
15
+ | Custom compatible / `custom` | HTTPS remote or loopback HTTP; optional core Bearer key | SSE when endpoint supports Chat Completions events | No vendor fields by default; explicit `enabledBody`/`disabledBody` / 默认不注入厂商字段 | `max_tokens`; common OpenAI/Anthropic/Ollama usage fields normalized | Validate the endpoint before trusting it with code or credentials / 发送代码前验证端点 |
16
+ | Extension / `extension:<id>` | Core HTTPS/loopback transport and optional Bearer only / 核心传输与可选 Bearer | Declared conservative in API v1 / v1 保守声明 | Adapter operation can transform non-secret reasoning config | Adapter maps body and normalized response | No custom credential scheme or headers; credential-like body fields rejected / 不支持自定义鉴权或 header |
17
+
18
+ ## Compatibility contract / 兼容契约
19
+
20
+ All built-in adapters return `content`, optional `reasoning`, normalized usage, finish reason, raw response, capabilities, attempts, and latency. Retries cover 429, selected 5xx, and network/body interruption; authentication, invalid parameters, and safety failures are not retried.
21
+
22
+ 所有内置 adapter 返回 `content`、可选 `reasoning`、标准 usage、finish reason、raw response、capability、attempts 与 latency。仅 429、部分 5xx、网络/响应中断会重试;鉴权、参数与安全错误不会重试。
23
+
24
+ Preset compatibility is declared by core version range plus `adapterContract: 1`. Run:
25
+
26
+ Preset 兼容性由核心版本范围与 `adapterContract: 1` 共同声明:
27
+
28
+ ```bash
29
+ aicommit preset show
30
+ aicommit preset validate --file=provider-presets.json
31
+ aicommit preset install --file=provider-presets.json
32
+ aicommit doctor -p provider-name
33
+ ```
34
+
35
+ Use an existing built-in adapter when only setup defaults change. Use `custom` for an OpenAI-compatible endpoint with optional body switches. Use a reviewed `providerAdapter` extension only when the JSON request/response dialect differs and core Bearer authorization is sufficient. A protocol requiring different transport, streaming parser, or credential scheme is not compatible with extension API v1 and must not be disguised as a preset.
36
+
37
+ 若只改变 setup 默认值,应复用内置 adapter;OpenAI-compatible endpoint 及少量 body 开关使用 `custom`;仅当 JSON 请求/响应方言不同且核心 Bearer 鉴权足够时,才使用已审查的 `providerAdapter` 扩展。若协议需要不同传输、流解析或鉴权方案,则不兼容扩展 API v1,不能伪装成 preset。
@@ -0,0 +1,100 @@
1
+ # Provider presets / Provider 预设
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` only supplies a provider ID, display label, adapter ID, secure endpoint, default model, and optional bounded `extraBody` defaults. Adding another OpenAI-compatible service with the `custom` adapter does not change Git, interaction, or request orchestration code.
4
+
5
+ Provider preset 是带版本的 setup 数据,不是请求代码。`src/providers.js` 中的稳定 adapter 负责请求/响应行为;`presets/provider-presets.json` 只提供 provider ID、显示名称、adapter ID、安全 endpoint、默认模型以及可选且有界的 `extraBody` 默认值。使用 `custom` adapter 新增另一个 OpenAI-compatible 服务时,不需要修改 Git、交互或请求编排代码。
6
+
7
+ ## Compatibility contract / 兼容契约
8
+
9
+ Every manifest declares:
10
+
11
+ 每份清单都声明:
12
+
13
+ ```json
14
+ {
15
+ "kind": "aicommit-provider-presets",
16
+ "schemaVersion": 1,
17
+ "version": "1.0.0",
18
+ "compatibility": {
19
+ "coreMinimum": "1.4.0",
20
+ "coreMaximumExclusive": "2.0.0",
21
+ "adapterContract": 1
22
+ }
23
+ }
24
+ ```
25
+
26
+ - `version` versions the independently replaceable preset data.
27
+ - The core range is inclusive at `coreMinimum` and exclusive at `coreMaximumExclusive`.
28
+ - Core prerelease versions and build metadata follow SemVer; build metadata is ignored for precedence.
29
+ - `adapterContract` declares the request-adapter interface expected by every entry.
30
+ - The runtime rejects unknown fields, duplicate/reserved IDs, unsupported adapters, remote HTTP, credentials, top-level `model`/`messages` overrides, oversized data, incompatible versions, and symlinked files.
31
+
32
+ - `version` 标识可独立替换的 preset 数据版本。
33
+ - core 范围包含 `coreMinimum`,不包含 `coreMaximumExclusive`。
34
+ - Core 的预发布版本与构建元数据遵循 SemVer;构建元数据不参与优先级比较。
35
+ - `adapterContract` 声明每个条目所依赖的请求 adapter 接口。
36
+ - 运行时拒绝未知字段、重复/保留 ID、不支持的 adapter、远程 HTTP、凭据、顶层 `model`/`messages` 覆盖、超限数据、不兼容版本和符号链接文件。
37
+
38
+ 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
+
40
+ 发布的 JSON Schema 位于 [`schemas/aicommit-provider-presets.schema.json`](../schemas/aicommit-provider-presets.schema.json)。运行时校验是最终依据,并补充 JSON Schema 无法完整表达的语义与安全检查。
41
+
42
+ ## Inspect and validate / 检视与校验
43
+
44
+ ```bash
45
+ aicommit preset path
46
+ aicommit preset show --output=json
47
+ aicommit preset validate --file=provider-presets.json --output=json
48
+ ```
49
+
50
+ The bundled manifest is used unless `~/.aicommit/provider-presets.json` exists. `show` reports the selected source, preset version, compatibility declaration, and provider count. These commands do not resolve provider credentials.
51
+
52
+ 默认使用随包发布的清单;如果存在 `~/.aicommit/provider-presets.json`,则优先使用用户清单。`show` 会报告选中来源、preset 版本、兼容声明和 provider 数量。这些命令不会解析 provider 凭据。
53
+
54
+ ## Independent update and rollback / 独立更新与回滚
55
+
56
+ Validate before installation, install atomically, then verify setup sees the expected source/version:
57
+
58
+ 安装前先校验,原子安装后再确认 setup 使用了预期来源与版本:
59
+
60
+ ```bash
61
+ aicommit preset validate --file=provider-presets.json
62
+ aicommit preset install --file=provider-presets.json
63
+ aicommit preset show --output=json
64
+ aicommit setup
65
+ ```
66
+
67
+ On a later install, AICommit writes the current valid manifest to `~/.aicommit/provider-presets.previous.json` before replacing it. Roll back without changing the core package:
68
+
69
+ 后续安装时,AICommit 会先把当前有效清单写入 `~/.aicommit/provider-presets.previous.json`,再执行替换。无需更改 core 包即可回滚:
70
+
71
+ ```bash
72
+ aicommit preset rollback
73
+ aicommit preset validate
74
+ ```
75
+
76
+ If the active user manifest is malformed or incompatible, installation preserves its raw bytes as `provider-presets.invalid-<timestamp>.json` before repairing the active file. / 如果活动用户清单损坏或不兼容,安装会先将原始内容保存为 `provider-presets.invalid-<timestamp>.json`,再修复活动文件。
77
+
78
+ There is deliberately no automatic network updater. Obtain manifests through a trusted channel, review the endpoint/model changes, and validate locally before installation.
79
+
80
+ 系统刻意不提供自动联网更新器。请通过可信渠道取得清单,审阅 endpoint/模型变更,并在安装前进行本地校验。
81
+
82
+ ## Add a compatible provider / 新增兼容 provider
83
+
84
+ Add one entry to a copied manifest, bump `version`, validate, and install it:
85
+
86
+ 在清单副本中增加一个条目、提升 `version`,然后校验并安装:
87
+
88
+ ```json
89
+ {
90
+ "id": "acme",
91
+ "label": "Acme Compatible",
92
+ "adapter": "custom",
93
+ "apiUrl": "https://api.acme.example/v1/chat/completions",
94
+ "modelId": "acme-chat"
95
+ }
96
+ ```
97
+
98
+ If the service speaks an existing adapter contract, no core flow changes are required. A genuinely new wire protocol belongs in a provider adapter extension, not in preset data.
99
+
100
+ 如果服务符合现有 adapter 契约,就不需要修改 core 流程。真正的新 wire protocol 应实现 provider adapter 扩展,而不是塞入 preset 数据。
@@ -0,0 +1,86 @@
1
+ # Team policy / 团队策略
2
+
3
+ AICommit supports a repository-owned `.aicommit.policy.json` for deterministic commit-message rules. The document is safe to commit because its strict schema accepts only a language and a complete `commitPolicy`; credentials, endpoints, provider settings, prompts, and unknown properties are rejected.
4
+
5
+ AICommit 支持由仓库维护的 `.aicommit.policy.json`,用于确定性地约束提交信息。该文件采用严格 schema,只接受语言与完整的 `commitPolicy`;凭据、endpoint、provider 设置、prompt 和未知字段都会被拒绝,因此可以安全提交到仓库。
6
+
7
+ ## Adopt the template / 引入模板
8
+
9
+ Generate the template from the same installed CLI that will validate it, review every rule, then commit it:
10
+
11
+ 使用将负责校验的同一份 CLI 生成模板,审阅所有规则后提交:
12
+
13
+ ```bash
14
+ aicommit policy template > .aicommit.policy.json
15
+ aicommit config validate
16
+ git add .aicommit.policy.json
17
+ ```
18
+
19
+ The template fully declares every policy field. AICommit loads it after user, project, and provider-scoped config, so personal settings cannot silently change team results. `policy check` always applies recognized commitlint constraints from the same repository with fixed local-only detection limits; generation applies the same constraints when its commitlint context source is enabled.
20
+
21
+ 模板完整声明全部策略字段。AICommit 在用户、项目和 provider 级配置之后加载它,因此个人设置不会悄悄改变团队校验结果。`policy check` 始终以固定的本地只读检测上限应用同仓库中识别到的 commitlint 约束;生成流程会在启用 commitlint 上下文源时应用相同约束。
22
+
23
+ ## Use the same check locally and in CI / 本地与 CI 使用同一校验
24
+
25
+ Install the sample [`commit-msg`](examples/commit-msg) hook, or call the equivalent command from Husky/lefthook:
26
+
27
+ 安装示例 [`commit-msg`](examples/commit-msg) hook,或在 Husky/lefthook 中调用同一命令:
28
+
29
+ ```bash
30
+ install -m 0755 docs/examples/commit-msg .git/hooks/commit-msg
31
+ ```
32
+
33
+ For pull requests, use the executable [GitHub Actions example](examples/aicommit-policy.yml), which validates the exact base-to-head range:
34
+
35
+ 对于 pull request,可使用可执行的 [GitHub Actions 示例](examples/aicommit-policy.yml),校验准确的 base-to-head 范围:
36
+
37
+ ```bash
38
+ aicommit policy check --range=origin/main..HEAD
39
+ ```
40
+
41
+ Both paths call the same validator. `--output=json` returns the effective policy, a SHA-256 policy fingerprint, result IDs, issue codes, and severity without returning commit-message contents or diagnostic text derived from them. A policy violation exits with code `2`. `policy template` and `policy check` never resolve environment credentials or invoke Git credential helpers.
42
+
43
+ 两条路径调用同一个校验器。`--output=json` 返回有效策略、SHA-256 策略指纹、结果 ID、问题代码和严重级别,但不回传提交信息正文或由其派生的诊断文本。策略违规以退出码 `2` 结束。`policy template` 和 `policy check` 都不会解析环境凭据,也不会调用 Git credential helper。
44
+
45
+ ## Migration / 迁移
46
+
47
+ 1. Move Conventional Commit types, scope rules, subject length, body rules, breaking-change handling, and language out of free-form `prompt` text and into `.aicommit.policy.json`.
48
+ 2. Declare every field instead of relying on personal defaults. Start with optional scopes and narrow the values only after current history has been sampled.
49
+ 3. Keep provider credentials in `~/.aicommit.config.json` or environment variables; never copy them into the repository policy.
50
+ 4. If commitlint already defines `type-enum`, `scope-enum`, `subject-max-length`, or `header-max-length`, keep that file committed. AICommit reads recognized scalar values as data and never executes the config.
51
+ 5. Run the local hook and CI example on the same known-good and known-bad messages. Their `policyFingerprint` and issue codes must match before making the gate required.
52
+
53
+ 中文迁移步骤:
54
+
55
+ 1. 将 Conventional Commit 类型、scope 规则、标题长度、正文规则、破坏性变更和语言要求从自由文本 `prompt` 迁移到 `.aicommit.policy.json`。
56
+ 2. 明确声明所有字段,不依赖个人默认值。可先保留可选 scope,再根据现有提交历史逐步收紧取值。
57
+ 3. provider 凭据继续放在 `~/.aicommit.config.json` 或环境变量中,绝不要复制到仓库策略。
58
+ 4. 如果 commitlint 已定义 `type-enum`、`scope-enum`、`subject-max-length` 或 `header-max-length`,继续提交该配置。AICommit 只按数据读取识别出的标量规则,不执行配置文件。
59
+ 5. 用同一组已知正确/错误消息分别运行本地 hook 与 CI 示例;在强制启用门禁前,确认两者的 `policyFingerprint` 和问题代码一致。
60
+
61
+ ## Examples / 示例
62
+
63
+ Require an `api` or `cli` scope and an English subject:
64
+
65
+ 要求 `api` 或 `cli` scope,并使用英文标题:
66
+
67
+ ```json
68
+ {
69
+ "kind": "aicommit-team-policy",
70
+ "version": 1,
71
+ "language": "en",
72
+ "commitPolicy": {
73
+ "version": 1,
74
+ "types": ["feat", "fix", "docs", "refactor", "test", "chore"],
75
+ "scope": { "mode": "required", "values": ["api", "cli"] },
76
+ "subject": { "maxLength": 72 },
77
+ "body": { "mode": "optional", "maxLines": 8 },
78
+ "breakingChange": "allow",
79
+ "language": "inherit"
80
+ }
81
+ }
82
+ ```
83
+
84
+ `feat(api): add retry budget` passes. `feat: add retry budget` fails with `scope_required`; `feat(api): 添加重试预算` fails with `language`.
85
+
86
+ `feat(api): add retry budget` 会通过。`feat: add retry budget` 以 `scope_required` 失败;`feat(api): 添加重试预算` 以 `language` 失败。
@@ -0,0 +1,37 @@
1
+ # Troubleshooting matrix / 故障排查矩阵
2
+
3
+ Start with credential-free inspection, then run live diagnostics only when provider access is intended:
4
+
5
+ 先执行无凭据检查;只有确实需要访问 provider 时才运行在线诊断:
6
+
7
+ ```bash
8
+ aicommit config path
9
+ aicommit config validate --output=json
10
+ aicommit config show --output=json
11
+ aicommit doctor --output=json
12
+ ```
13
+
14
+ JSON mode keeps one machine object on stdout and diagnostics on stderr. The `error.category` and process exit code are stable automation inputs.
15
+
16
+ JSON 模式保证 stdout 只有一个机器对象,诊断进入 stderr。`error.category` 与进程退出码可稳定用于自动化。
17
+
18
+ | Symptom / 症状 | Category / exit | Likely cause / 常见原因 | Check and recovery / 检查与恢复 |
19
+ | ------------------------------------------------------------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
20
+ | Config fails before Git/provider access / 在 Git/provider 前配置失败 | `config` / `2` | Malformed JSON, invalid URL, unsupported option, missing credential / JSON 损坏、URL 或选项无效、凭据缺失 | `aicommit config path`; `aicommit config validate`; fix only the user-owned file shown |
21
+ | Project settings are ignored / 项目设置被忽略 | warning | Repository config tried to set endpoint, credential, extension, reasoning, metrics, or raise a ceiling / 仓库配置尝试设置连接、凭据、扩展或提高预算 | Move trusted connection settings to `~/.aicommit.config.json`; keep team rules in `.aicommit.policy.json` |
22
+ | Not a Git repository, conflict, empty index / 非仓库、冲突或 index 为空 | `git_state` / `3` | Wrong directory or unsafe Git state / 目录错误或 Git 状态不安全 | `git status`; `aicommit /absolute/repo/path`; resolve conflicts before retrying |
23
+ | DNS, connection, or timeout / DNS、连接或超时 | `network` / `4` | Endpoint unavailable, proxy/TLS issue, budget too short / endpoint 不可达、代理/TLS、超时过短 | `aicommit doctor -p NAME`; verify HTTPS URL; raise user-owned `timeoutMs` only if expected |
24
+ | HTTP authentication/rate/parameter failure / 鉴权、限流或参数失败 | `provider` / `5` | Wrong key/model/body; non-retryable 4xx / key、model、body 错误 | Check `apiKeyEnv`, model and compatibility table; authentication is never retried automatically |
25
+ | Empty or malformed model reply / 空或畸形回复 | `response_format` / `6` | Unsupported response dialect, token limit, policy/extension validator failure / 响应方言、token 限制、policy/扩展校验失败 | Raise `maxTokens`, choose the matching adapter, inspect validator issue code; one correction is already attempted |
26
+ | `split run --scope=all --yes` stops before API call / split 非交互在 API 前停止 | `sensitive_data` / `7` | Complete untracked scan found sensitive-looking data / 完整未跟踪扫描发现疑似敏感数据 | Review/stage intended files explicitly; do not bypass without checking the actual content |
27
+ | Commit aborts after generation / 生成后提交中止 | `concurrent_modification` / `8` | Index/worktree changed during the protected window / 受保护窗口中 index/worktree 被修改 | Review `git status`, restore the intended snapshot, and generate again |
28
+ | Split stopped after one or more commits / split 部分提交后停止 | reported Git failure | Hook, crash, SIGINT, or concurrent pending edit / hook、崩溃、中断或待处理文件变化 | Run `aicommit split resume`; if another Git workflow already replaced the transaction, use `aicommit split abort`(只删除恢复元数据,不改提交或工作区) |
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
+ | 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
+ | 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 release `SHA256SUMS`; do not use `--force` to bypass integrity |
33
+ | 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
+
35
+ 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.
36
+
37
+ 若问题仍未解决,请记录 `aicommit doctor --output=json`、Node/Git 版本、错误分类与脱敏后的配置来源。不要在公开 issue 中附加 diff、commit message、配置文件、API key、reasoning、含秘密的扩展源码或 credential-helper 输出。
package/package.json ADDED
@@ -0,0 +1,100 @@
1
+ {
2
+ "name": "@hifullmoon/aicommit",
3
+ "version": "1.4.0",
4
+ "description": "Safe, local-first AI commit message generator for Git workflows",
5
+ "type": "module",
6
+ "bin": {
7
+ "aicommit": "./bin/aicommit.js"
8
+ },
9
+ "files": [
10
+ ".aicommit.config.example.json",
11
+ "CHANGELOG.md",
12
+ "LICENSE",
13
+ "README.md",
14
+ "SECURITY.md",
15
+ "bin/",
16
+ "docs/",
17
+ "presets/",
18
+ "schemas/",
19
+ "templates/",
20
+ "src/"
21
+ ],
22
+ "scripts": {
23
+ "start": "node bin/aicommit.js",
24
+ "test": "node --test --test-concurrency=1",
25
+ "lint": "eslint .",
26
+ "format": "prettier --write .",
27
+ "format:check": "prettier --check .",
28
+ "coverage": "c8 node --test --test-concurrency=1",
29
+ "eval": "node eval/run.mjs",
30
+ "test:package": "node scripts/package-smoke.mjs",
31
+ "test:homebrew": "node scripts/homebrew-smoke.mjs",
32
+ "release:assets": "node scripts/release-assets.mjs",
33
+ "release:npm:check": "node scripts/publish-npm-org.mjs",
34
+ "release:npm:publish": "node scripts/publish-npm-org.mjs --publish",
35
+ "ci": "npm run lint && npm run format:check && npm run eval && npm run coverage"
36
+ },
37
+ "c8": {
38
+ "all": true,
39
+ "include": [
40
+ "src/**/*.js",
41
+ "bin/**/*.js"
42
+ ],
43
+ "reporter": [
44
+ "text",
45
+ "lcov"
46
+ ],
47
+ "check-coverage": true,
48
+ "lines": 70
49
+ },
50
+ "dependencies": {
51
+ "@inquirer/checkbox": "^4.3.2",
52
+ "@inquirer/confirm": "^5.1.0",
53
+ "@inquirer/core": "^10.3.2",
54
+ "@inquirer/editor": "^4.1.0",
55
+ "@inquirer/input": "^4.3.1",
56
+ "@inquirer/password": "^4.0.23",
57
+ "@inquirer/select": "^4.1.0",
58
+ "boxen": "^8.0.1",
59
+ "chalk": "^5.4.0",
60
+ "ora": "^8.2.0",
61
+ "wrap-ansi": "^9.0.2"
62
+ },
63
+ "keywords": [
64
+ "git",
65
+ "commit",
66
+ "ai",
67
+ "cli",
68
+ "conventional-commits",
69
+ "openai",
70
+ "deepseek",
71
+ "openrouter",
72
+ "ollama"
73
+ ],
74
+ "repository": {
75
+ "type": "git",
76
+ "url": "git+https://github.com/hi-fullmoon/AICommit.git"
77
+ },
78
+ "bugs": {
79
+ "url": "https://github.com/hi-fullmoon/AICommit/issues"
80
+ },
81
+ "homepage": "https://github.com/hi-fullmoon/AICommit#readme",
82
+ "license": "MIT",
83
+ "publishConfig": {
84
+ "access": "public",
85
+ "provenance": true
86
+ },
87
+ "overrides": {
88
+ "c8": {
89
+ "test-exclude": "7.0.1"
90
+ }
91
+ },
92
+ "engines": {
93
+ "node": ">=18"
94
+ },
95
+ "devDependencies": {
96
+ "c8": "10.1.3",
97
+ "eslint": "9.39.5",
98
+ "prettier": "3.9.6"
99
+ }
100
+ }
@@ -0,0 +1,60 @@
1
+ {
2
+ "kind": "aicommit-provider-presets",
3
+ "schemaVersion": 1,
4
+ "version": "1.1.0",
5
+ "compatibility": {
6
+ "coreMinimum": "1.4.0",
7
+ "coreMaximumExclusive": "2.0.0",
8
+ "adapterContract": 1
9
+ },
10
+ "providers": [
11
+ {
12
+ "id": "openai",
13
+ "label": "OpenAI",
14
+ "adapter": "openai",
15
+ "apiUrl": "https://api.openai.com/v1/chat/completions",
16
+ "modelId": "gpt-4o"
17
+ },
18
+ {
19
+ "id": "deepseek",
20
+ "label": "DeepSeek",
21
+ "adapter": "deepseek",
22
+ "apiUrl": "https://api.deepseek.com/v1/chat/completions",
23
+ "modelId": "deepseek-v4-flash"
24
+ },
25
+ {
26
+ "id": "openrouter",
27
+ "label": "OpenRouter",
28
+ "adapter": "openrouter",
29
+ "apiUrl": "https://openrouter.ai/api/v1/chat/completions",
30
+ "modelId": "openai/gpt-4o-mini"
31
+ },
32
+ {
33
+ "id": "minimax",
34
+ "label": "MiniMax",
35
+ "adapter": "minimax",
36
+ "apiUrl": "https://api.minimaxi.com/v1/chat/completions",
37
+ "modelId": "MiniMax-M3",
38
+ "extraBody": {
39
+ "thinking": {
40
+ "type": "disabled"
41
+ },
42
+ "reasoning_split": true
43
+ }
44
+ },
45
+ {
46
+ "id": "kimi-code",
47
+ "label": "Kimi Code",
48
+ "adapter": "custom",
49
+ "apiUrl": "https://api.kimi.com/coding/v1/chat/completions",
50
+ "modelId": "kimi-for-coding"
51
+ },
52
+ {
53
+ "id": "ollama",
54
+ "label": "Ollama (local)",
55
+ "adapter": "ollama",
56
+ "apiUrl": "http://127.0.0.1:11434/api/chat",
57
+ "modelId": "qwen3:8b"
58
+ }
59
+ ]
60
+ }