refacil-sdd-ai 4.4.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/bin/cli.js +4 -4
- package/lib/commands/sdd.js +233 -16
- package/lib/installer.js +2 -2
- package/package.json +2 -2
- package/skills/apply/SKILL.md +9 -10
- package/skills/archive/SKILL.md +15 -23
- package/skills/prereqs/METHODOLOGY-CONTRACT.md +10 -7
- package/skills/propose/SKILL.md +7 -7
- package/skills/review/SKILL.md +28 -7
- package/skills/test/SKILL.md +12 -13
- package/skills/verify/SKILL.md +1 -4
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
|
@@ -17,8 +17,6 @@ function findProjectRoot() {
|
|
|
17
17
|
return process.cwd();
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
const projectRoot = findProjectRoot();
|
|
21
|
-
|
|
22
20
|
// --- Helpers ---
|
|
23
21
|
|
|
24
22
|
function parseArgs(argv) {
|
|
@@ -79,6 +77,65 @@ function autoMigrateOpenspec(root) {
|
|
|
79
77
|
// Si ambos existen o ninguno existe → no hacer nada
|
|
80
78
|
}
|
|
81
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
|
+
|
|
82
139
|
// --- Subcomandos ---
|
|
83
140
|
|
|
84
141
|
function cmdValidateName(argv) {
|
|
@@ -93,7 +150,7 @@ function cmdValidateName(argv) {
|
|
|
93
150
|
}
|
|
94
151
|
}
|
|
95
152
|
|
|
96
|
-
function cmdNewChange(argv) {
|
|
153
|
+
function cmdNewChange(argv, projectRoot) {
|
|
97
154
|
const args = parseArgs(argv);
|
|
98
155
|
const name = args._positional[0];
|
|
99
156
|
|
|
@@ -121,7 +178,7 @@ function cmdNewChange(argv) {
|
|
|
121
178
|
console.log(`Cambio '${name}' creado en refacil-sdd/changes/${name}/`);
|
|
122
179
|
}
|
|
123
180
|
|
|
124
|
-
function cmdArchive(argv) {
|
|
181
|
+
function cmdArchive(argv, projectRoot) {
|
|
125
182
|
const args = parseArgs(argv);
|
|
126
183
|
const name = args._positional[0];
|
|
127
184
|
|
|
@@ -148,6 +205,10 @@ function cmdArchive(argv) {
|
|
|
148
205
|
process.exit(1);
|
|
149
206
|
}
|
|
150
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
|
+
|
|
151
212
|
fs.mkdirSync(archiveDir, { recursive: true });
|
|
152
213
|
fs.renameSync(sourceDir, destDir);
|
|
153
214
|
|
|
@@ -159,7 +220,138 @@ function cmdArchive(argv) {
|
|
|
159
220
|
console.log(`Cambio '${name}' archivado en refacil-sdd/changes/archive/${date}-${name}/`);
|
|
160
221
|
}
|
|
161
222
|
|
|
162
|
-
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) {
|
|
163
355
|
const args = parseArgs(argv);
|
|
164
356
|
const wantJson = args.json === true;
|
|
165
357
|
|
|
@@ -198,7 +390,7 @@ function cmdList(argv) {
|
|
|
198
390
|
}
|
|
199
391
|
}
|
|
200
392
|
|
|
201
|
-
function cmdStatus(argv) {
|
|
393
|
+
function cmdStatus(argv, projectRoot) {
|
|
202
394
|
const args = parseArgs(argv);
|
|
203
395
|
const name = args._positional[0];
|
|
204
396
|
const wantJson = args.json === true;
|
|
@@ -287,7 +479,7 @@ function cmdStatus(argv) {
|
|
|
287
479
|
}
|
|
288
480
|
}
|
|
289
481
|
|
|
290
|
-
function cmdMarkReviewed(argv) {
|
|
482
|
+
function cmdMarkReviewed(argv, projectRoot) {
|
|
291
483
|
const args = parseArgs(argv);
|
|
292
484
|
const name = args._positional[0];
|
|
293
485
|
|
|
@@ -328,7 +520,7 @@ function cmdMarkReviewed(argv) {
|
|
|
328
520
|
console.log(`Review marcado como aprobado para '${name}' (verdict: ${payload.verdict})`);
|
|
329
521
|
}
|
|
330
522
|
|
|
331
|
-
function cmdTasksUpdate(argv) {
|
|
523
|
+
function cmdTasksUpdate(argv, projectRoot) {
|
|
332
524
|
const args = parseArgs(argv);
|
|
333
525
|
const name = args._positional[0];
|
|
334
526
|
|
|
@@ -404,44 +596,69 @@ function sddHelp() {
|
|
|
404
596
|
--task N Número de task (1-indexed)
|
|
405
597
|
--done Confirma que la task está hecha
|
|
406
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
|
|
407
610
|
|
|
408
611
|
Notas:
|
|
409
612
|
- Los nombres de cambio deben empezar con minúscula y usar solo [a-z0-9-]
|
|
410
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
|
|
411
615
|
`);
|
|
412
616
|
}
|
|
413
617
|
|
|
414
618
|
// --- Dispatcher ---
|
|
415
619
|
|
|
416
|
-
function handleSdd(sub, argv) {
|
|
620
|
+
function handleSdd(sub, argv, projectRoot) {
|
|
417
621
|
const args = argv || [];
|
|
622
|
+
const root = projectRoot || findProjectRoot();
|
|
418
623
|
|
|
419
624
|
switch (sub) {
|
|
420
625
|
case 'new-change':
|
|
421
|
-
cmdNewChange(args);
|
|
626
|
+
cmdNewChange(args, root);
|
|
422
627
|
break;
|
|
423
628
|
case 'archive':
|
|
424
|
-
cmdArchive(args);
|
|
629
|
+
cmdArchive(args, root);
|
|
425
630
|
break;
|
|
426
631
|
case 'list':
|
|
427
|
-
cmdList(args);
|
|
632
|
+
cmdList(args, root);
|
|
428
633
|
break;
|
|
429
634
|
case 'status':
|
|
430
|
-
cmdStatus(args);
|
|
635
|
+
cmdStatus(args, root);
|
|
431
636
|
break;
|
|
432
637
|
case 'mark-reviewed':
|
|
433
|
-
cmdMarkReviewed(args);
|
|
638
|
+
cmdMarkReviewed(args, root);
|
|
434
639
|
break;
|
|
435
640
|
case 'tasks-update':
|
|
436
|
-
cmdTasksUpdate(args);
|
|
641
|
+
cmdTasksUpdate(args, root);
|
|
437
642
|
break;
|
|
438
643
|
case 'validate-name':
|
|
439
644
|
cmdValidateName(args);
|
|
440
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;
|
|
441
658
|
default:
|
|
442
659
|
sddHelp();
|
|
443
660
|
process.exit(1);
|
|
444
661
|
}
|
|
445
662
|
}
|
|
446
663
|
|
|
447
|
-
module.exports = { handleSdd, parseArgs, autoMigrateOpenspec, validateChangeName };
|
|
664
|
+
module.exports = { handleSdd, parseArgs, autoMigrateOpenspec, validateChangeName, findProjectRoot };
|
package/lib/installer.js
CHANGED
|
@@ -297,9 +297,9 @@ function checkNodeVersion() {
|
|
|
297
297
|
const major = parseInt(version.split('.')[0].replace('v', ''));
|
|
298
298
|
const minor = parseInt(version.split('.')[1]);
|
|
299
299
|
|
|
300
|
-
if (major < 20
|
|
300
|
+
if (major < 20) {
|
|
301
301
|
console.log(`\n ADVERTENCIA: Node.js ${version} detectado.`);
|
|
302
|
-
console.log(' refacil-sdd-ai requiere Node.js >= 20.
|
|
302
|
+
console.log(' refacil-sdd-ai requiere Node.js >= 20.0.0.');
|
|
303
303
|
console.log(' Las skills se instalaran pero /refacil:setup podria fallar al instalar OpenSpec.\n');
|
|
304
304
|
return false;
|
|
305
305
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "refacil-sdd-ai",
|
|
3
|
-
"version": "4.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,22 +99,21 @@ 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:
|
|
102
|
+
### Step 2.5: Save cross-skill memory (memory.yaml)
|
|
103
103
|
|
|
104
|
-
After parsing the `refacil-apply-result` block
|
|
104
|
+
After parsing the `refacil-apply-result` block and only if `result` is not `"FAILED"`:
|
|
105
105
|
- Extract `touchedFiles` from the result (list of files actually created/modified by the implementer).
|
|
106
|
-
- Write or update `refacil-sdd/changes/<changeName>/memory.yaml` preserving any existing fields:
|
|
107
106
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
-
|
|
112
|
-
-
|
|
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>"
|
|
113
112
|
```
|
|
114
113
|
|
|
115
|
-
|
|
114
|
+
This command merges into memory.yaml at the repo root using `findProjectRoot()` — no manual path construction needed.
|
|
116
115
|
|
|
117
|
-
If `result` is `"FAILED"`, skip
|
|
116
|
+
If `result` is `"FAILED"`, skip and wait for user instructions.
|
|
118
117
|
|
|
119
118
|
### Step 3: Present result and next step
|
|
120
119
|
|
package/skills/archive/SKILL.md
CHANGED
|
@@ -61,25 +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
|
-
0. **
|
|
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
|
-
1. **
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
3. If `git mv` does not apply (untracked files or error), use instead:
|
|
76
|
-
- Linux/macOS/Windows: `mv "refacil-sdd/changes/[fix-name]" "refacil-sdd/changes/archive/[ISO-date]-[fix-name]"`. Always use `mv` (not `cp -r`) — verify source no longer exists after the move.
|
|
77
|
-
4. **Mandatory post-move verification**: run a listing/existence test to confirm:
|
|
78
|
-
- `refacil-sdd/changes/[fix-name]/` **no longer exists**.
|
|
79
|
-
- `refacil-sdd/changes/archive/[ISO-date]-[fix-name]/` **does exist** and contains `summary.md` (+ `.review-passed` if it existed).
|
|
80
|
-
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.
|
|
81
75
|
|
|
82
|
-
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`.
|
|
83
77
|
|
|
84
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.
|
|
85
79
|
|
|
@@ -103,7 +97,7 @@ Bug fixes only contain `summary.md` (and optionally `.review-passed`); they are
|
|
|
103
97
|
- **THEN** the system SHALL [normal behavior without regression]
|
|
104
98
|
```
|
|
105
99
|
|
|
106
|
-
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:
|
|
107
101
|
```yaml
|
|
108
102
|
verdict: APROBADO|APROBADO CON OBSERVACIONES
|
|
109
103
|
date: 2026-04-10T00:00:00.000Z
|
|
@@ -142,12 +136,10 @@ The spec and review evidence are written **before** running the CLI archive comm
|
|
|
142
136
|
```
|
|
143
137
|
- If `review.yaml` already exists, update only the fields that changed without removing others.
|
|
144
138
|
|
|
145
|
-
3. **
|
|
146
|
-
|
|
147
|
-
4. **Run the CLI archive**: `refacil-sdd-ai sdd archive <changeName>` — this moves the change to `refacil-sdd/changes/archive/<date>-<changeName>/`.
|
|
148
|
-
5. Verify the command completed successfully (exit 0) and the original folder no longer exists.
|
|
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>/`.
|
|
140
|
+
4. Verify the command completed successfully (exit 0) and the original folder no longer exists.
|
|
149
141
|
|
|
150
|
-
|
|
142
|
+
5. Continue to **Step 3**.
|
|
151
143
|
|
|
152
144
|
The goal is for `refacil-sdd/specs/` to document how the system works TODAY.
|
|
153
145
|
|
|
@@ -155,8 +147,8 @@ The goal is for `refacil-sdd/specs/` to document how the system works TODAY.
|
|
|
155
147
|
|
|
156
148
|
Before showing the summary, run a **final cleanup verification** (applies to both bug fixes and regular changes):
|
|
157
149
|
|
|
158
|
-
-
|
|
159
|
-
- 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.
|
|
160
152
|
|
|
161
153
|
```
|
|
162
154
|
=== Change archived ===
|
|
@@ -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
|
@@ -33,15 +33,15 @@ If the user did NOT provide sufficient context in `$ARGUMENTS`, ask:
|
|
|
33
33
|
|
|
34
34
|
If `$ARGUMENTS` is already clear, do not ask again.
|
|
35
35
|
|
|
36
|
-
### Step 1.5:
|
|
36
|
+
### Step 1.5: Validate change name (blocking)
|
|
37
37
|
|
|
38
|
-
|
|
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:
|
|
39
39
|
|
|
40
|
-
|
|
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.
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
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.
|
|
44
|
-
3. Communicate the final agreed slug to the user before generating.
|
|
44
|
+
Communicate the final agreed slug to the user before generating.
|
|
45
45
|
|
|
46
46
|
### Step 2: Delegate to the refacil-proposer sub-agent
|
|
47
47
|
|
|
@@ -98,6 +98,6 @@ Do you want me to continue with /refacil:apply?
|
|
|
98
98
|
|
|
99
99
|
## Rules
|
|
100
100
|
|
|
101
|
-
- **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.
|
|
102
102
|
- **Always delegate generation to the sub-agent**. Do not replicate the codebase exploration or artifact generation logic here.
|
|
103
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
|
@@ -66,7 +66,7 @@ Before invoking the sub-agent, extract the context that the auditor would otherw
|
|
|
66
66
|
|
|
67
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`.
|
|
68
68
|
|
|
69
|
-
4. **Cross-skill memory** —
|
|
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
70
|
|
|
71
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
72
|
|
|
@@ -107,11 +107,11 @@ Parse the `refacil-review-result` block from the sub-agent.
|
|
|
107
107
|
|
|
108
108
|
**If `verdict` is `REQUIERE CORRECCIONES`**:
|
|
109
109
|
- Only if `changeName` is not null (CR-01) AND the block includes a `failedFiles` field (CA-09 backward compat):
|
|
110
|
-
-
|
|
111
|
-
- If `changeName` is null or `failedFiles` is absent: skip silently
|
|
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
112
|
|
|
113
113
|
**If `verdict` is `APROBADO` or `APROBADO CON OBSERVACIONES`**:
|
|
114
|
-
-
|
|
114
|
+
- Run: `refacil-sdd-ai sdd clear-review-fails <changeName>`
|
|
115
115
|
|
|
116
116
|
### Step 3: Create `.review-passed` marker (if applicable)
|
|
117
117
|
|
|
@@ -138,6 +138,24 @@ Where the values are extracted from the sub-agent's `refacil-review-result` bloc
|
|
|
138
138
|
- `changeName` is null.
|
|
139
139
|
- The sub-agent returned `SCOPE_ERROR`.
|
|
140
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
|
+
|
|
141
159
|
### Step 4: Recommend next step
|
|
142
160
|
|
|
143
161
|
According to the parsed `verdict`, add at the end of your response:
|
|
@@ -148,9 +166,9 @@ The next step is to archive the change.
|
|
|
148
166
|
Do you want me to continue with /refacil:archive?
|
|
149
167
|
```
|
|
150
168
|
|
|
151
|
-
**If REQUIERE CORRECCIONES
|
|
169
|
+
**If REQUIERE CORRECCIONES** (after Step 3.5):
|
|
152
170
|
```
|
|
153
|
-
|
|
171
|
+
The next step is to re-verify the implementation.
|
|
154
172
|
Do you want me to continue with /refacil:verify?
|
|
155
173
|
```
|
|
156
174
|
|
|
@@ -160,4 +178,7 @@ Do you want me to continue with /refacil:verify?
|
|
|
160
178
|
- **Always delegate to the sub-agent**. Do not replicate checklist or evaluation logic here.
|
|
161
179
|
- **The marker is created by this skill, not the sub-agent**.
|
|
162
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."
|
|
163
|
-
- **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,23 +69,22 @@ 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:
|
|
72
|
+
### Step 3.5: Update cross-skill memory (memory.yaml)
|
|
73
73
|
|
|
74
74
|
After parsing the `refacil-test-result` block and only if `passed: true`:
|
|
75
|
-
- Extract from the result or from the briefing: `commandsRun` (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
- <
|
|
83
|
-
criteriaRun:
|
|
84
|
-
- CA-01
|
|
85
|
-
- CR-01
|
|
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>"
|
|
86
83
|
```
|
|
87
84
|
|
|
88
|
-
If
|
|
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).
|
|
89
88
|
|
|
90
89
|
### Step 4: Flow continuity (only if tests passed)
|
|
91
90
|
|
package/skills/verify/SKILL.md
CHANGED
|
@@ -50,10 +50,7 @@ Before invoking the sub-agent, extract the context that the validator would othe
|
|
|
50
50
|
|
|
51
51
|
3. **Scope files** — run `git diff --name-only HEAD` to get the files modified in this change.
|
|
52
52
|
|
|
53
|
-
4. **Cross-skill memory** —
|
|
54
|
-
- `commandsRun` — the test command(s) already executed by the tester. Include in the briefing so the validator uses the same command without re-discovering it.
|
|
55
|
-
- `criteriaRun` — the CA-XX/CR-XX already tested. Include in the briefing so the validator can skip re-reading specs for those criteria.
|
|
56
|
-
If the file does not exist, omit these fields — do not block (CR-04).
|
|
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).
|
|
57
54
|
|
|
58
55
|
Build the BRIEFING block:
|
|
59
56
|
|