Skip to content

Protect pre-existing user files from copyPackFile overwrite#300

Merged
bguidolim merged 2 commits intomainfrom
bruno/300-protect-preexisting-user-files
Mar 26, 2026
Merged

Protect pre-existing user files from copyPackFile overwrite#300
bguidolim merged 2 commits intomainfrom
bruno/300-protect-preexisting-user-files

Conversation

@bguidolim
Copy link
Collaborator

@bguidolim bguidolim commented Mar 26, 2026

Summary

When mcs sync installs a pack's copyPackFile component, it previously overwrote any existing file at the destination — including files the user created manually. This PR adds filesystem awareness to the DestinationCollisionResolver so pre-existing user files are never touched: hooks from packs are always namespaced into <pack-id>/ subdirectories, and other file types (commands, skills, agents) are namespaced only when a conflict with an untracked file is detected.

Changes

  • CollisionFilesystemContext protocol + ProjectCollisionContext / GlobalCollisionContext concrete types — enable the resolver to check filesystem state and distinguish mcs-tracked files from user files
  • Three-phase resolver pipeline: Phase 1 (single pass) builds collision map and always-namespaces hooks; Phase 1a resolves cross-pack collisions; Phase 1b detects user-file conflicts with warning
  • namespacedDestination helper centralizes the skill-suffix vs subdirectory-prefix namespacing rule in one place
  • PackArtifactRecord.allTrackedFiles(from:) shared static method ensures sync and doctor compute tracked files identically
  • SyncStrategy.makeCollisionContext and CheckScope.makeCollisionContext provide scope-appropriate context to the resolver from both sync and doctor paths
  • Configurator.configure() / dryRun() reordered: state loaded before collision resolution so tracked files are available
  • DoctorRunner passes filesystem context per scope for consistent namespaced-path doctor checks
  • New unit tests: HookAlwaysNamespaceTests (4 tests), UserFileConflictTests (5 tests) with MockCollisionContext
  • New integration tests: UserFileProtectionTests (4 tests) — pre-existing hook/command preserved, tracked file not false-positive, hook always namespaced
  • Updated existing tests: hook path assertions across LifecycleIntegrationTests, GlobalConfiguratorTests, ProjectConfiguratorTests updated for always-namespaced hooks

Test plan

  • swift test passes locally (889 tests, 0 failures)
  • swiftformat --lint . and swiftlint pass without violations
  • Affected commands verified with a real pack (e.g. mcs sync, mcs doctor)
Checklist for engine changes
  • Integration tests updated for new features (LifecycleIntegrationTestsUserFileProtectionTests, updated CrossPackCollisionTests)

@bguidolim bguidolim changed the title #300: Protect pre-existing user files from copyPackFile overwrite Protect pre-existing user files from copyPackFile overwrite Mar 26, 2026
- Add filesystem-aware collision resolver: hooks always namespace into
  <pack-id>/ subdirectories; other types namespace only when a
  pre-existing untracked file is detected at the destination
- Centralize tracked-files computation and namespacing rule into shared
  helpers (PackArtifactRecord.allTrackedFiles, namespacedDestination)
- Add unit tests (HookAlwaysNamespaceTests, UserFileConflictTests) and
  integration tests (UserFileProtectionTests) covering all scenarios
@bguidolim bguidolim force-pushed the bruno/300-protect-preexisting-user-files branch from 9328ce5 to 4548eec Compare March 26, 2026 12:15
…test

- Align phase numbering in DestinationCollisionResolver comments (Phase 0/1a/1b/2)
- Remove default nil from SyncStrategy.makeCollisionContext to enforce implementation
- Add .generic file type user-conflict test in DestinationCollisionResolverTests
@bguidolim bguidolim enabled auto-merge (squash) March 26, 2026 12:38
@bguidolim bguidolim merged commit 8630c5e into main Mar 26, 2026
4 checks passed
@bguidolim bguidolim deleted the bruno/300-protect-preexisting-user-files branch March 26, 2026 12:39
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.

1 participant