Q35: retired built-in skills come back when the bundle ships them again

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-10-08 07:00:57 -04:00
1 parent da072f9a9b
commit bbc60cd56a
4 files changed
+47 -9

No files matched your search

+12 -7
View File
@@ -30,6 +30,8 @@ export interface BuiltinSkillSyncReport {
imported: number;
/** Existing skills that got a new revision because the bundle changed them. */
upgraded: number;
/** Retired skills reactivated because the bundle ships them again. */
restored: number;
skipped: number;
/** Active skills retired because the bundle no longer carries their slug. */
retired: number;
@@ -75,18 +77,21 @@ export function stageBuiltinSkillsLibrary(sourceRoot: string, libraryRoot: strin
/**
* Makes the org catalogue mirror the bundle: publishes every staged skill
* the org does not carry yet, upgrades skills whose files changed (moving
* bindings onto the new revision), then retires active skills whose slug
* the bundle no longer ships. Retired skills leave list_skills and stop
* being grantable.
* the org does not carry yet, restores retired skills the bundle ships again,
* upgrades skills whose files changed (moving bindings onto the new
* revision), then retires active skills whose slug the bundle no longer
* ships. Retired skills leave list_skills and stop being grantable.
*/
export function importStagedSkills(skills: SkillService, orgId: string, staged: StagedBuiltinSkill[]): BuiltinSkillSyncReport {
const report: BuiltinSkillSyncReport = { imported: 0, upgraded: 0, skipped: 0, retired: 0, failures: [] };
const report: BuiltinSkillSyncReport = { imported: 0, upgraded: 0, restored: 0, skipped: 0, retired: 0, failures: [] };
for (const unit of staged) {
try {
if (skills.hasSkill(orgId, unit.slug)) {
if (skills.upgradeIfChanged(orgId, unit.directory, unit.manifest, unit.slug)) report.upgraded += 1;
else report.skipped += 1;
const restored = skills.restoreIfRetired(orgId, unit.slug);
if (restored) report.restored += 1;
const upgraded = skills.upgradeIfChanged(orgId, unit.directory, unit.manifest, unit.slug);
if (upgraded) report.upgraded += 1;
if (!restored && !upgraded) report.skipped += 1;
continue;
}
skills.importManifest(orgId, unit.directory, unit.manifest, unit.slug);
+18
View File
@@ -83,6 +83,24 @@ export class SkillService {
return retired;
}
/** Reactivates a retired skill; returns whether it was retired. */
restoreIfRetired(orgId: string, slug: string): boolean {
const skill = this.db.prepare("select id from skill_definitions where org_id = ? and slug = ? and status = 'retired'")
.get(orgId, slug) as { id: string } | undefined;
if (!skill) return false;
this.db.prepare("update skill_definitions set status = 'active' where id = ?").run(skill.id);
this.audit.record({
orgId,
entityType: "skill_definition",
entityId: skill.id,
actorType: "system",
actorId: null,
action: "restored",
payload: { slug, reason: "back_in_builtin_bundle" },
});
return true;
}
/** Publishes a new revision when the files changed and moves bindings on the latest revision onto it. */
upgradeIfChanged(orgId: string, directoryPath: string, manifest: SkillManifest, slug: string): boolean {
const latest = this.db.prepare(`