refacil-sdd-ai 5.0.9 → 5.1.0

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/lib/hooks.js CHANGED
@@ -332,8 +332,8 @@ function removeProjectLevelHooks(projectRoot) {
332
332
  if (fs.existsSync(claudeSettingsPath)) {
333
333
  try {
334
334
  const settings = JSON.parse(fs.readFileSync(claudeSettingsPath, 'utf8'));
335
+ let changed = false;
335
336
  if (settings && settings.hooks) {
336
- let changed = false;
337
337
  for (const event of Object.keys(settings.hooks)) {
338
338
  if (!Array.isArray(settings.hooks[event])) continue;
339
339
  const before = settings.hooks[event].length;
@@ -344,7 +344,16 @@ function removeProjectLevelHooks(projectRoot) {
344
344
  if (settings.hooks[event].length === 0) delete settings.hooks[event];
345
345
  }
346
346
  if (Object.keys(settings.hooks).length === 0) delete settings.hooks;
347
- if (changed) fs.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2) + '\n');
347
+ } else if (settings && Object.keys(settings).length === 0) {
348
+ // Already empty stub — treat as changed so it gets deleted below
349
+ changed = true;
350
+ }
351
+ if (changed) {
352
+ if (Object.keys(settings).length === 0) {
353
+ fs.unlinkSync(claudeSettingsPath);
354
+ } else {
355
+ fs.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2) + '\n');
356
+ }
348
357
  }
349
358
  } catch (_) {}
350
359
  }
@@ -361,7 +370,12 @@ function removeProjectLevelHooks(projectRoot) {
361
370
  try {
362
371
  const config = JSON.parse(fs.readFileSync(cursorPath, 'utf8'));
363
372
  const hooksObj = config.hooks;
364
- if (!hooksObj) continue;
373
+ if (!hooksObj) {
374
+ // No hooks key — delete if only a meaningless stub (version-only or empty)
375
+ const meaningfulKeys = Object.keys(config).filter(k => k !== 'version');
376
+ if (meaningfulKeys.length === 0) fs.unlinkSync(cursorPath);
377
+ continue;
378
+ }
365
379
  let changed = false;
366
380
  for (const evt of evts) {
367
381
  if (!Array.isArray(hooksObj[evt])) continue;
@@ -381,6 +395,16 @@ function removeProjectLevelHooks(projectRoot) {
381
395
  }
382
396
  } catch (_) {}
383
397
  }
398
+
399
+ // Remove IDE root dirs if now empty (hooks cleanup may have been the last file)
400
+ for (const ideDir of ['.claude', '.cursor', '.opencode']) {
401
+ const idePath = path.join(projectRoot, ideDir);
402
+ try {
403
+ if (fs.existsSync(idePath) && fs.readdirSync(idePath).length === 0) {
404
+ fs.rmdirSync(idePath);
405
+ }
406
+ } catch (_) {}
407
+ }
384
408
  }
385
409
 
386
410
  // ── Fachada pública ──────────────────────────────────────────────────────────
package/lib/installer.js CHANGED
@@ -328,6 +328,44 @@ function removeProjectLevelArtifacts(projectRoot) {
328
328
  try { fs.unlinkSync(versionFile); removed++; } catch (_) {}
329
329
  }
330
330
  }
331
+
332
+ // Clean .opencode/opencode.json — strip SDD-managed $schema key; delete file if no user keys remain
333
+ const ocJsonPath = path.join(projectRoot, '.opencode', 'opencode.json');
334
+ if (fs.existsSync(ocJsonPath)) {
335
+ try {
336
+ const json = JSON.parse(fs.readFileSync(ocJsonPath, 'utf8'));
337
+ delete json['$schema'];
338
+ if (Object.keys(json).length === 0) {
339
+ fs.unlinkSync(ocJsonPath);
340
+ removed++;
341
+ } else {
342
+ fs.writeFileSync(ocJsonPath, JSON.stringify(json, null, 2) + '\n');
343
+ }
344
+ } catch (_) {}
345
+ }
346
+
347
+ // Remove .opencode/plugins/refacil-hooks.js if present
348
+ const ocPlugin = path.join(projectRoot, '.opencode', 'plugins', 'refacil-hooks.js');
349
+ if (fs.existsSync(ocPlugin)) {
350
+ try { fs.unlinkSync(ocPlugin); removed++; } catch (_) {}
351
+ }
352
+ // Remove .opencode/plugins/ if now empty
353
+ const ocPluginsDir = path.join(projectRoot, '.opencode', 'plugins');
354
+ try {
355
+ if (fs.existsSync(ocPluginsDir) && fs.readdirSync(ocPluginsDir).length === 0) {
356
+ fs.rmdirSync(ocPluginsDir);
357
+ }
358
+ } catch (_) {}
359
+ // Remove IDE root dirs if now empty
360
+ for (const ideDir of ['.opencode', '.cursor', '.claude']) {
361
+ const idePath = path.join(projectRoot, ideDir);
362
+ try {
363
+ if (fs.existsSync(idePath) && fs.readdirSync(idePath).length === 0) {
364
+ fs.rmdirSync(idePath);
365
+ }
366
+ } catch (_) {}
367
+ }
368
+
331
369
  return removed;
332
370
  }
333
371
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "refacil-sdd-ai",
3
- "version": "5.0.9",
3
+ "version": "5.1.0",
4
4
  "description": "SDD-AI: Specification-Driven Development with AI — development methodology using AI with Claude Code, Cursor and OpenCode",
5
5
  "bin": {
6
6
  "refacil-sdd-ai": "./bin/cli.js"