mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-10-25 17:22:27 +08:00
feat(skills): auto-backup skill files before uninstall
Create a local backup under ~/.cc-switch/skill-backups/ before removing skill directories. The backup includes all skill files and a meta.json with original skill metadata. Old backups are pruned to keep at most 20. The backup path is returned to the frontend and shown in the success toast. Bump version to 3.12.3.
This commit is contained in:
1 parent
04254d6ffe
commit
9336001746
20 files changed
+850
-28
No files matched your search
@@ -125,6 +125,74 @@ fn sync_to_app_removes_disabled_and_orphaned_ssot_symlinks() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uninstall_skill_creates_backup_before_removing_ssot() {
|
||||
let _guard = test_mutex().lock().expect("acquire test mutex");
|
||||
reset_test_fs();
|
||||
let home = ensure_test_home();
|
||||
|
||||
let ssot_skill_dir = home.join(".cc-switch").join("skills").join("backup-skill");
|
||||
write_skill(&ssot_skill_dir, "Backup Skill");
|
||||
fs::write(ssot_skill_dir.join("prompt.md"), "backup me").expect("write prompt.md");
|
||||
|
||||
let state = create_test_state().expect("create test state");
|
||||
state
|
||||
.db
|
||||
.save_skill(&InstalledSkill {
|
||||
id: "local:backup-skill".to_string(),
|
||||
name: "Backup Skill".to_string(),
|
||||
description: Some("Back me up before uninstall".to_string()),
|
||||
directory: "backup-skill".to_string(),
|
||||
repo_owner: None,
|
||||
repo_name: None,
|
||||
repo_branch: None,
|
||||
readme_url: None,
|
||||
apps: SkillApps {
|
||||
claude: true,
|
||||
codex: false,
|
||||
gemini: false,
|
||||
opencode: false,
|
||||
},
|
||||
installed_at: 123,
|
||||
})
|
||||
.expect("save skill");
|
||||
|
||||
let result = SkillService::uninstall(&state.db, "local:backup-skill").expect("uninstall skill");
|
||||
let backup_path = result.backup_path.expect("backup path should be returned");
|
||||
let backup_dir = std::path::PathBuf::from(&backup_path);
|
||||
|
||||
assert!(backup_dir.exists(), "backup directory should exist");
|
||||
assert!(
|
||||
backup_dir.join("skill").join("SKILL.md").exists(),
|
||||
"backup should include SKILL.md"
|
||||
);
|
||||
assert_eq!(
|
||||
fs::read_to_string(backup_dir.join("skill").join("prompt.md"))
|
||||
.expect("read backed up prompt"),
|
||||
"backup me"
|
||||
);
|
||||
|
||||
let metadata: serde_json::Value = serde_json::from_str(
|
||||
&fs::read_to_string(backup_dir.join("meta.json")).expect("read backup metadata"),
|
||||
)
|
||||
.expect("parse backup metadata");
|
||||
assert_eq!(metadata["skill"]["directory"], "backup-skill");
|
||||
assert_eq!(metadata["skill"]["name"], "Backup Skill");
|
||||
|
||||
assert!(
|
||||
!ssot_skill_dir.exists(),
|
||||
"SSOT skill directory should be removed after uninstall"
|
||||
);
|
||||
assert!(
|
||||
state
|
||||
.db
|
||||
.get_installed_skill("local:backup-skill")
|
||||
.expect("query skill")
|
||||
.is_none(),
|
||||
"database row should be deleted after uninstall"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn migration_snapshot_overrides_multi_source_directory_inference() {
|
||||
let _guard = test_mutex().lock().expect("acquire test mutex");
|
||||
|
||||
Reference in new issue
Block a user