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 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 = process.cwd();
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.19.0
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();
@@ -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 cmdList(argv) {
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 || (major === 20 && minor < 19)) {
300
+ if (major < 20) {
301
301
  console.log(`\n ADVERTENCIA: Node.js ${version} detectado.`);
302
- console.log(' refacil-sdd-ai requiere Node.js >= 20.19.0.');
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.0",
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"
@@ -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: Write memory.yaml (CA-16 — cross-skill state)
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
- ```yaml
109
- lastStep: apply
110
- touchedFiles:
111
- - path/file-1.ts
112
- - path/file-2.ts
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
- If the file already exists, merge: update `lastStep` and `touchedFiles`; do not remove fields set by other steps (e.g. `commandsRun` from test).
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 the write and wait for user instructions.
116
+ If `result` is `"FAILED"`, skip and wait for user instructions.
118
117
 
119
118
  ### Step 3: Present result and next step
120
119
 
@@ -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 → Manual archiving (no `sdd archive` CLI)
64
+ ### Step 2A: Bug fix → Archive with native CLI
65
65
 
66
- Bug fixes only contain `summary.md` (and optionally `.review-passed`); they are not full proposal/spec/design/task trees. Archive them with **git mv** / **mv** per the steps below **do not** use `refacil-sdd-ai sdd archive` for these folders.
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. **Delete memory.yaml if present** (CA-18): run `rm -f "refacil-sdd/changes/[fix-name]/memory.yaml"` before moving the folder.
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. **Move to archive (move operation, not copy)**: transfer the full fix folder from `refacil-sdd/changes/[fix-name]/` to `refacil-sdd/changes/archive/[ISO-date]-[fix-name]/`. The source folder **must be eliminated** when done.
71
-
72
- Recommended execution order (deterministic and cross-platform):
73
- 1. Ensure the `refacil-sdd/changes/archive/` directory exists (create if not present).
74
- 2. Prefer an **atomic move** with `git mv "refacil-sdd/changes/[fix-name]" "refacil-sdd/changes/archive/[ISO-date]-[fix-name]"` when the fix is already under git control (moves and stages at once).
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**: Read the `summary.md` and `.review-passed` from the fix (from the **archived** path at `refacil-sdd/changes/archive/[ISO-date]-[fix-name]/`, no longer from the original path), and create an individual spec for the bug at `refacil-sdd/specs/[descriptive-name]/spec.md`.
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 `refacil-sdd/specs/[descriptive-name]/review.yaml` with the fields from `.review-passed` plus the Jira links from Step 1.5:
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. **Delete memory.yaml if present** (CA-18): before running the CLI archive, delete `refacil-sdd/changes/<changeName>/memory.yaml` if it exists run `rm -f "refacil-sdd/changes/<changeName>/memory.yaml"`. This is part of the archive cleanup.
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
- 6. Continue to **Step 3**.
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
- - `refacil-sdd/changes/[original-name]/` **must NOT exist** (only the archived version must survive in `refacil-sdd/changes/archive/...`).
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. Inform and ask for a task identifier (Jira or other).
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. Create the working branch:
68
- - Feature: `feature/<ID>`
69
- - Bugfix: `fix/<ID>`
70
- - Without ID: short descriptive name and recommend creating a ticket.
71
- 6. Restore `stash` if used.
72
- 7. If the user does not approve the process, stop.
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
 
@@ -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: Change folder identifier (blocking)
36
+ ### Step 1.5: Validate change name (blocking)
37
37
 
38
- The `refacil-sdd/changes/<name>/` directory **cannot** use a `<name>` whose **first character is not an ASCII letter** `[a-zA-Z]` — see **`refacil-prereqs/METHODOLOGY-CONTRACT.md` §9**. Names like `2026-04-17-expose-something` cause `refacil-sdd-ai sdd status <name>` and other SDD commands to fail.
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
- **Before delegating to the sub-agent:**
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
- 1. Agree on or derive the **final slug** of the change (kebab-case: `feat-...`, `expose-...`, `imp-...`, etc.). Dates or tickets do not go at the **start** of the name.
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 comply with **§9** of the methodology contract (first character ASCII letter; never start with a digit). Validate BEFORE delegating.
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`.)
@@ -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** — if `changeName` is not null and `refacil-sdd/changes/<changeName>/memory.yaml` exists, read it and extract `stackDetected`, `touchedFiles`. Include them in the briefing so the auditor skips re-discovery. If the file does not exist, omit — do not block (CR-04).
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
- - Write `refacil-sdd/changes/<changeName>/.review-last-fails.json` with content: `{ "failedFiles": [...] }` using the `failedFiles` array from the JSON block.
111
- - If `changeName` is null or `failedFiles` is absent: skip silently — existing behavior unchanged.
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
- - If `refacil-sdd/changes/<changeName>/.review-last-fails.json` exists: delete it (CA-08) — run `rm -f "refacil-sdd/changes/<changeName>/.review-last-fails.json"`.
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
- Once the corrections are applied, the next step is to re-verify the implementation.
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**: if the user confirms affirmatively ("yes", "ok", "go", "continue", etc.) the continuity question, immediately invoke the corresponding **Skill tool**: `skill: "refacil:archive"` if the verdict is APROBADO/APROBADO CON OBSERVACIONES, or `skill: "refacil:verify"` if REQUIERE CORRECCIONES. (See `METHODOLOGY-CONTRACT.md §5`.)
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`.)
@@ -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: Write memory.yaml (CA-16 — cross-skill state)
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` (list of test commands executed), `criteriaRun` (list of CA-XX/CR-XX covered by tests), `stackDetected` (if the tester identified the stack).
76
- - Write or update `refacil-sdd/changes/<changeName>/memory.yaml` preserving any existing fields:
77
-
78
- ```yaml
79
- lastStep: test
80
- stackDetected: <detected stack or omit>
81
- commandsRun:
82
- - <test command used>
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 the file already exists, merge: update `lastStep`, `stackDetected`, `commandsRun`, `criteriaRun`; preserve fields from other steps (e.g. `touchedFiles` from apply).
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
 
@@ -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** — if `changeName` is not null and `refacil-sdd/changes/<changeName>/memory.yaml` exists, read it and extract:
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