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 +3 -2
- package/bin/cli.js +29 -2
- package/lib/methodology-migration-pending.js +136 -0
- package/package.json +2 -2
- package/skills/update/SKILL.md +25 -9
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`)
|
|
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) |
|
|
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
|
-
|
|
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
|
|
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.
|
|
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"
|
package/skills/update/SKILL.md
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
13
|
+
## Paso 1: Validar con el CLI (obligatorio)
|
|
14
14
|
|
|
15
|
-
|
|
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 |
|
|
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
|
|
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
|
|
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:
|
|
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.
|