fix(generate): refuse to sweep orphans through a link out of the output root - #3295
Merged
Merged
Conversation
…ut root The file-feature orphan sweep enumerates candidates without following links inside the scanned directory, but the scanned directory itself was reached through any link in its path. A checked-out `.cursor/commands -> ~/notes` made every file in ~/notes read as an orphan, and `generate --delete` removed them (reproduced for commands and rules). removeOrphanAiFiles now refuses a candidate whose parent directory lands outside the output root, with the same warning shape as the write-side refusal, before the dry-run branch so --check agrees with a real run. Refs #3294 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y4MwhqMc6s4ct5MzMReGJj
Owner
Author
|
@dyoshikawa Thank you! |
This was referenced Oct 3, 2026
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.
Summary
Fixes item 7 of #3294: the
--deleteorphan sweep could follow a symlinked output directory out of the project and delete files there.Reproduction (on
main)The same happens for
rules(.claude/rules -> ~/somewhere).subagentsandskillswere already refused by their own guards, so only the shared file-feature path was affected.Candidate enumeration uses
followSymbolicLinks: false, which only covers links inside the scanned directory, not the directory itself.FeatureProcessor.removeOrphanAiFilesthen removed whatever was listed with no inside-root check.Fix
removeOrphanAiFilesnow asksrefusesDeleteOutsideRootbefore deleting each candidate. It uses the existingwritablePathEscapesRooton the candidate's parent directory, so:Refusing to delete "<path>": it resolves outside "<root>" through a symbolic linkwarning (same shape as the write-side refusal);--check/--dry-runagree with a real run instead of reporting a deletion forever.docs/reference/cli-commands.md(--deletesection);src/generated/docs-content.tsregenerated.Tests
Unit tests in
src/types/feature-processor.test.tsfor each of the cases above, including the dry-run case. I also re-ran the reproduction against this branch:precious.mdis kept and the warning is printed.The other follow-ups from #3294 (items 1-6, about
orphan-sweep.ts) go in a separate PR.Refs #3294
🤖 Generated with Claude Code
https://claude.ai/code/session_01Y4MwhqMc6s4ct5MzMReGJj