Skip to content

install --update / upgrade silently destroy local edits of url- and local-sourced installs (auto-pin protection only exists for github/gitlab) #194

Description

@eljulians

Component: crates/deploy | Severity: Critical (user data loss) | Status: Reproduced

The v1.6.0 protection ("install --update now compares every configured install target before saving local edits ... divergent edits now stop with an explicit error instead of risking silent data loss") does not apply to url or local entries. Editing the installed copy of a url/local-sourced skill and then running upgrade or install --update overwrites the edit with upstream content - no auto-pin, no warning, no error. The user cannot even protect themselves in advance: skillfile pin refuses for url entries ("not locked") and skips for local entries.

Where: auto-pin runs only for locked entries - crates/deploy/src/install.rs:189-233 (auto-pin path keyed off lock/cache SHA state that url/local entries never have); overwrite path crates/deploy/src/adapter.rs:403-414.

Repro (fully offline):

python3 -m http.server 8931 --directory www &   # www/skills/browser.md = "# Browser Skill"
mkdir proj && cd proj
printf 'install  claude-code  global\nurl  skill  browser  http://127.0.0.1:8931/skills/browser.md\n' > Skillfile
skillfile install
printf 'MY LOCAL EDIT\n' >> ~/.claude/skills/browser/SKILL.md
skillfile upgrade      # or: skillfile install --update
cat ~/.claude/skills/browser/SKILL.md   # edit gone; exit 0; no warning, no auto-pin

Reproduced identically for a local entry (edit the deployed copy, run install --update).

Expected: the same protection as github entries - auto-pin the edit, or stop with an explicit error.
Actual: silent clobber.

Fix sketch: run the same installed-vs-cache comparison for url/local entries before overwriting (for url entries the cache is the old upstream, exactly like github; for local entries compare against the source file) and either auto-pin or error.

Tests:

  1. Integration (crates/deploy/tests/install_deploy_all.rs): url-style cached entry deployed, dest edited, cmd_install(update=true) → assert edit survives as patch or run errors; must currently fail (edit lost).
  2. Functional (tests/cli.rs): local entry; edit deployed copy; skillfile install --update; assert non-clobber behavior.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcomponent: installInstall orchestration, update, dry-run, overwrite, rollback, and user-file safetyhelp wantedExtra attention is neededseverity: criticalCritical severity bug

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions