@lifeaitools/rdc-skills 0.9.6 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lifeaitools/rdc-skills",
3
- "version": "0.9.6",
4
- "description": "RDC typed-agent dispatch skill suite for Claude Code plan, build, review, overnight builds",
3
+ "version": "0.9.7",
4
+ "description": "RDC typed-agent dispatch skill suite for Claude Code \u00e2\u20ac\u201d plan, build, review, overnight builds",
5
5
  "keywords": [
6
6
  "claude-code",
7
7
  "claude-code-plugin",
@@ -120,6 +120,63 @@ function buildPluginCache(cacheDir, version, gitSha) {
120
120
  }
121
121
  }
122
122
 
123
+ // ── User-skills cleanup ───────────────────────────────────────────────────────
124
+ // Older installer versions wrote skill files directly to ~/.claude/skills/user/.
125
+ // Claude Code loads that directory AND the plugin cache, so any rdc skills left
126
+ // there produce duplicate registrations and break the resolver.
127
+ // This function nukes any entry whose frontmatter name starts with "rdc:".
128
+ function cleanUserSkills(userSkillsDir) {
129
+ if (!fs.existsSync(userSkillsDir)) return 0;
130
+ let removed = 0;
131
+ for (const entry of fs.readdirSync(userSkillsDir, { withFileTypes: true })) {
132
+ const candidate = path.join(userSkillsDir, entry.name);
133
+ let skillFile = null;
134
+ if (entry.isDirectory()) {
135
+ // New format: <name>/SKILL.md or <name>/skill.md
136
+ for (const sf of ['SKILL.md', 'skill.md']) {
137
+ const p = path.join(candidate, sf);
138
+ if (fs.existsSync(p)) { skillFile = p; break; }
139
+ }
140
+ } else if (entry.isFile() && entry.name.endsWith('.md') && entry.name !== 'skill.md' && entry.name !== 'SKILL.md' && entry.name !== 'README.md') {
141
+ // Old format: rdc-deploy.md flat file
142
+ skillFile = candidate;
143
+ }
144
+ if (!skillFile) continue;
145
+ const fm = readFrontmatter(skillFile);
146
+ if (fm.name && fm.name.startsWith('rdc:')) {
147
+ try {
148
+ if (entry.isDirectory()) fs.rmSync(candidate, { recursive: true, force: true });
149
+ else fs.unlinkSync(candidate);
150
+ removed++;
151
+ } catch {}
152
+ }
153
+ }
154
+ return removed;
155
+ }
156
+
157
+ // ── Stale hook cleanup ────────────────────────────────────────────────────────
158
+ // Remove hook files from ~/.claude/hooks/ that are no longer in the source hooks/ dir.
159
+ // Prevents orphaned hooks (removed from source but still installed) from misfiring.
160
+ function cleanStaleHooks(hooksDstDir, hooksSrcDir) {
161
+ if (!fs.existsSync(hooksDstDir) || !fs.existsSync(hooksSrcDir)) return 0;
162
+ const sourceFiles = new Set(fs.readdirSync(hooksSrcDir).filter(f => f.endsWith('.js')));
163
+ // These hooks were written by us (rdc-skills) — safe to remove if no longer in source.
164
+ // We only manage our own hooks; never touch hooks we didn't install.
165
+ const knownHooks = [
166
+ 'check-cwd.js', 'check-stale-work-items.js', 'check-services.js',
167
+ 'precompact-log.js', 'postcompact-log.js', 'restart-brief.js',
168
+ 'rate-limit-retry.js', 'post-work-check.js', 'no-stop-open-epics.js',
169
+ 'require-work-item-on-commit.js', 'verify-rdc-skills.js',
170
+ ];
171
+ let removed = 0;
172
+ for (const f of knownHooks) {
173
+ if (!sourceFiles.has(f) && fs.existsSync(path.join(hooksDstDir, f))) {
174
+ try { fs.unlinkSync(path.join(hooksDstDir, f)); removed++; } catch {}
175
+ }
176
+ }
177
+ return removed;
178
+ }
179
+
123
180
  // ── Cache flush helper ────────────────────────────────────────────────────────
124
181
  function flushOldCaches(cacheBase, keepVersion) {
125
182
  if (!fs.existsSync(cacheBase)) return 0;
@@ -480,6 +537,20 @@ async function main() {
480
537
  warn('[0/6] git pull failed — installing from local copy');
481
538
  }
482
539
 
540
+ // 0.5a. User-skills cleanup — remove any rdc: skills from ~/.claude/skills/user/
541
+ // (older installer versions wrote there; plugin cache is the only authoritative source)
542
+ {
543
+ const userSkillsDir = path.join(claudeHome, 'skills', 'user');
544
+ const purged = cleanUserSkills(userSkillsDir);
545
+ if (purged > 0) ok(`[0.5a] Skills cleanup — removed ${purged} stale rdc: skill(s) from skills/user/`);
546
+ }
547
+
548
+ // 0.5b. Stale hook cleanup — remove hooks we no longer ship
549
+ {
550
+ const staleRemoved = cleanStaleHooks(hooksDst, hooksSrc);
551
+ if (staleRemoved > 0) ok(`[0.5b] Hook cleanup — removed ${staleRemoved} orphaned hook file(s)`);
552
+ }
553
+
483
554
  // 0.5. Legacy cleanup — remove old commands/rdc/ (pre-plugin-system format)
484
555
  const legacyCommandsDir = path.join(claudeHome, 'commands', 'rdc');
485
556
  if (fs.existsSync(legacyCommandsDir)) {