Repository navigation
Conversation
The audit calls a worktree safe when removing it deletes an ignored file that exists nowhere else or orphans a commit only its HEAD reflog reaches, and it fetches and refreshes indexes while it claims to be read-only. These tests run the real script on real repositories and fail on main. They port the ignored-file and reflog cases from Michael Denyer's pstack-claude #277, and add the generator check from sergchil/jutsu da94424 that rejects a playbook which force-removes a worktree.
…mmits worktree-audit.sh bucketed a worktree safe when removing it would delete an ignored .env or orphan a commit only its HEAD reflog reaches. It now reads ignored paths with --ignored=matching and counts those outside a named list of build and cache directories as ignored:N (hold-ignored). It walks the worktree's HEAD reflog and counts commits no branch, tag, remote, or branch reflog reaches as reflog:N (hold-reflog). Both ports Michael Denyer's pstack-claude #277 to Lauren's bash script. The audit no longer fetches unless --fetch is given, and it sets GIT_OPTIONAL_LOCKS=0, so its git status no longer rewrites the index of a worktree an agent may be using. The read-only claim is now true by default.
Cleanup step 5 ran git worktree remove --force and then rm -rf on whatever survived, which deletes untracked and ignored files that exist nowhere else (cursor/plugins#449). It now runs a plain remove and treats its refusal as the stop. Step 4 names the ignored and reflog counts the audit adds, pauses on untracked scratch, and deletes only paths the user approves with a targeted git clean. The generator check fails when any playbook force-removes a worktree or runs rm -rf, as sergchil/jutsu da94424 does, so a sync cannot bring the step back silently.
Both icon copies carried a caBX chunk with an image generator's signed C2PA manifest, whose certificate and signature text a plugin directory screen can read as a credential. The files are Michael Denyer's from pstack-claude #271: every other chunk is byte-identical, so the pixels are unchanged. His test fails on any tracked PNG with a caBX chunk.
The audit still bucketed a worktree with only untracked files safe, as Lauren's script treats them as throwaway. cursor/plugins#449 covers them too, and the cleanup playbook now pauses on scratch and a plain remove refuses it, so the bucket says hold-scratch and the advice matches the playbook.
Two reviewers found that a status.showUntrackedFiles=no config made the new git status call fail, which the audit read as clean, so a worktree with an ignored .env bucketed safe again. Under that config a plain git worktree remove also deletes untracked files without refusing. The status call now passes --untracked-files=normal. A status call or HEAD reflog walk that fails holds the worktree as unknown or reflog:? instead of reading clean. A detached commit HEAD still points at is held after gc expires its reflog, since HEAD itself now feeds the reflog walk. An ignored file under a tracked directory that happens to be named build or target is held, since only the last component of an ignored path can mark it disposable. wip and scratch print together. Step 4 lists ignored files with the audit's own status call, names unknown, reads a prunable worktree's HEAD and reflog from the main checkout, and deletes approved scratch with --literal-pathspecs, so notes[1].md no longer also matches notes1.md. Step 5 says what a plain remove deletes. The generator check also rejects -ff, a recursive rm with its flags in any order, git clean -x, and git worktree prune, and lets git rm -r through.
VERSION, the manifests, and package.json move to 2.0.0-rc.7. CHANGES.md gets the entry with its behavior-delta table. NOTICE.md and NOTICE-skills.md credit Michael Denyer's pstack-claude #277 and #271 and sergchil/jutsu da94424, CONTRIBUTING.md names the two new forks, and the README's pinned installer command names the new tag.
The exception that let `git -C <path> rm -r --cached` through excused a recursive rm after any earlier git on the same line, so a line such as "If git refuses, rm -rf the directory." passed the check. It now excuses only `git rm` and `git -C <path> rm`. Cursor Bugbot found it on #26.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 65680c3. Configure here.
The path in the `git -C <path> rm` exception matched any non-space run, so a closing backtick or a glued semicolon became part of the path and a recursive rm after it passed the check. The path now stops at a backtick, `;`, `&`, or `|`. Cursor Bugbot found it on #26.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Why
Worktree cleanup could delete work that existed nowhere else (cursor/plugins#449). The audit bucketed a worktree
safewhen it held an ignored.env, untracked notes, or a commit only its HEAD reflog reached. Step 5 then removed it withgit worktree remove --forceandrm -rf. The audit also called itself read-only, yet it fetched (cursor/plugins#470), and itsgit statusrewrote each worktree's index.What changed
worktree-audit.shholds a worktree with ignored files outside build and cache directories, untracked scratch, a commit only HEAD or its reflog reaches, or a status or reflog git cannot read. The ignored and reflog checks port Michael Denyer's pstack-claude #277 to Lauren's bash script. The audit fetches only under--fetch.git worktree removeand stops when it refuses, as sergchil's jutsuda94424does.bun tools/generate.mjs --checkrejects a playbook that force-removes a worktree, runs a recursivermorgit clean -x, or prunes worktrees in bulk.caBXchunk (pstack-claude #271). The pixels do not change.Scope
assume-unchangedorskip-worktreehide. They readcleanhere, as they do upstream.Blast Radius
Only the worktree cleanup playbook and its audit change behavior. Cleanup now pauses on more worktrees and asks before it removes them. Apart from edits those two index flags hide, a removal deletes without a decision only ignored build and cache directories such as
node_modules. Neither hooks file changes.Verification
.envworktree and a detached-commit worktreesafe, and step 5 lost both. On this branch both hold, step 5 removes only the clean merged worktrees, and the.envand the commit survivegit gc.GIT_CONFIG_GLOBAL=/dev/null bun test tests/passes 550 with 0 failures, and the scripts suite,generate --check, and the sync dry runs at99743e9pass.status.showUntrackedFiles=noregression. Every finding that could lose work is fixed, apart from the index-flag gap above, and the ones left open only add holds. Cursor Bugbot then found two gaps in the check'sgit rmexception, both fixed with tests.