{"_id":"@chaoxu1997/gentle-committer","_rev":"7-55f8ec4bca9a2848908bf6a274c3af10","name":"@chaoxu1997/gentle-committer","dist-tags":{"latest":"0.3.2"},"versions":{"0.1.0":{"name":"@chaoxu1997/gentle-committer","version":"0.1.0","keywords":["pi","pi-extension","pi-package","git","conventional-commits","automation"],"author":{"name":"ChaoXu1997"},"license":"MIT","_id":"@chaoxu1997/gentle-committer@0.1.0","maintainers":[{"name":"chaoxu1997","email":"zhongchaoxu@163.com"}],"homepage":"https://github.com/ChaoXu1997/gentle-committer#readme","bugs":{"url":"https://github.com/ChaoXu1997/gentle-committer/issues"},"pi":{"extensions":["./index.ts"]},"dist":{"shasum":"f75038098ec97b443df41562e8aa74af98d679cf","tarball":"https://registry.npmjs.org/@chaoxu1997/gentle-committer/-/gentle-committer-0.1.0.tgz","fileCount":11,"integrity":"sha512-C8eNpeWFEwj5DK1e6vo1nhk7e9OG3QCy8svfTj+Hv4ZPCORBhYLJvcczoyajW598voWzebcEBtThGkTV9W6nnw==","signatures":[{"sig":"MEUCICiiLb52yR+sDxpD7h+T+I/Mxepqiu/AEOnEXzBP6OsbAiEA2a9n0U5d3J9kLaCnM48Q6uex9CINl0snl2vwEAJnHSw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":207013},"type":"module","engines":{"node":">=20"},"gitHead":"9caed6dfe046d941e689651ddce2048839f059fb","scripts":{"test":"node --import tsx --test tests/unit.test.ts tests/worker-edge.test.ts","test:all":"node --import tsx --test tests/*.test.ts","test:e2e":"PI_COMMITTER_E2E=1 node --import tsx --test tests/e2e.test.ts","benchmark":"node --import tsx --test tests/benchmark.test.ts"},"_npmUser":{"name":"chaoxu1997","email":"zhongchaoxu@163.com"},"repository":{"url":"git+https://github.com/ChaoXu1997/gentle-committer.git","type":"git"},"_npmVersion":"9.2.0","description":"gentle-pi-aware commit automation for pi — fork of pi-committer with review-mode/bypass-mode switching and work-unit commit discipline","directories":{},"_nodeVersion":"22.22.1","dependencies":{"jiti":"^2.7.0","smol-toml":"^1.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0"},"peerDependencies":{"typebox":"*","@earendil-works/pi-tui":"*","@earendil-works/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/gentle-committer_0.1.0_1785769307876_0.6995316405609286","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@chaoxu1997/gentle-committer","version":"0.1.1","keywords":["pi","pi-extension","pi-package","git","conventional-commits","automation"],"author":{"name":"ChaoXu1997"},"license":"MIT","_id":"@chaoxu1997/gentle-committer@0.1.1","maintainers":[{"name":"chaoxu1997","email":"zhongchaoxu@163.com"}],"homepage":"https://github.com/ChaoXu1997/gentle-committer#readme","bugs":{"url":"https://github.com/ChaoXu1997/gentle-committer/issues"},"pi":{"extensions":["./index.ts"]},"dist":{"shasum":"f6161cea545fa401a19d82ef19255177c165ccf1","tarball":"https://registry.npmjs.org/@chaoxu1997/gentle-committer/-/gentle-committer-0.1.1.tgz","fileCount":11,"integrity":"sha512-+GEfu9VO2s1eNIecEQ6Q04CeajR6VEtQj1DofRFG9AhqAlzastlrZyXvqSkXmLicjKoqj8k4xrfcXp2VpDQ6vQ==","signatures":[{"sig":"MEYCIQD/XbJf9aNPkWcIeoYlD/HHl/7i1nk2Ob2r7THt0Pg49gIhAMgx0DmLkUPBCsZGpZSc4kjZD4VDNXyCdc4gsMHdvxlm","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":209240},"type":"module","engines":{"node":">=20"},"gitHead":"3544521a7012f4a25de140eed18ffe02be994e2f","scripts":{"test":"node --import tsx --test tests/unit.test.ts tests/worker-edge.test.ts","test:all":"node --import tsx --test tests/*.test.ts","test:e2e":"PI_COMMITTER_E2E=1 node --import tsx --test tests/e2e.test.ts","benchmark":"node --import tsx --test tests/benchmark.test.ts"},"_npmUser":{"name":"chaoxu1997","email":"zhongchaoxu@163.com"},"repository":{"url":"git+https://github.com/ChaoXu1997/gentle-committer.git","type":"git"},"_npmVersion":"9.2.0","description":"Commit automation for the pi coding agent with review/bypass commit modes and work-unit commit discipline (independent project, originally derived from pi-committer)","directories":{},"_nodeVersion":"22.22.1","dependencies":{"jiti":"^2.7.0","smol-toml":"^1.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0"},"peerDependencies":{"typebox":"*","@earendil-works/pi-tui":"*","@earendil-works/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/gentle-committer_0.1.1_1785773303803_0.679199463821617","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@chaoxu1997/gentle-committer","version":"0.2.0","keywords":["pi","pi-extension","pi-package","git","conventional-commits","automation"],"author":{"name":"ChaoXu1997"},"license":"MIT","_id":"@chaoxu1997/gentle-committer@0.2.0","maintainers":[{"name":"chaoxu1997","email":"zhongchaoxu@163.com"}],"homepage":"https://github.com/ChaoXu1997/gentle-committer#readme","bugs":{"url":"https://github.com/ChaoXu1997/gentle-committer/issues"},"pi":{"extensions":["./index.ts"]},"dist":{"shasum":"9d50d5596c34d3f69cb9aab5bfc791ffeffc061e","tarball":"https://registry.npmjs.org/@chaoxu1997/gentle-committer/-/gentle-committer-0.2.0.tgz","fileCount":11,"integrity":"sha512-A7t+a1lJf05NnX6WZXXImfX7Y2kMD569aTsESCR+eOTe/f71aydCS2BWrC38FPLza9Fr+z9gPlDDYcGk/J0U1w==","signatures":[{"sig":"MEQCIElAiVgsYIxugAdM2UDu237M5wg8IHkEPBxv5WX/YCUFAiA7e6HT+6OX/6YJzDELBPPM0V2VeQHTcByxMnVopo5kwQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":212158},"type":"module","engines":{"node":">=20"},"gitHead":"75ba66da5f6405f4907ff7980c4451a0941ff7b8","scripts":{"test":"node --import tsx --test tests/unit.test.ts tests/worker-edge.test.ts","test:all":"node --import tsx --test tests/*.test.ts","test:e2e":"PI_COMMITTER_E2E=1 node --import tsx --test tests/e2e.test.ts","benchmark":"node --import tsx --test tests/benchmark.test.ts"},"_npmUser":{"name":"chaoxu1997","email":"zhongchaoxu@163.com"},"repository":{"url":"git+https://github.com/ChaoXu1997/gentle-committer.git","type":"git"},"_npmVersion":"9.2.0","description":"Commit automation for the pi coding agent with review/bypass commit modes and work-unit commit discipline (independent project, originally derived from pi-committer)","directories":{},"_nodeVersion":"22.22.1","dependencies":{"jiti":"^2.7.0","smol-toml":"^1.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0"},"peerDependencies":{"typebox":"*","@earendil-works/pi-tui":"*","@earendil-works/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/gentle-committer_0.2.0_1785773893035_0.27825660308446953","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@chaoxu1997/gentle-committer","version":"0.2.1","keywords":["pi","pi-extension","pi-package","git","conventional-commits","automation"],"author":{"name":"ChaoXu1997"},"license":"MIT","_id":"@chaoxu1997/gentle-committer@0.2.1","maintainers":[{"name":"chaoxu1997","email":"zhongchaoxu@163.com"}],"homepage":"https://github.com/ChaoXu1997/gentle-committer#readme","bugs":{"url":"https://github.com/ChaoXu1997/gentle-committer/issues"},"pi":{"extensions":["./index.ts"]},"dist":{"shasum":"1be0321dd50f94da51ccc9a572daf1318df6f104","tarball":"https://registry.npmjs.org/@chaoxu1997/gentle-committer/-/gentle-committer-0.2.1.tgz","fileCount":11,"integrity":"sha512-xb9AU/EVxYJ7K9INl8EcVjraoUD7BLxxmY5vIgSOjHk+MqU50KO5CxSoTbQbA4frLwJuGOTEztNpvoWrcML1sQ==","signatures":[{"sig":"MEQCICpXrNwN7wDDEkJE5ZeO7ifmcZVCdvuNqJvRqyrdyENVAiAfa3RuUTd8OZ54ZYYdH6UKbng4060P/Fh5N+Ds/lGmdw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":214320},"type":"module","engines":{"node":">=20"},"gitHead":"75ba66da5f6405f4907ff7980c4451a0941ff7b8","scripts":{"test":"node --import tsx --test tests/unit.test.ts tests/worker-edge.test.ts","test:all":"node --import tsx --test tests/*.test.ts","test:e2e":"PI_COMMITTER_E2E=1 node --import tsx --test tests/e2e.test.ts","benchmark":"node --import tsx --test tests/benchmark.test.ts"},"_npmUser":{"name":"chaoxu1997","email":"zhongchaoxu@163.com"},"repository":{"url":"git+https://github.com/ChaoXu1997/gentle-committer.git","type":"git"},"_npmVersion":"9.2.0","description":"Commit automation for the pi coding agent with review/bypass commit modes and work-unit commit discipline (independent project, originally derived from pi-committer)","directories":{},"_nodeVersion":"22.22.1","dependencies":{"jiti":"^2.7.0","smol-toml":"^1.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0"},"peerDependencies":{"typebox":"*","@earendil-works/pi-tui":"*","@earendil-works/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/gentle-committer_0.2.1_1785774912641_0.4175236831418896","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@chaoxu1997/gentle-committer","version":"0.3.0","keywords":["pi","pi-extension","pi-package","git","conventional-commits","automation"],"author":{"name":"ChaoXu1997"},"license":"MIT","_id":"@chaoxu1997/gentle-committer@0.3.0","maintainers":[{"name":"chaoxu1997","email":"zhongchaoxu@163.com"}],"homepage":"https://github.com/ChaoXu1997/gentle-committer#readme","bugs":{"url":"https://github.com/ChaoXu1997/gentle-committer/issues"},"pi":{"extensions":["./index.ts"]},"dist":{"shasum":"f28ff0419a75f6a503a69fc0cb11986d3f634a9e","tarball":"https://registry.npmjs.org/@chaoxu1997/gentle-committer/-/gentle-committer-0.3.0.tgz","fileCount":11,"integrity":"sha512-cVforNk2VSguooKa/ZuKbO8hkiMK/wQ4lM9CGYN/e7mD3Nyv1a/NutbzGpqIKuauQvJahYdLyTmOb+7IG2yLrA==","signatures":[{"sig":"MEYCIQDhYypaiSvaQupkPZOVpFRzYnz6pN1MQDXVXRasYfTfzgIhAMLZTRIO0/9ptu2YEIivmri+q4APsZ5pzvGGkS1ybt7i","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":214987},"type":"module","engines":{"node":">=20"},"gitHead":"0ebd86ef7933ebe7ac1d6434b48c9814471d91f2","scripts":{"test":"node --import tsx --test tests/unit.test.ts tests/worker-edge.test.ts","test:all":"node --import tsx --test tests/*.test.ts","test:e2e":"PI_COMMITTER_E2E=1 node --import tsx --test tests/e2e.test.ts","benchmark":"node --import tsx --test tests/benchmark.test.ts"},"_npmUser":{"name":"chaoxu1997","email":"zhongchaoxu@163.com"},"repository":{"url":"git+https://github.com/ChaoXu1997/gentle-committer.git","type":"git"},"_npmVersion":"9.2.0","description":"Commit automation for the pi coding agent with review/bypass commit modes and work-unit commit discipline (independent project, originally derived from pi-committer)","directories":{},"_nodeVersion":"22.22.1","dependencies":{"jiti":"^2.7.0","smol-toml":"^1.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0"},"peerDependencies":{"typebox":"*","@earendil-works/pi-tui":"*","@earendil-works/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/gentle-committer_0.3.0_1785775655356_0.6750622715332384","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@chaoxu1997/gentle-committer","version":"0.3.1","keywords":["pi","pi-extension","pi-package","git","conventional-commits","automation"],"author":{"name":"ChaoXu1997"},"license":"MIT","_id":"@chaoxu1997/gentle-committer@0.3.1","maintainers":[{"name":"chaoxu1997","email":"zhongchaoxu@163.com"}],"homepage":"https://github.com/ChaoXu1997/gentle-committer#readme","bugs":{"url":"https://github.com/ChaoXu1997/gentle-committer/issues"},"pi":{"extensions":["./index.ts"]},"dist":{"shasum":"e1eee3b4896e1f9cbe58dc53b60b7409f394c75a","tarball":"https://registry.npmjs.org/@chaoxu1997/gentle-committer/-/gentle-committer-0.3.1.tgz","fileCount":11,"integrity":"sha512-bjf3INtjtXjCRZRdO1AWRC5o2z6STqTR2yHYkBNXjz+iENQuNAZuWAMztJpptLbHBxms3r0dAobpiWhec90p9g==","signatures":[{"sig":"MEUCIBTHS3OMXDQDa7D+mJ6okCEDX5/BldG9SveVgT+vYHm/AiEAhTShXRpUgGaI5F2DEKLN00zKi/7q4YBHxJ4qdT9EL9U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":215657},"type":"module","engines":{"node":">=20"},"gitHead":"e95ead82a2459fffaf7690c57fc7bab709504bf7","scripts":{"test":"node --import tsx --test tests/unit.test.ts tests/worker-edge.test.ts","test:all":"node --import tsx --test tests/*.test.ts","test:e2e":"PI_COMMITTER_E2E=1 node --import tsx --test tests/e2e.test.ts","benchmark":"node --import tsx --test tests/benchmark.test.ts"},"_npmUser":{"name":"chaoxu1997","email":"zhongchaoxu@163.com"},"repository":{"url":"git+https://github.com/ChaoXu1997/gentle-committer.git","type":"git"},"_npmVersion":"9.2.0","description":"Commit automation for the pi coding agent with review/bypass commit modes and work-unit commit discipline (independent project, originally derived from pi-committer)","directories":{},"_nodeVersion":"22.22.1","dependencies":{"jiti":"^2.7.0","smol-toml":"^1.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.0"},"peerDependencies":{"typebox":"*","@earendil-works/pi-tui":"*","@earendil-works/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/gentle-committer_0.3.1_1785776381276_0.5486749111468925","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@chaoxu1997/gentle-committer","version":"0.3.2","description":"Commit automation for the pi coding agent with review/bypass commit modes and work-unit commit discipline (independent project, originally derived from pi-committer)","type":"module","license":"MIT","author":{"name":"ChaoXu1997"},"homepage":"https://github.com/ChaoXu1997/gentle-committer#readme","repository":{"type":"git","url":"git+https://github.com/ChaoXu1997/gentle-committer.git"},"bugs":{"url":"https://github.com/ChaoXu1997/gentle-committer/issues"},"keywords":["pi","pi-extension","pi-package","git","conventional-commits","automation"],"engines":{"node":">=20"},"scripts":{"test":"node --import tsx --test tests/unit.test.ts tests/worker-edge.test.ts","test:e2e":"PI_COMMITTER_E2E=1 node --import tsx --test tests/e2e.test.ts","test:all":"node --import tsx --test tests/*.test.ts","benchmark":"node --import tsx --test tests/benchmark.test.ts"},"dependencies":{"smol-toml":"^1.3.0","jiti":"^2.7.0"},"peerDependencies":{"@earendil-works/pi-tui":"*","typebox":"*","@earendil-works/pi-coding-agent":"*"},"devDependencies":{"tsx":"^4.19.0"},"publishConfig":{"access":"public"},"pi":{"extensions":["./index.ts"]},"gitHead":"c540995abc1d6fed0c84cb40c01a0bfb07c16b57","_id":"@chaoxu1997/gentle-committer@0.3.2","_nodeVersion":"22.22.1","_npmVersion":"9.2.0","dist":{"integrity":"sha512-3YD6T2thBoudhQOk0pt01e4/Z4A1COMpjKQrLl3TO3RZszZG7NWk5HoT6WEAr2dXz39oWjBcm3HGjA20plqzLQ==","shasum":"e1c74fd1ed816d53d2e482b6ceaa5011e2fd32a6","tarball":"https://registry.npmjs.org/@chaoxu1997/gentle-committer/-/gentle-committer-0.3.2.tgz","fileCount":11,"unpackedSize":217334,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBFv6Z3Dibnxwiqly9jVEh4dwzenBGo5tehZsivuGa/0AiA2bC9jI8+1MdgWqWbYOsxRJizvrseVhAhDg/pTdetCCw=="}]},"_npmUser":{"name":"chaoxu1997","email":"zhongchaoxu@163.com"},"directories":{},"maintainers":[{"name":"chaoxu1997","email":"zhongchaoxu@163.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/gentle-committer_0.3.2_1785777432383_0.00633977665509744"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-03T15:01:47.638Z","modified":"2026-08-03T17:17:12.710Z","0.1.0":"2026-08-03T15:01:48.021Z","0.1.1":"2026-08-03T16:08:23.978Z","0.2.0":"2026-08-03T16:18:13.176Z","0.2.1":"2026-08-03T16:35:12.775Z","0.3.0":"2026-08-03T16:47:35.514Z","0.3.1":"2026-08-03T16:59:41.428Z","0.3.2":"2026-08-03T17:17:12.529Z"},"bugs":{"url":"https://github.com/ChaoXu1997/gentle-committer/issues"},"author":{"name":"ChaoXu1997"},"license":"MIT","homepage":"https://github.com/ChaoXu1997/gentle-committer#readme","keywords":["pi","pi-extension","pi-package","git","conventional-commits","automation"],"repository":{"type":"git","url":"git+https://github.com/ChaoXu1997/gentle-committer.git"},"description":"Commit automation for the pi coding agent with review/bypass commit modes and work-unit commit discipline (independent project, originally derived from pi-committer)","maintainers":[{"name":"chaoxu1997","email":"zhongchaoxu@163.com"}],"readme":"# gentle-committer\n\n> **gentle-committer** is an independent commit-automation extension for the [pi coding agent](https://pi.ai), originally derived from [pi-committer](https://github.com/tmonk/pi-committer) v0.12.8 and adapted for the [gentle-pi](https://github.com/Gentleman-Programming/gentle-pi) ecosystem. All credit for the original commit automation goes to the pi-committer contributors; this project is MIT under the same terms.\n\nCommit automation for the [pi coding agent](https://pi.ai) with a **`commit_mode` switch**: commit directly (`bypass`) **or** route each commit through gentle-ai's review gate (`review`) — plus optional **work-unit commit discipline** injected into the commit-message prompts.\n\n| Mode | What happens | When to use |\n| --- | --- | --- |\n| `bypass` (default) | stage → generate message → `git commit` (byte-identical to pi-committer) | everyday work; developing gentle-committer itself |\n| `review` | stage + generate message → write a message file → hand off a `git commit -F` directive so gentle-ai's gate reviews the commit before it lands | features/changes you want reviewed before they land |\n\nOverride per-commit without touching config: `commit_changes({mode: \"review\"})` for a big feature, `commit_changes({mode: \"bypass\"})` for a quick fix.\n\n```bash\npi install npm:@chaoxu1997/gentle-committer\n```\n\n## What's different from pi-committer\n\n| Area | pi-committer | gentle-committer |\n| --- | --- | --- |\n| Commit path | always `execSync` direct | `bypass` (direct) **or** `review` (gentle-ai gate) |\n| Per-commit mode | — | `commit_changes({mode})` override |\n| Commit-message prompt | fixed | + optional work-unit rules (`prompt_rules_path`) |\n| gentle-ai coupling | — | **none** — review fires via the existing bash gate |\n| Everything else | — | unchanged (staged commits, subagent, multi-repo, async, widget) |\n\n## Quick start\n\n1. **Install** (above) — pi auto-loads it on startup.\n2. **Enable + pick a mode** in `.pi-committer.toml`:\n\n   ```toml\n   [committer]\n   enabled     = true\n   commit_mode = \"bypass\"   # or \"review\"\n   ```\n\n3. **Commit**: ask the agent to commit, run `/commit`, or (with `trigger_mode = \"on_goal\"`) let it auto-commit when a [pi-goal](https://pi.dev/packages/@capyup/pi-goal) completes.\n\n## Commit modes\n\n### `bypass` (default) — direct commit\n\nStage → subagent generates a conventional message → `git commit`. Byte-identical to upstream pi-committer. No gate.\n\n### `review` — commit through gentle-ai's gate\n\nStage + generate the message, **but do not commit**. Instead:\n\n```text\ncommit_changes({mode:\"review\"})\n  → stages files, generates message\n  → writes .git/gentle_committer_pending_msg\n  → returns a directive (pending: true, NO commit):\n      \"Run: git commit -F .git/gentle_committer_pending_msg\n       gentle-ai's gate will review the commit before it lands.\n       Do NOT modify the staging area (git add/reset/restore).\"\n  → the model runs `git commit -F <file>`\n  → gentle-ai's bash gate intercepts `git commit` → review → receipt → gate\n  → the commit lands ONLY if the review passes\n```\n\n**Why indirect?** An extension cannot call the `gentle_review` tool in-process (its execute closure is private; `ExtensionAPI` exposes no `invokeTool`). So gentle-committer prepares the commit and lets the model's `git commit` trip gentle-ai's **existing** gate. Zero coupling — gentle-ai can upgrade without affecting gentle-committer.\n\n**Review-mode guardrails:**\n\n- [ ] Async worker is disabled (review is synchronous; one message file).\n- [ ] Grouped/staged commits collapse to a **single** commit (one message, one directive).\n- [ ] Automatic triggers (`turn_end` / `tool_result` / `goal_event`) are suppressed — call `commit_changes` explicitly so the directive reaches the model.\n- [ ] If `commit_mode = \"review\"` but gentle-ai isn't loaded, it warns and falls back to `bypass`.\n\n### Per-call mode override\n\nDon't want to flip a global config? Pass `mode` to `commit_changes`:\n\n| You say | Model calls | Result |\n| --- | --- | --- |\n| \"just commit this\" | `commit_changes({mode:\"bypass\"})` | direct commit |\n| \"review then commit\" | `commit_changes({mode:\"review\"})` | directive → gate |\n| (nothing) | `commit_changes()` | uses `commit_mode` config (default `bypass`) |\n\n> **SDD vs review-mode** — SDD reviews the *design/spec* (planning); review-mode gates the *commit diff* (publish). They compose: SDD plan + implement → `commit_changes({mode:\"review\"})`.\n\n## Configuration\n\nCreate `.pi-committer.toml` (or `.pi-committer.json`) in your project root. The extension walks up directories to find it.\n\n```toml\n[committer]\nenabled           = true\ncommit_mode       = \"bypass\"            # bypass | review            (gentle-committer)\nprompt_rules_path = \"commit-rules/work-unit-commits.md\"               # (gentle-committer, optional)\ntrigger_mode      = \"on_goal\"           # on_goal | agent_sensible | after_tool | manual\nstaged_commits    = true\nmin_changes       = 1\nexclude_patterns  = [\"*.log\", \"node_modules/\"]\n\n# subagent_model             = \"openai/gpt-4o-mini\"\n# subagent_grouping_min_files = 15   # ≥N files → subagent splits into groups\n# subagent_message_min_files  = 3    # <N files → deterministic message (no LLM)\n# async_threshold            = 10    # ≥N files → background subprocess; 0 = always sync\n# custom_types               = [\"api\", \"wip\"]\n# allowed_scopes             = [\"api\", \"cli\", \"core\"]\n# defer_to_goal_audit        = false\n# detailed_body              = true\n```\n\n| Key | Default | Purpose |\n| --- | --- | --- |\n| `enabled` | `false` | master switch |\n| `commit_mode` | `\"bypass\"` | direct commit vs gentle-ai gate |\n| `prompt_rules_path` | *unset* | markdown appended to the commit-message prompts |\n| `trigger_mode` | `\"on_goal\"` | when to auto-commit |\n| `staged_commits` | `true` | subagent splits the diff into logical commits |\n| `async_threshold` | `10` | ≥ N files → fork into a background subprocess |\n| `subagent_model` | agent model | model used to generate messages |\n| `exclude_patterns` | `[]` | glob patterns to skip |\n\n### Trigger modes\n\n| Mode | Behaviour |\n| --- | --- |\n| `on_goal` (default) | commits when a pi-goal transitions to `complete` |\n| `agent_sensible` | commits after every agent turn |\n| `after_tool` | commits after each tool call |\n| `manual` | never auto-commits; `/commit` or `commit_changes` only |\n\n## Work-unit commit rules (`prompt_rules_path`)\n\nPoint `prompt_rules_path` at a markdown file (this repo ships `commit-rules/work-unit-commits.md`). Its content is appended to the grouping and single-message prompts — commit-by-work-unit, tests-with-code, scope-equals-work-unit, one-purpose-per-commit. When unset or unreadable, prompts are **byte-identical** to upstream pi-committer (bypass mode is unaffected).\n\n## Features\n\n- **`commit_mode` switch** — direct commit (`bypass`) or gentle-ai-gated commit (`review`).\n- **Per-call `mode` override** on `commit_changes` — pick the path per commit.\n- Commits automatically when a [pi-goal](https://pi.dev/packages/@capyup/pi-goal) completes (`on_goal` trigger, opt-in).\n- Splits diffs into separate commits via a subagent (feature + tests in one commit, docs in another).\n- Commit messages generated by a subagent using your model — pick it with `/commit-model` or `subagent_model`.\n- Detects and commits in **any** git repositories the agent touched.\n- `commit_changes` tool that agents can call to checkpoint work.\n- Exclusion patterns for files matching globs (`*.log`, `build/`, etc.).\n- Slash commands: `/commit`, `/commit-config`, `/commit-model`.\n\n## Usage\n\nEnable auto-commit, then drive it by goal, command, or tool:\n\n```toml\n# .pi-committer.toml\n[committer]\nenabled = true\n```\n\n### Auto-commit on goal completion\n\nWith `trigger_mode = \"on_goal\"` (default), the extension hooks into [pi-goal](https://pi.dev/packages/@capyup/pi-goal)'s lifecycle and commits when a goal transitions to **complete**:\n\n```text\n/goals \"Add user authentication\"   ← start a goal\n> agent implements auth logic       ← work happens\n> pi-goal marks the goal complete   ← gentle-committer auto-commits\n```\n\n### Manual commit\n\n```text\n/commit\n```\n\nOr ask the agent to \"save my progress\" — it calls `commit_changes` (pass `{mode:\"review\"}` if you want it gated).\n\n### Choose the commit-message model\n\n```text\n/commit-model\n```\n\nOpens an interactive selector. Defaults to your current agent model.\n\n### Reload config\n\n```text\n/commit-config\n```\n\n## Staged commits\n\nWhen `staged_commits = true` (default), the subagent receives the diff and organizes changes into commit groups. Editing a source file, adding tests, and updating docs might produce:\n\n```text\nfeat(api): add user authentication endpoint\ntest(api): add authentication tests\ndocs: update API documentation\n```\n\nThe subagent decides the grouping from the diff content, not from file extensions. *(In `review` mode this is forced to a single commit — one message file, one directive.)*\n\n## Multi-repo\n\nIf the agent edits files in multiple git repositories during a session, `commit_changes` finds and commits in all of them. Detection works via session tool-call history — repos where the agent created or modified files using `write` or `edit` are detected on top of the primary working directory.\n\n## Deterministic commit message fallback\n\nWhen the subagent is unavailable or returns nothing, gentle-committer generates a deterministic message using string analysis — no LLM call:\n\n- **Smart scope** — longest common ancestor directory across changed files; omitted if files span unrelated directories.\n- **Specific description** — meaningful keywords from file names (strips extensions, skips `__init__`/`conftest`, converts `snake_case` to words). Never \"update N modules\".\n- **Contamination guard** — `isValidDiffContent` / `isValidDiffStat` / `isValidCommitMessage` reject non-diff output so unrelated shell output can't leak into a message.\n\nEvery fallback decision logs a `DIAG:` diagnostic to help identify root causes.\n\n## Architecture\n\n```text\nExtension events (turn_end, tool_result, goal_event)  +  commit_changes tool\n            │\n            ▼\n      commitAllRepos(dir, ctx)\n            │\n            ├─ findDirtyRepos(ctx)          discover all dirty repos\n            │\n            └─ tryCommit(repo, ...)          for each dirty repo\n                   │\n                   ├─ stageAll / unstageExcluded / filterGitignored\n                   │\n                   ├─ resolveEffectiveCommitMode(pi, override?)   bypass | review (+R9 fallback)\n                   │\n                   ├─ buildGroupingPrompt / buildSingleMessagePrompt   (prompt-builders.ts)\n                   │      └─ + loadCommitRules(prompt_rules_path)        append work-unit rules\n                   │\n                   ├─ generateStagedCommitGroups / generateCommitMessageViaSubagent\n                   │      └─ createAgentSession    no tools, diff inline\n                   │\n                   └─ performCommit(mode, …)        (commit-emission.ts)\n                          ├─ bypass → execSync(\"git commit -F -\")   (byte-identical)\n                          └─ review → write .git/gentle_committer_pending_msg + handoff directive\n```\n\nThe commit-emission shim (`commit-emission.ts`) and prompt builders (`prompt-builders.ts`) are shared by both the main process and the async worker, with **no circular imports** (commit-emission uses only node builtins; prompt-builders takes a type-only `CommitterConfig`). The subagent uses `createAgentSession` from `@earendil-works/pi-coding-agent` — no `pi-subagents` dependency required.\n\n## Requirements\n\n- [pi coding agent](https://pi.ai) 0.71+\n- Node.js 20+\n- Git\n\n## Install from source\n\n```bash\ngit clone https://github.com/ChaoXu1997/gentle-committer.git\ncd gentle-committer && npm install\n\n# try it in a session without installing\npi -e ./index.ts\n```\n\n## Development\n\n```bash\ncd gentle-committer\nnpm install\n\nnpm test            # unit + worker-edge tests\nnpm run test:all    # full suite\nnpm run test:e2e    # end-to-end (PI_COMMITTER_E2E=1)\n```\n\n> Tests run via `tsx` (this node build's `--experimental-strip-types` is unreliable); the worker fork resolves `tsx`/`jiti` loaders automatically.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}