refacil-sdd-ai 4.5.7 → 4.5.8
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/lib/commands/sdd.js +111 -18
- package/package.json +1 -1
- package/skills/archive/SKILL.md +3 -1
package/lib/commands/sdd.js
CHANGED
|
@@ -62,6 +62,47 @@ function validateChangeName(name) {
|
|
|
62
62
|
return { valid: true };
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
function resolveExistingChangeName(projectRoot, inputName) {
|
|
66
|
+
if (!inputName || typeof inputName !== 'string') {
|
|
67
|
+
return { ok: false, reason: 'El nombre del cambio no puede estar vacío.' };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const normalizedInput = inputName.trim();
|
|
71
|
+
const lowerInput = normalizedInput.toLowerCase();
|
|
72
|
+
const changesDir = path.join(projectRoot, 'refacil-sdd', 'changes');
|
|
73
|
+
|
|
74
|
+
// Keep backward-compatible behavior when directory doesn't exist yet.
|
|
75
|
+
if (!fs.existsSync(changesDir)) {
|
|
76
|
+
return { ok: true, name: lowerInput };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const entries = fs.readdirSync(changesDir, { withFileTypes: true })
|
|
80
|
+
.filter((e) => e.isDirectory() && e.name !== 'archive')
|
|
81
|
+
.map((e) => e.name);
|
|
82
|
+
|
|
83
|
+
if (entries.includes(normalizedInput)) {
|
|
84
|
+
return { ok: true, name: normalizedInput };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (entries.includes(lowerInput)) {
|
|
88
|
+
return { ok: true, name: lowerInput };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const ciMatches = entries.filter((n) => n.toLowerCase() === lowerInput);
|
|
92
|
+
if (ciMatches.length === 1) {
|
|
93
|
+
return { ok: true, name: ciMatches[0] };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (ciMatches.length > 1) {
|
|
97
|
+
return {
|
|
98
|
+
ok: false,
|
|
99
|
+
reason: `Nombre de cambio ambiguo: '${inputName}'. Coincidencias: ${ciMatches.join(', ')}`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return { ok: true, name: lowerInput };
|
|
104
|
+
}
|
|
105
|
+
|
|
65
106
|
function autoMigrateOpenspec(root) {
|
|
66
107
|
const oldDir = path.join(root, 'openspec');
|
|
67
108
|
const newDir = path.join(root, 'refacil-sdd');
|
|
@@ -180,7 +221,15 @@ function cmdNewChange(argv, projectRoot) {
|
|
|
180
221
|
|
|
181
222
|
function cmdArchive(argv, projectRoot) {
|
|
182
223
|
const args = parseArgs(argv);
|
|
183
|
-
const
|
|
224
|
+
const rawName = args._positional[0];
|
|
225
|
+
|
|
226
|
+
autoMigrateOpenspec(projectRoot);
|
|
227
|
+
const resolved = resolveExistingChangeName(projectRoot, rawName);
|
|
228
|
+
if (!resolved.ok) {
|
|
229
|
+
console.error(resolved.reason);
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
const name = resolved.name;
|
|
184
233
|
|
|
185
234
|
const validation = validateChangeName(name);
|
|
186
235
|
if (!validation.valid) {
|
|
@@ -188,8 +237,6 @@ function cmdArchive(argv, projectRoot) {
|
|
|
188
237
|
process.exit(1);
|
|
189
238
|
}
|
|
190
239
|
|
|
191
|
-
autoMigrateOpenspec(projectRoot);
|
|
192
|
-
|
|
193
240
|
const sourceDir = path.join(projectRoot, 'refacil-sdd', 'changes', name);
|
|
194
241
|
if (!fs.existsSync(sourceDir)) {
|
|
195
242
|
console.error(`No existe el cambio '${name}' en refacil-sdd/changes/${name}/`);
|
|
@@ -222,14 +269,21 @@ function cmdArchive(argv, projectRoot) {
|
|
|
222
269
|
|
|
223
270
|
function cmdSetMemory(argv, projectRoot) {
|
|
224
271
|
const args = parseArgs(argv);
|
|
225
|
-
const
|
|
272
|
+
const rawName = args._positional[0];
|
|
226
273
|
|
|
227
|
-
if (!
|
|
274
|
+
if (!rawName) {
|
|
228
275
|
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
276
|
process.exit(1);
|
|
230
277
|
}
|
|
231
278
|
|
|
232
279
|
const root = projectRoot;
|
|
280
|
+
autoMigrateOpenspec(root);
|
|
281
|
+
const resolved = resolveExistingChangeName(root, rawName);
|
|
282
|
+
if (!resolved.ok) {
|
|
283
|
+
console.error(resolved.reason);
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
286
|
+
const name = resolved.name;
|
|
233
287
|
|
|
234
288
|
// Guard: ensure the change directory exists before any file operation
|
|
235
289
|
const changeDir = path.join(root, 'refacil-sdd', 'changes', name);
|
|
@@ -274,15 +328,22 @@ function cmdSetMemory(argv, projectRoot) {
|
|
|
274
328
|
|
|
275
329
|
function cmdGetMemory(argv, projectRoot) {
|
|
276
330
|
const args = parseArgs(argv);
|
|
277
|
-
const
|
|
331
|
+
const rawName = args._positional[0];
|
|
278
332
|
const wantJson = args.json === true;
|
|
279
333
|
|
|
280
|
-
if (!
|
|
334
|
+
if (!rawName) {
|
|
281
335
|
console.error('Uso: refacil-sdd-ai sdd get-memory <nombre-cambio> [--json]');
|
|
282
336
|
process.exit(1);
|
|
283
337
|
}
|
|
284
338
|
|
|
285
339
|
const root = projectRoot;
|
|
340
|
+
autoMigrateOpenspec(root);
|
|
341
|
+
const resolved = resolveExistingChangeName(root, rawName);
|
|
342
|
+
if (!resolved.ok) {
|
|
343
|
+
console.error(resolved.reason);
|
|
344
|
+
process.exit(1);
|
|
345
|
+
}
|
|
346
|
+
const name = resolved.name;
|
|
286
347
|
const memoryPath = path.join(root, 'refacil-sdd', 'changes', name, 'memory.yaml');
|
|
287
348
|
|
|
288
349
|
if (!fs.existsSync(memoryPath)) {
|
|
@@ -309,14 +370,21 @@ function cmdGetMemory(argv, projectRoot) {
|
|
|
309
370
|
|
|
310
371
|
function cmdSetReviewFails(argv, projectRoot) {
|
|
311
372
|
const args = parseArgs(argv);
|
|
312
|
-
const
|
|
373
|
+
const rawName = args._positional[0];
|
|
313
374
|
|
|
314
|
-
if (!
|
|
375
|
+
if (!rawName) {
|
|
315
376
|
console.error('Uso: refacil-sdd-ai sdd set-review-fails <nombre-cambio> --files <csv>');
|
|
316
377
|
process.exit(1);
|
|
317
378
|
}
|
|
318
379
|
|
|
319
380
|
const root = projectRoot;
|
|
381
|
+
autoMigrateOpenspec(root);
|
|
382
|
+
const resolved = resolveExistingChangeName(root, rawName);
|
|
383
|
+
if (!resolved.ok) {
|
|
384
|
+
console.error(resolved.reason);
|
|
385
|
+
process.exit(1);
|
|
386
|
+
}
|
|
387
|
+
const name = resolved.name;
|
|
320
388
|
const changeDir = path.join(root, 'refacil-sdd', 'changes', name);
|
|
321
389
|
if (!fs.existsSync(changeDir)) {
|
|
322
390
|
console.error(`No existe el cambio '${name}' en refacil-sdd/changes/${name}/`);
|
|
@@ -334,14 +402,21 @@ function cmdSetReviewFails(argv, projectRoot) {
|
|
|
334
402
|
|
|
335
403
|
function cmdClearReviewFails(argv, projectRoot) {
|
|
336
404
|
const args = parseArgs(argv);
|
|
337
|
-
const
|
|
405
|
+
const rawName = args._positional[0];
|
|
338
406
|
|
|
339
|
-
if (!
|
|
407
|
+
if (!rawName) {
|
|
340
408
|
console.error('Uso: refacil-sdd-ai sdd clear-review-fails <nombre-cambio>');
|
|
341
409
|
process.exit(1);
|
|
342
410
|
}
|
|
343
411
|
|
|
344
412
|
const root = projectRoot;
|
|
413
|
+
autoMigrateOpenspec(root);
|
|
414
|
+
const resolved = resolveExistingChangeName(root, rawName);
|
|
415
|
+
if (!resolved.ok) {
|
|
416
|
+
console.error(resolved.reason);
|
|
417
|
+
process.exit(1);
|
|
418
|
+
}
|
|
419
|
+
const name = resolved.name;
|
|
345
420
|
const reviewFailsPath = path.join(root, 'refacil-sdd', 'changes', name, '.review-last-fails.json');
|
|
346
421
|
|
|
347
422
|
if (fs.existsSync(reviewFailsPath)) {
|
|
@@ -392,15 +467,21 @@ function cmdList(argv, projectRoot) {
|
|
|
392
467
|
|
|
393
468
|
function cmdStatus(argv, projectRoot) {
|
|
394
469
|
const args = parseArgs(argv);
|
|
395
|
-
const
|
|
470
|
+
const rawName = args._positional[0];
|
|
396
471
|
const wantJson = args.json === true;
|
|
397
472
|
|
|
398
|
-
if (!
|
|
473
|
+
if (!rawName) {
|
|
399
474
|
console.error('Uso: refacil-sdd-ai sdd status <nombre-cambio> [--json]');
|
|
400
475
|
process.exit(1);
|
|
401
476
|
}
|
|
402
477
|
|
|
403
478
|
autoMigrateOpenspec(projectRoot);
|
|
479
|
+
const resolved = resolveExistingChangeName(projectRoot, rawName);
|
|
480
|
+
if (!resolved.ok) {
|
|
481
|
+
console.error(resolved.reason);
|
|
482
|
+
process.exit(1);
|
|
483
|
+
}
|
|
484
|
+
const name = resolved.name;
|
|
404
485
|
|
|
405
486
|
const changeDir = path.join(projectRoot, 'refacil-sdd', 'changes', name);
|
|
406
487
|
if (!fs.existsSync(changeDir)) {
|
|
@@ -481,9 +562,9 @@ function cmdStatus(argv, projectRoot) {
|
|
|
481
562
|
|
|
482
563
|
function cmdMarkReviewed(argv, projectRoot) {
|
|
483
564
|
const args = parseArgs(argv);
|
|
484
|
-
const
|
|
565
|
+
const rawName = args._positional[0];
|
|
485
566
|
|
|
486
|
-
if (!
|
|
567
|
+
if (!rawName) {
|
|
487
568
|
console.error('Uso: refacil-sdd-ai sdd mark-reviewed <nombre-cambio> --verdict <verdict> --summary "<resumen>" [--fail-count N] [--preexisting-count N] [--blockers]');
|
|
488
569
|
process.exit(1);
|
|
489
570
|
}
|
|
@@ -499,6 +580,12 @@ function cmdMarkReviewed(argv, projectRoot) {
|
|
|
499
580
|
}
|
|
500
581
|
|
|
501
582
|
autoMigrateOpenspec(projectRoot);
|
|
583
|
+
const resolved = resolveExistingChangeName(projectRoot, rawName);
|
|
584
|
+
if (!resolved.ok) {
|
|
585
|
+
console.error(resolved.reason);
|
|
586
|
+
process.exit(1);
|
|
587
|
+
}
|
|
588
|
+
const name = resolved.name;
|
|
502
589
|
|
|
503
590
|
const changeDir = path.join(projectRoot, 'refacil-sdd', 'changes', name);
|
|
504
591
|
if (!fs.existsSync(changeDir)) {
|
|
@@ -522,9 +609,9 @@ function cmdMarkReviewed(argv, projectRoot) {
|
|
|
522
609
|
|
|
523
610
|
function cmdTasksUpdate(argv, projectRoot) {
|
|
524
611
|
const args = parseArgs(argv);
|
|
525
|
-
const
|
|
612
|
+
const rawName = args._positional[0];
|
|
526
613
|
|
|
527
|
-
if (!
|
|
614
|
+
if (!rawName) {
|
|
528
615
|
console.error('Uso: refacil-sdd-ai sdd tasks-update <nombre-cambio> --task N --done');
|
|
529
616
|
process.exit(1);
|
|
530
617
|
}
|
|
@@ -541,6 +628,12 @@ function cmdTasksUpdate(argv, projectRoot) {
|
|
|
541
628
|
}
|
|
542
629
|
|
|
543
630
|
autoMigrateOpenspec(projectRoot);
|
|
631
|
+
const resolved = resolveExistingChangeName(projectRoot, rawName);
|
|
632
|
+
if (!resolved.ok) {
|
|
633
|
+
console.error(resolved.reason);
|
|
634
|
+
process.exit(1);
|
|
635
|
+
}
|
|
636
|
+
const name = resolved.name;
|
|
544
637
|
|
|
545
638
|
const tasksFile = path.join(projectRoot, 'refacil-sdd', 'changes', name, 'tasks.md');
|
|
546
639
|
if (!fs.existsSync(tasksFile)) {
|
|
@@ -661,4 +754,4 @@ function handleSdd(sub, argv, projectRoot) {
|
|
|
661
754
|
}
|
|
662
755
|
}
|
|
663
756
|
|
|
664
|
-
module.exports = { handleSdd, parseArgs, autoMigrateOpenspec, validateChangeName, findProjectRoot };
|
|
757
|
+
module.exports = { handleSdd, parseArgs, autoMigrateOpenspec, validateChangeName, resolveExistingChangeName, findProjectRoot };
|
package/package.json
CHANGED
package/skills/archive/SKILL.md
CHANGED
|
@@ -22,7 +22,7 @@ Verify the change is truly complete:
|
|
|
22
22
|
|
|
23
23
|
2. **Tests pass**: Resolve and run the test command according to `refacil-prereqs/METHODOLOGY-CONTRACT.md`. If there are failing tests, inform and ask if they want to continue.
|
|
24
24
|
|
|
25
|
-
3. **
|
|
25
|
+
3. **Working tree scope hygiene**: Run `git status` and check whether there are files unrelated to the current change scope. It is expected to have uncommitted changes in this step. If unrelated files are detected, warn the user and ask whether to continue archiving anyway. Do not suggest commit in this step; commit/push decisions are handled in `refacil:up-code`.
|
|
26
26
|
|
|
27
27
|
4. **Review approved (blocking)**: Verify that the `.review-passed` file exists in the change folder (`refacil-sdd/changes/[change-name]/.review-passed`) following **`METHODOLOGY-CONTRACT.md` §8** (dotfile; do not conclude by listings without dotfiles). If it does NOT exist, **stop the archiving** and inform the user:
|
|
28
28
|
```
|
|
@@ -126,6 +126,8 @@ Bug fixes only contain `summary.md` (and optionally `.review-passed`). The CLI `
|
|
|
126
126
|
|
|
127
127
|
The spec and review evidence are written **before** running the CLI archive command, while the artifacts are still at their original paths. The CLI only moves the folder — it never syncs specs.
|
|
128
128
|
|
|
129
|
+
`refacil-sdd-ai sdd archive` normalizes the provided `changeName` to lowercase before validation/path resolution. Prefer lowercase names for consistency across commands and records.
|
|
130
|
+
|
|
129
131
|
1. **Sync spec to `refacil-sdd/specs/` (before archiving)**:
|
|
130
132
|
- Read `refacil-sdd/changes/<changeName>/specs.md` (and all `.md` under `specs/` if that subfolder exists).
|
|
131
133
|
- Determine the spec folder name: use `<changeName>` unless a more descriptive name is clearly better.
|