Skip to content

fix(sync): safely clean unreferenced attachments - #843

Open
ctawiah wants to merge 1 commit into
ctawiah/sync-attachment-review-outputfrom
ctawiah/sync-attachment-cleanup-safety
Open

ctawiah wants to merge 1 commit into
ctawiah/sync-attachment-review-outputfrom
ctawiah/sync-attachment-cleanup-safety

Conversation

@ctawiah

@ctawiah ctawiah commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Context

A local tool or skill file is no longer needed after the final synchronized variation stops referencing it. This layer completes the attachment lifecycle by finding those files and asking before removing them. It applies the same behavior to normal syncs and watch mode.

What changes

  • Finds local tool and skill files that are not referenced by any synchronized variation.
  • Prompts before deleting an unreferenced file.
  • Treats --yes as confirmation for attachment cleanup along with the rest of the sync.
  • Removes confirmed files as one transaction so a failed deletion can be rolled back safely.
  • Rejects unexpected paths, duplicate selections, non-regular files, and symbolic links before deleting anything.
  • Runs cleanup only after a successful sync or after confirming that there are no resource changes to apply.
  • Watches all managed source files directly instead of rebuilding the watch scope from project directories.
  • Passes watcher state into each sync run explicitly.

This cleanup only removes local files. It does not delete tools or skills from LaunchDarkly.

Review focus

  • Does cleanup wait until the final local reference has been removed?
  • Are interactive confirmation and --yes handled consistently?
  • Can a partial filesystem failure leave a deleted attachment file behind?
  • Does watch mode run the same cleanup and confirmation flow as a normal sync?
  • Are path and symbolic-link checks applied before any file is moved or removed?

Verification

  • go test ./internal/sync/local ./internal/sync/prompt ./internal/sync/detach
  • go test ./...
  • go vet ./internal/sync/... ./cmd/sync
  • git diff --check

Related changes

Review the stack in this order:

  1. Confirm destructive watch actions
  2. Guarantee prompt fingerprint convergence
  3. Add searchable attachment API foundations
  4. Reconcile variation attachments
  5. Attach tools and skills to variations
  6. Render attachment-aware review output
  7. Safely clean unreferenced attachments
  8. Persist sync manifests in LaunchDarkly

Note

Overview
Adds orphaned local attachment cleanup after sync: the local store can list tool/skill files under .launchdarkly that no variation still references, delete them in a staged batch (with path, symlink, and duplicate checks), and the prompt flow runs this after a successful sync or when the plan has no changes (including if the user declines applying changes).

Interactive sync lists unreferenced files and asks Delete these unreferenced local files?; --yes skips that prompt. Cleanup only removes local files—LaunchDarkly tools/skills are untouched.

Watch / file discovery: SourceFiles now includes every file under managed project trees (not only variation wrappers), and the file watcher is passed into runWorkspaceSync explicitly instead of living on Options.

Deletion semantics: commitDeletions treats the batch rename as the commit point and no longer rolls back on backup cleanup failures.

Removes unused Store.ProjectKeys.

Reviewed by Cursor Bugbot for commit f183b15. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread internal/sync/prompt/runner.go
@ctawiah
ctawiah force-pushed the ctawiah/sync-attachment-cleanup-safety branch from 055ffba to 0f4b180 Compare October 7, 2026 15:41
@ctawiah
ctawiah force-pushed the ctawiah/sync-attachment-cleanup-safety branch from 0f4b180 to f183b15 Compare October 7, 2026 15:44

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f183b15. Configure here.

for _, file := range deleted {
_ = console.Printf("- %s/%s\n", ".launchdarkly", file)
}
return nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleanup deletes stale orphan list

Medium Severity

cleanupOrphanedAttachments deletes the attachment list gathered before the confirmation prompt and never recompiles the workspace. A variation can regain a reference while that prompt is open, especially in watch mode, and DeleteAttachments still removes the file. The main sync re-reads state after review; cleanup does not.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f183b15. Configure here.

)
if err != nil {
return err
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No-op sync fails without TTY

Medium Severity

When unreferenced attachment files exist, cleanup always prompts unless --yes is set. A no-change sync in a non-TTY environment (CI or redirected stdin) now returns interactive confirmation requires a terminal after a successful no-op, even though the user never asked to apply changes.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f183b15. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants