refacil-sdd-ai 4.0.10 → 4.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/README.md +4 -3
- package/bin/cli.js +41 -2
- package/lib/methodology-migration-pending.js +136 -0
- package/package.json +2 -2
- package/skills/update/SKILL.md +28 -10
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
|
|
|
@@ -233,8 +234,8 @@ Se instalan en `.claude/settings.json` **y** `.cursor/settings.json` durante `in
|
|
|
233
234
|
|
|
234
235
|
| Hook | Evento | Que hace |
|
|
235
236
|
|---|---|---|
|
|
236
|
-
| `check-update` | `SessionStart` |
|
|
237
|
-
| `notify-update` | `UserPromptSubmit` (Claude Code) / `beforeSubmitPrompt` (Cursor) |
|
|
237
|
+
| `check-update` | `SessionStart` | Al inicio borra `.refacil-pending-update` si ya no hay migracion (flags obsoletos). Luego: npm, sync skills, **compact-guidance**. Si hubo sync de skills y **si** hay migracion pendiente, escribe el flag para `notify-update`. |
|
|
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();
|
|
@@ -45,6 +46,15 @@ function writePendingUpdateFlag(root, fromVersion, toVersion) {
|
|
|
45
46
|
} catch (_) {}
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
/** Borra `.refacil-pending-update` si ya no hay migracion (flags viejos o sync de skills sin migracion). */
|
|
50
|
+
function clearStalePendingUpdateFlag(root) {
|
|
51
|
+
const flagPath = path.join(root, '.refacil-pending-update');
|
|
52
|
+
if (!fs.existsSync(flagPath)) return;
|
|
53
|
+
if (!methodologyMigrationPending(root).pending) {
|
|
54
|
+
try { fs.unlinkSync(flagPath); } catch (_) {}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
48
58
|
function readStdinPrompt() {
|
|
49
59
|
try {
|
|
50
60
|
const raw = fs.readFileSync(0, 'utf8');
|
|
@@ -62,6 +72,12 @@ function notifyUpdate() {
|
|
|
62
72
|
let info = {};
|
|
63
73
|
try { info = JSON.parse(fs.readFileSync(flagPath, 'utf8')); } catch (_) {}
|
|
64
74
|
|
|
75
|
+
const mig = methodologyMigrationPending(projectRoot);
|
|
76
|
+
if (!mig.pending) {
|
|
77
|
+
try { fs.unlinkSync(flagPath); } catch (_) {}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
65
81
|
const fromLabel = info.from ? `v${info.from}` : 'version anterior';
|
|
66
82
|
|
|
67
83
|
// Si el usuario ya está ejecutando /refacil:update, dejar pasar y borrar el flag
|
|
@@ -145,7 +161,24 @@ function syncRepoSkillsIfStale(globalVersion) {
|
|
|
145
161
|
}
|
|
146
162
|
}
|
|
147
163
|
|
|
164
|
+
function migrationPendingCmd() {
|
|
165
|
+
const wantJson = process.argv.includes('--json');
|
|
166
|
+
const { pending, reasons } = methodologyMigrationPending(projectRoot);
|
|
167
|
+
if (wantJson) {
|
|
168
|
+
process.stdout.write(`${JSON.stringify({ pending, reasons })}\n`);
|
|
169
|
+
} else if (pending) {
|
|
170
|
+
console.log(' Migraciones de metodologia pendientes:');
|
|
171
|
+
for (const r of reasons) console.log(` - ${r}`);
|
|
172
|
+
} else {
|
|
173
|
+
console.log(' Sin migraciones de metodologia pendientes (criterio alineado con hooks y /refacil:update).');
|
|
174
|
+
}
|
|
175
|
+
clearStalePendingUpdateFlag(projectRoot);
|
|
176
|
+
process.exit(pending ? 1 : 0);
|
|
177
|
+
}
|
|
178
|
+
|
|
148
179
|
function checkUpdate() {
|
|
180
|
+
clearStalePendingUpdateFlag(projectRoot);
|
|
181
|
+
|
|
149
182
|
const { execSync } = require('child_process');
|
|
150
183
|
let localVersion = getPackageVersion(packageRoot);
|
|
151
184
|
|
|
@@ -188,7 +221,9 @@ function checkUpdate() {
|
|
|
188
221
|
`[refacil-sdd-ai] Skills de este repo sincronizadas (${fromLabel} -> v${syncResult.to}). ` +
|
|
189
222
|
'Reinicia la sesion de Claude Code o Cursor para detectar los cambios.',
|
|
190
223
|
);
|
|
191
|
-
|
|
224
|
+
if (methodologyMigrationPending(projectRoot).pending) {
|
|
225
|
+
writePendingUpdateFlag(projectRoot, syncResult.from, syncResult.to);
|
|
226
|
+
}
|
|
192
227
|
} else if (syncResult && syncResult.failed) {
|
|
193
228
|
console.log(
|
|
194
229
|
`[refacil-sdd-ai] Skills de este repo estan desactualizadas respecto al paquete global (v${syncResult.to}) ` +
|
|
@@ -401,8 +436,9 @@ function help() {
|
|
|
401
436
|
Comandos:
|
|
402
437
|
init Instala skills en .claude/ y .cursor/, crea CLAUDE.md y .cursorrules
|
|
403
438
|
update Re-copia skills (para actualizar a nueva version del paquete)
|
|
439
|
+
migration-pending Misma validacion que hooks/notify-update: lista migraciones (exit 1 si hay; --json)
|
|
404
440
|
check-update Sincroniza skills y compact-guidance al inicio de sesion (hook SessionStart)
|
|
405
|
-
notify-update Notifica
|
|
441
|
+
notify-update Notifica migracion de metodologia solo si aplica (hook UserPromptSubmit)
|
|
406
442
|
check-review Verifica que el review se haya completado (usado por hook PreToolUse)
|
|
407
443
|
compact-bash Reescribe comandos Bash bare para reducir tokens (usado por hook PreToolUse)
|
|
408
444
|
compact Subcomandos del hook compact-bash:
|
|
@@ -452,6 +488,9 @@ switch (command) {
|
|
|
452
488
|
case 'update':
|
|
453
489
|
update();
|
|
454
490
|
break;
|
|
491
|
+
case 'migration-pending':
|
|
492
|
+
migrationPendingCmd();
|
|
493
|
+
break;
|
|
455
494
|
case 'check-update':
|
|
456
495
|
checkUpdate();
|
|
457
496
|
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.1.0",
|
|
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
|
|
|
@@ -96,19 +111,22 @@ Conjunto requerido de commands: `.claude/commands/opsx/` → `apply.md`, `archiv
|
|
|
96
111
|
|
|
97
112
|
## Paso 4: Limpiar flag de actualizacion pendiente
|
|
98
113
|
|
|
99
|
-
|
|
114
|
+
Tras migrar, elimina el flag en la raiz del repo si sigue existiendo:
|
|
100
115
|
|
|
101
116
|
```bash
|
|
102
117
|
rm -f .refacil-pending-update
|
|
103
118
|
```
|
|
104
119
|
|
|
120
|
+
Si no hubo cambios (Paso 1 dio exit 0), el flag obsoleto suele borrarse solo al proximo `check-update` (SessionStart) o al ejecutar `refacil-sdd-ai migration-pending` con exit 0; el `rm` manual solo hace falta si aplicaste migraciones a mano o quedo un vestigio.
|
|
121
|
+
|
|
105
122
|
## Paso 5: Resumen
|
|
106
123
|
|
|
107
124
|
Informar que archivos se crearon o modificaron. Mencionar que el bloque `compact-guidance` se sincronizara automaticamente en el proximo SessionStart.
|
|
108
125
|
|
|
109
126
|
## Reglas
|
|
110
127
|
|
|
128
|
+
- **Deteccion**: confiar en `refacil-sdd-ai migration-pending` (mismo criterio que `check-update` / `notify-update`).
|
|
111
129
|
- Solo aplica lo que este pendiente — no toca archivos que ya cumplen el patron.
|
|
112
130
|
- No inventa contenido: distribuye lo que ya existe en AGENTS.md sin agregar ni eliminar informacion.
|
|
113
131
|
- No ejecuta pasos de OpenSpec, hooks ni instalacion de skills.
|
|
114
|
-
- Extensible:
|
|
132
|
+
- 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.
|