@rethunk/mcp-multi-root-git 2.9.1 → 4.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.
Files changed (75) hide show
  1. package/AGENTS.md +23 -19
  2. package/CHANGELOG.md +145 -39
  3. package/HUMANS.md +23 -42
  4. package/README.md +30 -13
  5. package/dist/repo-paths.js +57 -13
  6. package/dist/server/batch-commit-tool.js +203 -53
  7. package/dist/server/error-codes.js +31 -16
  8. package/dist/server/git-blame-tool.js +66 -19
  9. package/dist/server/git-branch-tool.js +151 -0
  10. package/dist/server/git-cherry-pick-tool.js +221 -12
  11. package/dist/server/git-conflicts-tool.js +230 -0
  12. package/dist/server/git-diff-summary-tool.js +39 -28
  13. package/dist/server/git-diff-tool.js +56 -31
  14. package/dist/server/git-grep-tool.js +188 -0
  15. package/dist/server/git-inventory-tool.js +30 -10
  16. package/dist/server/git-log-tool.js +37 -6
  17. package/dist/server/git-merge-tool.js +71 -13
  18. package/dist/server/git-parity-tool.js +15 -6
  19. package/dist/server/git-push-tool.js +4 -2
  20. package/dist/server/git-refs.js +48 -17
  21. package/dist/server/git-reset-soft-tool.js +1 -1
  22. package/dist/server/git-revert-tool.js +160 -0
  23. package/dist/server/git-show-tool.js +5 -10
  24. package/dist/server/git-stash-tool.js +112 -78
  25. package/dist/server/git-status-tool.js +2 -2
  26. package/dist/server/git-tag-tool.js +8 -13
  27. package/dist/server/git-worktree-tool.js +67 -59
  28. package/dist/server/git.js +116 -24
  29. package/dist/server/inventory.js +90 -32
  30. package/dist/server/list-presets-tool.js +2 -8
  31. package/dist/server/presets-resource.js +37 -20
  32. package/dist/server/presets.js +87 -15
  33. package/dist/server/roots.js +52 -79
  34. package/dist/server/schemas.js +18 -19
  35. package/dist/server/test-harness.js +11 -4
  36. package/dist/server/tool-parameter-schemas.js +47 -58
  37. package/dist/server/tools.js +36 -17
  38. package/dist/server.js +1 -1
  39. package/docs/install.md +52 -5
  40. package/docs/mcp-tools.md +472 -284
  41. package/package.json +6 -6
  42. package/schemas/batch_commit.json +5 -17
  43. package/schemas/git_blame.json +13 -11
  44. package/schemas/git_branch.json +54 -0
  45. package/schemas/git_cherry_pick.json +13 -15
  46. package/schemas/git_cherry_pick_continue.json +34 -0
  47. package/schemas/git_conflicts.json +38 -0
  48. package/schemas/git_diff.json +12 -10
  49. package/schemas/git_diff_summary.json +1 -15
  50. package/schemas/git_grep.json +85 -0
  51. package/schemas/git_inventory.json +32 -23
  52. package/schemas/git_log.json +20 -24
  53. package/schemas/git_merge.json +3 -15
  54. package/schemas/git_parity.json +13 -23
  55. package/schemas/git_push.json +1 -13
  56. package/schemas/git_reset_soft.json +1 -13
  57. package/schemas/git_revert.json +47 -0
  58. package/schemas/git_show.json +2 -8
  59. package/schemas/git_stash_apply.json +2 -8
  60. package/schemas/git_stash_push.json +47 -0
  61. package/schemas/git_status.json +13 -23
  62. package/schemas/git_tag.json +1 -7
  63. package/schemas/git_worktree_add.json +2 -14
  64. package/schemas/git_worktree_remove.json +2 -14
  65. package/schemas/index.json +28 -23
  66. package/schemas/list_presets.json +13 -23
  67. package/tool-parameters.schema.json +407 -423
  68. package/dist/server/git-branch-list-tool.js +0 -138
  69. package/dist/server/git-fetch-tool.js +0 -266
  70. package/dist/server/git-reflog-tool.js +0 -126
  71. package/schemas/git_branch_list.json +0 -36
  72. package/schemas/git_fetch.json +0 -52
  73. package/schemas/git_reflog.json +0 -44
  74. package/schemas/git_stash_list.json +0 -30
  75. package/schemas/git_worktree_list.json +0 -30
package/AGENTS.md CHANGED
@@ -15,48 +15,54 @@ IDEs injecting this as context: do not re-link from rules.
15
15
 
16
16
  | File | Symbols |
17
17
  |------|---------|
18
- | [`src/server.ts`](src/server.ts) | `FastMCP` + `roots: { enabled: true }`; `readMcpServerVersion()`; `registerRethunkGitTools` |
19
- | [`src/server/json.ts`](src/server/json.ts) | `jsonRespond()` (minified, no envelope), `spreadWhen`, `spreadDefined` |
18
+ | [`src/server.ts`](src/server.ts) | `FastMCP` + `roots: { enabled: true }`; `MCP_JSON_FORMAT_VERSION`; `registerRethunkGitTools` |
19
+ | [`src/server/json.ts`](src/server/json.ts) | `jsonRespond()` (minified, no envelope), `readMcpServerVersion()`, `spreadWhen`, `spreadDefined` |
20
20
  | [`src/server/git.ts`](src/server/git.ts) | `gateGit`, `spawnGitAsync` (optional `{ timeoutMs, signal }`), `asyncPool`, `GIT_SUBPROCESS_PARALLELISM`, `GIT_SUBPROCESS_TIMEOUT_MS`, `gitTopLevel`, `gitRevParseGitDir`, `gitRevParseHead`, `parseGitSubmodulePaths`, `hasGitMetadata`, `gitStatusSnapshotAsync`, `gitStatusShortBranchAsync`, `fetchAheadBehind`, `isSafeGitUpstreamToken` |
21
- | [`src/server/roots.ts`](src/server/roots.ts) | `requireGitAndRoots`, `requireSingleRepo`, `resolveAbsoluteGitRootsList`, `GitRootPickArgs` — shared tool preludes; session root resolution; optional `absoluteGitRoots` bulk pick |
21
+ | [`src/server/roots.ts`](src/server/roots.ts) | `requireGitAndRoots` (fan-out `root` resolution: string / string[] / `"*"`), `requireSingleRepo` (`workspaceRoot`), `resolveRootPathList`, `RootPickArgs` — shared tool preludes; session root resolution |
22
22
  | [`src/server/presets.ts`](src/server/presets.ts) | `PRESET_FILE_PATH`, `loadPresetsFromGitTop`, `presetLoadErrorPayload`, `applyPresetNestedRoots`, `applyPresetParityPairs`; Zod schemas must match [`git-mcp-presets.schema.json`](git-mcp-presets.schema.json) |
23
- | [`src/server/schemas.ts`](src/server/schemas.ts) | `WorkspacePickSchema`, `MAX_INVENTORY_ROOTS_DEFAULT`, **`MAX_ABSOLUTE_GIT_ROOTS`** (256), optional **`absoluteGitRoots`** on workspace pick |
23
+ | [`src/server/schemas.ts`](src/server/schemas.ts) | `WorkspacePickSchema` (single-repo: `workspaceRoot` + `format`), `RootPickSchema` (fan-out: polymorphic `root` + `format`), `MAX_INVENTORY_ROOTS_DEFAULT`, **`MAX_ROOT_PATHS`** (256) |
24
24
  | [`src/server/inventory.ts`](src/server/inventory.ts) | `InventoryEntryJson`, `validateRepoPath`, `makeSkipEntry`, `buildInventorySectionMarkdown`, `collectInventoryEntry` |
25
- | [`src/server/git-refs.ts`](src/server/git-refs.ts) | `isProtectedBranch`, `isSafeGitRefToken`, `isSafeGitRangeToken`, `isSafeGitAncestorRef`; `getCurrentBranch`, `resolveRef`, `isWorkingTreeClean`, `isFullyMergedInto`, `isContentEquivalentlyMergedInto`, `commitListBetween`; `listWorktrees`, `worktreeForBranch`; `inferRemoteFromUpstream`; `conflictPaths` |
25
+ | [`src/server/git-refs.ts`](src/server/git-refs.ts) | `isProtectedBranch`, `isSafeGitRefToken`, `isSafeGitRangeToken`, `isSafeGitAncestorRef`, `isSafeGitCommitIsh`; `getCurrentBranch`, `resolveRef`, `isWorkingTreeClean`, `isFullyMergedInto`, `isContentEquivalentlyMergedInto`, `commitListBetween`; `listWorktrees`, `worktreeForBranch`; `inferRemoteFromUpstream`; `conflictPaths` |
26
+ | [`src/server/error-codes.ts`](src/server/error-codes.ts) | `ERROR_CODES` (centralised error-code registry — the exact `error` field strings on the wire), `ErrorCode` type |
26
27
  | [`src/server/tools.ts`](src/server/tools.ts) | `registerRethunkGitTools` — dispatches to `register*` below; `selectToolRegistrars(envValue, registrars)` — pure parse/filter fn for `RETHUNK_GIT_TOOLS` (reads env inside `registerRethunkGitTools`, not at module scope); `TOOL_REGISTRARS` ordered array |
27
28
  | [`src/server/git-status-tool.ts`](src/server/git-status-tool.ts) | `git_status` |
28
- | [`src/server/git-inventory-tool.ts`](src/server/git-inventory-tool.ts) | `git_inventory` |
29
+ | [`src/server/git-inventory-tool.ts`](src/server/git-inventory-tool.ts) | `git_inventory` — optional `compareRefs: { left, right }` ahead/behind between arbitrary local refs |
29
30
  | [`src/server/git-parity-tool.ts`](src/server/git-parity-tool.ts) | `git_parity` |
30
31
  | [`src/server/list-presets-tool.ts`](src/server/list-presets-tool.ts) | `list_presets` |
31
- | [`src/server/git-log-tool.ts`](src/server/git-log-tool.ts) | `git_log` — v3 JSON shape: `sha` (full), `workspaceRoot`, no `sha7`/`ageRelative`, optional `email` |
32
+ | [`src/server/git-log-tool.ts`](src/server/git-log-tool.ts) | `git_log` — v3 JSON shape: `sha` (full), `workspaceRoot`, no `sha7`/`ageRelative`, optional `email`; optional `follow` (exactly one `paths` entry) |
33
+ | [`src/server/git-grep-tool.ts`](src/server/git-grep-tool.ts) | `git_grep` — read-only fan-out pickaxe history search (`git log -S`/`-G` via required `pickaxe`, `commits[]` per root); content mode removed in v6 |
32
34
  | [`src/server/git-diff-summary-tool.ts`](src/server/git-diff-summary-tool.ts) | `git_diff_summary` — structured token-efficient diff viewer; read-only |
33
35
  | [`src/server/git-diff-tool.ts`](src/server/git-diff-tool.ts) | `git_diff` — raw scoped diff text; read-only |
34
36
  | [`src/server/git-show-tool.ts`](src/server/git-show-tool.ts) | `git_show` — inspect commit message + diff or file content at a ref; read-only |
35
- | [`src/server/git-stash-tool.ts`](src/server/git-stash-tool.ts) | `git_stash_list`, `git_stash_apply` |
36
- | [`src/server/git-fetch-tool.ts`](src/server/git-fetch-tool.ts) | `git_fetch` — fetch remote refs without touching the working tree |
37
+ | [`src/server/git-conflicts-tool.ts`](src/server/git-conflicts-tool.ts) | `git_conflicts` — inspect unresolved merge conflicts (state detection + per-file ours/theirs/base hunk parsing) |
38
+ | [`src/server/git-stash-tool.ts`](src/server/git-stash-tool.ts) | `git_stash_apply`, `git_stash_push` |
39
+ | [`src/server/git-blame-tool.ts`](src/server/git-blame-tool.ts) | `git_blame` — file authorship, run-length grouped by contiguous same-commit line runs; read-only |
37
40
  | [`src/server/git-tag-tool.ts`](src/server/git-tag-tool.ts) | `git_tag` — create/delete annotated or lightweight tags |
38
- | [`src/server/git-worktree-tool.ts`](src/server/git-worktree-tool.ts) | `git_worktree_list`, `git_worktree_add`, `git_worktree_remove` |
41
+ | [`src/server/git-branch-tool.ts`](src/server/git-branch-tool.ts) | `git_branch` create/delete/rename local branches; protected-name checks on every action |
42
+ | [`src/server/git-worktree-tool.ts`](src/server/git-worktree-tool.ts) | `git_worktree_add`, `git_worktree_remove` |
39
43
  | [`src/server/batch-commit-tool.ts`](src/server/batch-commit-tool.ts) | `batch_commit` — sequential multi-commit; mutating; exports `PushReport`, `runPushAfter` |
40
44
  | [`src/server/git-push-tool.ts`](src/server/git-push-tool.ts) | `git_push` — standalone push with optional upstream tracking |
41
45
  | [`src/server/git-merge-tool.ts`](src/server/git-merge-tool.ts) | `git_merge` — mutating |
42
- | [`src/server/git-cherry-pick-tool.ts`](src/server/git-cherry-pick-tool.ts) | `git_cherry_pick` — mutating |
46
+ | [`src/server/git-cherry-pick-tool.ts`](src/server/git-cherry-pick-tool.ts) | `git_cherry_pick` (`onConflict?: "abort"\|"pause"`), `git_cherry_pick_continue` (`action?: "continue"\|"abort"`, resumes/aborts a paused cherry-pick) both mutating |
43
47
  | [`src/server/git-reset-soft-tool.ts`](src/server/git-reset-soft-tool.ts) | `git_reset_soft` — soft-reset; mutating |
48
+ | [`src/server/git-revert-tool.ts`](src/server/git-revert-tool.ts) | `git_revert` — inverse-commit revert; mutating, non-history-rewriting |
44
49
  | [`src/server/presets-resource.ts`](src/server/presets-resource.ts) | `rethunk-git://presets` resource |
45
50
  | [`src/server/tool-parameter-schemas.ts`](src/server/tool-parameter-schemas.ts) | `buildToolParameterSchemaDocument`, `captureToolParameterSchemas`; backs `tool-parameters.schema.json` and published `schemas/*.json` snapshots |
51
+ | [`src/server/coverage.ts`](src/server/coverage.ts) | `parseAllFilesLineCoverage` — parses bun test coverage output for `coverage:check` CI gate |
46
52
  | [`src/repo-paths.ts`](src/repo-paths.ts) | `resolvePathForRepo`, `assertRelativePathUnderTop`, `isStrictlyUnderGitTop` |
47
53
 
48
54
  ## Changing contracts
49
55
 
50
56
  - **No banner paragraphs** in shipped docs. Use normal titles + cross-links.
51
- - **JSON format version** (currently `"3"`, exported as `MCP_JSON_FORMAT_VERSION` in `src/server.ts` and surfaced via the FastMCP `instructions` field — discoverable from the MCP `initialize` response): bump on incompatible JSON changes (renamed/nested/omitted fields). Document migration here + [docs/mcp-tools.md](docs/mcp-tools.md). v2 removed the `rethunkGitMcp` envelope; payloads are minified; optional fields omitted when empty/null/false. v3 changes in `git_log`: `sha7` → `sha` (full SHA), `workspace_root` → `workspaceRoot`, `ageRelative` removed, `email` omitted when empty.
57
+ - **JSON format version** (currently `"6"`, exported as `MCP_JSON_FORMAT_VERSION` in `src/server.ts` and surfaced via the FastMCP `instructions` field — discoverable from the MCP `initialize` response): bump on incompatible JSON changes (renamed/nested/omitted fields). Document migration here + [docs/mcp-tools.md](docs/mcp-tools.md). v2 removed the `rethunkGitMcp` envelope; payloads are minified; optional fields omitted when empty/null/false. v3 changes in `git_log`: `sha7` → `sha` (full SHA), `workspace_root` → `workspaceRoot`, `ageRelative` removed, `email` omitted when empty. v4 changes: `git_blame` output run-length grouped (`lines[]` → `groups[]`, commit metadata once per contiguous run, `maxLines` cap with `truncated`/`omittedLines`); `git_diff_summary` per-file `truncated` omitted when false. v5 changes: `batch_commit` successful `results[*]` entries drop the echoed `message`/`files` (the caller already supplied both) — failing entries still carry them for diagnosis. v6 changes: tool surface reduced to 24 (seven thin read wrappers removed — see [CONTRIBUTING.md — Tool inclusion criteria](CONTRIBUTING.md#tool-inclusion-criteria)); `git_grep` is pickaxe-only (`pickaxe` required, `pattern`/`filesOnly` removed, results always `commits[]`).
52
58
  - **Preset file:** keep `presets.ts` Zod schemas aligned with [`git-mcp-presets.schema.json`](git-mcp-presets.schema.json).
53
59
  - **Public tool surface:** rename/add → update [docs/mcp-tools.md](docs/mcp-tools.md) + [README.md](README.md) (if mentioned), then regenerate the shipped schema artifacts (`tool-parameters.schema.json`, `schemas/index.json`, `schemas/*.json`). Install/client wiring → [docs/install.md](docs/install.md) only.
54
60
 
55
61
  ## Validate + CI
56
62
 
57
- Local: `bun run build` | `bun run lint` | `bun run schema:tools:check` | `bun run test`. CI ([`ci.yml`](.github/workflows/ci.yml)) runs same on PRs + `main` after `bun install --frozen-lockfile`, then `bun run test:coverage` + `bun run coverage:check`, and uploads prerelease `npm pack` artifact. Tag `v*.*.*` matching `package.json` version → [`release.yml`](.github/workflows/release.yml) publishes to GitHub Packages as `@rethunk-ai/mcp-multi-root-git` + cuts GitHub Release. npmjs publish is manual (see [HUMANS.md](HUMANS.md)).
63
+ Local: `bun run build` | `bun run lint` | `bun run typecheck` | `bun run schema:tools:check` | `bun run schema:individual:check` | `bun run test`. CI ([`ci.yml`](.github/workflows/ci.yml)) runs the same gates once each on PRs + `main` after `bun install --frozen-lockfile` (schema checks, lint, typecheck, `bun run test:coverage` + `bun run coverage:check`, build), and uploads prerelease `npm pack` artifact. Tag `v*.*.*` matching `package.json` version → [`release.yml`](.github/workflows/release.yml) publishes to GitHub Packages as `@rethunk-ai/mcp-multi-root-git` + cuts GitHub Release. npmjs publish is manual (see [HUMANS.md](HUMANS.md)).
58
64
 
59
- Optional [`.githooks/`](.githooks): `bun run setup-hooks` once per clone. pre-commit=`check`; pre-push=frozen install + build + check + test.
65
+ Optional [`.githooks/`](.githooks): `bun run setup-hooks` once per clone. pre-commit=`lint`; pre-push=frozen install + build + lint + test.
60
66
 
61
67
  Path confinement: [`src/repo-paths.ts`](src/repo-paths.ts) — extend tests when changing.
62
68
 
@@ -66,13 +72,11 @@ Rules for LLMs operating in or against this repository.
66
72
 
67
73
  **End-user Git/MCP preference** (status/log/diff/commits): **`~/.claude/CLAUDE.md`** § **Git & GitHub** — same policy when dogfooding this server from a harness.
68
74
 
69
- **Mutating tools use `workspaceRoot` as trusted operator input** `git_fetch`, `batch_commit`, `git_push`, `git_merge`, `git_cherry_pick`, `git_reset_soft`, `git_tag`, and `git_stash_apply` operate on roots resolved via `requireGitAndRoots` / `requireSingleRepo`. Pass the target repo as `workspaceRoot` (trusted caller input) or via MCP roots. The `absoluteGitRoots` bulk multi-root parameter is not accepted by mutating tools — passing it is rejected.
75
+ **One routing param per tool** — the six fan-out read tools (`git_status`, `git_inventory`, `git_parity`, `list_presets`, `git_log`, `git_grep`) take polymorphic **`root`** (string = one repo, string[] = explicit repo list, `"*"` = every MCP root). Every other tool — including all mutating tools (`batch_commit`, `git_push`, `git_merge`, `git_cherry_pick`, `git_reset_soft`, `git_revert`, `git_tag`, `git_branch`, `git_stash_apply`, `git_stash_push`, worktree add/remove) takes only **`workspaceRoot`** (trusted operator input) and resolves via `requireSingleRepo`; multi-repo routing params are not accepted on writes.
70
76
 
71
- **`batch_commit` atomic staging — single call per logical change** — Do NOT attempt incremental staging across multiple `batch_commit` calls. Each call is self-contained: it stages all files in all entries, commits them sequentially, and the moment the call completes, all commits have landed. Include all related files (for all related commit entries) in a single `batch_commit` call. A call cannot be resumed or extended by a later call — each is an independent transaction. If entry N fails, entries before N remain committed; entries after N are skipped (not rolled back).
77
+ **`batch_commit` atomic staging — single call per logical change** — Do NOT attempt incremental staging across multiple `batch_commit` calls. Each call is self-contained: it stages all files in all entries, commits them sequentially, and the moment the call completes, all commits have landed. Include all related files (for all related commit entries) in a single `batch_commit` call. A call cannot be resumed or extended by a later call — each is an independent transaction. If entry N fails, entries before N remain committed; entries after N are skipped (not rolled back). Each commit isolates the index: unrelated pre-staged paths are temporarily unstaged around an index-based `git commit` (pathspec/`--only` is avoided so hunk-level staging stays intact).
72
78
 
73
- **`absoluteGitRoots` is read-only** — pass it only on read tools (`git_status`, `git_inventory`, `git_parity`, `git_log`, `git_diff_summary`, `list_presets`). Mutating tools reject this parameter.
74
-
75
- **Protected branches are enforced by the server** — do not attempt `git_worktree_add` with a branch name matching `main`, `master`, `dev`, `develop`, `stable`, `trunk`, `prod`, `production`, `release*`, or `hotfix*`. The server rejects such calls.
79
+ **Protected branches are enforced by the server** — do not attempt `git_worktree_add` or `git_branch` (create/delete/rename, in any role) with a branch name in the protected set: exact matches `main`, `master`, `dev`, `develop`, `stable`, `trunk`, `prod`, `production`, `head`; or names matching `^(release|hotfix)[-/].+$` (e.g. `release/1.0`, `hotfix-123` bare `release`/`hotfix` alone are not protected). The server rejects such calls.
76
80
 
77
81
  **Never force-push** — `git_push` has no force-push mode by design. `git_merge` with `strategy: "ff-only"` will fail cleanly rather than force.
78
82
 
package/CHANGELOG.md CHANGED
@@ -2,6 +2,132 @@
2
2
 
3
3
  All notable changes to `@rethunk/mcp-multi-root-git` are documented here. Format loosely follows [Keep a Changelog](https://keepachangelog.com); the project uses [Semantic Versioning](https://semver.org).
4
4
 
5
+ ## [Unreleased]
6
+
7
+ ## [4.0.0] — 2026-07-18
8
+
9
+ **Breaking release: the tool surface shrinks from 31 to 24.** Seven thin read wrappers are removed and `git_grep` is reduced to pickaxe-only; `MCP_JSON_FORMAT_VERSION` bumps to **`"6"`**. Rationale is codified in [CONTRIBUTING.md — Tool inclusion criteria](CONTRIBUTING.md#tool-inclusion-criteria): a tool must deliver enforced write policy, fan-out call compression, or large-output compression — wrappers over tiny-output git commands whose Bash equivalents are frictionless on modern harnesses no longer earn a schema slot.
10
+
11
+ ### Removed
12
+
13
+ - **`git_fetch`** — its case rested on sandboxed-Bash network friction that no longer exists; raw `git fetch` output is tiny.
14
+ - **`git_remote`, `git_describe`, `git_stash_list`, `git_reflog`, `git_branch_list`, `git_worktree_list`** — thin wrappers over ~50–200-token porcelain commands; zero per-call token savings while costing schema space in every non-deferred client session.
15
+ - **`git_grep` content mode** — `pattern`, `filesOnly`, and ref-tree content search removed; working-tree content search duplicated the native grep/rg tooling every MCP client ships. `pickaxe` is now **required**; results always carry `commits[]` (never `matches`/`files`).
16
+ - **Error codes** — `pattern_or_pickaxe_required`, `remote_list_failed`, `describe_failed`, `no_tag_found`, `unsafe_match_pattern`, `stash_list_failed`, `branch_list_failed`, `reflog_failed` leave the registry with their tools.
17
+
18
+ ### Changed
19
+
20
+ - **`MCP_JSON_FORMAT_VERSION` `"5"` → `"6"`** — migration notes in [AGENTS.md](AGENTS.md) and [docs/mcp-tools.md](docs/mcp-tools.md).
21
+ - **Docs** — all shipped docs (mcp-tools, install, HUMANS, SECURITY, AGENTS, README) aligned with the 24-tool surface; schema artifacts regenerated.
22
+ - **CONTRIBUTING.md** — new **Tool inclusion criteria** section governing future additions and removals; “Adding a git tool” now starts with the criteria gate.
23
+
24
+ ### Added
25
+
26
+ - **`git_cherry_pick` `onConflict`** — `"abort"` (default, unchanged) or `"pause"`: on conflict, leave the conflict and native cherry-pick sequencer state in place instead of rolling back the whole range (`conflict.paused: true`, applied-so-far count derived from the HEAD advance). Closes the abort-only gap that previously forced a shell fallback to resolve conflicts on a multi-commit cherry-pick range.
27
+ - **`git_cherry_pick` guard** — a second `git_cherry_pick` call while one is already in progress (e.g. left paused) now returns a structured `cherry_pick_in_progress` error (with the conflicting `commit`) instead of the generic `working_tree_dirty`.
28
+ - **`git_cherry_pick_continue`** — new tool to resume (`action: "continue"`, default) or roll back (`action: "abort"`) a cherry-pick left in progress. Stateless: probes `CHERRY_PICK_HEAD` live off `.git` rather than depending on the pausing call. `continue` requires no remaining unmerged paths (`cherry_pick_unresolved_paths` otherwise), then runs `git -c core.editor=true cherry-pick --continue`; if a later pick in the same range then conflicts, the response reports it the same shape as a paused `git_cherry_pick` call so the tool can be called again to walk the rest of the range. `abort` reuses `git_cherry_pick`'s hardened abort helper/reporting (`cherry_pick_abort_failed` on abort failure). Errors `no_cherry_pick_in_progress` when nothing is in progress.
29
+
30
+ ## [3.3.0] — 2026-07-18
31
+
32
+ Feature and hardening release: deepen fan-out reads (pickaxe / follow / compareRefs), tighten path and ref safety, isolate `batch_commit` staging, and align CI/release with the local `ci` script. Additive JSON / behavior only — `MCP_JSON_FORMAT_VERSION` stays at `"5"`.
33
+
34
+ ### Added
35
+
36
+ - **`RETHUNK_GIT_TOOLS=*`** — bare `*` is now an all-tools sentinel (registers every tool) instead of an unrecognized name that emptied the allowlist.
37
+ - **`git_grep` `pickaxe`** — optional `{ mode: "S"|"G", term }` history search (`git log -S`/`-G`) returning `commits[]` per root; `pattern` optional when pickaxe is set (`pattern_or_pickaxe_required` when neither is provided).
38
+ - **`git_log` `follow`** — optional rename-aware history (`git log --follow`); requires exactly one `paths` entry else `invalid_paths`.
39
+ - **`git_inventory` `compareRefs`** — optional `{ left, right }` ahead/behind between arbitrary local refs (independent of upstream); bad tokens → `unsafe_ref_token`.
40
+ - **`git_diff` `maxBytes`** — optional UTF-8 byte cap on returned diff text (default `512000`, range 1024–10000000); oversized output sets `truncated: true`.
41
+ - **Subprocess bounds** — `spawnGitAsync` stdout/stderr capped (default 16 MiB, `GIT_SUBPROCESS_MAX_BUFFER_BYTES`); overflow kills the child and returns `truncated: true`. Hung children escalate SIGTERM → SIGKILL after 2s. Sync helpers gain `GIT_SYNC_TIMEOUT_MS` (30s).
42
+ - **`stash_apply_failed`** — registered in the central error-code registry and emitted on failed stash apply/pop.
43
+
44
+ ### Changed
45
+
46
+ - **CI** — `ci.yml` check job runs `bun run ci` so workflow gates stay aligned with the local script (including coverage `pipefail` and schema checks).
47
+ - **CI** — workflow Bun pin aligned to `packageManager` **1.3.14**; GitHub Actions third-party action pins bumped (`5fa33af`).
48
+ - **Release** — tag publish workflow no longer duplicates build or test after `bun run ci`; verifies a `CHANGELOG.md` section exists for the tagged version before publish.
49
+ - **Release / CI pack** — workflows use `npm pack --ignore-scripts` and `npm publish --ignore-scripts` so `prepublishOnly` does not re-run the full CI suite.
50
+ - **Publish preflight** — coverage threshold checks delegate to `bun run coverage:check` instead of duplicating parser logic.
51
+ - **Schema artifacts** — capture now drives `registerRethunkGitTools` (same path as the live server) instead of a parallel `register*` list, so published parameter schemas cannot silently omit a newly added tool; `schema:individual` / `--check` hard-fails on missing capture schemas and rejects orphan `schemas/*.json` files left after renames/removals.
52
+ - **`root: "*"` fan-out** — capped at `MAX_ROOT_PATHS` (256); oversize sessions return `{ error: root_list_too_many, max, count }` like explicit root arrays. `RootPickSchema` no longer Zod-`.max`s the array (execute-path structured error instead of FastMCP `too_big`).
53
+ - **Docs** — align `docs/mcp-tools.md` with wire contracts: fan-out feature params (`pickaxe` / `follow` / `compareRefs`), `git_diff` `maxBytes`, merge/cherry-pick abort-failure codes, stash apply `conflictPaths` + `destructiveHint`, worktree path argv safety, `batch_commit` index isolation, and related error-table cleanups (`MCP_JSON_FORMAT_VERSION` unchanged).
54
+ - **`SECURITY.md`** — refresh threat model to the full 30-tool surface (read + mutate), including previously omitted mutators; disclose trusted-operator `workspaceRoot` / explicit `root` paths (no MCP-session whitelist this release); document shipped controls (realpath confinement, protected-branch enforcement, no force-push, argv-array spawn + ref validators); correct aspirational claims; add `RETHUNK_GIT_TOOLS` hardening, read-tool content-exfil risk, and soft-reset vs revert rewrite matrix.
55
+ - **`git_stash_apply`** — on failure emits `error: stash_apply_failed` plus optional `conflictPaths`; sets `destructiveHint: true` (pop can delete a stash entry).
56
+ - **`git_merge` / `git_cherry_pick`** — abort helpers surface `--abort` failure (`merge_abort_failed` / `rebase_abort_failed` / `cherry_pick_abort_failed`) instead of claiming a cleaned tree when abort itself failed. `git_cherry_pick` hard-caps expanded picks at 100 (`cherry_pick_too_many_commits`). `git_merge` `auto`/`rebase` rewrite the **source** branch tip when rebasing (documented; behavior unchanged). `deleteMergedWorktrees` skips protected **source branch names**.
57
+ - **`git_diff_summary`** — `totalFiles` / `totalAdditions` / `totalDeletions` count the post-filter set; `excludedFiles` includes exclude-pattern hits and `fileFilter` drops; `truncatedFiles` is the `maxFiles` omit count.
58
+ - **`git_show`** — `git_show_failed` includes `detail` (stderr/stdout trim).
59
+ - **`git_tag`** — tag names use `isSafeGitRefToken`; create `ref` uses `isSafeGitCommitIsh`; tool description is create/delete only.
60
+
61
+ ### Fixed
62
+
63
+ - **Path confinement** — fail closed when `realpath` cannot resolve a path used for repo bounds checks (no ENOENT false-accept via intermediate symlinks outside the git toplevel); missing leaves under a symlink alias of the same toplevel still resolve correctly for deletion staging.
64
+ - **`isSafeGitAncestorRef`** — now delegates to `isSafeGitCommitIsh`, rejecting `..` ranges, `.lock` suffixes, `//`, trailing `/`/`.`, mid-name `~`/`^`, and leading `+` (previously accepted by a looser charset-only check).
65
+ - **`isSafeGitRefToken`** — rejects leading `+` (git force-update refspec); closes force-push/fetch via `branch=+name` when callers use this validator.
66
+ - **`listWorktrees`** — returns `{ ok:false, detail }` on git failure instead of an empty array.
67
+ - **`batch_commit` index isolation** — unrelated pre-staged paths are temporarily unstaged around an index-based `git commit` (avoids pathspec/`--only`, which would squash hunk staging); mid-entry `stage_failed` unstages that entry's paths; dryRun restores the pre-call index via `write-tree`/`read-tree`; fails closed when index snapshot `write-tree` fails; rejects `.` / repo-root / directory pathspecs (`invalid_paths`); line-range staging uses `git diff --` / `--no-index` for untracked and rejects `from > to` (`invalid_line_range`).
68
+ - **`git_log` path confinement** — each `paths` entry gated with `resolvePathForRepo` / `assertRelativePathUnderTop`; escaping paths yield `path_escapes_repo` per root.
69
+ - **`git_parity` / `git_inventory` non-git wording** — `pairs[*].error` and inventory `skipReason` use plain description strings (no nested minified JSON).
70
+ - **`git_diff` / `git_diff_summary` / `git_conflicts`** — honor docs precedence (`base` over `staged`; ignore `head` without `base`); emit bare `unsafe_range_token`; fix rename numstat counts; report `path_escapes_repo` on escaped conflict paths; flag incomplete conflict markers as `truncated`.
71
+ - **`git_push` / `git_fetch`** — reject leading `+` force-update refspecs on branch args.
72
+ - **`git_worktree_add` / `git_worktree_remove`** — reject leading-dash and NUL paths; pass path after `--`; trim `branch`/`baseRef` before spawn; sibling worktrees outside toplevel remain allowed.
73
+
74
+ ## [3.2.0] — 2026-07-10
75
+
76
+ Feature release: seven new tools (23 → 30 registered; content search, conflict inspection, remote/describe read access, branch lifecycle, revert, and stash push), plus argv-safety and range-validation fixes across the diff/blame/show/diff-summary family. The **`root`** fan-out routing param now applies to **six** read tools (see 3.0.0 migration — `git_grep` joins `git_status`, `git_inventory`, `git_parity`, `list_presets`, and `git_log`). Additive JSON changes only — `MCP_JSON_FORMAT_VERSION` stays at `"5"`.
77
+
78
+ ### Added
79
+
80
+ - **`git_grep`** — read-only fan-out content search (`git grep -n -e <pattern>`) across one or more roots. Optional `ref` searches the tree at a commit/branch instead of the working tree; `paths` scopes the search (confined to the repo root); `ignoreCase`/`filesOnly`/`maxMatches` tune output. A clean "no matches" `git grep` exit is treated as success with an empty result set, not an error. Pickaxe/history content search (`-S`/`-G`) is out of scope.
81
+ - `git_conflicts` — read-only inspection of unresolved merge conflicts after `git_merge`/`git_cherry_pick` reports them: detects the in-progress operation (merge/cherry-pick/revert/rebase) and parses each conflicted file's `<<<<<<</|||||||/=======/>>>>>>>` markers into structured ours/theirs/base hunks with line numbers and branch labels, so an agent can resolve conflicts without a raw file read. `withHunks`/`maxLinesPerFile` control cost.
82
+ - `git_remote` — list configured git remotes (`git remote -v`), returning name/fetchUrl/pushUrl (pushUrl omitted when identical to fetchUrl).
83
+ - `git_describe` — describe a commit relative to the nearest reachable tag (`git describe --long`), returning parsed tag/distance/sha.
84
+ - `git_branch` — create, delete, or rename a local branch (`action: "create"|"delete"|"rename"`), with protected-branch rejection on every action (source, target, and rename endpoints) and `force` for `-D` deletes of unmerged branches.
85
+ - `git_revert` — creates new commit(s) that undo one or more source commits (`git revert`), applied in listed order; never rewrites history, unlike `git_reset_soft`. Refuses on a dirty tree; on conflict aborts and leaves the tree clean, reporting structured conflict paths. `noCommit` stages the revert(s) without committing; `mainline` selects the parent when reverting a merge commit.
86
+ - **`git_stash_push`** — stash working-tree changes (`git stash push`). Optional `message`, `includeUntracked` (-u), `keepIndex` (--keep-index), and `paths` to scope the stash. Returns the new stash ref/SHA/subject, or `{ stashed: false, reason: "no_local_changes" }` when there is nothing to stash.
87
+
88
+ ### Changed
89
+
90
+ - PR CI (`ci.yml`) now runs each gate exactly once (build/lint/typecheck/schema-check/test were previously duplicated between `bun run ci` and separate CI steps); the local `ci` script gained the `schema:individual:check` step CI already ran, so the two stay in sync. The tag release workflow (`release.yml`) still duplicated build and tests until the fixes documented under `[Unreleased]`.
91
+ - `git_fetch` moved from the read-only registrar group to the head of the mutating group (it updates refs) — the registration order now matches `tool-parameter-schemas.ts` and the docs table, which already classified it as mutating.
92
+ - Added test coverage for `presets-resource.ts`'s `rethunk-git://presets` resource load handler (valid preset, invalid JSON, missing file) — it previously had none.
93
+
94
+ ### Fixed
95
+
96
+ - **`git_diff`/`git_blame`/`git_show`** — `base`/`head`/`ref` now accept ancestor notation (`HEAD~3`, `main^2`, `v1.0.0~2^1`) consistently across all three tools via a shared `isSafeGitCommitIsh` validator. Previously `git_diff` and `git_blame` rejected the documented `HEAD~3` example outright; `git_show` accepted ancestor notation but via a looser validator that lacked the `..`/`.lock`/`//`/`@{` guards the other tools had (now hardened to match).
97
+ - **`git_diff_summary`/`git_cherry_pick` range endpoints** — `isSafeGitRangeToken` validated each side of an `A..B`/`A...B` range with the base ref-token check (no `~`/`^` support), so `git_diff_summary`'s own documented example `"HEAD~3..HEAD"` was rejected with `unsafe_range_token`. Endpoints (and the no-range single-ref fallthrough) now validate with `isSafeGitCommitIsh`; `git_diff_summary` also dropped its separate ad hoc range-parsing regex in favor of the shared validator.
98
+ - `git_fetch` — corrected a stale comment describing the non-porcelain fallback path as pending work; no behavior change.
99
+
100
+ ## [3.1.0] — 2026-07-04
101
+
102
+ Token-cost reduction in `batch_commit` output. JSON format version bumped **4 → 5**.
103
+
104
+ ### Changed — breaking
105
+
106
+ - **`batch_commit` success entries drop echoed `message`/`files`.** Every entry in the JSON `results[]` array repeated the caller's own `message` and full `files[]` from the request, even on success — pure repetition, since the caller already has both. Successful entries now carry only `index`, `ok`, `sha` (or `staged`/`diffStat` in dry-run mode), and `output` when present. Failing entries are unchanged: `message`/`files` stay so the caller can identify the failed commit without cross-referencing the request. `MCP_JSON_FORMAT_VERSION` bumped to `"5"`.
107
+
108
+ ## [3.0.0] — 2026-07-03
109
+
110
+ Major release: token-cost reduction across the tool surface. Every tool now carries exactly one routing parameter, `git_blame` output is run-length grouped, and integer bounds are explicit. JSON format version bumped **3 → 4**.
111
+
112
+ ### Changed — breaking
113
+
114
+ - **Routing-param consolidation.** The four overlapping routing params (`workspaceRoot`, `rootIndex`, `allWorkspaceRoots`, `absoluteGitRoots`) are replaced by exactly one param per tool. The five fan-out read tools (`git_status`, `git_inventory`, `git_parity`, `list_presets`, `git_log`) take polymorphic **`root`**: a string (one repo path), a string array (explicit repo list — the old `absoluteGitRoots`), or `"*"` (every MCP root — the old `allWorkspaceRoots`). All other 18 tools take only **`workspaceRoot`** (`git_diff_summary` loses `absoluteGitRoots`). Defaults are unchanged: first MCP root, else `process.cwd()`.
115
+ - **`rootIndex` removed fleet-wide.** It was vestigial (no real consumer); the `root_index_out_of_range` error code is gone with it.
116
+ - **Root-validation error codes renamed.** `invalid_absolute_git_root` → `invalid_root_path`; `absolute_git_roots_empty` / `_too_many` / `_preset_conflict` / `_nested_or_preset_conflict` → `root_list_empty` / `root_list_too_many` / `root_list_preset_conflict` / `root_list_nested_or_preset_conflict`. `absolute_git_roots_exclusive` and `absolute_git_roots_single_repo_only` are removed — with a single routing param those states are unrepresentable.
117
+ - **`git_blame` output v4: run-length grouped.** JSON shape changed from `lines[]` (sha/author/date/summary repeated on every line) to `groups[]` — one entry per contiguous same-commit run carrying `sha`/`author`/`date`/`summary`/`startLine`/`endLine` once, plus `lines: [{ line, content }]`. Markdown output grouped the same way. `MCP_JSON_FORMAT_VERSION` bumped to `"4"`.
118
+ - **`git_diff_summary` per-file `truncated` omitted when false** (was always emitted), matching the format-contract rule that optional fields are absent when empty/null/false.
119
+
120
+ ### Added
121
+
122
+ - **`git_blame` `maxLines`** (default 2000, max 10000) — caps blamed lines; overflow is signalled with top-level `truncated: true` + `omittedLines`.
123
+
124
+ ### Fixed
125
+
126
+ - **Unbounded `.int()` params serialized `"maximum":9007199254740991` into tool schemas.** Explicit caps added: `batch_commit` `lines.from`/`lines.to` and `git_blame` `startLine`/`endLine` at 1000000, `git_stash_apply` `index` at 10000.
127
+
128
+ - **`batch_commit` hunk-level staging (`{ path, lines }`) could corrupt the git index.** `extractOverlappingHunks` joined the selected hunk(s) without a trailing newline; whenever the selection wasn't the *last* hunk in the file's real diff, the written patch file's final line had no newline terminator and `git apply --cached` rejected it with `error: corrupt patch at ...`. Fixed by always terminating the extracted patch with `\n`. Confirmed against a real multi-hunk diff before and after the fix; regression test added (`stages a non-final hunk without corrupting the patch`).
129
+ - **`batch_commit` `dryRun: true` could leave a partially-staged index after a failure.** When a commit entry listed multiple files and an earlier file staged successfully but a later file in the *same* entry failed to stage, the earlier file's staged state was never added to the dry-run cleanup set (tracking only happened after the whole per-file loop completed without failure) — so a failed "dry run" left real, uncommitted staged changes in the index. Fixed by tracking each file for cleanup immediately after it stages, not gated behind the later failure check. Regression test added (`dryRun: true unstages an earlier file when a later file in the same commit fails to stage`).
130
+
5
131
  ## [2.9.1] — 2026-06-11
6
132
 
7
133
  Patch release: security hardening, schema refresh, and developer-tooling correctness. No JSON-format change.
@@ -102,14 +228,11 @@ Bug-fix and documentation release; includes one new `git_log` output format.
102
228
  - **`git_cherry_pick`**: branch deletion after cherry-pick now uses patch-id equivalence by default so source branches with differing SHAs but identical content are correctly detected as merged. Pass `strictMergedRefEquality: true` for strict SHA-reachability semantics.
103
229
  - **`parseGitSubmodulePaths`**: non-regular files at `.gitmodules` (character devices, sockets — common in Claude Code / sandbox environments) are now rejected via `lstatSync().isFile()` before `readFileSync`, preventing `EACCES` errors.
104
230
 
105
- ### Tests
231
+ ### Changed
106
232
 
107
233
  - Integration tests added for `git_stash_list`, `git_stash_apply`, `git_fetch`, `git_status`, `git_inventory`, and `git_parity` execute paths.
108
234
  - `isContentEquivalentlyMergedInto` integration tests via real git repos with cherry-picked and diverged histories.
109
235
  - `batch_commit` dryRun tests covering deleted-file unstaging.
110
-
111
- ### Documentation
112
-
113
236
  - **`git_status`, `git_inventory`, `git_parity`, `list_presets`** now have complete parameter tables, JSON shape examples, and error code tables in `docs/mcp-tools.md`.
114
237
  - **`git_cherry_pick`** `strictMergedRefEquality` parameter added to docs; `deleteMergedBranches` description corrected (default is patch-id equivalence, not SHA-reachability).
115
238
  - **`batch_commit`** `files` parameter and `stage_failed` error code updated to document deleted-file staging path.
@@ -129,28 +252,22 @@ New git MCP tools, better `batch_commit` ergonomics, published schema coverage f
129
252
  - **`GIT_SUBPROCESS_PARALLELISM`** is now configurable via environment and clamps to a safe `2×CPU` maximum.
130
253
  - **`git_show`**, **`git_fetch`**, and **`git_tag`** now use the standard single-repo workspace pick (`workspaceRoot` / `rootIndex`) and omit multi-root-only parameters.
131
254
  - **Build / release tooling** now aligns on Bun `1.3.13`, updated dev dependencies, and the current prerelease tarball flow.
132
-
133
- ### Fixed
134
-
135
- - **MCP roots** — workspace root collection now scans active MCP sessions and dedupes `file://` roots instead of relying on a fixed server `cwd`.
136
- - **`git_push`** and **`batch_commit`** now surface raw git stdout/stderr on failure for easier recovery.
137
- - **Published schema snapshots** are now complete and in sync with the registered tool surface, including `schema:tools:check`.
138
- - **`publish:preflight`** now writes temporary coverage output under the platform temp directory instead of a hard-coded `/tmp` path.
139
-
140
- ### Documentation
141
-
142
255
  - **README / HUMANS / AGENTS / CONTRIBUTING / install docs** refreshed for the current tool surface, shipped schema artifacts, and contributor workflow.
143
256
  - **`SECURITY.md`** added with repository access, git-operation risk, and disclosure guidance.
144
257
  - **`docs/mcp-tools.md`** now documents the full tool surface, `batch_commit` atomic staging semantics, and the shipped schema artifacts.
145
258
  - **`TODO.md`** backlog entries now reflect genuine remaining gaps instead of listing already-implemented tools as missing.
146
259
  - **`specs/` scaffold** added with standard `active`, `done`, and `parked` layout for repo planning.
147
260
  - **CHANGELOG references** for `v2.3.2`–`v2.3.4` were restored.
148
-
149
- ### Tests
150
-
151
261
  - Coverage expanded across `list_presets`, `git_parity`, `git_cherry_pick`, `git_merge`, `git_show`, schema generation, and roots handling.
152
262
  - The shared git test harness now reuses repo-init / commit helpers and speeds up fixture setup.
153
263
 
264
+ ### Fixed
265
+
266
+ - **MCP roots** — workspace root collection now scans active MCP sessions and dedupes `file://` roots instead of relying on a fixed server `cwd`.
267
+ - **`git_push`** and **`batch_commit`** now surface raw git stdout/stderr on failure for easier recovery.
268
+ - **Published schema snapshots** are now complete and in sync with the registered tool surface, including `schema:tools:check`.
269
+ - **`publish:preflight`** now writes temporary coverage output under the platform temp directory instead of a hard-coded `/tmp` path.
270
+
154
271
  ## [2.3.4] — 2026-04-26
155
272
 
156
273
  Publication-prep patch for the `absoluteGitRoots` line.
@@ -164,7 +281,7 @@ Publication-prep patch for the `absoluteGitRoots` line.
164
281
 
165
282
  - **CI coverage gate** now checks `% Lines` from Bun's coverage table instead of accidentally reading `% Funcs`.
166
283
 
167
- ### Documentation
284
+ ### Changed
168
285
 
169
286
  - **`HUMANS.md`** — added sibling-clone `absoluteGitRoots` examples for `git_status` and `git_parity`.
170
287
  - **`docs/mcp-tools.md`** — clarified direct `git_push` use for already-committed work and `git_parity` sibling-clone batches.
@@ -181,12 +298,9 @@ Publication-prep patch for the `absoluteGitRoots` line.
181
298
 
182
299
  ## [2.3.2] — 2026-04-21
183
300
 
184
- ### CI
301
+ ### Changed
185
302
 
186
303
  - Coverage gate added: `bun run test:coverage` enforces an 80% line-coverage minimum in CI (`check` job).
187
-
188
- ### Documentation
189
-
190
304
  - **`CONTRIBUTING.md`** — new file; consolidates dev setup, hook table, commit conventions, CI description, PR checklist, path-confinement guidance, and how-to-add-a-tool guidance for mutating tools.
191
305
  - **`HUMANS.md`** — Development section replaced with a pointer to `CONTRIBUTING.md`; preset file, `git_not_found`, install reference, and publishing steps remain.
192
306
  - **`AGENTS.md`** — corrected pre-push hook description (missing `test` step) and updated canonical-docs link for dev/CI content.
@@ -196,7 +310,7 @@ Publication-prep patch for the `absoluteGitRoots` line.
196
310
 
197
311
  Documentation-only patch following the 2.3.0 release.
198
312
 
199
- ### Documentation
313
+ ### Changed
200
314
 
201
315
  - **`README.md`** — one-liner description updated to include `git_log`, `git_push`, `git_worktree_*`, and `git_reset_soft`.
202
316
  - **`HUMANS.md`** — opening line corrected from "Read-only MCP git tools" to "MCP git tools" (mutating operations have been present since v2.2.0).
@@ -229,22 +343,13 @@ Consumers using `format: "json"` with `git_log` must update field names. All oth
229
343
  - **Token efficiency:** `readOnlyHint: true` added to `git_status`, `git_inventory`, `git_parity`, and `list_presets`. "See docs/mcp-tools.md" suffix dropped from all 9 tool descriptions; descriptions are now self-contained.
230
344
  - **`WorkspacePickSchema`** — `rootIndex` and `allWorkspaceRoots` parameters carry inline descriptions so LLMs can pick them without consulting external docs.
231
345
  - **`git_merge`** — protected-branch list in the description collapsed to a single canonical reference (was duplicated inline).
232
-
233
- ### Internal
234
-
235
346
  - `requireSingleRepo` helper extracted to `roots.ts`; replaces copy-paste preludes across `batch_commit`, `git_diff_summary`, `git_merge`, `git_cherry_pick`, `git_push`, `git_reset_soft`, and all `git_worktree_*`.
236
347
  - `conflictPaths` extracted from `git-merge-tool.ts` to `git-refs.ts`; shared by `git_merge` and `git_cherry_pick`.
237
348
  - `inferRemoteFromUpstream` extracted to `git-refs.ts`; shared by `runPushAfter` (`batch_commit`) and `git_push`.
238
349
  - `isWorkingTreeClean` used consistently everywhere (was inlined in `git_reset_soft`).
239
-
240
- ### Tests
241
-
242
350
  - Coverage: **88.6% lines / 92.8% functions** (up from 69.9% / 71.4%).
243
351
  - 262 tests across 15 files (up from 134 across 7 files).
244
352
  - New test files: `presets.test.ts`, `inventory.test.ts`, `git-utils.test.ts`, `json.test.ts`, `git-reset-soft-tool.test.ts`, `git-push-tool.test.ts`, `git-worktree-tool.test.ts`, `roots.test.ts`. `git-refs.test.ts` extended with `isSafeGitAncestorRef` cases.
245
-
246
- ### Documentation
247
-
248
353
  - `docs/mcp-tools.md` — all new tools documented with parameter tables, JSON shapes, and error-code tables.
249
354
  - `AGENTS.md` — implementation map updated with all new and refactored modules.
250
355
 
@@ -262,31 +367,32 @@ Mutating git operations: merge, cherry-pick, and optional push-after for `batch_
262
367
 
263
368
  - **Internal** — shared ref/branch helpers extracted to a common module; merge/cherry-pick/batch-commit implementations now reuse the same dirty-tree guards, protected-name checks, and upstream detection.
264
369
  - **Tooling** — Biome upgraded to 2.4.11; dev dependency refresh.
265
-
266
- ### Documentation
267
-
268
370
  - `docs/mcp-tools.md` — `git_merge` and `git_cherry_pick` sections with parameters, JSON shape, and error codes; `batch_commit` `push: "after"` option documented.
269
371
 
270
- ## [2.1.0] — prior
372
+ ## [2.1.0] — 2026-04-12
271
373
 
272
374
  - Added `git_log` — path-filtered, time-windowed log across workspace roots.
273
375
  - Added `git_diff_summary` — structured, token-efficient diff viewer with per-file truncation and default exclusions (lock files, `dist`, vendor).
274
376
  - Added `batch_commit` — sequential multi-commit tool. Mutating, not idempotent.
275
377
  - Test harness: fake-server duck-type lets unit tests drive the full FastMCP execute path without a live transport.
276
378
 
277
- ## [2.0.1] — prior
379
+ ## [2.0.1] — 2026-04-11
278
380
 
279
381
  - Bug fixes and internal cleanup; no public tool-surface change.
280
382
 
281
- ## [2.0.0] — prior
383
+ ## [2.0.0] — 2026-04-11
282
384
 
283
385
  - **Breaking:** JSON response envelope removed. `MCP_JSON_FORMAT_VERSION` now `"2"`; payloads are minified, and optional fields are omitted when empty / `null` / `false` (consumers test for presence, not equality to `null`).
284
386
  - Initial preset file schema (`.rethunk/git-mcp-presets.json`) with wrapped and legacy-map layouts.
285
387
 
286
- ## [1.0.0] — prior
388
+ ## [1.0.0] — 2026-04-05
287
389
 
288
390
  - Initial release: `git_status`, `git_inventory`, `git_parity`, `list_presets`.
289
391
 
392
+ [3.3.0]: https://github.com/Rethunk-AI/mcp-multi-root-git/releases/tag/v3.3.0
393
+ [3.2.0]: https://github.com/Rethunk-AI/mcp-multi-root-git/releases/tag/v3.2.0
394
+ [3.1.0]: https://github.com/Rethunk-AI/mcp-multi-root-git/releases/tag/v3.1.0
395
+ [3.0.0]: https://github.com/Rethunk-AI/mcp-multi-root-git/releases/tag/v3.0.0
290
396
  [2.9.1]: https://github.com/Rethunk-AI/mcp-multi-root-git/releases/tag/v2.9.1
291
397
  [2.9.0]: https://github.com/Rethunk-AI/mcp-multi-root-git/releases/tag/v2.9.0
292
398
  [2.8.1]: https://github.com/Rethunk-AI/mcp-multi-root-git/releases/tag/v2.8.1
package/HUMANS.md CHANGED
@@ -53,30 +53,12 @@ With **multiple MCP file roots**, the server picks a root whose git toplevel def
53
53
 
54
54
  If you installed from **GitHub Packages**, use **`./node_modules/@rethunk-ai/mcp-multi-root-git/git-mcp-presets.schema.json`** in **`$schema`** instead (see [docs/install.md](docs/install.md#github-packages)).
55
55
 
56
- ## Tool parameter schema artifact
57
-
58
- The package ships **`tool-parameters.schema.json`**, a generated JSON Schema snapshot of every registered tool's parameter schema, plus the published **`schemas/`** directory with **`schemas/index.json`** and one per-tool JSON Schema file. Maintainers regenerate them with:
59
-
60
- ```bash
61
- bun run schema:tools
62
- bun run schema:individual
63
- ```
64
-
65
- CI and `prepublishOnly` use:
66
-
67
- ```bash
68
- bun run schema:tools:check
69
- bun run schema:individual
70
- ```
71
-
72
- These artifacts are for inspection, drift checks, code generation, and clients that want offline schema snapshots. Runtime MCP schema discovery remains the source of truth for connected clients.
73
-
74
56
  **Layouts:**
75
57
 
76
58
  1. **Wrapped (recommended):** `{ "schemaVersion": "1", "presets": { "<name>": { ... } } }`.
77
59
  2. **Legacy map:** `{ "<preset-name>": { ... } }` with optional top-level `"schemaVersion"` and `"$schema"`.
78
60
 
79
- Invalid JSON or schema errors return **`preset_file_invalid`** (not a silent empty result).
61
+ Invalid JSON returns **`invalid_json`**; schema violations return **`invalid_schema`** (not a silent empty result).
80
62
 
81
63
  ### Preset entry (quick reference)
82
64
 
@@ -92,16 +74,22 @@ Invalid JSON or schema errors return **`preset_file_invalid`** (not a silent emp
92
74
 
93
75
  Relative preset paths must stay inside the git toplevel; escapes are rejected.
94
76
 
77
+ ## Tool parameter schema artifact
78
+
79
+ The package ships **`tool-parameters.schema.json`**, a generated JSON Schema snapshot of every registered tool's parameter schema, plus the published **`schemas/`** directory with **`schemas/index.json`** and one per-tool JSON Schema file. These artifacts are for inspection, drift checks, code generation, and clients that want offline schema snapshots. Runtime MCP schema discovery remains the source of truth for connected clients.
80
+
81
+ Maintainers regenerate and verify them as part of [CONTRIBUTING.md](CONTRIBUTING.md) development setup.
82
+
95
83
  ## Sibling clone batches
96
84
 
97
- Use **`absoluteGitRoots`** when you want one read-only call to inspect independent sibling clones that are not all exposed as MCP workspace roots. This is most useful from agent workflows rooted at a parent directory or when an MCP client exposes only one repo root.
85
+ Pass a **`root` array** on the fan-out read tools (`git_status`, `git_inventory`, `git_parity`, `list_presets`, `git_log`, `git_grep`) when you want one read-only call to inspect independent sibling clones that are not all exposed as MCP workspace roots. This is most useful from agent workflows rooted at a parent directory or when an MCP client exposes only one repo root.
98
86
 
99
87
  Example `git_status` batch:
100
88
 
101
89
  ```json
102
90
  {
103
91
  "format": "json",
104
- "absoluteGitRoots": [
92
+ "root": [
105
93
  "/usr/local/src/com.github/Rethunk-AI/mcp-multi-root-git",
106
94
  "/usr/local/src/com.github/Rethunk-AI/rethunk-github-mcp"
107
95
  ]
@@ -113,7 +101,7 @@ Example `git_parity` batch using the same pair in each sibling clone:
113
101
  ```json
114
102
  {
115
103
  "format": "json",
116
- "absoluteGitRoots": [
104
+ "root": [
117
105
  "/usr/local/src/com.github/Rethunk-AI/mcp-multi-root-git",
118
106
  "/usr/local/src/com.github/Rethunk-AI/rethunk-github-mcp"
119
107
  ],
@@ -121,27 +109,19 @@ Example `git_parity` batch using the same pair in each sibling clone:
121
109
  }
122
110
  ```
123
111
 
124
- `absoluteGitRoots` is read-only by design. Mutating tools such as **`batch_commit`**, **`git_push`**, **`git_merge`**, and **`git_cherry_pick`** omit it from their schema; use `workspaceRoot` or MCP roots for writes. Full parameter rules and error codes live in **[docs/mcp-tools.md](docs/mcp-tools.md#absoluteGitRoots-sibling-clones)**.
112
+ Multi-repo routing is read-only by design. Mutating tools such as **`batch_commit`**, **`git_push`**, **`git_merge`**, and **`git_cherry_pick`** accept only `workspaceRoot`; use it or MCP roots for writes. Full parameter rules and error codes live in **[docs/mcp-tools.md](docs/mcp-tools.md#root-resolution)**.
125
113
 
126
114
  ## Prerequisites
127
115
 
128
- - **Git** on `PATH` (`git --version`). Missing git → all tools return `git_not_found`.
129
- - **Node.js ≥ 22** (for `npx`) or **Bun** (for `bunx`). See `engines` in `package.json`.
130
- - No other runtime dependencies; the server is a self-contained MCP stdio process.
116
+ Git, Node.js, and Bun version requirements: **[docs/install.md](docs/install.md#prerequisites)**.
131
117
 
132
118
  ## Running the server
133
119
 
134
- The server is a **stdio** MCP process — your MCP client starts it. You do not run it directly. Quick start:
120
+ The server is a **stdio** MCP process — your MCP client starts it. You do not run it directly.
135
121
 
136
- ```bash
137
- # npmjs (public, may lag tags)
138
- npx -y @rethunk/mcp-multi-root-git
139
-
140
- # GitHub Packages (CI-aligned, every tag)
141
- npx -y @rethunk-ai/mcp-multi-root-git # requires ~/.npmrc with @rethunk-ai registry token
142
- ```
122
+ Install, per-client MCP wiring, and environment variables (`RETHUNK_GIT_TOOLS`, `GIT_SUBPROCESS_PARALLELISM`, `GIT_SUBPROCESS_TIMEOUT_MS`): **[docs/install.md](docs/install.md)** — see [Environment variables](docs/install.md#environment-variables).
143
123
 
144
- Add the server to your MCP client config under a stable name (e.g. `rethunk-git`). Full per-client config (Cursor, VS Code, Claude Desktop, Zed): **[docs/install.md](docs/install.md)**.
124
+ Add the server to your MCP client config under a stable name (e.g. `rethunk-git`).
145
125
 
146
126
  ## Common operations
147
127
 
@@ -154,26 +134,27 @@ Call tools by their registered id (prefix depends on client config name):
154
134
  | Compare HEAD between path pairs | `git_parity` |
155
135
  | List preset names | `list_presets` |
156
136
  | View commit log | `git_log` |
137
+ | Pickaxe history search (which commits changed a term) | `git_grep` |
157
138
  | View structured diff | `git_diff_summary` |
158
139
  | View raw diff text | `git_diff` |
159
140
  | Inspect commit content | `git_show` |
160
- | List stashes | `git_stash_list` |
141
+ | Blame lines in a file | `git_blame` |
142
+ | Inspect unresolved merge conflicts | `git_conflicts` |
143
+ | Stash working-tree changes | `git_stash_push` |
161
144
  | Apply or pop a stash | `git_stash_apply` |
162
- | Fetch remote refs | `git_fetch` |
163
145
  | Create commits | `batch_commit` |
164
146
  | Push a branch | `git_push` |
165
147
  | Create or delete tags | `git_tag` |
148
+ | Create, delete, or rename branches | `git_branch` |
166
149
  | Merge branches | `git_merge` |
167
150
  | Cherry-pick commits | `git_cherry_pick` |
151
+ | Resume/abort a paused cherry-pick | `git_cherry_pick_continue` |
152
+ | Revert commits | `git_revert` |
168
153
  | Soft-reset HEAD | `git_reset_soft` |
169
- | Manage worktrees | `git_worktree_list` / `git_worktree_add` / `git_worktree_remove` |
154
+ | Manage worktrees | `git_worktree_add` / `git_worktree_remove` |
170
155
 
171
156
  Full parameter tables and JSON shapes: **[docs/mcp-tools.md](docs/mcp-tools.md)**.
172
157
 
173
- ## `git_not_found`
174
-
175
- If **`git`** is missing or not runnable, tools and the presets resource respond with **`git_not_found`**. Ensure `git` is on `PATH` in the environment that launches the MCP server.
176
-
177
158
  ## Installation
178
159
 
179
160
  **Full install instructions and MCP client wiring:** **[docs/install.md](docs/install.md)**.
package/README.md CHANGED
@@ -1,12 +1,35 @@
1
- # @rethunk/mcp-multi-root-git
1
+ <h1 align="center">@rethunk/mcp-multi-root-git</h1>
2
+
3
+ <div align="center">
2
4
 
3
5
  [![CI](https://github.com/Rethunk-AI/mcp-multi-root-git/actions/workflows/ci.yml/badge.svg)](https://github.com/Rethunk-AI/mcp-multi-root-git/actions/workflows/ci.yml)
4
6
  [![npm version](https://img.shields.io/npm/v/%40rethunk%2Fmcp-multi-root-git.svg)](https://www.npmjs.com/package/@rethunk/mcp-multi-root-git)
5
7
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
8
 
7
- **git** tools over MCP: status, multi-root inventory, `HEAD` parity, presets, logs, structured and raw diff views, commit inspection, fetch, stash, tag, batch commit, push, merge, cherry-pick, worktrees, soft-reset, blame, branch listing, and reflog. **Install and MCP client wiring:** **[docs/install.md](docs/install.md)** only — do not duplicate those steps elsewhere.
9
+ </div>
10
+
11
+ ---
12
+
13
+ MCP **stdio** server exposing **git** tools to AI clients — status, multi-root inventory, parity checks, presets, logs, pickaxe history search, diffs, commits, push, merge, worktrees, and more. One server process spans every workspace root the client registers at `initialize`.
14
+
15
+ **Repository:** [github.com/Rethunk-AI/mcp-multi-root-git](https://github.com/Rethunk-AI/mcp-multi-root-git) · **npmjs (manual releases):** [`@rethunk/mcp-multi-root-git`](https://www.npmjs.com/package/@rethunk/mcp-multi-root-git) · **GitHub Packages (CI on each tag):** [`@rethunk-ai/mcp-multi-root-git`](https://github.com/Rethunk-AI/mcp-multi-root-git/packages) — see [docs/install.md](docs/install.md) and [HUMANS.md#publishing](HUMANS.md#publishing).
16
+
17
+ ## Quick start
18
+
19
+ ```bash
20
+ npx -y @rethunk/mcp-multi-root-git
21
+ ```
8
22
 
9
- **Repository:** [github.com/Rethunk-AI/mcp-multi-root-git](https://github.com/Rethunk-AI/mcp-multi-root-git) · **npmjs (manual releases):** [`@rethunk/mcp-multi-root-git`](https://www.npmjs.com/package/@rethunk/mcp-multi-root-git) · **GitHub Packages (CI on each tag):** [`@rethunk-ai/mcp-multi-root-git`](https://github.com/Rethunk-AI/mcp-multi-root-git/packages) see [docs/install.md](docs/install.md) and [HUMANS.md](HUMANS.md) Publishing.
23
+ Full install, prerequisites, and MCP client wiring: [HUMANS.md](HUMANS.md) and [docs/install.md](docs/install.md).
24
+
25
+ ## Highlights
26
+
27
+ - **Multi-root fan-out** — `git_status`, `git_inventory`, `git_parity`, `git_log`, and `git_grep` route across one repo, an explicit list, or every MCP root (`"*"`)
28
+ - **Structured JSON** — minified tool payloads (format version 5); optional fields omitted when empty
29
+ - **Presets** — `.rethunk/git-mcp-presets.json` at the git toplevel for nested roots and parity pairs
30
+ - **Read and write git** — diffs, blame, conflicts, stash, `batch_commit`, push, merge, cherry-pick, revert, branches, tags, and worktrees (writes take a single `workspaceRoot`)
31
+ - **Deliberately small surface** — 24 tools; every tool must clear the [inclusion criteria](CONTRIBUTING.md#tool-inclusion-criteria) (enforced policy on writes, fan-out call compression, or large-output compression)
32
+ - **Published schemas** — `schemas/index.json` and per-tool JSON Schema files for offline validation
10
33
 
11
34
  ## Documentation
12
35
 
@@ -19,16 +42,10 @@
19
42
  | **[AGENTS.md](AGENTS.md)** | Contributors: implementation map ([`src/server/`](src/server/) + entry [`src/server.ts`](src/server.ts)), contract bumps, CI |
20
43
  | **[CONTRIBUTING.md](CONTRIBUTING.md)** | Dev setup, hooks, commit conventions, release checks, and how to add tools |
21
44
  | **[SECURITY.md](SECURITY.md)** | Disclosure policy, threat model, and repository safety guidance |
45
+ | **[CHANGELOG.md](CHANGELOG.md)** | Release notes (Keep a Changelog style) |
46
+ | **[TODO.md](TODO.md)** | Future backlog and planned work |
22
47
  | **[specs/README.md](specs/README.md)** | Active / done / parked specification layout used for repo planning |
23
48
 
24
- **Tools at a glance:** see the table in **[docs/mcp-tools.md](docs/mcp-tools.md)**.
25
-
26
- ## JSON Schemas
27
-
28
- All MCP tool parameters are published as JSON Schema (draft 2020-12) documents in the **[`schemas/`](schemas/)** directory. Tools and validators can use these schemas to validate tool input arguments without reading source code.
29
-
30
- **Schema files:**
31
- - `schemas/index.json` — Index of all 20 tool schemas with file paths
32
- - `schemas/{tool_name}.json` — Individual schema for each tool (e.g., `schemas/batch_commit.json`, `schemas/git_status.json`)
49
+ ## License
33
50
 
34
- For programmatic use, read `schemas/index.json` to discover available tools and their schema files.
51
+ Copyright (c) 2026 Rethunk Tech. Licensed under the MIT License see [LICENSE](LICENSE) for details.