@hifullmoon/aicommit 2.4.1 → 2.6.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.
@@ -144,6 +144,12 @@
144
144
  "chunkInputTokens": 12000,
145
145
  "maxTotalTokens": 200000,
146
146
  "concurrency": 2,
147
- "timeoutMs": 180000
147
+ "timeoutMs": 180000,
148
+ "cache": {
149
+ "enabled": true,
150
+ "ttlMs": 86400000,
151
+ "maxBytes": 33554432,
152
+ "allowUnprotected": false
153
+ }
148
154
  }
149
155
  }
package/CHANGELOG.md CHANGED
@@ -4,6 +4,33 @@ This file lists notable user-facing changes. Internal refactors, test-only chang
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [2.6.0] - 2026-09-14
8
+
9
+ ### Added
10
+
11
+ - Added `generate --scope=staged|all` and `apply` for a reviewable single-commit plan that rechecks the repository snapshot before committing.
12
+ - Added read-only `split status --output=json` so interrupted split transactions expose completed commits and the next recovery action.
13
+
14
+ ### Changed
15
+
16
+ - Machine output schema 1.1 now reports commit IDs, plan paths, explicit change scope, and structured recovery errors. Consumers pinned to schema 1.0 should update their parsers.
17
+ - Staged snapshot checks use Git object IDs instead of regenerating full patches, and normal generation skips `git diff --stat` unless its diff is truncated.
18
+
19
+ ### Fixed
20
+
21
+ - Split planning now displays the final model request's thinking for large changes and preserves it in interactive review; `auto` mode displays thinking when a provider emits it. JSON output remains free of model reasoning.
22
+
23
+ ## [2.5.0] - 2026-09-10
24
+
25
+ ### Added
26
+
27
+ - Added short-lived, content-addressed recovery caching for validated `deep` analysis chunks so identical snapshots resume after failures without repeating completed provider requests.
28
+
29
+ ### Fixed
30
+
31
+ - Packed `deep` analysis fragments using the configured token estimate instead of character counts, avoiding unnecessary requests and premature aggregate-budget failures for ASCII-heavy diffs.
32
+ - Large split plans now preflight deep-analysis and downstream planning cost, batch local candidates hierarchically, and offer one complete conservative plan when the bounded budget cannot finish. Non-interactive committing requires the explicit `--allow-single-fallback` opt-in.
33
+
7
34
  ## [2.4.1] - 2026-09-10
8
35
 
9
36
  ### Fixed
@@ -206,7 +233,9 @@ This file lists notable user-facing changes. Internal refactors, test-only chang
206
233
  - Added file-level split planning and execution with Git-state concurrency checks.
207
234
  - Added provider presets and user/project configuration boundaries.
208
235
 
209
- [Unreleased]: https://github.com/hi-fullmoon/AICommit/compare/v2.4.1...HEAD
236
+ [Unreleased]: https://github.com/hi-fullmoon/AICommit/compare/v2.6.0...HEAD
237
+ [2.6.0]: https://github.com/hi-fullmoon/AICommit/releases/tag/v2.6.0
238
+ [2.5.0]: https://github.com/hi-fullmoon/AICommit/releases/tag/v2.5.0
210
239
  [2.4.1]: https://github.com/hi-fullmoon/AICommit/releases/tag/v2.4.1
211
240
  [2.4.0]: https://github.com/hi-fullmoon/AICommit/releases/tag/v2.4.0
212
241
  [2.3.0]: https://github.com/hi-fullmoon/AICommit/releases/tag/v2.3.0
package/README.md CHANGED
@@ -197,6 +197,7 @@ This is the only supported user-config shape. Earlier flat or provider-level `mo
197
197
  | `maxFileDiffChars` | Target per-file fragment size; remaining content is analyzed in subsequent chunks (default: `3000`) |
198
198
  | `splitMaxDiffChars` | Context character budget for each split-planning request (default: `16000`) |
199
199
  | `splitMaxPlanFiles` | Files or candidate groups per planning request; larger changes use hierarchical planning (default: `100`) |
200
+ | `largeChange` | Large-change strategy, budgets, and short-lived chunk recovery cache; personal config only, retaining protected summaries for 24 hours up to 32 MiB by default |
200
201
  | `diffContextLines` | Context lines around each diff hunk (`git diff --unified=<n>`); lower values mean fewer tokens (default: `1`) |
201
202
  | `stripFiles` | Extra files to stub out of the diff like lock files, matched by basename with `*`/`?` wildcards, e.g. `["*.min.js", "*.map", "*.snap"]` (default: `[]`; project-level entries are merged with user-level ones, not replaced) |
202
203
  | `regenerateWithDiff` | `true` re-sends the full diff on every regenerate for more varied rewrites; `false` (default) only asks the model to reword its previous message, which is far cheaper |
@@ -310,10 +311,15 @@ aicommit --dry-run # generate and review without creating a commit
310
311
  aicommit split --dry-run # review a split plan without creating commits
311
312
  aicommit --yes # non-interactively commit already staged changes
312
313
  aicommit --yes --dry-run # non-interactively preview all changes; restores staging
314
+ aicommit --yes --dry-run --scope=staged --output=json # preview only the index
315
+ aicommit generate --scope=staged --file=/tmp/commit-plan.json --yes --output=json
316
+ aicommit apply --file=/tmp/commit-plan.json --yes --output=json
313
317
  aicommit split --scope=all --yes # non-interactively plan and commit all working-tree changes
318
+ aicommit split --scope=all --yes --allow-single-fallback # explicitly permit a conservative fallback commit
314
319
  aicommit split plan --scope=staged --file=/tmp/split-plan.json --yes
315
320
  aicommit split apply --file=/tmp/split-plan.json --yes
316
321
  aicommit split resume --yes # resume an interrupted split transaction
322
+ aicommit split status --output=json # inspect recovery state without changing Git
317
323
  aicommit split abort --yes # discard a stale checkpoint; keep commits and changes
318
324
  aicommit --reasoning=low # stream low-effort reasoning; Ctrl+O expands/collapses it
319
325
  aicommit --no-reasoning # explicitly disable reasoning when supported
@@ -324,20 +330,21 @@ aicommit --yes --output=json # emit one schema-validated JSON result on stdout
324
330
  aicommit -h # help
325
331
  ```
326
332
 
327
- | Option | Description |
328
- | ------------------ | ---------------------------------------------------------------------------- |
329
- | `-l`, `--lang` | Commit message language (`zh` or `en`) |
330
- | `-p`, `--provider` | Use the named provider from `providers` |
331
- | `-m`, `--model` | Use a named model profile from the selected provider |
332
- | `--scope` | `staged` or `all` scope for `aicommit split` and `aicommit split plan` |
333
- | `--file` | JSON plan path for `aicommit split plan` and `aicommit split apply` |
334
- | `--dry-run` | Generate and review a message or split plan without creating commits |
335
- | `-y`, `--yes` | Accept without prompts; normal mode requires explicitly staged changes |
336
- | `--reasoning` | Enable reasoning with `low`, `medium`, `high`, `xhigh`, or `max` effort |
337
- | `--no-reasoning` | Explicitly disable reasoning when the selected provider/model supports it |
338
- | `--output` | `text` (default) or one JSON object; commit/split JSON flows require `--yes` |
339
- | `-v`, `--version` | Show version |
340
- | `-h`, `--help` | Show help |
333
+ | Option | Description |
334
+ | ------------------------- | ------------------------------------------------------------------------------ |
335
+ | `-l`, `--lang` | Commit message language (`zh` or `en`) |
336
+ | `-p`, `--provider` | Use the named provider from `providers` |
337
+ | `-m`, `--model` | Use a named model profile from the selected provider |
338
+ | `--scope` | `staged` or `all` scope for dry-run, generate, and split planning |
339
+ | `--file` | JSON plan path for generate/apply and split plan/apply |
340
+ | `--dry-run` | Generate and review a message or split plan without creating commits |
341
+ | `-y`, `--yes` | Accept without prompts; normal mode requires explicitly staged changes |
342
+ | `--allow-single-fallback` | Explicitly permit non-interactive split to create one complete fallback commit |
343
+ | `--reasoning` | Enable reasoning with `low`, `medium`, `high`, `xhigh`, or `max` effort |
344
+ | `--no-reasoning` | Explicitly disable reasoning when the selected provider/model supports it |
345
+ | `--output` | `text` (default) or one JSON object; commit/split JSON flows require `--yes` |
346
+ | `-v`, `--version` | Show version |
347
+ | `-h`, `--help` | Show help |
341
348
 
342
349
  ### Configuration inspection
343
350
 
@@ -385,11 +392,13 @@ Verify the registration with `whence -w _aicommit`; it should print `_aicommit:
385
392
 
386
393
  ### Machine-readable output
387
394
 
388
- Use `--output=json` for scripts and CI. Commit and split flows also require `--yes`, preventing a machine consumer from hanging on an interactive prompt. stdout contains exactly one JSON object; progress, debug details, and diagnostics go to stderr. `doctor --output=json` and `update --output=json` do not require `--yes`.
395
+ Use `--output=json` for scripts and CI. Commit, generate, apply, and split execution flows also require `--yes`, preventing a machine consumer from hanging on an interactive prompt. stdout contains exactly one JSON object; progress, debug details, and diagnostics go to stderr. `split status`, `doctor`, and `update` in JSON mode do not require `--yes`.
396
+
397
+ For an agent-reviewed single commit, run `generate --scope=staged|all --file=<path> --yes --output=json`, inspect the returned message and plan, then run `apply --file=<path> --yes --output=json`. The plan is a validated one-group artifact; apply checks its base HEAD, change list, and content fingerprint before committing. Keep the file outside the worktree or in `.git/aicommit/`. `generate --scope=all` includes staged, unstaged, and untracked changes, restores its temporary staging, and refuses detected sensitive content in non-interactive mode. For a quick preview without an artifact, use `--dry-run --scope=staged|all --yes --output=json`; an omitted scope retains the older automatic staging behavior when the index is empty.
389
398
 
390
399
  ```json
391
400
  {
392
- "schemaVersion": "1.0",
401
+ "schemaVersion": "1.1",
393
402
  "ok": true,
394
403
  "message": "fix: handle provider retry limits",
395
404
  "plan": null,
@@ -404,11 +413,16 @@ Use `--output=json` for scripts and CI. Commit and split flows also require `--y
404
413
  "warnings": [],
405
414
  "exitReason": "dry_run",
406
415
  "committed": false,
416
+ "commitState": "none",
417
+ "commitSha": null,
418
+ "planFile": null,
419
+ "scope": "staged",
420
+ "changeCount": 1,
407
421
  "error": null
408
422
  }
409
423
  ```
410
424
 
411
- The published [JSON schema](schemas/aicommit-output.schema.json) covers success, split-plan, doctor/check, and error results. Machine output never includes the diff or model reasoning. Split output exposes only each group message and its assigned paths.
425
+ The published [JSON schema](schemas/aicommit-output.schema.json) covers success, plans, status, doctor/check, and error results. Machine output never includes the diff or model reasoning. Plans expose only each group message and its assigned paths. `committed` reports whether this invocation created a commit; `commitState` describes `none`, `partial`, `complete`, or `unknown` transaction state. A split failure can return `committed: true` with `error.code: "split_partial_failure"`, completed commit IDs in `data.split`, and `error.nextAction`. After a crash that emits no JSON, use `split status --output=json` before retrying.
412
426
 
413
427
  Stable process exits are shared by text and JSON modes:
414
428
 
@@ -441,7 +455,7 @@ The staged index (or complete split-mode working tree, including untracked file
441
455
 
442
456
  Reasoning defaults to `on` with `medium` effort. It is mapped natively for OpenAI reasoning models, DeepSeek, OpenRouter, and MiniMax; models that do not expose reasoning continue normally and show an unavailable notice instead of failing. Official OpenAI endpoints validate the selected effort against the model generation before sending the request, so unsupported combinations such as `o3 --no-reasoning` or `gpt-5.1 --reasoning=max` fail locally with a clear list of supported levels. DeepSeek's current `deepseek-v4-flash` and `deepseek-v4-pro` models receive `thinking: { "type": "enabled" }` plus `reasoning_effort`; `medium`/`xhigh` are normalized to DeepSeek's `high` level.
443
457
 
444
- When reasoning mode is `on` (including via `--reasoning=<level>`), aicommit requests a streaming response and displays reasoning as it arrives. The live view follows the newest two terminal lines by default; press `Ctrl+O` to expand or collapse the accumulated text during generation or review. Long expanded output is kept inside the terminal viewport—use `PageUp`/`PageDown` to read every page. Holding `Ctrl+O` counts as one toggle, so key repeat cannot leave duplicate panels behind. Output is sanitized and capped by `reasoning.maxDisplayChars`; providers that do not expose reasoning show a short unavailable notice.
458
+ When reasoning mode is `on` (including via `--reasoning=<level>`), aicommit requests a streaming response and displays reasoning as it arrives. In `auto` mode it also displays thinking if the provider emits it, without forcing reasoning on. Split mode streams the final planning request's thinking, including when large changes use batched analysis; the review prompt keeps that reasoning available. Intermediate analysis batches show progress rather than mixing several reasoning streams. The live panel requires an interactive terminal, and JSON output never includes reasoning. The live view follows the newest two terminal lines by default; press `Ctrl+O` to expand or collapse the accumulated text during generation or review. Long expanded output is kept inside the terminal viewport—use `PageUp`/`PageDown` to read every page. Holding `Ctrl+O` counts as one toggle, so key repeat cannot leave duplicate panels behind. Output is sanitized and capped by `reasoning.maxDisplayChars`; providers that do not expose reasoning show a short unavailable notice.
445
459
 
446
460
  ```json
447
461
  {
@@ -478,7 +492,7 @@ The default `largeChange.strategy: "auto"` inventories every file locally, group
478
492
 
479
493
  A normal commit typically needs one model request, with no per-file AI calls or recursive model reduction. The inventory contains at most 16 representative groups under a UTF-8 byte budget, prioritizing coverage across code, configuration, tests, and other categories. It explicitly describes sampling limits. Both terminal and JSON output distinguish fully analyzed files, representative excerpts, and metadata-only files. Provider retries, response recovery, policy correction, and user-requested regeneration can still add requests.
480
494
 
481
- Split mode builds local candidates and plans them in one model request. The complete candidate inventory must fit `splitMaxPlanFiles` and the input budget; otherwise it stops before calling the provider and suggests staging a smaller logical change or explicitly selecting deep analysis. File membership is still validated completely, with no automatic catch-all commits. Small changes keep the existing request path.
495
+ Split mode builds local candidates and sends them in bounded batches of at most `splitMaxPlanFiles`, then merges the batch plans hierarchically. Every file remains represented even when the complete candidate inventory cannot fit one request. If `deep` analysis exhausts its aggregate budget or the hierarchy cannot converge, interactive and dry-run flows produce one conservative all-files plan with an explicit warning instead of using incomplete model output. Non-interactive committing stops unless `--allow-single-fallback` explicitly authorizes that degradation. Small changes keep the existing request path.
482
496
 
483
497
  For exhaustive chunk-by-chunk model analysis, opt in through personal configuration:
484
498
 
@@ -489,11 +503,17 @@ For exhaustive chunk-by-chunk model analysis, opt in through personal configurat
489
503
  "chunkInputTokens": 12000,
490
504
  "maxTotalTokens": 200000,
491
505
  "concurrency": 2,
492
- "timeoutMs": 180000
506
+ "timeoutMs": 180000,
507
+ "cache": {
508
+ "enabled": true,
509
+ "ttlMs": 86400000,
510
+ "maxBytes": 33554432,
511
+ "allowUnprotected": false
512
+ }
493
513
  }
494
514
  }
495
515
  ```
496
516
 
497
- `deep` spends more requests and tokens, with a maximum of 256 requests. Repository configuration cannot change this personal strategy or raise the spending budget. Both strategies use conservative token estimates; missing usage retains the reservation. Retries, reduction, planning, and final generation share the budget. Budget exhaustion or invalid groups stop execution without automatically committing incomplete results.
517
+ `deep` spends more requests and tokens, with a maximum of 256 requests. Before dispatch, a preflight estimate covers initial chunks, required reductions, and the minimum hierarchical planning tree; an impossible deep run switches to the local inventory path, and validated cache hits are excluded from that estimate. Validated initial fact chunks are stored briefly under Git metadata, reused when the same snapshot is retried after failure or interruption, and removed after complete generation succeeds. The cache does not directly store captured diffs, reasoning, credentials, or complete provider responses; it stores model summaries that may contain code-derived details. Unprotected original input is not persisted unless personal configuration explicitly enables `allowUnprotected`. Repository configuration cannot change this personal strategy, enable unprotected caching, or raise spending/cache ceilings. Both strategies use conservative token estimates; cache hits consume no request or token budget. Incomplete model output is never committed: budget/capacity fallback is a new complete plan containing every reviewed file; interactive runs show it for review, while non-interactive committing requires `--allow-single-fallback`.
498
518
 
499
- Complete patches and larger untracked text are captured in local temporary files, with descriptors opened only during reads and writes. Files are cleaned on normal exit or cancellation; crashes may leave them behind. Content reads are bounded. Lines exceeding 1 MiB, independent groups that cannot fit a global planning budget, and experimental hunk planning for large changes fail explicitly.
519
+ Complete patches and larger untracked text are captured in local temporary files, with descriptors opened only during reads and writes. Files are cleaned on normal exit or cancellation; crashes may leave them behind. Content reads are bounded. Lines exceeding 1 MiB and experimental hunk planning for large changes fail explicitly; file-level planning capacity uses the complete conservative fallback.
package/README.zh-CN.md CHANGED
@@ -199,6 +199,7 @@ aicommit -p deepseek -m reasoner
199
199
  | `maxFileDiffChars` | 单文件正文分块参考大小;剩余内容继续分析(默认:`3000`) |
200
200
  | `splitMaxDiffChars` | 每次批次规划的上下文字符预算(默认:`16000`) |
201
201
  | `splitMaxPlanFiles` | 每次规划的文件或候选组数量上限;超限分层规划(默认:`100`) |
202
+ | `largeChange` | 大变更策略、预算和短期分块恢复缓存;缓存只接受个人配置,默认保留受保护摘要 24 小时、最多 32 MiB |
202
203
  | `diffContextLines` | 每个 diff hunk 周围的上下文行数(`git diff --unified=<n>`);越小越节省 token(默认:`1`) |
203
204
  | `stripFiles` | 额外替换为占位的文件,按 basename 使用 `*` / `?` 通配,如 `["*.min.js", "*.map", "*.snap"]`(默认:`[]`;项目项与用户项合并而非覆盖) |
204
205
  | `regenerateWithDiff` | `true` 表示每次重写都重发完整 diff,以获得更多变化;`false`(默认)只要求模型改写上一条消息,成本更低 |
@@ -312,10 +313,15 @@ aicommit --dry-run # 生成并审阅,但不创建提交
312
313
  aicommit split --dry-run # 审阅拆分计划,但不创建提交
313
314
  aicommit --yes # 非交互提交已明确暂存的变更
314
315
  aicommit --yes --dry-run # 非交互预览所有变更;退出时恢复暂存状态
316
+ aicommit --yes --dry-run --scope=staged --output=json # 只预览暂存区
317
+ aicommit generate --scope=staged --file=/tmp/commit-plan.json --yes --output=json
318
+ aicommit apply --file=/tmp/commit-plan.json --yes --output=json
315
319
  aicommit split --scope=all --yes # 非交互规划并提交所有工作区变更
320
+ aicommit split --scope=all --yes --allow-single-fallback # 明确允许规划预算耗尽后的保守提交
316
321
  aicommit split plan --scope=staged --file=/tmp/split-plan.json --yes
317
322
  aicommit split apply --file=/tmp/split-plan.json --yes
318
323
  aicommit split resume --yes # 恢复中断的拆分事务
324
+ aicommit split status --output=json # 只读查询恢复状态
319
325
  aicommit split abort --yes # 丢弃过期 checkpoint;保留提交和变更
320
326
  aicommit --reasoning=low # 流式显示低强度推理;Ctrl+O 展开或收起
321
327
  aicommit --no-reasoning # Provider / 模型支持时显式关闭推理
@@ -326,20 +332,21 @@ aicommit --yes --output=json # 向 stdout 输出一个通过 schema 校验的 JS
326
332
  aicommit -h # 帮助
327
333
  ```
328
334
 
329
- | 选项 | 说明 |
330
- | ------------------ | ------------------------------------------------------------------- |
331
- | `-l`, `--lang` | 提交信息语言:`zh` 或 `en` |
332
- | `-p`, `--provider` | 使用 `providers` 中的命名 Provider |
333
- | `-m`, `--model` | 使用所选 Provider 下的命名模型配置 |
334
- | `--scope` | `aicommit split` 和 `aicommit split plan` 的范围:`staged` 或 `all` |
335
- | `--file` | `aicommit split plan` 和 `aicommit split apply` 的 JSON 计划路径 |
336
- | `--dry-run` | 生成并审阅消息或拆分计划,但不创建提交 |
337
- | `-y`, `--yes` | 不提示直接接受;普通模式要求变更已明确暂存 |
338
- | `--reasoning` | 启用推理,可选强度:`low`、`medium`、`high`、`xhigh` 或 `max` |
339
- | `--no-reasoning` | 所选 Provider / 模型支持时显式关闭推理 |
340
- | `--output` | `text`(默认)或单个 JSON 对象;提交 / 拆分的 JSON 流程要求 `--yes` |
341
- | `-v`, `--version` | 显示版本 |
342
- | `-h`, `--help` | 显示帮助 |
335
+ | 选项 | 说明 |
336
+ | ------------------------- | ------------------------------------------------------------------- |
337
+ | `-l`, `--lang` | 提交信息语言:`zh` 或 `en` |
338
+ | `-p`, `--provider` | 使用 `providers` 中的命名 Provider |
339
+ | `-m`, `--model` | 使用所选 Provider 下的命名模型配置 |
340
+ | `--scope` | dry-run、generate 和 split 规划的范围:`staged` 或 `all` |
341
+ | `--file` | generate/apply 和 split plan/apply 的 JSON 计划路径 |
342
+ | `--dry-run` | 生成并审阅消息或拆分计划,但不创建提交 |
343
+ | `-y`, `--yes` | 不提示直接接受;普通模式要求变更已明确暂存 |
344
+ | `--allow-single-fallback` | 明确允许非交互拆分创建一个覆盖完整变更的保守提交 |
345
+ | `--reasoning` | 启用推理,可选强度:`low`、`medium`、`high`、`xhigh` 或 `max` |
346
+ | `--no-reasoning` | 所选 Provider / 模型支持时显式关闭推理 |
347
+ | `--output` | `text`(默认)或单个 JSON 对象;提交 / 拆分的 JSON 流程要求 `--yes` |
348
+ | `-v`, `--version` | 显示版本 |
349
+ | `-h`, `--help` | 显示帮助 |
343
350
 
344
351
  ### 配置检查
345
352
 
@@ -387,11 +394,13 @@ exec zsh
387
394
 
388
395
  ### 机器可读输出
389
396
 
390
- 脚本和 CI 请使用 `--output=json`。提交和 split 流程还必须使用 `--yes`,避免机器消费者卡在交互提示上。stdout 只包含一个 JSON 对象;进度、调试信息和诊断输出会写入 stderr。`doctor --output=json` 和 `update --output=json` 不要求 `--yes`。
397
+ 脚本和 CI 请使用 `--output=json`。提交、generate、apply 和 split 执行流程还必须使用 `--yes`,避免机器消费者卡在交互提示上。stdout 只包含一个 JSON 对象;进度、调试信息和诊断输出会写入 stderr。`split status`、`doctor` 和 `update` 的 JSON 模式不要求 `--yes`。
398
+
399
+ 让 AI 审阅单次提交时,先执行 `generate --scope=staged|all --file=<路径> --yes --output=json`,检查返回的消息和计划,再执行 `apply --file=<路径> --yes --output=json`。计划复用经过校验的单组工件;apply 会在提交前核对基础 HEAD、变更清单和内容指纹。计划文件应放在工作区外或 `.git/aicommit/`。`generate --scope=all` 包含已暂存、未暂存和未跟踪变更,结束时恢复临时暂存;非交互模式遇到检测出的敏感内容会停止。只想快速预览时,可用 `--dry-run --scope=staged|all --yes --output=json`;不指定范围时,保留旧版在暂存区为空时自动暂存的行为。
391
400
 
392
401
  ```json
393
402
  {
394
- "schemaVersion": "1.0",
403
+ "schemaVersion": "1.1",
395
404
  "ok": true,
396
405
  "message": "fix: handle provider retry limits",
397
406
  "plan": null,
@@ -406,11 +415,16 @@ exec zsh
406
415
  "warnings": [],
407
416
  "exitReason": "dry_run",
408
417
  "committed": false,
418
+ "commitState": "none",
419
+ "commitSha": null,
420
+ "planFile": null,
421
+ "scope": "staged",
422
+ "changeCount": 1,
409
423
  "error": null
410
424
  }
411
425
  ```
412
426
 
413
- 已发布的 [JSON schema](schemas/aicommit-output.schema.json) 覆盖成功、拆分计划、doctor / check 和错误结果。机器输出绝不包含 diff 或模型推理。split 输出只暴露每组消息及其分配路径。
427
+ 已发布的 [JSON schema](schemas/aicommit-output.schema.json) 覆盖成功、计划、状态、doctor / check 和错误结果。机器输出绝不包含 diff 或模型推理;计划只暴露每组消息及其分配路径。`committed` 表示本次调用是否创建了提交;`commitState` 表示事务处于 `none`、`partial`、`complete` 或 `unknown`。拆分失败时可能返回 `committed: true`、`error.code: "split_partial_failure"`、`data.split` 中已完成的提交 ID,以及 `error.nextAction`。若进程崩溃而没有输出 JSON,应先执行 `split status --output=json` 再决定下一步。
414
428
 
415
429
  文本与 JSON 模式共享稳定的进程退出码:
416
430
 
@@ -443,7 +457,7 @@ exec zsh
443
457
 
444
458
  推理默认为 `on`,强度为 `medium`。OpenAI 推理模型、DeepSeek、OpenRouter 和 MiniMax 使用各自原生映射;不暴露推理能力的模型会正常继续,并显示“不可用”提示,而不是失败。官方 OpenAI 端点会在发送请求前根据模型代际校验所选强度,因此 `o3 --no-reasoning` 或 `gpt-5.1 --reasoning=max` 等不支持的组合会在本地失败,并清楚列出支持的级别。DeepSeek 当前的 `deepseek-v4-flash` 和 `deepseek-v4-pro` 会收到 `thinking: { "type": "enabled" }` 与 `reasoning_effort`;`medium` / `xhigh` 会归一化为 DeepSeek 的 `high` 级别。
445
459
 
446
- 推理模式为 `on` 时(包括通过 `--reasoning=<level>` 启用),AICommit 会请求流式响应并实时显示推理。默认实时视图跟随终端最新两行;生成或审阅期间按 `Ctrl+O` 可展开或收起累计文本。较长的展开输出会限制在终端视口内,可用 `PageUp` / `PageDown` 阅读所有页面。长按 `Ctrl+O` 只计为一次切换,避免按键重复留下多个面板。输出会经过清理,并受 `reasoning.maxDisplayChars` 限制;不暴露推理的 Provider 会显示简短的不可用提示。
460
+ 推理模式为 `on` 时(包括通过 `--reasoning=<level>` 启用),AICommit 会请求流式响应并实时显示推理;`auto` 模式下若 Provider 主动返回 think,也会显示,但不会强制开启推理。split 模式会显示最终规划请求的 think,大变更走分批分析时也一样,并在审阅界面保留这段内容;前面的分析批次只显示进度,避免多个推理流混在一起。实时面板需要交互式终端,JSON 输出始终不包含推理。默认实时视图跟随终端最新两行;生成或审阅期间按 `Ctrl+O` 可展开或收起累计文本。较长的展开输出会限制在终端视口内,可用 `PageUp` / `PageDown` 阅读所有页面。长按 `Ctrl+O` 只计为一次切换,避免按键重复留下多个面板。输出会经过清理,并受 `reasoning.maxDisplayChars` 限制;不暴露推理的 Provider 会显示简短的不可用提示。
447
461
 
448
462
  ```json
449
463
  {
@@ -480,7 +494,7 @@ exec zsh
480
494
 
481
495
  普通提交通常只需要一次模型请求,不会为每个文件调用 AI,也不会递归调用模型汇总。摘要最多包含 16 个代表组,并受 UTF-8 字节预算约束;优先覆盖代码、配置和测试等不同类别。摘要明确说明抽样范围,界面和 JSON 分别报告全文分析、代表片段和仅元数据的文件数,不把抽样视为完整理解。提供方重试、响应恢复、格式修正和用户重新生成仍可能增加请求。
482
496
 
483
- 批次提交先在本地建立候选组,再用一次模型请求规划。只有完整候选清单能放入 `splitMaxPlanFiles` 和输入预算时才请求模型;否则在请求前停止,提示暂存更小的逻辑变更或显式选择深度分析。所有文件的归属仍进行完整性校验,不会因数量过多生成兜底提交。小变更保持原有请求路径。
497
+ 批次提交先在本地建立候选组,再按每批最多 `splitMaxPlanFiles` 个候选发送,并分层合并各批计划;完整候选清单放不进一次请求时,仍会保留每个文件。如果 `deep` 分析耗尽总预算,或分层规划无法收敛,交互和 dry-run 流程会明确警告并生成一个覆盖全部文件的保守计划,而不会采用不完整的模型结果;非交互提交默认停止,只有显式传入 `--allow-single-fallback` 才允许该降级。小变更保持原有请求路径。
484
498
 
485
499
  确实需要逐块 AI 分析时,在个人配置中设置:
486
500
 
@@ -491,11 +505,17 @@ exec zsh
491
505
  "chunkInputTokens": 12000,
492
506
  "maxTotalTokens": 200000,
493
507
  "concurrency": 2,
494
- "timeoutMs": 180000
508
+ "timeoutMs": 180000,
509
+ "cache": {
510
+ "enabled": true,
511
+ "ttlMs": 86400000,
512
+ "maxBytes": 33554432,
513
+ "allowUnprotected": false
514
+ }
495
515
  }
496
516
  }
497
517
  ```
498
518
 
499
- `deep` 会增加请求和 token 消耗,最多 256 次请求。仓库配置不能切换这项个人策略或提高费用预算。两种策略均使用保守 token 估算,未知 usage 按预留额度计入;重试、汇总、规划和消息生成共用预算。超限或无效分组会停止,不自动提交不完整结果。
519
+ `deep` 会增加请求和 token 消耗,最多 256 次请求。请求前会预估初始分块、必要归并和最小分层规划树的成本;确定无法装入总预算时直接切换到本地清单路径,已验证的缓存命中不计入这次预估。通过完整校验的初始事实分块会短期写入 Git 元数据目录;同一快照失败或中断后重试时直接复用,完整生成成功后清理。缓存不直接保存捕获的 diff、推理、凭据或完整 Provider 响应,只保存可能包含代码派生细节的模型摘要;选择发送未保护的原始内容时默认不落盘,只有个人配置显式设置 `allowUnprotected: true` 才允许。仓库配置不能切换策略、启用未保护缓存或提高费用与缓存上限。两种策略均使用保守 token 估算,未知 usage 按预留额度计入;缓存命中不计请求或 token。模型的不完整输出永远不会被提交:预算或容量降级会重新生成一个包含全部已审核文件的完整计划;交互模式先展示确认,非交互提交则要求 `--allow-single-fallback`。
500
520
 
501
- 完整补丁及较大未跟踪文本暂存到本地临时文件,只在读写时打开文件句柄,正常结束或取消时清理;异常崩溃可能遗留临时文件。正文读取有界。单行超过 1 MiB、无法在预算内合并的独立分组,以及大变更的实验性 hunk 规划会明确报错。
521
+ 完整补丁及较大未跟踪文本暂存到本地临时文件,只在读写时打开文件句柄,正常结束或取消时清理;异常崩溃可能遗留临时文件。正文读取有界。单行超过 1 MiB 和大变更的实验性 hunk 规划会明确报错;文件级规划容量不足时使用覆盖完整变更的保守回退。
@@ -33,7 +33,7 @@ The release workflow uses npm Trusted Publishing without a long-lived `NPM_TOKEN
33
33
  ```bash
34
34
  workdir=$(mktemp -d)
35
35
  cd "$workdir"
36
- npm install --package-lock-only @hifullmoon/aicommit@2.4.1
36
+ npm install --package-lock-only @hifullmoon/aicommit@2.6.0
37
37
  npm audit signatures
38
38
  ```
39
39
 
@@ -112,7 +112,7 @@
112
112
  - [ ] 本地展开组 ID 到文件路径,校验完整覆盖、唯一归属及合法引用,替换超额文件兜底提交。
113
113
  - [ ] 为最终分组生成消息,复用已有分析;大量分组的消息生成也纳入总预算。
114
114
  - [ ] 未解决归属显示为待处理项,允许在现有审阅中调整;未解决前不执行、不导出可执行计划。
115
- - [ ] 非交互模式遇不完整分析或非法分组,在自动暂存前失败。
115
+ - [ ] 非交互模式绝不采用不完整分析或非法模型分组;确定性的预算/容量耗尽只有在显式允许单提交降级时才使用覆盖全部文件的保守计划,其余情况在自动暂存前失败。
116
116
  - [ ] 继续生成现有 split plan 工件,由已有 apply / checkpoint / resume 流程执行;内部分析 ID 不改变外部路径语义。
117
117
  - [ ] 验证实验性 hunk 归属和跨块片段映射;无法处理时给出明确错误。
118
118
 
@@ -136,18 +136,18 @@
136
136
 
137
137
  使用临时仓库和模拟 Provider 构造测试,不把巨型 fixture 提交到仓库。确定性测试验证边界和完整性,语义评估单独记录,不用字符串快照冒充摘要质量验证。
138
138
 
139
- | 场景 | 必须验证 |
140
- | ------------------------------------- | ------------------------------------------ |
141
- | 普通小提交 | 一次生成请求,已有消息策略和交互保持兼容 |
142
- | 10,000 个小文件 | 全量清单完整,请求有界;预算不足时正确停止 |
143
- | 超过 64 MiB 的源码补丁 | 流式读取、指纹校验与内存规模符合预期 |
144
- | 巨型 hunk、超长单行 | 不导致超限请求或无界内存,覆盖状态诚实 |
145
- | 二进制、lock、生成文件、批量重命名 | 正文策略正确,路径仍完整纳入提交 |
146
- | 跨目录实现与测试 | 可形成同一逻辑组,分块不强制分组 |
147
- | 敏感文件、未跟踪符号链接 | 保持现有保护行为,不因分块绕过 |
148
- | 429、响应截断、错误 ID、usage 缺失 | 重试有界、校验拒绝非法响应、预算保守记账 |
149
- | 超时、Ctrl+C、Git 失败、并发修改 | 清理资源、不误提交、不破坏真实 index |
150
- | split 导出、apply、hook 失败与 resume | 原有工件和事务恢复兼容 |
139
+ | 场景 | 必须验证 |
140
+ | ------------------------------------- | ------------------------------------------------------------ |
141
+ | 普通小提交 | 一次生成请求,已有消息策略和交互保持兼容 |
142
+ | 10,000 个小文件 | 全量清单完整,请求有界;预算不足时生成明确标记的完整保守计划 |
143
+ | 超过 64 MiB 的源码补丁 | 流式读取、指纹校验与内存规模符合预期 |
144
+ | 巨型 hunk、超长单行 | 不导致超限请求或无界内存,覆盖状态诚实 |
145
+ | 二进制、lock、生成文件、批量重命名 | 正文策略正确,路径仍完整纳入提交 |
146
+ | 跨目录实现与测试 | 可形成同一逻辑组,分块不强制分组 |
147
+ | 敏感文件、未跟踪符号链接 | 保持现有保护行为,不因分块绕过 |
148
+ | 429、响应截断、错误 ID、usage 缺失 | 重试有界、校验拒绝非法响应、预算保守记账 |
149
+ | 超时、Ctrl+C、Git 失败、并发修改 | 清理资源、不误提交、不破坏真实 index |
150
+ | split 导出、apply、hook 失败与 resume | 原有工件和事务恢复兼容 |
151
151
 
152
152
  - [ ] 记录峰值 RSS、总耗时、请求数、输入 / 输出 token 及覆盖情况;至少比较两个补丁体量,确认正文内存有界。
153
153
  - [ ] 记录小提交相对基线的额外耗时,测量后确定可接受阈值及最终预算默认值。
@@ -177,7 +177,7 @@
177
177
  - Git 内容使用直接写临时文件的方式捕获,Node 按 64 KiB 读取,避免同步 stdout 缓冲上限;没有引入长期运行的异步 Git 子进程。临时文件空间取决于变更大小,Git 捕获有 120 秒命令超时。
178
178
  - token 计数采用保守估算并结合 Provider 模型窗口。Provider 上下文超限明确失败,尚未实现 tokenizer 精确计数和 Provider 报错后的自动缩块。
179
179
  - 分析不完整时统一停止,不生成可直接接受的部分草稿。完整分析结果的改写继续使用现有审阅流程。
180
- - 批次分层规划允许合并候选组;无法收敛时要求缩小范围,不把未解决文件自动塞入兜底组。大变更不支持实验性 hunk 规划,单行超过 1 MiB 明确拒绝。
180
+ - 批次分层规划允许合并候选组;深度分析会先预估成本,候选清单可分批并继续分层合并。预算耗尽或规划无法收敛时,不采用半份模型结果,而是明确警告并生成覆盖全部文件的单提交保守计划。大变更不支持实验性 hunk 规划,单行超过 1 MiB 明确拒绝。
181
181
  - 未新增真实 Provider 的语义质量基准;本次验证使用模拟 Provider,不能据此保证任意模型的摘要和分组质量。
182
182
 
183
183
  ### 验证结果
package/docs/privacy.md CHANGED
@@ -57,6 +57,6 @@ Use `aicommit config show` to inspect effective local state without revealing cr
57
57
 
58
58
  ## Large-change snapshots / 大变更快照
59
59
 
60
- Default large-change analysis sends a bounded local inventory and selected protected excerpts to the configured provider, without per-file model requests. Explicit `deep` analysis sends protected fragments and intermediate factual summaries. Both local inventories and model summaries remain untrusted input. Full Git patches and larger untracked text are captured in private local temporary files, with bounded memory reads. Normal completion and Ctrl+C clean them up; an abnormal crash can leave snapshots in the system temporary directory. Summaries are reused only within the current run and are not added to JSON output or split checkpoints.
60
+ Default large-change analysis sends a bounded local inventory and selected protected excerpts to the configured provider, without per-file model requests. Explicit `deep` analysis sends protected fragments and intermediate factual summaries. Both local inventories and model summaries remain untrusted input. Full Git patches and larger untracked text are captured in private local temporary files, with bounded memory reads. Validated initial `deep` summaries may be stored under private Git metadata for up to 24 hours so an interrupted identical snapshot can resume; entries contain generic fragment IDs and model summaries, not the captured diff, reasoning, credentials, or complete provider responses. Because summaries are derived from repository content, they may still contain code details. Successful generation removes its cache. Unprotected original input is not persisted unless the user explicitly enables `largeChange.cache.allowUnprotected` in personal configuration. Cache entries are not added to JSON output or split checkpoints.
61
61
 
62
- 默认大变更分析向已配置 Provider 发送受限本地清单和选定的保护后片段,不逐文件调用模型。明确选择 `deep` 时才发送分块片段和中间事实摘要。本地清单和模型摘要均视为不可信输入。完整 Git 补丁和较大未跟踪文本保存在本地私有临时文件中,按块读取;正常结束及 Ctrl+C 会清理,异常崩溃可能在系统临时目录留下快照。摘要仅在本次运行中复用,不加入 JSON 输出或 split checkpoint。
62
+ 默认大变更分析向已配置 Provider 发送受限本地清单和选定的保护后片段,不逐文件调用模型。明确选择 `deep` 时才发送分块片段和中间事实摘要。本地清单和模型摘要均视为不可信输入。完整 Git 补丁和较大未跟踪文本保存在本地私有临时文件中,按块读取。通过校验的初始 `deep` 摘要可在私有 Git 元数据目录中保留最多 24 小时,让完全相同的快照在中断后续跑;缓存只含通用片段 ID 和模型摘要,不直接保存捕获的 diff、推理、凭据或完整 Provider 响应。摘要源自仓库内容,仍可能包含代码细节。完整生成成功后会删除本次缓存。未保护原始内容仅在用户通过个人配置显式启用 `largeChange.cache.allowUnprotected` 时持久化。缓存不会加入 JSON 输出或 split checkpoint。
@@ -15,20 +15,20 @@ JSON mode keeps one machine object on stdout and diagnostics on stderr. The `err
15
15
 
16
16
  JSON 模式保证 stdout 只有一个机器对象,诊断进入 stderr。`error.category` 与进程退出码可稳定用于自动化。
17
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, reasoning, 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, or policy validation 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
- | `aicommit update` refuses the installation / update 拒绝当前安装 | `config` / `2` | Source checkout, npm link, or another active Node/npm environment / 源码、npm link 或当前是另一套 Node/npm 环境 | Activate the Node environment that installed AICommit, or run `npm install --global @hifullmoon/aicommit@latest` manually |
30
- | `aicommit update` cannot reach npm / update 无法访问 npm | `network` / `4` | Registry authentication, proxy, DNS, or network failure / registry 鉴权、代理、DNS 或网络失败 | Check `npm config get registry` and npm authentication/proxy settings, then retry |
31
- | 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 |
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, reasoning, 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, or policy validation 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 部分提交后停止 | `git_state` / `3` | Hook, crash, SIGINT, or concurrent pending edit / hook、崩溃、中断或待处理文件变化 | Inspect `aicommit split status --output=json`, then run `aicommit split resume --yes`; only use `split abort` to discard recovery metadata |
29
+ | `aicommit update` refuses the installation / update 拒绝当前安装 | `config` / `2` | Source checkout, npm link, or another active Node/npm environment / 源码、npm link 或当前是另一套 Node/npm 环境 | Activate the Node environment that installed AICommit, or run `npm install --global @hifullmoon/aicommit@latest` manually |
30
+ | `aicommit update` cannot reach npm / update 无法访问 npm | `network` / `4` | Registry authentication, proxy, DNS, or network failure / registry 鉴权、代理、DNS 或网络失败 | Check `npm config get registry` and npm authentication/proxy settings, then retry |
31
+ | 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 |
32
32
 
33
33
  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, or credential-helper output to a public issue.
34
34
 
@@ -36,10 +36,14 @@ If a failure remains, capture `aicommit doctor --output=json`, Node/Git versions
36
36
 
37
37
  ## Large-change limits / 大变更限制
38
38
 
39
- Default `auto` analysis builds a local inventory and selects bounded excerpts without model reduction calls. If a complete split candidate inventory cannot fit one request, stage a smaller logical change or explicitly choose personal `largeChange.strategy: "deep"`. Deep analysis can reach its fixed request (256) or depth (8) limits; increasing token or time budgets does not raise those limits. Token/time limits remain configurable in personal settings. Unknown model token counts use conservative estimates; an oversized request fails before dispatch, and provider-context errors are not blindly replayed.
39
+ Default `auto` analysis builds a local inventory and selects bounded excerpts, then batches oversized split inventories and merges their plans hierarchically. Deep analysis still has fixed request (256) and depth (8) limits. If its aggregate token/time budget is exhausted or hierarchical planning cannot converge, split mode emits an explicit warning and can fall back to one complete all-files plan; it never uses a partial model plan. Interactive and dry-run flows show that plan, while non-interactive committing requires the explicit `--allow-single-fallback` option. Token/time limits remain configurable in personal settings. Unknown model token counts use conservative estimates; an oversized request is not dispatched, and provider-context errors are not blindly replayed.
40
40
 
41
- 默认 `auto` 在本地建立清单并选择受限片段,不调用模型递归汇总。完整拆分候选清单放不进一次请求时,请暂存更小的逻辑变更,或明确在个人配置中选择 `largeChange.strategy: "deep"`。深度分析的请求数(256)和汇总层级(8)上限固定,提高 token 或时间预算不会改变它们;token 和时间预算可在个人配置中调整。未知模型采用保守 token 估算,输入估算超限会在发送前失败;Provider 上下文超限不会盲目重试。
41
+ 默认 `auto` 在本地建立清单并选择受限片段;拆分候选过多时会分批请求,再分层合并计划。深度分析仍有固定的请求数(256)和汇总层级(8)上限。如果总 token/时间预算耗尽,或分层规划无法收敛,拆分模式会明确警告,并可降级为一个覆盖全部文件的计划,绝不会采用模型返回的半份计划。交互和 dry-run 流程会展示该计划;非交互提交必须显式传入 `--allow-single-fallback`。token 和时间预算仍可在个人配置中调整。未知模型采用保守 token 估算,单次输入超限时不会发送该请求;Provider 上下文超限不会盲目重试。
42
42
 
43
- Text lines over 1 MiB fail explicitly. Large-change hunk plans are unsupported; use file-level split. Metadata-only files remain in the complete plan. Invalid, duplicate, or missing IDs are response-format errors, not automatic catch-all groups.
43
+ Validated initial `deep` chunks are cached under private Git metadata after a failed or interrupted run. A retry of the identical snapshot and model settings reports cached chunks and requests only the remainder. Any input/model/protection change causes a miss. Successful generation clears the active cache; stale entries expire after 24 hours. Unprotected input is not cached unless personal `largeChange.cache.allowUnprotected` is explicitly enabled.
44
+
45
+ 失败或中断后,已经通过校验的初始 `deep` 分块会缓存在私有 Git 元数据中。使用相同快照和模型设置重试时会报告缓存命中,并只请求剩余分块;输入、模型或保护模式发生任何变化都会失效。完整生成成功后清理当前缓存,遗留项 24 小时后过期。未保护内容只有在个人配置显式启用 `largeChange.cache.allowUnprotected` 时才缓存。
46
+
47
+ Text lines over 1 MiB fail explicitly. Large-change hunk plans are unsupported; use file-level split. Metadata-only files remain in the complete plan. Invalid provider output remains a response-format error; only deterministic budget/capacity exhaustion activates the complete all-files fallback.
44
48
 
45
49
  单行超过 1 MiB 会明确报错。大变更暂不支持 hunk 规划,请使用文件级拆分。仅统计的文件仍纳入完整计划。无效、重复或遗漏 ID 会报响应格式错误,不会自动归入兜底组。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hifullmoon/aicommit",
3
- "version": "2.4.1",
3
+ "version": "2.6.0",
4
4
  "description": "Safe, local-first AI commit message generator for Git workflows",
5
5
  "type": "module",
6
6
  "bin": {