Detect file renames without triggering deletions#587
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds end-to-end rename support to the code-link workflow (CLI watcher → CLI controller → plugin) by detecting unlink+add rename patterns locally, sending a new file-rename message type, and applying the rename remotely via Framer’s codeFile.rename() API. It also adds suppression for chokidar “echo” events caused by the watcher’s own sanitization renames to avoid false remote deletions.
Changes:
- Add hash-based unlink+add pairing with a short buffer to emit a single local
renamewatcher event. - Introduce
file-renameCLI→plugin message + controller effect to send renames and update local tracking. - Implement plugin-side remote rename application via
codeFile.rename()and update shared message types accordingly.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| plugins/code-link/src/api.ts | Adds applyRemoteRename() to rename Framer code files and acknowledge via file-synced. |
| plugins/code-link/src/App.tsx | Handles incoming file-rename messages and invokes the new API method. |
| packages/code-link-shared/src/types.ts | Extends shared message union/validation to include file-rename. |
| packages/code-link-cli/src/utils/project.ts | Adjusts directory-name sanitization rules (now preserves spaces). |
| packages/code-link-cli/src/utils/hash-tracker.ts | Reuses shared hashing utility from state persistence (removes local crypto hashing). |
| packages/code-link-cli/src/types.ts | Adds rename watcher event kind and oldRelativePath metadata. |
| packages/code-link-cli/src/helpers/watcher.ts | Implements rename detection + sanitization echo suppression + buffer cleanup on close. |
| packages/code-link-cli/src/helpers/watcher.test.ts | Adds unit tests covering rename detection, buffering, and echo suppression. |
| packages/code-link-cli/src/helpers/installer.ts | Minor formatting cleanup (whitespace). |
| packages/code-link-cli/src/helpers/files.test.ts | Adjusts test typings for conflict content values. |
| packages/code-link-cli/src/controller.ts | Adds rename handling in the state machine and a new SEND_FILE_RENAME effect. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Dang ok I guess I will start doing copilot + devin + cursor haha |
|
@cursor review |
|
@devin are you here to review |
|
This PR has become testing grounds for how cursor bugbot kinda sucks at finding things in one pass and loves to go in circles |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
|
@cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
| export function toDirectoryName(name: string): string { | ||
| return name | ||
| .replace(/[^a-zA-Z0-9-]/g, "-") | ||
| .replace(/[^a-zA-Z0-9- ]/g, "-") |
There was a problem hiding this comment.
Ambiguous regex character class relies on legacy parsing
Low Severity
The character class [^a-zA-Z0-9- ] contains an ambiguous - between 9 and (space). JavaScript parses this as a range from - (ASCII 45) to (ASCII 32), which is invalid since the start exceeds the end. In non-unicode mode this silently falls back to treating both as literal characters, but adding the u flag would cause a SyntaxError. Placing the hyphen at the end of the class (e.g., [^a-zA-Z0-9 -]) would make the intent unambiguous and work in both modes. The PR discussion also notes this is "a bit stinky."
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
Nick-Lucas
left a comment
There was a problem hiding this comment.
Approving + ticking QA on the basis that this is an in development plugin and still being shaken down and improved as we go. Lots of review bots too so let's favour forward motion though I don't have time to QA/review properly
Move the file-synced WebSocket message inside the existing-file guard so the CLI is not told a rename succeeded when the target file was never found in Framer. Also reorder rename-effect tracking to update state only after a successful send, and fix minor type/style issues.
Reuse hashFileContent from state-persistence instead of maintaining a private copy.
…on on send failure
4503ed9 to
553d7af
Compare


Description
This PR implements proper file rename detection in the code-link CLI and fixes the echo event bug that was causing false deletions. The changes include:
codeFile.rename()API to properly rename files without deletionrace?.tsx→race_.tsxorNew Folder With Items/→New_Folder_With_Items/)Without the echo suppression fix, renaming files locally would trigger a delete operation on the remote plugin, undoing the rename. The 100ms buffer for rename detection ensures that both unlink and add events are matched regardless of their arrival order.
Drive-by improvements
api.ts(rename, delete, sync operations)normalizedCodeFileName()helper to reduce duplicationChangelog
file-renamemessage type for CLI-to-plugin communicationSEND_FILE_RENAMEeffect in CLI controller to handle rename eventsapplyRemoteRename()method in plugin API using Framer'scodeFile.rename()Testing