{"_id":"@ahm3tj4f/pi-undo","_rev":"4-8ff52856305a9982be9ffc59abccefc5","name":"@ahm3tj4f/pi-undo","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"@ahm3tj4f/pi-undo","version":"0.1.0","keywords":["pi-package","pi","undo","redo","snapshots","opencode"],"license":"MIT","_id":"@ahm3tj4f/pi-undo@0.1.0","maintainers":[{"name":"ahm3tj4f","email":"ahmetleo56@gmail.com"}],"pi":{"extensions":["./src/index.ts"]},"dist":{"shasum":"ad68c6fd974f5c97f29da95e79fa84a33b796557","tarball":"https://registry.npmjs.org/@ahm3tj4f/pi-undo/-/pi-undo-0.1.0.tgz","fileCount":11,"integrity":"sha512-f9V7BYVdCoHRMn6nh0iHvgkv0ySsj8HL+c89b5CWqmZeUbis7H5SMHd2zRzG7AjL4SeT+1oJ7A0fsapOYvhquw==","signatures":[{"sig":"MEUCIQCppfga/9tf2Yl3H+gPwA7tpCc11gofzOcWWG1NWZLfWgIgR+1XZI7tWPyuafqJmWgTGt3E2dFfjXNHiJQJ2BGMciw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40891},"type":"module","scripts":{"test":"node --test test/*.test.ts","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ahm3tj4f","email":"ahmetleo56@gmail.com"},"_npmVersion":"11.12.1","description":"Undo/redo for pi, but this time it works. Per-message snapshots, ported from OpenCode's exact undo/redo philosophy.","directories":{},"_nodeVersion":"26.0.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.6.0","@types/node":"^22.0.0","@earendil-works/pi-coding-agent":"^0.84.0"},"peerDependencies":{"@earendil-works/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/pi-undo_0.1.0_1786055674932_0.5483443624416242","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@ahm3tj4f/pi-undo","version":"0.2.0","keywords":["pi-package","pi","undo","redo","snapshots","opencode"],"license":"MIT","_id":"@ahm3tj4f/pi-undo@0.2.0","maintainers":[{"name":"ahm3tj4f","email":"ahmetleo56@gmail.com"}],"pi":{"extensions":["./src/index.ts"]},"dist":{"shasum":"f2dfa83b08f16934d167d8805cfb92870fa7e006","tarball":"https://registry.npmjs.org/@ahm3tj4f/pi-undo/-/pi-undo-0.2.0.tgz","fileCount":12,"integrity":"sha512-jqHD0EUppK55zilsdcSkdI+XdGWNHcorIJPB4V6tuo2al/Joa05IHfR7G4PgskeZYFAyOcz7uc6+pBuzWoJ5Hg==","signatures":[{"sig":"MEUCIA3y/5PgYDly3mCJAWQRv5pEMpFVvvUJDz6WPgZxM/KYAiEA9rY7d1dkC2oedaywkt4OtQir/+h2fL3b+OO5L6Fy9s0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51450},"type":"module","gitHead":"3a04db91bef417e909b5e6902db6a550fb2e7cb6","scripts":{"test":"node --test test/*.test.ts","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ahm3tj4f","email":"ahmetleo56@gmail.com"},"_npmVersion":"11.12.1","description":"Undo/redo for pi, but this time it works. Per-message snapshots, ported from OpenCode's exact undo/redo philosophy.","directories":{},"_nodeVersion":"26.0.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.6.0","@types/node":"^22.0.0","@earendil-works/pi-coding-agent":"^0.84.0"},"peerDependencies":{"@earendil-works/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/pi-undo_0.2.0_1786106941566_0.12943677921068963","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@ahm3tj4f/pi-undo","version":"0.3.0","keywords":["pi-package","pi","undo","redo","snapshots","opencode"],"license":"MIT","_id":"@ahm3tj4f/pi-undo@0.3.0","maintainers":[{"name":"ahm3tj4f","email":"ahmetleo56@gmail.com"}],"pi":{"extensions":["./src/index.ts"]},"dist":{"shasum":"06940dea4f492c63e60528fd56089827d30be35f","tarball":"https://registry.npmjs.org/@ahm3tj4f/pi-undo/-/pi-undo-0.3.0.tgz","fileCount":12,"integrity":"sha512-8p2sx4UPCAUqKHF/wIgzcEy7ttApd0ikL0NGHr7CHkXX0AY4WfNU0ctd8uzhIGtfnuuytm8Owtv+wLy83eZzOw==","signatures":[{"sig":"MEQCIE1rksPiKJfaFmMeJ67xq/sl7QIuDrC0zV/JNszUBEmKAiA/5Dr5A8pvXs4IfCfEbm+Yi8rkFewqCGVSJG2tKyYNeA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":56170},"type":"module","gitHead":"4b9c6d74ad44f050305de47f72000d4eb306b955","scripts":{"test":"node --test test/*.test.ts","typecheck":"tsc --noEmit"},"_npmUser":{"name":"ahm3tj4f","email":"ahmetleo56@gmail.com"},"_npmVersion":"11.12.1","description":"Undo/redo for pi, but this time it works. Per-message snapshots, ported from OpenCode's exact undo/redo philosophy.","directories":{},"_nodeVersion":"26.0.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.6.0","@types/node":"^22.0.0","@earendil-works/pi-coding-agent":"^0.84.0"},"peerDependencies":{"@earendil-works/pi-coding-agent":"*"},"_npmOperationalInternal":{"tmp":"tmp/pi-undo_0.3.0_1786196262941_0.6132976537341019","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@ahm3tj4f/pi-undo","version":"0.4.0","description":"Undo/redo for pi, but this time it works. Per-message snapshots, ported from OpenCode's exact undo/redo philosophy.","license":"MIT","type":"module","keywords":["pi-package","pi","undo","redo","snapshots","opencode"],"publishConfig":{"access":"public"},"pi":{"extensions":["./src/index.ts"]},"scripts":{"typecheck":"tsc --noEmit","test":"node --test test/*.test.ts"},"peerDependencies":{"@earendil-works/pi-coding-agent":"*"},"devDependencies":{"@earendil-works/pi-coding-agent":"^0.84.0","@types/node":"^22.0.0","typescript":"^5.6.0"},"dependencies":{"ignore":"^7.0.6"},"gitHead":"ed97163d58716c9ef4b3e592078d8eab1c6977f4","_id":"@ahm3tj4f/pi-undo@0.4.0","_nodeVersion":"26.0.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-QhI7ME9Nj5cFtlde2HKxiBoFrkv4CjJrvFw6xKR6eK01PpyEwWPPbYJqJ5JD10IBCDRE+mmjr/uBR5nacBqoEg==","shasum":"2d4dd515d8cc31785405c6b8e961b1efdc759a75","tarball":"https://registry.npmjs.org/@ahm3tj4f/pi-undo/-/pi-undo-0.4.0.tgz","fileCount":13,"unpackedSize":75186,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDlun2F2dedZiDIbQOoHleayDGZDwglL06y9VdUrozjAwIgC9x/wlzm1lcLoXd+fWddl5IHBTvhh25F5F2c1QmO/Dg="}]},"_npmUser":{"name":"ahm3tj4f","email":"ahmetleo56@gmail.com"},"directories":{},"maintainers":[{"name":"ahm3tj4f","email":"ahmetleo56@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pi-undo_0.4.0_1786629225264_0.9846105983798339"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-06T22:34:34.754Z","modified":"2026-08-13T13:53:45.590Z","0.1.0":"2026-08-06T22:34:35.106Z","0.2.0":"2026-08-07T12:49:01.698Z","0.3.0":"2026-08-08T13:37:43.081Z","0.4.0":"2026-08-13T13:53:45.431Z"},"license":"MIT","keywords":["pi-package","pi","undo","redo","snapshots","opencode"],"description":"Undo/redo for pi, but this time it works. Per-message snapshots, ported from OpenCode's exact undo/redo philosophy.","maintainers":[{"name":"ahm3tj4f","email":"ahmetleo56@gmail.com"}],"readme":"# pi-undo\n\n[![npm version](https://img.shields.io/npm/v/@ahm3tj4f/pi-undo)](https://www.npmjs.com/package/@ahm3tj4f/pi-undo)\n[![npm downloads](https://img.shields.io/npm/dm/@ahm3tj4f/pi-undo)](https://www.npmjs.com/package/@ahm3tj4f/pi-undo)\n[![license](https://img.shields.io/npm/l/@ahm3tj4f/pi-undo)](https://github.com/ahm3tj4f/pi-undo/blob/main/LICENSE)\n\nUndo/redo for pi. But this time it works.\n\nThis is a port of OpenCode's exact undo/redo philosophy: snapshot the files\nper message with a shadow git repo, restore only what that message changed,\nand never lose your work in the process.\n\n## How it works\n\nEach user message gets two git tree hashes: one before the turn, one after.\nThe trees live in a shadow repo under `~/.pi/agent/pi-undo/snapshots/`.\nThe checkpoints are persisted in the session, so undo and redo work after a\nrestart.\n\n## Why this works\n\n- **Works without git.** Non-git directories are fully supported.\n- **Fast on big repos.** Object reuse via git alternates, incremental adds,\n  batched restores. No full `git add` twice per turn.\n- **Garbage collection.** Daily gc keeps the snapshot store bounded. Old\n  snapshots get pruned, so storage doesn't grow forever.\n- **Cancel and failures are safe.** Cancel mid-undo rolls the files back.\n  Restores are verified by tree hash and roll back on mismatch. Manual\n  edits trigger a question first, so nothing gets clobbered.\n- **Two snapshots per message.** Each user message gets a before and an\n  after tree hash. Undo restores only the files that message changed.\n- **Gitignored files are undoable when the session edits them.** The shadow\n  repo snapshots gitignored files too, so a file the current pi session\n  touched can always be undone, even if it is in `.gitignore`. A gitignored\n  file with manual edits since the message triggers the manual-edits\n  question. Confirming restores the file and loses the manual edits.\n  Declining blocks the undo. Only pi-undo's own `excludeDirectories` are\n  never snapshotted.\n- **Undo restores only what this session wrote.** Each message records which\n  files its `write` and `edit` tools touched. Undo restores those files.\n  Files that changed during the message for another reason are listed in\n  the dialog and never restored; a warning names them. Files that another\n  pi session touched get the session id in the warning. The records live\n  in a small journal under the snapshot store, so they survive restarts.\n  Changes made by bash commands cannot be attributed and are warned about\n  the same way.\n\n## Configuration\n\npi-undo reads one config file: `~/.pi/agent/pi-undo.json`. On the first run\nthe file is created with the default values, and you edit it directly to\nchange them. Add or remove patterns in `excludeDirectories`, or change\n`maxFiles`. The list in the file is the complete list: removing an entry\nreally un-excludes that path.\n\n```json\n{\n  \"excludeDirectories\": [\"node_modules\", \"dist\", \"Downloads\", \"tmp\"],\n  \"maxFiles\": 100000\n}\n```\n\n| Field | What it does |\n| -------- | ------------ |\n| `excludeDirectories` | Full gitignore glob patterns, never snapshotted. Plain names match at any depth; globs like `**/build-*` or `*.tmp` work; a trailing slash means directories only |\n| `maxFiles` | Snapshot size cap (default 100000). Over this, snapshots are skipped for that message with a one-time warning instead of making pi slow |\n\n## Commands\n\n| Command | What it does                                                                                                     |\n| ------- | ---------------------------------------------------------------------------------------------------------------- |\n| `/undo` | Aborts the agent, shows a diff preview, restores the files to before the last message, and puts the prompt back. |\n| `/redo` | Re-applies the most recently undone message. Survives restarts.                                                  |\n| `/diff` | Shows what `/undo` would restore.                                                                                |\n\n## Install\n\n```bash\npi install npm:@ahm3tj4f/pi-undo\n\n# OR\n\npi install git:github.com/ahm3tj4f/pi-undo\n```\n","readmeFilename":"README.md"}