refacil-sdd-ai 4.0.10 → 4.0.11

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/README.md CHANGED
@@ -64,6 +64,7 @@ npm uninstall -g refacil-sdd-ai
64
64
  |---|---|
65
65
  | `refacil-sdd-ai init` | Instala skills y hooks en el repo actual |
66
66
  | `refacil-sdd-ai update` | Re-copia skills y hooks a la ultima version |
67
+ | `refacil-sdd-ai migration-pending [--json]` | Misma deteccion que hooks/`notify-update`; exit 1 si hay migracion de metodologia pendiente (uso en `/refacil:update`) |
67
68
  | `refacil-sdd-ai clean` | Elimina skills y hooks SDD-AI del repo |
68
69
  | `refacil-sdd-ai help` | Ver ayuda |
69
70
 
@@ -72,7 +73,7 @@ npm uninstall -g refacil-sdd-ai
72
73
  | Comando | Descripcion |
73
74
  |---|---|
74
75
  | `refacil-sdd-ai check-update` | (`SessionStart`) Verifica nueva version, sincroniza skills y `compact-guidance` en AGENTS.md |
75
- | `refacil-sdd-ai notify-update` | (`UserPromptSubmit` / `beforeSubmitPrompt`) Pregunta al usuario si desea ejecutar `/refacil:update` cuando hay migraciones pendientes |
76
+ | `refacil-sdd-ai notify-update` | (`UserPromptSubmit` / `beforeSubmitPrompt`) Solo actua si hay migracion de metodologia pendiente (misma logica que `/refacil:update`); si no, no interrumpe |
76
77
  | `refacil-sdd-ai check-review` | (`PreToolUse`) Bloquea `git push` si falta `.review-passed` en algun cambio activo |
77
78
  | `refacil-sdd-ai compact-bash` | (`PreToolUse`) Reescribe comandos Bash bare via `updatedInput` |
78
79
 
@@ -234,7 +235,7 @@ Se instalan en `.claude/settings.json` **y** `.cursor/settings.json` durante `in
234
235
  | Hook | Evento | Que hace |
235
236
  |---|---|---|
236
237
  | `check-update` | `SessionStart` | Chequea nueva version en npm, la instala, sincroniza skills y **sincroniza el bloque `compact-guidance`** en `AGENTS.md`. Si hubo actualizacion, escribe un flag de notificacion para el siguiente hook. |
237
- | `notify-update` | `UserPromptSubmit` (Claude Code) / `beforeSubmitPrompt` (Cursor) | Antes de procesar el siguiente mensaje del usuario, lee el flag de actualizacion pendiente. Si existe, inyecta la instruccion para que el agente pregunte al usuario si desea ejecutar `/refacil:update`. El flag se borra tras notificar. |
238
+ | `notify-update` | `UserPromptSubmit` (Claude Code) / `beforeSubmitPrompt` (Cursor) | Si existe flag y **hay migracion de metodologia pendiente** (misma tabla que `/refacil:update`), inyecta la instruccion o pausa el primer mensaje; si solo hubo sync de skills sin migracion, el flag no se crea o se descarta sin preguntar. |
238
239
  | `compact-bash` | `PreToolUse` (Bash) | Reescribe silenciosamente comandos Bash bare via `updatedInput`. Sin turnos extra, sin que el IDE vea el cambio. Requiere Claude Code >= 2.1.89. |
239
240
  | `check-review` | `PreToolUse` (Bash) | Intercepta `git push` y bloquea si falta `.review-passed` en algun cambio activo. |
240
241
 
package/bin/cli.js CHANGED
@@ -25,6 +25,7 @@ const { installHooks, uninstallHooks, cleanLegacySettingsHooks } = require('../l
25
25
  const { handleCompact } = require('../lib/commands/compact');
26
26
  const { handleBus } = require('../lib/commands/bus');
27
27
  const { syncIgnoreFiles } = require('../lib/ignore-files');
28
+ const { methodologyMigrationPending } = require('../lib/methodology-migration-pending');
28
29
 
29
30
  const packageRoot = path.resolve(__dirname, '..');
30
31
  const projectRoot = process.cwd();
@@ -62,6 +63,12 @@ function notifyUpdate() {
62
63
  let info = {};
63
64
  try { info = JSON.parse(fs.readFileSync(flagPath, 'utf8')); } catch (_) {}
64
65
 
66
+ const mig = methodologyMigrationPending(projectRoot);
67
+ if (!mig.pending) {
68
+ try { fs.unlinkSync(flagPath); } catch (_) {}
69
+ return;
70
+ }
71
+
65
72
  const fromLabel = info.from ? `v${info.from}` : 'version anterior';
66
73
 
67
74
  // Si el usuario ya está ejecutando /refacil:update, dejar pasar y borrar el flag
@@ -145,6 +152,20 @@ function syncRepoSkillsIfStale(globalVersion) {
145
152
  }
146
153
  }
147
154
 
155
+ function migrationPendingCmd() {
156
+ const wantJson = process.argv.includes('--json');
157
+ const { pending, reasons } = methodologyMigrationPending(projectRoot);
158
+ if (wantJson) {
159
+ process.stdout.write(`${JSON.stringify({ pending, reasons })}\n`);
160
+ } else if (pending) {
161
+ console.log(' Migraciones de metodologia pendientes:');
162
+ for (const r of reasons) console.log(` - ${r}`);
163
+ } else {
164
+ console.log(' Sin migraciones de metodologia pendientes (criterio alineado con hooks y /refacil:update).');
165
+ }
166
+ process.exit(pending ? 1 : 0);
167
+ }
168
+
148
169
  function checkUpdate() {
149
170
  const { execSync } = require('child_process');
150
171
  let localVersion = getPackageVersion(packageRoot);
@@ -188,7 +209,9 @@ function checkUpdate() {
188
209
  `[refacil-sdd-ai] Skills de este repo sincronizadas (${fromLabel} -> v${syncResult.to}). ` +
189
210
  'Reinicia la sesion de Claude Code o Cursor para detectar los cambios.',
190
211
  );
191
- writePendingUpdateFlag(projectRoot, syncResult.from, syncResult.to);
212
+ if (methodologyMigrationPending(projectRoot).pending) {
213
+ writePendingUpdateFlag(projectRoot, syncResult.from, syncResult.to);
214
+ }
192
215
  } else if (syncResult && syncResult.failed) {
193
216
  console.log(
194
217
  `[refacil-sdd-ai] Skills de este repo estan desactualizadas respecto al paquete global (v${syncResult.to}) ` +
@@ -401,8 +424,9 @@ function help() {
401
424
  Comandos:
402
425
  init Instala skills en .claude/ y .cursor/, crea CLAUDE.md y .cursorrules
403
426
  update Re-copia skills (para actualizar a nueva version del paquete)
427
+ migration-pending Misma validacion que hooks/notify-update: lista migraciones (exit 1 si hay; --json)
404
428
  check-update Sincroniza skills y compact-guidance al inicio de sesion (hook SessionStart)
405
- notify-update Notifica al LLM sobre migraciones pendientes (hook UserPromptSubmit)
429
+ notify-update Notifica migracion de metodologia solo si aplica (hook UserPromptSubmit)
406
430
  check-review Verifica que el review se haya completado (usado por hook PreToolUse)
407
431
  compact-bash Reescribe comandos Bash bare para reducir tokens (usado por hook PreToolUse)
408
432
  compact Subcomandos del hook compact-bash:
@@ -452,6 +476,9 @@ switch (command) {
452
476
  case 'update':
453
477
  update();
454
478
  break;
479
+ case 'migration-pending':
480
+ migrationPendingCmd();
481
+ break;
455
482
  case 'check-update':
456
483
  checkUpdate();
457
484
  break;
@@ -0,0 +1,136 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ /**
7
+ * Motor compartido con `refacil-sdd-ai migration-pending`, hooks `check-update` / `notify-update`
8
+ * y la skill `refacil:update`. Si ninguna condicion aplica, no hace falta migrar metodologia.
9
+ */
10
+ const REQUIRED_OPENSPEC_SKILLS = new Set([
11
+ 'openspec-propose',
12
+ 'openspec-explore',
13
+ 'openspec-apply-change',
14
+ 'openspec-archive-change',
15
+ 'openspec-verify-change',
16
+ ]);
17
+
18
+ const REQUIRED_OPSX_CLAUDE = new Set([
19
+ 'apply.md',
20
+ 'archive.md',
21
+ 'explore.md',
22
+ 'propose.md',
23
+ 'verify.md',
24
+ ]);
25
+
26
+ const REQUIRED_OPSX_CURSOR = new Set([
27
+ 'opsx-apply.md',
28
+ 'opsx-archive.md',
29
+ 'opsx-explore.md',
30
+ 'opsx-propose.md',
31
+ 'opsx-verify.md',
32
+ ]);
33
+
34
+ function legacyIndexDoc(filePath) {
35
+ if (!fs.existsSync(filePath)) return false;
36
+ const content = fs.readFileSync(filePath, 'utf8');
37
+ const lines = content.split(/\r?\n/).length;
38
+ const pointsToAgents = /AGENTS\.md/i.test(content);
39
+ return lines > 5 || !pointsToAgents;
40
+ }
41
+
42
+ function collectExtraOpenspecSkills(root) {
43
+ const out = [];
44
+ for (const rel of ['.claude/skills', '.cursor/skills']) {
45
+ const full = path.join(root, rel);
46
+ if (!fs.existsSync(full)) continue;
47
+ let names;
48
+ try {
49
+ names = fs.readdirSync(full, { withFileTypes: true });
50
+ } catch (_) {
51
+ continue;
52
+ }
53
+ for (const d of names) {
54
+ if (!d.isDirectory()) continue;
55
+ const name = d.name;
56
+ if (!name.startsWith('openspec-')) continue;
57
+ if (REQUIRED_OPENSPEC_SKILLS.has(name)) continue;
58
+ out.push(path.join(rel, name));
59
+ }
60
+ }
61
+ return out;
62
+ }
63
+
64
+ function collectExtraOpsxClaude(root) {
65
+ const dir = path.join(root, '.claude', 'commands', 'opsx');
66
+ if (!fs.existsSync(dir)) return [];
67
+ let names;
68
+ try {
69
+ names = fs.readdirSync(dir);
70
+ } catch (_) {
71
+ return [];
72
+ }
73
+ const extra = [];
74
+ for (const name of names) {
75
+ if (!name.endsWith('.md')) continue;
76
+ if (REQUIRED_OPSX_CLAUDE.has(name)) continue;
77
+ extra.push(path.join('.claude/commands/opsx', name));
78
+ }
79
+ return extra;
80
+ }
81
+
82
+ function collectExtraOpsxCursor(root) {
83
+ const dir = path.join(root, '.cursor', 'commands');
84
+ if (!fs.existsSync(dir)) return [];
85
+ let names;
86
+ try {
87
+ names = fs.readdirSync(dir);
88
+ } catch (_) {
89
+ return [];
90
+ }
91
+ const extra = [];
92
+ for (const name of names) {
93
+ if (!name.startsWith('opsx-') || !name.endsWith('.md')) continue;
94
+ if (REQUIRED_OPSX_CURSOR.has(name)) continue;
95
+ extra.push(path.join('.cursor/commands', name));
96
+ }
97
+ return extra;
98
+ }
99
+
100
+ /**
101
+ * @param {string} root - raíz del repo
102
+ * @returns {{ pending: boolean, reasons: string[] }}
103
+ */
104
+ function methodologyMigrationPending(root) {
105
+ const reasons = [];
106
+
107
+ const agentsMd = path.join(root, 'AGENTS.md');
108
+ const agentsDir = path.join(root, '.agents');
109
+ if (fs.existsSync(agentsMd) && !fs.existsSync(agentsDir)) {
110
+ reasons.push('AGENTS.md existe sin carpeta .agents/');
111
+ }
112
+
113
+ const claudeMd = path.join(root, 'CLAUDE.md');
114
+ if (legacyIndexDoc(claudeMd)) {
115
+ reasons.push('CLAUDE.md requiere normalización (índice mínimo → AGENTS.md)');
116
+ }
117
+
118
+ const cursorRules = path.join(root, '.cursorrules');
119
+ if (legacyIndexDoc(cursorRules)) {
120
+ reasons.push('.cursorrules requiere normalización (índice mínimo → AGENTS.md)');
121
+ }
122
+
123
+ const extraSkills = collectExtraOpenspecSkills(root);
124
+ if (extraSkills.length) {
125
+ reasons.push(`skills OpenSpec sobrantes: ${extraSkills.join(', ')}`);
126
+ }
127
+
128
+ const extraOpsx = [...collectExtraOpsxClaude(root), ...collectExtraOpsxCursor(root)];
129
+ if (extraOpsx.length) {
130
+ reasons.push(`commands opsx sobrantes: ${extraOpsx.join(', ')}`);
131
+ }
132
+
133
+ return { pending: reasons.length > 0, reasons };
134
+ }
135
+
136
+ module.exports = { methodologyMigrationPending };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "refacil-sdd-ai",
3
- "version": "4.0.10",
3
+ "version": "4.0.11",
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"
@@ -37,7 +37,7 @@
37
37
  "node": ">=20.19.0"
38
38
  },
39
39
  "scripts": {
40
- "test": "node --test test/hooks.test.js test/installer.test.js test/ignore-files.test.js"
40
+ "test": "node --test test/hooks.test.js test/installer.test.js test/ignore-files.test.js test/methodology-migration-pending.test.js"
41
41
  },
42
42
  "dependencies": {
43
43
  "ws": "^8.18.0"
@@ -8,26 +8,41 @@ user-invocable: true
8
8
 
9
9
  Detecta el estado actual del repo y aplica solo lo que este pendiente. No repite pasos de instalacion (OpenSpec, hooks, skills).
10
10
 
11
- ## Paso 1: Detectar migraciones pendientes
11
+ El hook `notify-update` usa el **mismo motor** que este comando; no re-evalues a mano el repo para decidir si hay trabajo.
12
12
 
13
- Evalua cada condicion y marca si aplica:
13
+ ## Paso 1: Validar con el CLI (obligatorio)
14
14
 
15
- | # | Condicion detectada | Migracion |
15
+ En la **raiz del repo** (donde esta `AGENTS.md` o `.claude/`), ejecuta con `Bash`:
16
+
17
+ ```bash
18
+ refacil-sdd-ai migration-pending
19
+ ```
20
+
21
+ - **Codigo de salida 0**: no hay migraciones de metodologia pendientes → informa al usuario que todo esta al dia respecto a este criterio y **termina** (sin tocar archivos).
22
+ - **Codigo de salida 1**: hay al menos una razon listada en stdout → continua al Paso 2.
23
+
24
+ Opcional para parseo estable: `refacil-sdd-ai migration-pending --json` → objeto `{ "pending": bool, "reasons": string[] }`.
25
+
26
+ No sustituyas este paso por inspeccion manual del arbol salvo que el comando falle (error de entorno); en ese caso documenta el error y pide reintentar.
27
+
28
+ ### Referencia (mapeo razon → accion en Paso 3)
29
+
30
+ La implementacion vive en `lib/methodology-migration-pending.js` del paquete; la tabla resume lo que detecta:
31
+
32
+ | # | Condicion (resumen) | Migracion en Paso 3 |
16
33
  |---|---|---|
17
34
  | 1 | `AGENTS.md` existe y no existe carpeta `.agents/` | Reestructurar en `.agents/` + reescribir como indice |
18
35
  | 2 | `CLAUDE.md` tiene mas de 5 lineas o no apunta a `AGENTS.md` | Reemplazar por indice minimo |
19
36
  | 3 | `.cursorrules` tiene mas de 5 lineas o no apunta a `AGENTS.md` | Reemplazar por indice minimo |
20
- | 4 | Existen skills `openspec-*` o commands `opsx-*` fuera del conjunto requerido en `.claude/` o `.cursor/` | Eliminar los sobrantes y reconfigurar OpenSpec |
21
-
22
- Si ninguna condicion aplica: informar al usuario que todo esta al dia y salir sin cambios.
37
+ | 4 | Skills `openspec-*` o commands `opsx-*` fuera del conjunto requerido | Eliminar sobrantes y reconfigurar OpenSpec |
23
38
 
24
39
  ## Paso 2: Confirmar con el usuario
25
40
 
26
- Mostrar la lista de migraciones detectadas y pedir confirmacion antes de aplicar cualquier cambio.
41
+ Mostrar al usuario las mismas lineas que imprimio `migration-pending` (o el array `reasons` del JSON) y pedir confirmacion antes de aplicar cualquier cambio.
27
42
 
28
43
  ## Paso 3: Aplicar migraciones confirmadas
29
44
 
30
- Ejecutar solo las migraciones marcadas en el Paso 1.
45
+ Ejecutar solo las migraciones que correspondan a las razones detectadas (ver tabla de referencia arriba).
31
46
 
32
47
  ### Migracion 1 — AGENTS.md → `.agents/` + indice
33
48
 
@@ -108,7 +123,8 @@ Informar que archivos se crearon o modificaron. Mencionar que el bloque `compact
108
123
 
109
124
  ## Reglas
110
125
 
126
+ - **Deteccion**: confiar en `refacil-sdd-ai migration-pending` (mismo criterio que `check-update` / `notify-update`).
111
127
  - Solo aplica lo que este pendiente — no toca archivos que ya cumplen el patron.
112
128
  - No inventa contenido: distribuye lo que ya existe en AGENTS.md sin agregar ni eliminar informacion.
113
129
  - No ejecuta pasos de OpenSpec, hooks ni instalacion de skills.
114
- - Extensible: futuras versiones de la metodologia agregaran filas a la tabla del Paso 1 sin cambiar la estructura de la skill.
130
+ - Extensible: nuevas reglas de deteccion se agregan en el paquete (`methodology-migration-pending.js`); esta skill actualiza la tabla de referencia y los pasos de aplicacion cuando cambie el contrato.