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:
- 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).
- Functional (
tests/cli.rs): local entry; edit deployed copy; skillfile install --update; assert non-clobber behavior.
Component:
crates/deploy| Severity: Critical (user data loss) | Status: ReproducedThe v1.6.0 protection ("
install --updatenow 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 tourlorlocalentries. Editing the installed copy of a url/local-sourced skill and then runningupgradeorinstall --updateoverwrites the edit with upstream content - no auto-pin, no warning, no error. The user cannot even protect themselves in advance:skillfile pinrefuses 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 pathcrates/deploy/src/adapter.rs:403-414.Repro (fully offline):
Reproduced identically for a
localentry (edit the deployed copy, runinstall --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:
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).tests/cli.rs): local entry; edit deployed copy;skillfile install --update; assert non-clobber behavior.