refacil-sdd-ai 4.0.6 → 4.0.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.
Files changed (3) hide show
  1. package/bin/cli.js +39 -16
  2. package/lib/hooks.js +31 -2
  3. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -21,7 +21,7 @@ const {
21
21
  checkNodeVersion,
22
22
  checkClaudeCodeVersion,
23
23
  } = require('../lib/installer');
24
- const { installHooks, uninstallHooks } = require('../lib/hooks');
24
+ const { installHooks, uninstallHooks, cleanLegacySettingsHooks } = require('../lib/hooks');
25
25
  const { handleCompact } = require('../lib/commands/compact');
26
26
  const { handleBus } = require('../lib/commands/bus');
27
27
  const { syncIgnoreFiles } = require('../lib/ignore-files');
@@ -31,6 +31,8 @@ const projectRoot = process.cwd();
31
31
 
32
32
  // --- check-update (SessionStart) + notify-update (UserPromptSubmit) ---
33
33
 
34
+ const isCursor = process.argv.includes('--cursor');
35
+
34
36
  function ideBaseDir(root) {
35
37
  const claudeDir = path.join(root, '.claude');
36
38
  const cursorDir = path.join(root, '.cursor');
@@ -38,17 +40,23 @@ function ideBaseDir(root) {
38
40
  }
39
41
 
40
42
  function writePendingUpdateFlag(root, fromVersion, toVersion) {
41
- const base = ideBaseDir(root);
42
- if (!base) return;
43
43
  try {
44
- fs.writeFileSync(path.join(base, '.refacil-pending-update'), JSON.stringify({ from: fromVersion, to: toVersion }));
44
+ fs.writeFileSync(path.join(root, '.refacil-pending-update'), JSON.stringify({ from: fromVersion, to: toVersion }));
45
45
  } catch (_) {}
46
46
  }
47
47
 
48
+ function readStdinPrompt() {
49
+ try {
50
+ const raw = fs.readFileSync(0, 'utf8');
51
+ const data = JSON.parse(raw);
52
+ return (data.prompt || data.message || '').trim().toLowerCase();
53
+ } catch (_) {
54
+ return '';
55
+ }
56
+ }
57
+
48
58
  function notifyUpdate() {
49
- const base = ideBaseDir(projectRoot);
50
- if (!base) return;
51
- const flagPath = path.join(base, '.refacil-pending-update');
59
+ const flagPath = path.join(projectRoot, '.refacil-pending-update');
52
60
  if (!fs.existsSync(flagPath)) return;
53
61
 
54
62
  let info = {};
@@ -56,24 +64,37 @@ function notifyUpdate() {
56
64
 
57
65
  const fromLabel = info.from ? `v${info.from}` : 'version anterior';
58
66
 
67
+ // Si el usuario ya está ejecutando /refacil:update, dejar pasar y borrar el flag
68
+ const prompt = readStdinPrompt();
69
+ if (prompt.includes('refacil:update') || prompt.includes('refacil/update')) {
70
+ try { fs.unlinkSync(flagPath); } catch (_) {}
71
+ return;
72
+ }
73
+
59
74
  if (!info.shown) {
60
- // Primera vez: bloquear al usuario para que lo vea claramente
75
+ // Primera vez: bloquear para que el usuario lo vea claramente
61
76
  try { fs.writeFileSync(flagPath, JSON.stringify({ ...info, shown: true })); } catch (_) {}
62
- const msg =
77
+ const userMsg =
63
78
  `[refacil-sdd-ai] Actualizacion de metodologia detectada (${fromLabel} → v${info.to}).\n` +
64
79
  `Tu mensaje fue pausado. ¿Deseas aplicar las migraciones pendientes antes de continuar?\n` +
65
80
  ` • Si: ejecuta /refacil:update\n` +
66
81
  ` • No: reenvía tu mensaje anterior para continuar sin actualizar.`;
67
- process.stdout.write(msg + '\n');
68
- process.stderr.write(msg + '\n');
82
+ if (isCursor) {
83
+ process.stdout.write(JSON.stringify({ continue: false, user_message: userMsg }) + '\n');
84
+ } else {
85
+ process.stdout.write(userMsg + '\n');
86
+ process.stderr.write(userMsg + '\n');
87
+ }
69
88
  process.exit(2);
70
89
  } else {
71
- // Segunda vez: dejar pasar pero avisar al LLM para que lo gestione
90
+ // Segunda vez: dejar pasar y avisar al LLM (solo Claude Code soporta inyectar contexto)
72
91
  try { fs.unlinkSync(flagPath); } catch (_) {}
73
- console.log(
74
- `[refacil-sdd-ai] IMPORTANTE: hay una actualizacion de la metodologia SDD-AI pendiente (${fromLabel} → v${info.to}). ` +
75
- `Antes de responder al usuario, preguntale si desea ejecutar /refacil:update ahora.`,
76
- );
92
+ if (!isCursor) {
93
+ console.log(
94
+ `[refacil-sdd-ai] IMPORTANTE: hay una actualizacion de la metodologia SDD-AI pendiente (${fromLabel} v${info.to}). ` +
95
+ `Antes de responder al usuario, preguntale si desea ejecutar /refacil:update ahora.`,
96
+ );
97
+ }
77
98
  }
78
99
  }
79
100
 
@@ -114,6 +135,8 @@ function checkUpdate() {
114
135
  process.stderr.write(`[refacil-sdd-ai] No se pudo sincronizar compact-guidance: ${err.message}\n`);
115
136
  }
116
137
 
138
+ cleanLegacySettingsHooks(projectRoot);
139
+
117
140
  const syncResult = syncRepoSkillsIfStale(localVersion);
118
141
  if (syncResult && !syncResult.failed) {
119
142
  const fromLabel = syncResult.from ? `v${syncResult.from}` : 'version desconocida';
package/lib/hooks.js CHANGED
@@ -53,7 +53,7 @@ function installCursorHooks(projectRoot) {
53
53
 
54
54
  ensure('beforeSubmitPrompt', '_sdd_notify', {
55
55
  _sdd_notify: true,
56
- command: 'refacil-sdd-ai notify-update',
56
+ command: 'refacil-sdd-ai notify-update --cursor',
57
57
  });
58
58
 
59
59
  if (!changed) {
@@ -189,6 +189,35 @@ function uninstallClaudeHooks(projectRoot) {
189
189
  return true;
190
190
  }
191
191
 
192
+ // ── Limpieza de hooks SDD en settings.json (migracion legacy) ───────────────
193
+
194
+ function cleanLegacySettingsHooks(projectRoot) {
195
+ const sddMarkers = ['_sdd', '_sdd_compact', '_sdd_review', '_sdd_notify'];
196
+ const evts = ['SessionStart', 'PreToolUse', 'UserPromptSubmit', 'beforeSubmitPrompt', 'Stop', 'afterAgentResponse'];
197
+
198
+ for (const ideDir of ['.cursor', '.claude']) {
199
+ const settingsPath = path.join(projectRoot, ideDir, 'settings.json');
200
+ if (!fs.existsSync(settingsPath)) continue;
201
+
202
+ let settings;
203
+ try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch (_) { continue; }
204
+ if (!settings || !settings.hooks) continue;
205
+
206
+ let changed = false;
207
+ for (const evt of evts) {
208
+ if (!Array.isArray(settings.hooks[evt])) continue;
209
+ const before = settings.hooks[evt].length;
210
+ settings.hooks[evt] = settings.hooks[evt].filter((h) => !sddMarkers.some((m) => h[m] === true));
211
+ if (settings.hooks[evt].length !== before) changed = true;
212
+ if (settings.hooks[evt].length === 0) delete settings.hooks[evt];
213
+ }
214
+ if (Object.keys(settings.hooks).length === 0) delete settings.hooks;
215
+ if (changed) {
216
+ try { fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n'); } catch (_) {}
217
+ }
218
+ }
219
+ }
220
+
192
221
  // ── Fachada pública ──────────────────────────────────────────────────────────
193
222
 
194
223
  function installHooks(ideDir, projectRoot) {
@@ -203,4 +232,4 @@ function uninstallHooks(ideDir, projectRoot) {
203
232
  : uninstallClaudeHooks(projectRoot);
204
233
  }
205
234
 
206
- module.exports = { installHooks, uninstallHooks };
235
+ module.exports = { installHooks, uninstallHooks, cleanLegacySettingsHooks };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "refacil-sdd-ai",
3
- "version": "4.0.6",
3
+ "version": "4.0.7",
4
4
  "description": "SDD-AI: Specification-Driven Development with AI — metodologia de desarrollo con IA usando OpenSpec, Claude Code y Cursor",
5
5
  "bin": {
6
6
  "refacil-sdd-ai": "./bin/cli.js"