refacil-sdd-ai 4.3.0 → 4.4.1
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/agents/auditor.md +8 -1
- package/agents/proposer.md +1 -1
- package/bin/cli.js +4 -4
- package/lib/commands/sdd.js +246 -15
- package/lib/installer.js +5 -3
- package/package.json +2 -2
- package/skills/apply/SKILL.md +16 -0
- package/skills/archive/SKILL.md +13 -17
- package/skills/explore/SKILL.md +12 -0
- package/skills/prereqs/METHODOLOGY-CONTRACT.md +10 -7
- package/skills/propose/SKILL.md +19 -7
- package/skills/review/SKILL.md +54 -5
- package/skills/test/SKILL.md +17 -0
- package/skills/verify/SKILL.md +30 -2
package/agents/auditor.md
CHANGED
|
@@ -157,10 +157,17 @@ Next step: [/refacil:archive | /refacil:verify]
|
|
|
157
157
|
"summary": "<1-line summary>",
|
|
158
158
|
"failCount": <integer count of FAILs in NEW code>,
|
|
159
159
|
"preexistingCount": <integer count of pre-existing FAILs found>,
|
|
160
|
-
"blockers": <true|false — new code only
|
|
160
|
+
"blockers": <true|false — new code only>,
|
|
161
|
+
"failedFiles": ["path/to/file-1.ts", "path/to/file-2.ts"]
|
|
161
162
|
}
|
|
162
163
|
```
|
|
163
164
|
|
|
165
|
+
**`failedFiles` rules**:
|
|
166
|
+
- On `REQUIERE CORRECCIONES`: list the relative paths (from repo root) of every file in the **blocking scope** (`changedFiles`) that had at least one CRITICAL or HIGH FAIL.
|
|
167
|
+
- On `APROBADO` or `APROBADO CON OBSERVACIONES`: emit `"failedFiles": []`.
|
|
168
|
+
- Files with only MEDIUM/LOW findings do NOT appear in `failedFiles`.
|
|
169
|
+
- Pre-existing context files do NOT appear in `failedFiles` — only blocking scope.
|
|
170
|
+
|
|
164
171
|
**IMPORTANT about the JSON block**:
|
|
165
172
|
- Use the literal fence ` ```refacil-review-result ` (not ` ```json `).
|
|
166
173
|
- Emit it ALWAYS, even if the verdict is `REQUIERE CORRECCIONES`.
|
package/agents/proposer.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: refacil-proposer
|
|
3
3
|
description: Generates SDD-AI planning artifacts (proposal, specs, design, tasks) for any codebase. Delegated by /refacil:propose — do not invoke directly.
|
|
4
4
|
tools: Read, Grep, Glob, Bash, Edit, Write
|
|
5
|
-
model:
|
|
5
|
+
model: sonnet
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# refacil-proposer — Planning Artifact Generator
|
package/bin/cli.js
CHANGED
|
@@ -25,12 +25,12 @@ const {
|
|
|
25
25
|
const { installHooks, uninstallHooks, cleanLegacySettingsHooks } = require('../lib/hooks');
|
|
26
26
|
const { handleCompact } = require('../lib/commands/compact');
|
|
27
27
|
const { handleBus } = require('../lib/commands/bus');
|
|
28
|
-
const { handleSdd, autoMigrateOpenspec } = require('../lib/commands/sdd');
|
|
28
|
+
const { handleSdd, autoMigrateOpenspec, findProjectRoot } = require('../lib/commands/sdd');
|
|
29
29
|
const { syncIgnoreFiles } = require('../lib/ignore-files');
|
|
30
30
|
const { methodologyMigrationPending } = require('../lib/methodology-migration-pending');
|
|
31
31
|
|
|
32
32
|
const packageRoot = path.resolve(__dirname, '..');
|
|
33
|
-
const projectRoot =
|
|
33
|
+
const projectRoot = findProjectRoot();
|
|
34
34
|
|
|
35
35
|
// --- check-update (SessionStart) + notify-update (UserPromptSubmit) ---
|
|
36
36
|
|
|
@@ -506,7 +506,7 @@ function help() {
|
|
|
506
506
|
4. Run: /refacil:setup (generates AGENTS.md for your project)
|
|
507
507
|
|
|
508
508
|
Requirements:
|
|
509
|
-
- Node.js >= 20.
|
|
509
|
+
- Node.js >= 20.0.0
|
|
510
510
|
- Claude Code >= 2.1.89 (required by compact-bash for silent rewrite) or Cursor
|
|
511
511
|
`);
|
|
512
512
|
}
|
|
@@ -549,7 +549,7 @@ switch (command) {
|
|
|
549
549
|
handleBus(process.argv[3], process.argv.slice(4), packageRoot);
|
|
550
550
|
break;
|
|
551
551
|
case 'sdd':
|
|
552
|
-
handleSdd(process.argv[3], process.argv.slice(4));
|
|
552
|
+
handleSdd(process.argv[3], process.argv.slice(4), projectRoot);
|
|
553
553
|
break;
|
|
554
554
|
case 'clean':
|
|
555
555
|
clean();
|
package/lib/commands/sdd.js
CHANGED
|
@@ -3,7 +3,19 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
function findProjectRoot() {
|
|
7
|
+
let dir = process.cwd();
|
|
8
|
+
const { root } = path.parse(dir);
|
|
9
|
+
while (dir !== root) {
|
|
10
|
+
if (fs.existsSync(path.join(dir, 'refacil-sdd')) || fs.existsSync(path.join(dir, '.git'))) {
|
|
11
|
+
return dir;
|
|
12
|
+
}
|
|
13
|
+
const parent = path.dirname(dir);
|
|
14
|
+
if (parent === dir) break;
|
|
15
|
+
dir = parent;
|
|
16
|
+
}
|
|
17
|
+
return process.cwd();
|
|
18
|
+
}
|
|
7
19
|
|
|
8
20
|
// --- Helpers ---
|
|
9
21
|
|
|
@@ -65,6 +77,65 @@ function autoMigrateOpenspec(root) {
|
|
|
65
77
|
// Si ambos existen o ninguno existe → no hacer nada
|
|
66
78
|
}
|
|
67
79
|
|
|
80
|
+
// --- Minimal YAML parser/serializer for memory.yaml ---
|
|
81
|
+
// Supports: string values and string-array values only.
|
|
82
|
+
|
|
83
|
+
function parseMemoryYaml(content) {
|
|
84
|
+
const result = {};
|
|
85
|
+
const lines = content.split('\n');
|
|
86
|
+
let currentKey = null;
|
|
87
|
+
let currentList = null;
|
|
88
|
+
|
|
89
|
+
for (const line of lines) {
|
|
90
|
+
if (!line.trim() || line.trim().startsWith('#')) continue;
|
|
91
|
+
|
|
92
|
+
// List item: " - value"
|
|
93
|
+
if (/^\s{2,}- /.test(line)) {
|
|
94
|
+
const value = line.replace(/^\s*- /, '').trim();
|
|
95
|
+
if (currentKey && currentList !== null) {
|
|
96
|
+
currentList.push(value);
|
|
97
|
+
}
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Key-value: "key: value" or "key:" (empty/start of list)
|
|
102
|
+
const kvMatch = line.match(/^([a-zA-Z][a-zA-Z0-9_-]*):\s*(.*)/);
|
|
103
|
+
if (kvMatch) {
|
|
104
|
+
currentKey = kvMatch[1];
|
|
105
|
+
const val = kvMatch[2].trim();
|
|
106
|
+
if (val === '') {
|
|
107
|
+
// Could be a list
|
|
108
|
+
currentList = [];
|
|
109
|
+
result[currentKey] = currentList;
|
|
110
|
+
} else {
|
|
111
|
+
currentList = null;
|
|
112
|
+
result[currentKey] = val;
|
|
113
|
+
}
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
currentKey = null;
|
|
118
|
+
currentList = null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function serializeMemoryYaml(obj) {
|
|
125
|
+
const lines = [];
|
|
126
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
127
|
+
if (Array.isArray(value)) {
|
|
128
|
+
lines.push(`${key}:`);
|
|
129
|
+
for (const item of value) {
|
|
130
|
+
lines.push(` - ${item}`);
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
lines.push(`${key}: ${value}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return lines.join('\n') + '\n';
|
|
137
|
+
}
|
|
138
|
+
|
|
68
139
|
// --- Subcomandos ---
|
|
69
140
|
|
|
70
141
|
function cmdValidateName(argv) {
|
|
@@ -79,7 +150,7 @@ function cmdValidateName(argv) {
|
|
|
79
150
|
}
|
|
80
151
|
}
|
|
81
152
|
|
|
82
|
-
function cmdNewChange(argv) {
|
|
153
|
+
function cmdNewChange(argv, projectRoot) {
|
|
83
154
|
const args = parseArgs(argv);
|
|
84
155
|
const name = args._positional[0];
|
|
85
156
|
|
|
@@ -107,7 +178,7 @@ function cmdNewChange(argv) {
|
|
|
107
178
|
console.log(`Cambio '${name}' creado en refacil-sdd/changes/${name}/`);
|
|
108
179
|
}
|
|
109
180
|
|
|
110
|
-
function cmdArchive(argv) {
|
|
181
|
+
function cmdArchive(argv, projectRoot) {
|
|
111
182
|
const args = parseArgs(argv);
|
|
112
183
|
const name = args._positional[0];
|
|
113
184
|
|
|
@@ -134,6 +205,10 @@ function cmdArchive(argv) {
|
|
|
134
205
|
process.exit(1);
|
|
135
206
|
}
|
|
136
207
|
|
|
208
|
+
// Delete memory.yaml before archiving (CA-18)
|
|
209
|
+
const memoryFile = path.join(sourceDir, 'memory.yaml');
|
|
210
|
+
if (fs.existsSync(memoryFile)) fs.unlinkSync(memoryFile);
|
|
211
|
+
|
|
137
212
|
fs.mkdirSync(archiveDir, { recursive: true });
|
|
138
213
|
fs.renameSync(sourceDir, destDir);
|
|
139
214
|
|
|
@@ -145,7 +220,138 @@ function cmdArchive(argv) {
|
|
|
145
220
|
console.log(`Cambio '${name}' archivado en refacil-sdd/changes/archive/${date}-${name}/`);
|
|
146
221
|
}
|
|
147
222
|
|
|
148
|
-
function
|
|
223
|
+
function cmdSetMemory(argv, projectRoot) {
|
|
224
|
+
const args = parseArgs(argv);
|
|
225
|
+
const name = args._positional[0];
|
|
226
|
+
|
|
227
|
+
if (!name) {
|
|
228
|
+
console.error('Uso: refacil-sdd-ai sdd set-memory <nombre-cambio> [--last-step <value>] [--stack-detected <value>] [--touched-files <csv>] [--commands-run <value>] [--criteria-run <csv>]');
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const root = projectRoot;
|
|
233
|
+
|
|
234
|
+
// Guard: ensure the change directory exists before any file operation
|
|
235
|
+
const changeDir = path.join(root, 'refacil-sdd', 'changes', name);
|
|
236
|
+
if (!fs.existsSync(changeDir)) {
|
|
237
|
+
console.error(`No existe el cambio '${name}' en refacil-sdd/changes/${name}/`);
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Require at least one field flag
|
|
242
|
+
const knownFlags = ['last-step', 'stack-detected', 'touched-files', 'commands-run', 'criteria-run'];
|
|
243
|
+
if (!knownFlags.some((f) => args[f] !== undefined)) {
|
|
244
|
+
console.error('set-memory: debe especificar al menos un campo (--last-step, --stack-detected, --touched-files, --commands-run, --criteria-run)');
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const memoryPath = path.join(changeDir, 'memory.yaml');
|
|
249
|
+
|
|
250
|
+
// Read existing memory to merge
|
|
251
|
+
let existing = {};
|
|
252
|
+
if (fs.existsSync(memoryPath)) {
|
|
253
|
+
try {
|
|
254
|
+
existing = parseMemoryYaml(fs.readFileSync(memoryPath, 'utf8'));
|
|
255
|
+
} catch (_) {
|
|
256
|
+
existing = {};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Apply flags
|
|
261
|
+
if (args['last-step']) existing['lastStep'] = args['last-step'];
|
|
262
|
+
if (args['stack-detected']) existing['stackDetected'] = args['stack-detected'];
|
|
263
|
+
if (args['touched-files']) {
|
|
264
|
+
existing['touchedFiles'] = args['touched-files'].split(',').map((s) => s.trim()).filter(Boolean);
|
|
265
|
+
}
|
|
266
|
+
if (args['commands-run']) existing['commandsRun'] = args['commands-run'];
|
|
267
|
+
if (args['criteria-run']) {
|
|
268
|
+
existing['criteriaRun'] = args['criteria-run'].split(',').map((s) => s.trim()).filter(Boolean);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
fs.writeFileSync(memoryPath, serializeMemoryYaml(existing), 'utf8');
|
|
272
|
+
console.log(`memory.yaml actualizado para '${name}'`);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function cmdGetMemory(argv, projectRoot) {
|
|
276
|
+
const args = parseArgs(argv);
|
|
277
|
+
const name = args._positional[0];
|
|
278
|
+
const wantJson = args.json === true;
|
|
279
|
+
|
|
280
|
+
if (!name) {
|
|
281
|
+
console.error('Uso: refacil-sdd-ai sdd get-memory <nombre-cambio> [--json]');
|
|
282
|
+
process.exit(1);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const root = projectRoot;
|
|
286
|
+
const memoryPath = path.join(root, 'refacil-sdd', 'changes', name, 'memory.yaml');
|
|
287
|
+
|
|
288
|
+
if (!fs.existsSync(memoryPath)) {
|
|
289
|
+
if (wantJson) {
|
|
290
|
+
process.stdout.write('{}\n');
|
|
291
|
+
}
|
|
292
|
+
process.exit(0);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const content = fs.readFileSync(memoryPath, 'utf8');
|
|
296
|
+
|
|
297
|
+
if (wantJson) {
|
|
298
|
+
let parsed = {};
|
|
299
|
+
try {
|
|
300
|
+
parsed = parseMemoryYaml(content);
|
|
301
|
+
} catch (_) {
|
|
302
|
+
parsed = {};
|
|
303
|
+
}
|
|
304
|
+
process.stdout.write(JSON.stringify(parsed) + '\n');
|
|
305
|
+
} else {
|
|
306
|
+
process.stdout.write(content);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function cmdSetReviewFails(argv, projectRoot) {
|
|
311
|
+
const args = parseArgs(argv);
|
|
312
|
+
const name = args._positional[0];
|
|
313
|
+
|
|
314
|
+
if (!name) {
|
|
315
|
+
console.error('Uso: refacil-sdd-ai sdd set-review-fails <nombre-cambio> --files <csv>');
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const root = projectRoot;
|
|
320
|
+
const changeDir = path.join(root, 'refacil-sdd', 'changes', name);
|
|
321
|
+
if (!fs.existsSync(changeDir)) {
|
|
322
|
+
console.error(`No existe el cambio '${name}' en refacil-sdd/changes/${name}/`);
|
|
323
|
+
process.exit(1);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const files = args.files
|
|
327
|
+
? args.files.split(',').map((s) => s.trim()).filter(Boolean)
|
|
328
|
+
: [];
|
|
329
|
+
|
|
330
|
+
const reviewFailsPath = path.join(changeDir, '.review-last-fails.json');
|
|
331
|
+
fs.writeFileSync(reviewFailsPath, JSON.stringify({ failedFiles: files }, null, 2), 'utf8');
|
|
332
|
+
console.log(`.review-last-fails.json actualizado para '${name}'`);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function cmdClearReviewFails(argv, projectRoot) {
|
|
336
|
+
const args = parseArgs(argv);
|
|
337
|
+
const name = args._positional[0];
|
|
338
|
+
|
|
339
|
+
if (!name) {
|
|
340
|
+
console.error('Uso: refacil-sdd-ai sdd clear-review-fails <nombre-cambio>');
|
|
341
|
+
process.exit(1);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const root = projectRoot;
|
|
345
|
+
const reviewFailsPath = path.join(root, 'refacil-sdd', 'changes', name, '.review-last-fails.json');
|
|
346
|
+
|
|
347
|
+
if (fs.existsSync(reviewFailsPath)) {
|
|
348
|
+
fs.unlinkSync(reviewFailsPath);
|
|
349
|
+
console.log(`.review-last-fails.json eliminado para '${name}'`);
|
|
350
|
+
}
|
|
351
|
+
// Silent exit 0 if not exists
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function cmdList(argv, projectRoot) {
|
|
149
355
|
const args = parseArgs(argv);
|
|
150
356
|
const wantJson = args.json === true;
|
|
151
357
|
|
|
@@ -184,7 +390,7 @@ function cmdList(argv) {
|
|
|
184
390
|
}
|
|
185
391
|
}
|
|
186
392
|
|
|
187
|
-
function cmdStatus(argv) {
|
|
393
|
+
function cmdStatus(argv, projectRoot) {
|
|
188
394
|
const args = parseArgs(argv);
|
|
189
395
|
const name = args._positional[0];
|
|
190
396
|
const wantJson = args.json === true;
|
|
@@ -273,7 +479,7 @@ function cmdStatus(argv) {
|
|
|
273
479
|
}
|
|
274
480
|
}
|
|
275
481
|
|
|
276
|
-
function cmdMarkReviewed(argv) {
|
|
482
|
+
function cmdMarkReviewed(argv, projectRoot) {
|
|
277
483
|
const args = parseArgs(argv);
|
|
278
484
|
const name = args._positional[0];
|
|
279
485
|
|
|
@@ -314,7 +520,7 @@ function cmdMarkReviewed(argv) {
|
|
|
314
520
|
console.log(`Review marcado como aprobado para '${name}' (verdict: ${payload.verdict})`);
|
|
315
521
|
}
|
|
316
522
|
|
|
317
|
-
function cmdTasksUpdate(argv) {
|
|
523
|
+
function cmdTasksUpdate(argv, projectRoot) {
|
|
318
524
|
const args = parseArgs(argv);
|
|
319
525
|
const name = args._positional[0];
|
|
320
526
|
|
|
@@ -390,44 +596,69 @@ function sddHelp() {
|
|
|
390
596
|
--task N Número de task (1-indexed)
|
|
391
597
|
--done Confirma que la task está hecha
|
|
392
598
|
sdd validate-name <nombre> Valida el formato del nombre de un cambio
|
|
599
|
+
sdd set-memory <nombre> Escribe o fusiona campos en memory.yaml del cambio
|
|
600
|
+
[--last-step <value>] Último paso ejecutado (apply, test, etc.)
|
|
601
|
+
[--stack-detected <value>] Stack tecnológico detectado
|
|
602
|
+
[--touched-files <csv>] Archivos modificados (separados por coma)
|
|
603
|
+
[--commands-run <value>] Comando de test ejecutado
|
|
604
|
+
[--criteria-run <csv>] Criterios CA/CR ejecutados (separados por coma)
|
|
605
|
+
sdd get-memory <nombre> Lee memory.yaml del cambio
|
|
606
|
+
[--json] Salida en JSON (por defecto: YAML raw)
|
|
607
|
+
sdd set-review-fails <nombre> Escribe .review-last-fails.json con archivos fallidos
|
|
608
|
+
--files <csv> Archivos con fallos (separados por coma)
|
|
609
|
+
sdd clear-review-fails <nombre> Elimina .review-last-fails.json del cambio
|
|
393
610
|
|
|
394
611
|
Notas:
|
|
395
612
|
- Los nombres de cambio deben empezar con minúscula y usar solo [a-z0-9-]
|
|
396
613
|
- Si existe openspec/ y no existe refacil-sdd/, se migra automáticamente
|
|
614
|
+
- sdd archive elimina memory.yaml automáticamente antes de mover el cambio
|
|
397
615
|
`);
|
|
398
616
|
}
|
|
399
617
|
|
|
400
618
|
// --- Dispatcher ---
|
|
401
619
|
|
|
402
|
-
function handleSdd(sub, argv) {
|
|
620
|
+
function handleSdd(sub, argv, projectRoot) {
|
|
403
621
|
const args = argv || [];
|
|
622
|
+
const root = projectRoot || findProjectRoot();
|
|
404
623
|
|
|
405
624
|
switch (sub) {
|
|
406
625
|
case 'new-change':
|
|
407
|
-
cmdNewChange(args);
|
|
626
|
+
cmdNewChange(args, root);
|
|
408
627
|
break;
|
|
409
628
|
case 'archive':
|
|
410
|
-
cmdArchive(args);
|
|
629
|
+
cmdArchive(args, root);
|
|
411
630
|
break;
|
|
412
631
|
case 'list':
|
|
413
|
-
cmdList(args);
|
|
632
|
+
cmdList(args, root);
|
|
414
633
|
break;
|
|
415
634
|
case 'status':
|
|
416
|
-
cmdStatus(args);
|
|
635
|
+
cmdStatus(args, root);
|
|
417
636
|
break;
|
|
418
637
|
case 'mark-reviewed':
|
|
419
|
-
cmdMarkReviewed(args);
|
|
638
|
+
cmdMarkReviewed(args, root);
|
|
420
639
|
break;
|
|
421
640
|
case 'tasks-update':
|
|
422
|
-
cmdTasksUpdate(args);
|
|
641
|
+
cmdTasksUpdate(args, root);
|
|
423
642
|
break;
|
|
424
643
|
case 'validate-name':
|
|
425
644
|
cmdValidateName(args);
|
|
426
645
|
break;
|
|
646
|
+
case 'set-memory':
|
|
647
|
+
cmdSetMemory(args, root);
|
|
648
|
+
break;
|
|
649
|
+
case 'get-memory':
|
|
650
|
+
cmdGetMemory(args, root);
|
|
651
|
+
break;
|
|
652
|
+
case 'set-review-fails':
|
|
653
|
+
cmdSetReviewFails(args, root);
|
|
654
|
+
break;
|
|
655
|
+
case 'clear-review-fails':
|
|
656
|
+
cmdClearReviewFails(args, root);
|
|
657
|
+
break;
|
|
427
658
|
default:
|
|
428
659
|
sddHelp();
|
|
429
660
|
process.exit(1);
|
|
430
661
|
}
|
|
431
662
|
}
|
|
432
663
|
|
|
433
|
-
module.exports = { handleSdd, parseArgs, autoMigrateOpenspec, validateChangeName };
|
|
664
|
+
module.exports = { handleSdd, parseArgs, autoMigrateOpenspec, validateChangeName, findProjectRoot };
|
package/lib/installer.js
CHANGED
|
@@ -71,10 +71,12 @@ function installSkills(packageRoot, projectRoot) {
|
|
|
71
71
|
// Claude Code: tools allowlist granular, model: sonnet|opus|haiku
|
|
72
72
|
// Cursor: readonly: true|false (booleano), model: inherit (default)
|
|
73
73
|
function transformFrontmatterForCursor(content) {
|
|
74
|
-
const
|
|
74
|
+
const normalized = content.replace(/\r\n/g, '\n');
|
|
75
|
+
const match = normalized.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
75
76
|
if (!match) return content;
|
|
76
77
|
|
|
77
78
|
const [, frontmatterRaw, body] = match;
|
|
79
|
+
// work with normalized content from here on
|
|
78
80
|
const lines = frontmatterRaw.split('\n');
|
|
79
81
|
const out = [];
|
|
80
82
|
let toolsLine = null;
|
|
@@ -295,9 +297,9 @@ function checkNodeVersion() {
|
|
|
295
297
|
const major = parseInt(version.split('.')[0].replace('v', ''));
|
|
296
298
|
const minor = parseInt(version.split('.')[1]);
|
|
297
299
|
|
|
298
|
-
if (major < 20
|
|
300
|
+
if (major < 20) {
|
|
299
301
|
console.log(`\n ADVERTENCIA: Node.js ${version} detectado.`);
|
|
300
|
-
console.log(' refacil-sdd-ai requiere Node.js >= 20.
|
|
302
|
+
console.log(' refacil-sdd-ai requiere Node.js >= 20.0.0.');
|
|
301
303
|
console.log(' Las skills se instalaran pero /refacil:setup podria fallar al instalar OpenSpec.\n');
|
|
302
304
|
return false;
|
|
303
305
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "refacil-sdd-ai",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.1",
|
|
4
4
|
"description": "SDD-AI: Specification-Driven Development with AI — development methodology using AI with Claude Code and Cursor",
|
|
5
5
|
"bin": {
|
|
6
6
|
"refacil-sdd-ai": "./bin/cli.js"
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"node": ">=20.0.0"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
|
-
"test": "node --test test/hooks.test.js test/installer.test.js test/ignore-files.test.js test/methodology-migration-pending.test.js test/sdd.test.js test/refactor-integrar-openspec-nativo.test.js test/refactor-rutas-refacil-sdd.test.js test/refactor-agents-english.test.js test/remove-openspec-legacy.test.js"
|
|
38
|
+
"test": "node --test test/hooks.test.js test/installer.test.js test/ignore-files.test.js test/methodology-migration-pending.test.js test/sdd.test.js test/refactor-integrar-openspec-nativo.test.js test/refactor-rutas-refacil-sdd.test.js test/refactor-agents-english.test.js test/remove-openspec-legacy.test.js test/find-project-root.test.js"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"ws": "^8.18.0"
|
package/skills/apply/SKILL.md
CHANGED
|
@@ -99,6 +99,22 @@ The sub-agent will use the briefing as the primary guide and will only read the
|
|
|
99
99
|
|
|
100
100
|
Returns ONE single message with the report + JSON block fenced as ` ```refacil-apply-result `.
|
|
101
101
|
|
|
102
|
+
### Step 2.5: Save cross-skill memory (memory.yaml)
|
|
103
|
+
|
|
104
|
+
After parsing the `refacil-apply-result` block and only if `result` is not `"FAILED"`:
|
|
105
|
+
- Extract `touchedFiles` from the result (list of files actually created/modified by the implementer).
|
|
106
|
+
|
|
107
|
+
Run:
|
|
108
|
+
```bash
|
|
109
|
+
refacil-sdd-ai sdd set-memory <changeName> \
|
|
110
|
+
--last-step apply \
|
|
111
|
+
--touched-files "<comma-separated list of modified files>"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
This command merges into memory.yaml at the repo root using `findProjectRoot()` — no manual path construction needed.
|
|
115
|
+
|
|
116
|
+
If `result` is `"FAILED"`, skip and wait for user instructions.
|
|
117
|
+
|
|
102
118
|
### Step 3: Present result and next step
|
|
103
119
|
|
|
104
120
|
Show the user the **report** (everything before the `refacil-apply-result` block). Do not show the JSON block — it is internal metadata.
|
package/skills/archive/SKILL.md
CHANGED
|
@@ -61,23 +61,19 @@ Inspect the change folder in `refacil-sdd/changes/`:
|
|
|
61
61
|
|
|
62
62
|
Depending on the type, follow the corresponding step:
|
|
63
63
|
|
|
64
|
-
### Step 2A: Bug fix →
|
|
64
|
+
### Step 2A: Bug fix → Archive with native CLI
|
|
65
65
|
|
|
66
|
-
Bug fixes only contain `summary.md` (and optionally `.review-passed`)
|
|
66
|
+
Bug fixes only contain `summary.md` (and optionally `.review-passed`). The CLI `refacil-sdd-ai sdd archive` handles the folder move internally with its own `findProjectRoot()`, so there is no need for manual `mv` — use the CLI for the move, and only write specs/review.yaml manually (the CLI does not cover those).
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
0. **Read artifacts before archiving**: read `summary.md` and `.review-passed` from `refacil-sdd/changes/[fix-name]/` **now**, before the CLI moves the folder. The archived path will be different.
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
4. **Mandatory post-move verification**: run a listing/existence test to confirm:
|
|
76
|
-
- `refacil-sdd/changes/[fix-name]/` **no longer exists**.
|
|
77
|
-
- `refacil-sdd/changes/archive/[ISO-date]-[fix-name]/` **does exist** and contains `summary.md` (+ `.review-passed` if it existed).
|
|
78
|
-
5. If the verification fails (source folder survived), explicitly delete it with `rm -rf "refacil-sdd/changes/[fix-name]"` and re-verify. Do not continue to step 2 until the state is consistent.
|
|
70
|
+
1. **Archive with the CLI** — let the CLI handle the move (it automatically deletes memory.yaml if present):
|
|
71
|
+
```bash
|
|
72
|
+
refacil-sdd-ai sdd archive [fix-name]
|
|
73
|
+
```
|
|
74
|
+
The CLI resolves the repo root internally, deletes memory.yaml if present, moves the folder to `refacil-sdd/changes/archive/[ISO-date]-[fix-name]/`, and exits with code 0 on success. If it exits non-zero, stop and report the error to the user.
|
|
79
75
|
|
|
80
|
-
2. **Document in specs**:
|
|
76
|
+
2. **Document in specs**: using the content read in step 0, create an individual spec at `$(git rev-parse --show-toplevel)/refacil-sdd/specs/[descriptive-name]/spec.md`.
|
|
81
77
|
|
|
82
78
|
**Spec folder name**: Use a short, clear kebab-case description of the bug (e.g. `fix-session-timeout-redis`, `fix-null-pointer-payment-callback`). **Do NOT use ticket IDs** (REF-123, JIRA-456, etc.) — the name must be descriptive so `/refacil:explore` can find and understand the fix without external context.
|
|
83
79
|
|
|
@@ -101,7 +97,7 @@ Bug fixes only contain `summary.md` (and optionally `.review-passed`); they are
|
|
|
101
97
|
- **THEN** the system SHALL [normal behavior without regression]
|
|
102
98
|
```
|
|
103
99
|
|
|
104
|
-
3. **Persist review metadata separately**: create
|
|
100
|
+
3. **Persist review metadata separately**: create `$(git rev-parse --show-toplevel)/refacil-sdd/specs/[descriptive-name]/review.yaml` with the fields from `.review-passed` plus the Jira links from Step 1.5:
|
|
105
101
|
```yaml
|
|
106
102
|
verdict: APROBADO|APROBADO CON OBSERVACIONES
|
|
107
103
|
date: 2026-04-10T00:00:00.000Z
|
|
@@ -140,7 +136,7 @@ The spec and review evidence are written **before** running the CLI archive comm
|
|
|
140
136
|
```
|
|
141
137
|
- If `review.yaml` already exists, update only the fields that changed without removing others.
|
|
142
138
|
|
|
143
|
-
3. **Run the CLI archive**: `refacil-sdd-ai sdd archive <changeName>` —
|
|
139
|
+
3. **Run the CLI archive**: `refacil-sdd-ai sdd archive <changeName>` — the CLI automatically deletes memory.yaml if present, then moves the change to `refacil-sdd/changes/archive/<date>-<changeName>/`.
|
|
144
140
|
4. Verify the command completed successfully (exit 0) and the original folder no longer exists.
|
|
145
141
|
|
|
146
142
|
5. Continue to **Step 3**.
|
|
@@ -151,8 +147,8 @@ The goal is for `refacil-sdd/specs/` to document how the system works TODAY.
|
|
|
151
147
|
|
|
152
148
|
Before showing the summary, run a **final cleanup verification** (applies to both bug fixes and regular changes):
|
|
153
149
|
|
|
154
|
-
-
|
|
155
|
-
- If the source folder survived for any reason (failed move, partial copy, interrupted move), explicitly delete it with `rm -rf "refacil-sdd/changes/[original-name]"` before confirming to the user.
|
|
150
|
+
- `$(git rev-parse --show-toplevel)/refacil-sdd/changes/[original-name]/` **must NOT exist** (only the archived version must survive in `refacil-sdd/changes/archive/...`).
|
|
151
|
+
- If the source folder survived for any reason (failed move, partial copy, interrupted move), explicitly delete it with `rm -rf "$(git rev-parse --show-toplevel)/refacil-sdd/changes/[original-name]"` before confirming to the user.
|
|
156
152
|
|
|
157
153
|
```
|
|
158
154
|
=== Change archived ===
|
package/skills/explore/SKILL.md
CHANGED
|
@@ -17,6 +17,18 @@ This skill is a **thin wrapper** that delegates the investigation to the `refaci
|
|
|
17
17
|
- If `$ARGUMENTS` is empty, ask the user for the question or topic to explore BEFORE invoking the sub-agent.
|
|
18
18
|
- If there is a question, continue.
|
|
19
19
|
|
|
20
|
+
### Step 0.1: Duplicate exploration guard (CA-11)
|
|
21
|
+
|
|
22
|
+
Before delegating, check the current session conversation context for a prior complete exploration report with overlapping scope (same modules, files, or question topic):
|
|
23
|
+
|
|
24
|
+
- **If a prior complete exploration exists for the same or highly overlapping topic**: summarize the already-known context in 2-3 sentences and ask:
|
|
25
|
+
```
|
|
26
|
+
I already explored [topic] earlier in this session. The key findings were: [summary].
|
|
27
|
+
Do you want me to run a targeted follow-up on a specific aspect, or proceed with a new full exploration?
|
|
28
|
+
```
|
|
29
|
+
Wait for the user's answer before proceeding.
|
|
30
|
+
- **If there is no prior exploration** (or it is on a clearly different topic): continue to Step 1 without interruption.
|
|
31
|
+
|
|
20
32
|
### Step 1: Delegate to the refacil-investigator sub-agent
|
|
21
33
|
|
|
22
34
|
Invoke the `refacil-investigator` sub-agent passing it:
|
|
@@ -57,19 +57,22 @@ Critical rule:
|
|
|
57
57
|
|
|
58
58
|
If the current branch is protected and code needs to be written:
|
|
59
59
|
|
|
60
|
-
1.
|
|
60
|
+
1. **Ask for a task identifier first** — before any git action, ask the user:
|
|
61
|
+
*"What is the task number or name for this branch? (e.g. SEGINF-20, REF-123, or a short descriptive name)"*
|
|
62
|
+
Wait for the user's answer before continuing.
|
|
61
63
|
2. Verify clean working directory (`git status --porcelain`).
|
|
62
64
|
3. If there are uncommitted changes, ask for approval to `git stash push -m "auto-stash-refacil"`.
|
|
63
65
|
4. Detect the base branch to create a working branch from:
|
|
64
66
|
- Prefer `develop`, then `dev`.
|
|
65
67
|
- Only if neither exists (new repo), use `main` or `master` as a temporary exception.
|
|
66
68
|
- Switch and update (`git pull origin <base>`). If none exist, stop.
|
|
67
|
-
5.
|
|
68
|
-
- Feature: `feature/<ID>`
|
|
69
|
-
- Bugfix: `fix/<ID>`
|
|
70
|
-
- Without ID: short descriptive name and
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
5. **Propose the branch name and wait for explicit user approval before creating it:**
|
|
70
|
+
- Feature: `feature/<ID>` (e.g. `feature/SEGINF-20`)
|
|
71
|
+
- Bugfix: `fix/<ID>` (e.g. `fix/SEGINF-20`)
|
|
72
|
+
- Without ID: propose a short descriptive name (e.g. `fix/project-root-consistency`) and **require explicit approval** before proceeding.
|
|
73
|
+
Example: *"I'll create branch `fix/SEGINF-20` from `develop`. Shall I proceed?"*
|
|
74
|
+
6. **Only after explicit user confirmation**: create the branch and restore stash if used.
|
|
75
|
+
7. If the user does not approve at any point, stop.
|
|
73
76
|
|
|
74
77
|
## §5 — Output policy (UX)
|
|
75
78
|
|
package/skills/propose/SKILL.md
CHANGED
|
@@ -12,6 +12,18 @@ This skill is a **wrapper** that prepares the scope, delegates SDD artifact gene
|
|
|
12
12
|
|
|
13
13
|
## Flow
|
|
14
14
|
|
|
15
|
+
### Step 0.5: Duplicate exploration guard (CA-11)
|
|
16
|
+
|
|
17
|
+
Before gathering context or delegating, check the current session conversation for a prior complete exploration report with overlapping scope (same modules, files, or described topic):
|
|
18
|
+
|
|
19
|
+
- **If a prior complete exploration exists for the same or highly overlapping topic**: summarize the already-known context in 2-3 sentences and ask:
|
|
20
|
+
```
|
|
21
|
+
I already explored [topic] earlier in this session. The key findings were: [summary].
|
|
22
|
+
Do you want me to run a targeted follow-up, or proceed with the full exploration for this proposal?
|
|
23
|
+
```
|
|
24
|
+
Wait for the user's answer. If they confirm "proceed", continue to Step 1 — do not re-invoke a full exploration automatically.
|
|
25
|
+
- **If there is no prior exploration** for this topic: continue to Step 1 without interruption.
|
|
26
|
+
|
|
15
27
|
### Step 1: Understand the change
|
|
16
28
|
|
|
17
29
|
If the user did NOT provide sufficient context in `$ARGUMENTS`, ask:
|
|
@@ -21,15 +33,15 @@ If the user did NOT provide sufficient context in `$ARGUMENTS`, ask:
|
|
|
21
33
|
|
|
22
34
|
If `$ARGUMENTS` is already clear, do not ask again.
|
|
23
35
|
|
|
24
|
-
### Step 1.5:
|
|
36
|
+
### Step 1.5: Validate change name (blocking)
|
|
25
37
|
|
|
26
|
-
|
|
38
|
+
Before delegating to the sub-agent, agree on or derive the **final slug** of the change (kebab-case: `feat-...`, `expose-...`, `imp-...`, etc.) then validate it with the CLI:
|
|
27
39
|
|
|
28
|
-
|
|
40
|
+
Run `refacil-sdd-ai sdd validate-name <slug>`:
|
|
41
|
+
- If exit 0: the name is valid — continue.
|
|
42
|
+
- If exit 1: show the CLI's error message to the user and ask them to provide a corrected slug. Repeat until `sdd validate-name` exits 0.
|
|
29
43
|
|
|
30
|
-
|
|
31
|
-
2. If the user proposes an invalid name, **correct it** (e.g. `feat-` or `change-` prefix) or ask for the correct slug; **do not** delegate until you have a valid name.
|
|
32
|
-
3. Communicate the final agreed slug to the user before generating.
|
|
44
|
+
Communicate the final agreed slug to the user before generating.
|
|
33
45
|
|
|
34
46
|
### Step 2: Delegate to the refacil-proposer sub-agent
|
|
35
47
|
|
|
@@ -86,6 +98,6 @@ Do you want me to continue with /refacil:apply?
|
|
|
86
98
|
|
|
87
99
|
## Rules
|
|
88
100
|
|
|
89
|
-
- **Change folder name**: always
|
|
101
|
+
- **Change folder name**: always validate with `refacil-sdd-ai sdd validate-name <slug>` before delegating. Do not proceed if it exits 1.
|
|
90
102
|
- **Always delegate generation to the sub-agent**. Do not replicate the codebase exploration or artifact generation logic here.
|
|
91
103
|
- **Flow continuity**: if the user confirms affirmatively ("yes", "ok", "go", "continue", etc.) the continuity question in Step 4, immediately invoke the **Skill tool** with `skill: "refacil:apply"`. Do not describe it in text or wait for the user to type `/refacil:apply`. (See `METHODOLOGY-CONTRACT.md §5`.)
|
package/skills/review/SKILL.md
CHANGED
|
@@ -43,11 +43,21 @@ If you already have a `changeName`, run `refacil-sdd-ai sdd status <changeName>
|
|
|
43
43
|
The change [name] already has an approved review ([verdict] — [date]) and there are no subsequent changes.
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
### Step 0.4: Incremental scope (CA-07 — only if re-running after REQUIERE CORRECCIONES)
|
|
47
|
+
|
|
48
|
+
If `changeName` is not null, check whether `refacil-sdd/changes/<changeName>/.review-last-fails.json` exists (read by explicit path — it is NOT a dotfile but may be hidden in listings):
|
|
49
|
+
|
|
50
|
+
- **If the file EXISTS**: read `failedFiles` from it. Compute:
|
|
51
|
+
`incrementalScope = failedFiles ∪ changedFilesUnion`
|
|
52
|
+
- If `incrementalScope` is empty (CR-02): fall back to `changedFilesUnion` and add a comment in the briefing: `"# warning: incremental scope was empty — using full changedFilesUnion"`.
|
|
53
|
+
- Use `incrementalScope` as `changedFiles` in the briefing (Step 0.5), instead of the full `changedFilesUnion`.
|
|
54
|
+
- **If the file does NOT exist**: use `changedFilesUnion` as `changedFiles` normally.
|
|
55
|
+
|
|
46
56
|
### Step 0.5: Build briefing for the sub-agent (reduces auditor tool calls)
|
|
47
57
|
|
|
48
58
|
Before invoking the sub-agent, extract the context that the auditor would otherwise calculate on its own:
|
|
49
59
|
|
|
50
|
-
1. **Changed files** — use
|
|
60
|
+
1. **Changed files** — use the scope resolved in Step 0.4 (`incrementalScope` if available, otherwise `changedFilesUnion`). Do not run `git diff` or `git status` again.
|
|
51
61
|
|
|
52
62
|
2. **Project type** — read `package.json` (if it exists) and inspect the dependencies:
|
|
53
63
|
- Backend indicators: `@nestjs/*`, `express`, `fastify`, `koa`, `typeorm`, `prisma`, `pg`, `mongoose`, `bullmq`, `amqplib`
|
|
@@ -56,6 +66,10 @@ Before invoking the sub-agent, extract the context that the auditor would otherw
|
|
|
56
66
|
|
|
57
67
|
3. **Change objective** (only if there is an active change in `refacil-sdd/changes/`) — read the first section of `proposal.md`. Extract the objective in 1-2 sentences. If the scope is `git-diff` without an active change → `null`.
|
|
58
68
|
|
|
69
|
+
4. **Cross-skill memory** — run `refacil-sdd-ai sdd get-memory <changeName> --json` and parse the JSON to extract `stackDetected` and `touchedFiles`. Include them in the briefing so the auditor skips re-discovery. If the command outputs `{}` or fails, omit — do not block (CR-04).
|
|
70
|
+
|
|
71
|
+
5. **Mode** — default `concise`. If re-running after a prior `REQUIERE CORRECCIONES` (i.e., `.review-last-fails.json` was found with non-empty `failedFiles` in Step 0.4): set `mode: focused` — the auditor re-evaluates only the failing checklist items on the `failedFiles` (CR-05: focused mode still reads those files). Otherwise keep `concise`.
|
|
72
|
+
|
|
59
73
|
Build the BRIEFING block:
|
|
60
74
|
|
|
61
75
|
```
|
|
@@ -64,7 +78,9 @@ scope: <changeName | "git-diff">
|
|
|
64
78
|
changedFiles: [path/file-1.ts, path/file-2.ts, ...]
|
|
65
79
|
projectType: backend | frontend | fullstack | library
|
|
66
80
|
changeObjective: <objective in 1-2 sentences, or null>
|
|
67
|
-
mode: concise | detailed
|
|
81
|
+
mode: concise | detailed | focused
|
|
82
|
+
stackDetected: <from memory.yaml, or omit>
|
|
83
|
+
touchedFiles: [...] # from memory.yaml — omit if not present
|
|
68
84
|
```
|
|
69
85
|
|
|
70
86
|
### Step 1: Delegate to the refacil-auditor sub-agent
|
|
@@ -85,6 +101,18 @@ Show the user the **concise report** (everything before the `refacil-review-resu
|
|
|
85
101
|
|
|
86
102
|
**If the sub-agent returned `SCOPE_ERROR: <reason>`**: propagate the error to the user and ask for clarification. Do not write a marker.
|
|
87
103
|
|
|
104
|
+
### Step 2.5: Persist or clean incremental-scope state (CA-06/CA-08/CA-09/CR-01)
|
|
105
|
+
|
|
106
|
+
Parse the `refacil-review-result` block from the sub-agent.
|
|
107
|
+
|
|
108
|
+
**If `verdict` is `REQUIERE CORRECCIONES`**:
|
|
109
|
+
- Only if `changeName` is not null (CR-01) AND the block includes a `failedFiles` field (CA-09 backward compat):
|
|
110
|
+
- Run: `refacil-sdd-ai sdd set-review-fails <changeName> --files "<comma-separated failedFiles>"`
|
|
111
|
+
- If `changeName` is null or `failedFiles` is absent: skip silently.
|
|
112
|
+
|
|
113
|
+
**If `verdict` is `APROBADO` or `APROBADO CON OBSERVACIONES`**:
|
|
114
|
+
- Run: `refacil-sdd-ai sdd clear-review-fails <changeName>`
|
|
115
|
+
|
|
88
116
|
### Step 3: Create `.review-passed` marker (if applicable)
|
|
89
117
|
|
|
90
118
|
Parse the ` ```refacil-review-result ` block from the sub-agent. If `verdict` is **APROBADO** or **APROBADO CON OBSERVACIONES** and `changeName` is not null:
|
|
@@ -110,6 +138,24 @@ Where the values are extracted from the sub-agent's `refacil-review-result` bloc
|
|
|
110
138
|
- `changeName` is null.
|
|
111
139
|
- The sub-agent returned `SCOPE_ERROR`.
|
|
112
140
|
|
|
141
|
+
### Step 3.5: Offer to apply corrections (only if REQUIERE CORRECCIONES)
|
|
142
|
+
|
|
143
|
+
If `verdict` is `REQUIERE CORRECCIONES`, after showing the report present a numbered list of the findings (blockers first, then medium/low) and ask:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
X corrections are needed. Do you want me to apply them?
|
|
147
|
+
- "yes" / "all" — apply all
|
|
148
|
+
- "1, 3" (numbers) — apply only those items
|
|
149
|
+
- "no" / "skip" — you'll handle them manually
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**According to the user's response:**
|
|
153
|
+
- **"yes" / "all"**: apply every correction using Edit/Write/Bash tools directly in this skill. After each correction, note it as applied.
|
|
154
|
+
- **"N, M" (specific items)**: apply only those numbered items.
|
|
155
|
+
- **"no" / "skip" / no answer**: do not apply anything — continue to Step 4.
|
|
156
|
+
|
|
157
|
+
After applying corrections (if any): summarize what was applied, then continue to Step 4.
|
|
158
|
+
|
|
113
159
|
### Step 4: Recommend next step
|
|
114
160
|
|
|
115
161
|
According to the parsed `verdict`, add at the end of your response:
|
|
@@ -120,9 +166,9 @@ The next step is to archive the change.
|
|
|
120
166
|
Do you want me to continue with /refacil:archive?
|
|
121
167
|
```
|
|
122
168
|
|
|
123
|
-
**If REQUIERE CORRECCIONES
|
|
169
|
+
**If REQUIERE CORRECCIONES** (after Step 3.5):
|
|
124
170
|
```
|
|
125
|
-
|
|
171
|
+
The next step is to re-verify the implementation.
|
|
126
172
|
Do you want me to continue with /refacil:verify?
|
|
127
173
|
```
|
|
128
174
|
|
|
@@ -132,4 +178,7 @@ Do you want me to continue with /refacil:verify?
|
|
|
132
178
|
- **Always delegate to the sub-agent**. Do not replicate checklist or evaluation logic here.
|
|
133
179
|
- **The marker is created by this skill, not the sub-agent**.
|
|
134
180
|
- If the sub-agent returned something out of format (no parseable JSON block and not `SCOPE_ERROR`), inform the user: "The reviewer returned an unstructured report — no marker was created. Review the report manually."
|
|
135
|
-
- **Flow continuity**:
|
|
181
|
+
- **Flow continuity**:
|
|
182
|
+
- If verdict is APROBADO/APROBADO CON OBSERVACIONES and user confirms → immediately invoke `skill: "refacil:archive"`.
|
|
183
|
+
- If verdict is REQUIERE CORRECCIONES and user confirms verify (Step 4) → immediately invoke `skill: "refacil:verify"`.
|
|
184
|
+
- Do not describe the skill in text or wait for the user to type the command. (See `METHODOLOGY-CONTRACT.md §5`.)
|
package/skills/test/SKILL.md
CHANGED
|
@@ -69,6 +69,23 @@ Parse the `refacil-test-result` block from the sub-agent:
|
|
|
69
69
|
- **If `passed: false`** (tests failed): present the `issues` from the JSON and ask the user how to proceed. **Do not continue to Step 4** until the tests pass.
|
|
70
70
|
- **If `passed: true`**: continue to Step 4.
|
|
71
71
|
|
|
72
|
+
### Step 3.5: Update cross-skill memory (memory.yaml)
|
|
73
|
+
|
|
74
|
+
After parsing the `refacil-test-result` block and only if `passed: true`:
|
|
75
|
+
- Extract from the result or from the briefing: `commandsRun` (test command used), `criteriaRun` (list of CA-XX/CR-XX covered by tests), `stackDetected` (if the tester identified the stack).
|
|
76
|
+
|
|
77
|
+
Run:
|
|
78
|
+
```bash
|
|
79
|
+
refacil-sdd-ai sdd set-memory <changeName> \
|
|
80
|
+
--last-step test \
|
|
81
|
+
--commands-run "<test command used>" \
|
|
82
|
+
--criteria-run "<comma-separated criteria IDs that were run>"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
If `stackDetected` is available, add `--stack-detected "<stack>"` to the command as well.
|
|
86
|
+
|
|
87
|
+
This command merges into memory.yaml, preserving fields from other steps (e.g. `touchedFiles` from apply).
|
|
88
|
+
|
|
72
89
|
### Step 4: Flow continuity (only if tests passed)
|
|
73
90
|
|
|
74
91
|
Add:
|
package/skills/verify/SKILL.md
CHANGED
|
@@ -27,6 +27,16 @@ If you already have a `changeName`, run `refacil-sdd-ai sdd status <changeName>
|
|
|
27
27
|
|
|
28
28
|
If **this session** inspects the change directory before or after delegating, apply **`refacil-prereqs/METHODOLOGY-CONTRACT.md` §8**.
|
|
29
29
|
|
|
30
|
+
### Step 0.6: Verify validator agent is installed (blocking — CA-12)
|
|
31
|
+
|
|
32
|
+
Before doing anything else, check that `.claude/agents/refacil-validator.md` exists (read by explicit path or `ls -la .claude/agents/refacil-validator.md`).
|
|
33
|
+
|
|
34
|
+
**If the file does NOT exist**, stop immediately:
|
|
35
|
+
```
|
|
36
|
+
El agente `refacil-validator` no está instalado. Ejecuta `/refacil:update` y reinicia la sesión antes de volver a correr `/refacil:verify`.
|
|
37
|
+
```
|
|
38
|
+
Do not continue and do not escalate to any other agent.
|
|
39
|
+
|
|
30
40
|
### Step 1: Build briefing for the sub-agent (reduces validator tool calls)
|
|
31
41
|
|
|
32
42
|
Before invoking the sub-agent, extract the context that the validator would otherwise calculate on its own:
|
|
@@ -40,6 +50,8 @@ Before invoking the sub-agent, extract the context that the validator would othe
|
|
|
40
50
|
|
|
41
51
|
3. **Scope files** — run `git diff --name-only HEAD` to get the files modified in this change.
|
|
42
52
|
|
|
53
|
+
4. **Cross-skill memory** — run `refacil-sdd-ai sdd get-memory <changeName> --json` and parse the JSON output to extract `commandsRun` and `criteriaRun`. Include them in the briefing so the validator uses the same command without re-discovering it and can skip re-reading specs for those criteria. If the output is `{}` or the command fails, skip — do not block verification (CR-04).
|
|
54
|
+
|
|
43
55
|
Build the BRIEFING block:
|
|
44
56
|
|
|
45
57
|
```
|
|
@@ -54,6 +66,8 @@ criteria:
|
|
|
54
66
|
- CR-01: <description>
|
|
55
67
|
changedFiles: [path/file-1.ts, ...]
|
|
56
68
|
mode: concise | detailed
|
|
69
|
+
commandsRun: [<command>, ...] # from memory.yaml — omit if not present
|
|
70
|
+
criteriaRun: [CA-01, CR-01, ...] # from memory.yaml — omit if not present
|
|
57
71
|
```
|
|
58
72
|
|
|
59
73
|
### Step 2: Delegate to the refacil-validator sub-agent
|
|
@@ -73,7 +87,18 @@ The sub-agent:
|
|
|
73
87
|
|
|
74
88
|
Show the user the **combined report** (everything before the `refacil-verify-result` block). Do not show the JSON block — it is internal metadata.
|
|
75
89
|
|
|
76
|
-
**If the sub-agent
|
|
90
|
+
**If the sub-agent failed to load** (tool error, agent type not found, or no response at all): stop immediately and do NOT escalate to any other agent:
|
|
91
|
+
```
|
|
92
|
+
The validator sub-agent could not be loaded — retry or run `/refacil:verify` again.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**If the sub-agent responded but without a `refacil-verify-result` block** (unstructured output): show the raw report and stop:
|
|
96
|
+
```
|
|
97
|
+
The validator returned an unstructured report — continue manually.
|
|
98
|
+
```
|
|
99
|
+
Do not re-invoke a different agent.
|
|
100
|
+
|
|
101
|
+
**If the sub-agent returned a scope error** (`SCOPE_ERROR: <reason>`, without JSON block): propagate to the user and ask for clarification. This is NOT the CA-01 failsafe — the agent loaded correctly but found an ambiguous scope.
|
|
77
102
|
|
|
78
103
|
### Step 4: Process the result
|
|
79
104
|
|
|
@@ -124,5 +149,8 @@ Do you want me to apply these corrections? (yes/no)
|
|
|
124
149
|
- **Corrections are ONLY applied by this wrapper** (Step 5), after explicit approval.
|
|
125
150
|
- **Corrections must be surgical**: only what is necessary to resolve the reported issues.
|
|
126
151
|
- Maximum 2 rounds of automatic correction before escalating to manual.
|
|
127
|
-
-
|
|
152
|
+
- **Sub-agent failsafe (CA-01)**: if the validator fails to load (tool error) or returns no response — stop and inform the user. Do NOT escalate to any other agent.
|
|
153
|
+
- **Unstructured output (CA-02)**: if the validator responds but without a `refacil-verify-result` block — show the raw report and stop. Do NOT re-invoke another agent.
|
|
154
|
+
- **SCOPE_ERROR (CR-03)**: if the validator returns `SCOPE_ERROR: <reason>` — propagate and ask for clarification. CA-01 does NOT apply here.
|
|
155
|
+
- **Agent missing (CA-12)**: checked in Step 0.6 — stop before delegating if `.claude/agents/refacil-validator.md` is absent.
|
|
128
156
|
- **Flow continuity**: if the result is APPROVED and the user confirms affirmatively, immediately invoke the **Skill tool** with `skill: "refacil:review"`. (See `METHODOLOGY-CONTRACT.md §5`.)
|