specatlas 0.1.15 → 0.1.16
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/dist/bin.js +74 -12
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -8976,6 +8976,7 @@ import path13 from "path";
|
|
|
8976
8976
|
import path14 from "path";
|
|
8977
8977
|
import path15 from "path";
|
|
8978
8978
|
import { promises as fs } from "fs";
|
|
8979
|
+
import { cp, rename, rm } from "fs/promises";
|
|
8979
8980
|
import path16 from "path";
|
|
8980
8981
|
import path17 from "path";
|
|
8981
8982
|
import path18 from "path";
|
|
@@ -9620,12 +9621,12 @@ function lintDelta(delta, livingRequirements, path192, opts = {}) {
|
|
|
9620
9621
|
out.push(diag("TRACE-007", "error", `REMOVED ${req.id} no existe en la spec viva`, { path: path192, line: req.line }));
|
|
9621
9622
|
}
|
|
9622
9623
|
}
|
|
9623
|
-
for (const
|
|
9624
|
-
if (
|
|
9625
|
-
out.push(diag("LINT-DLT-003", "error", `RENAMED cambia el id (${
|
|
9624
|
+
for (const rename2 of delta.renamed) {
|
|
9625
|
+
if (rename2.from.id !== rename2.to.id) {
|
|
9626
|
+
out.push(diag("LINT-DLT-003", "error", `RENAMED cambia el id (${rename2.from.id} \u2192 ${rename2.to.id}); los ids son inmutables`, { path: path192, line: rename2.line }));
|
|
9626
9627
|
}
|
|
9627
|
-
if (!livingRequirements.has(
|
|
9628
|
-
out.push(diag("TRACE-007", "error", `RENAMED ${
|
|
9628
|
+
if (!livingRequirements.has(rename2.from.id)) {
|
|
9629
|
+
out.push(diag("TRACE-007", "error", `RENAMED ${rename2.from.id} no existe en la spec viva`, { path: path192, line: rename2.line }));
|
|
9629
9630
|
}
|
|
9630
9631
|
}
|
|
9631
9632
|
return out;
|
|
@@ -12539,16 +12540,16 @@ function foldDelta(livingBody, delta, language = "es") {
|
|
|
12539
12540
|
lines = [...lines.slice(0, range.start), ...lines.slice(range.end)];
|
|
12540
12541
|
applied.removed.push(req.id);
|
|
12541
12542
|
}
|
|
12542
|
-
for (const
|
|
12543
|
-
const range = findRange(
|
|
12543
|
+
for (const rename2 of delta.renamed) {
|
|
12544
|
+
const range = findRange(rename2.from.id);
|
|
12544
12545
|
if (!range) {
|
|
12545
|
-
diagnostics.push(diag("TRACE-007", "error", `No se puede renombrar ${
|
|
12546
|
+
diagnostics.push(diag("TRACE-007", "error", `No se puede renombrar ${rename2.from.id}: no existe en la spec viva`, { path: delta.path, line: rename2.line }));
|
|
12546
12547
|
continue;
|
|
12547
12548
|
}
|
|
12548
12549
|
const header = lines[range.start] ?? "";
|
|
12549
12550
|
const label = /Requirement/i.test(header) ? "Requirement" : "Requisito";
|
|
12550
|
-
lines[range.start] = header.replace(REQ_HEADER_RE, (_match, id) => `### ${label}: ${id} \u2014 ${
|
|
12551
|
-
applied.renamed.push(
|
|
12551
|
+
lines[range.start] = header.replace(REQ_HEADER_RE, (_match, id) => `### ${label}: ${id} \u2014 ${rename2.to.title}`);
|
|
12552
|
+
applied.renamed.push(rename2.from.id);
|
|
12552
12553
|
}
|
|
12553
12554
|
for (const req of delta.added) {
|
|
12554
12555
|
const rendered = renderRequirement(req, language);
|
|
@@ -12563,6 +12564,46 @@ function trimTrailingBlanks(lines) {
|
|
|
12563
12564
|
while (out.length > 0 && (out[out.length - 1] ?? "").trim() === "") out.pop();
|
|
12564
12565
|
return out;
|
|
12565
12566
|
}
|
|
12567
|
+
var TRANSIENT_MOVE_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "ENOTEMPTY", "EACCES"]);
|
|
12568
|
+
function delay(ms) {
|
|
12569
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
12570
|
+
}
|
|
12571
|
+
async function moveDirectory(from, to, ops = {}) {
|
|
12572
|
+
const doRename = ops.rename ?? rename;
|
|
12573
|
+
const doCopy = ops.cp ?? cp;
|
|
12574
|
+
const doRemove = ops.rm ?? rm;
|
|
12575
|
+
let lastError;
|
|
12576
|
+
for (let attempt = 1; attempt <= 3; attempt += 1) {
|
|
12577
|
+
try {
|
|
12578
|
+
await doRename(from, to);
|
|
12579
|
+
return { strategy: "rename" };
|
|
12580
|
+
} catch (error) {
|
|
12581
|
+
lastError = error;
|
|
12582
|
+
const code = error.code ?? "";
|
|
12583
|
+
if (!TRANSIENT_MOVE_CODES.has(code)) throw error;
|
|
12584
|
+
await delay(250 * attempt);
|
|
12585
|
+
}
|
|
12586
|
+
}
|
|
12587
|
+
await doCopy(from, to, { recursive: true, force: true });
|
|
12588
|
+
for (let attempt = 1; attempt <= 3; attempt += 1) {
|
|
12589
|
+
try {
|
|
12590
|
+
await doRemove(from, { recursive: true, force: true, maxRetries: 2 });
|
|
12591
|
+
return { strategy: "copy" };
|
|
12592
|
+
} catch (error) {
|
|
12593
|
+
lastError = error;
|
|
12594
|
+
await delay(350 * attempt);
|
|
12595
|
+
}
|
|
12596
|
+
}
|
|
12597
|
+
await doRemove(to, { recursive: true, force: true }).catch(() => void 0);
|
|
12598
|
+
throw lastError;
|
|
12599
|
+
}
|
|
12600
|
+
async function restoreFile(file, previous) {
|
|
12601
|
+
try {
|
|
12602
|
+
if (previous === void 0) await fs.rm(file, { force: true });
|
|
12603
|
+
else await writeText(file, previous);
|
|
12604
|
+
} catch {
|
|
12605
|
+
}
|
|
12606
|
+
}
|
|
12566
12607
|
async function archiveChange(opts) {
|
|
12567
12608
|
const root = path16.resolve(opts.root);
|
|
12568
12609
|
const diagnostics = [];
|
|
@@ -12587,7 +12628,17 @@ async function archiveChange(opts) {
|
|
|
12587
12628
|
}
|
|
12588
12629
|
if (!opts.dryRun) {
|
|
12589
12630
|
await ensureDir(path16.dirname(targetFix));
|
|
12590
|
-
|
|
12631
|
+
try {
|
|
12632
|
+
await moveDirectory(change.dir, targetFix);
|
|
12633
|
+
} catch (error) {
|
|
12634
|
+
diagnostics.push(
|
|
12635
|
+
diag("ATLAS-ARCH-004", "error", `No se pudo mover el cambio al hist\xF3rico: ${error.message}`, {
|
|
12636
|
+
path: change.dir,
|
|
12637
|
+
suggestion: "Cierra las pesta\xF1as con archivos de este cambio (y espera unos segundos si OneDrive est\xE1 sincronizando) y vuelve a intentar"
|
|
12638
|
+
})
|
|
12639
|
+
);
|
|
12640
|
+
return { slug: opts.slug, fold: emptyFold, diagnostics, dryRun: false };
|
|
12641
|
+
}
|
|
12591
12642
|
await regenerateIndex(root, config);
|
|
12592
12643
|
}
|
|
12593
12644
|
return { slug: opts.slug, archivedTo: targetFix, fold: emptyFold, diagnostics, dryRun: opts.dryRun ?? false };
|
|
@@ -12640,7 +12691,18 @@ ${body}`;
|
|
|
12640
12691
|
if (!opts.dryRun) {
|
|
12641
12692
|
await writeText(specFile, nextContent);
|
|
12642
12693
|
await ensureDir(archiveDir);
|
|
12643
|
-
|
|
12694
|
+
try {
|
|
12695
|
+
await moveDirectory(change.dir, target);
|
|
12696
|
+
} catch (error) {
|
|
12697
|
+
await restoreFile(specFile, existing);
|
|
12698
|
+
diagnostics.push(
|
|
12699
|
+
diag("ATLAS-ARCH-004", "error", `No se pudo mover el cambio al hist\xF3rico: ${error.message}`, {
|
|
12700
|
+
path: change.dir,
|
|
12701
|
+
suggestion: "Cierra las pesta\xF1as con archivos de este cambio (y espera unos segundos si OneDrive est\xE1 sincronizando) y vuelve a intentar; el cambio y la spec viva quedaron como estaban"
|
|
12702
|
+
})
|
|
12703
|
+
);
|
|
12704
|
+
return { slug: opts.slug, domain, fold, diagnostics, dryRun: false };
|
|
12705
|
+
}
|
|
12644
12706
|
await regenerateIndex(root, config, now);
|
|
12645
12707
|
}
|
|
12646
12708
|
return { slug: opts.slug, domain, archivedTo: target, fold, diagnostics, dryRun: opts.dryRun ?? false };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specatlas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "SpecAtlas: kernel determinista de Spec-Driven Development (CLI)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@specatlas/adapters": "0.1.1",
|
|
43
|
-
"@specatlas/core": "0.1.
|
|
43
|
+
"@specatlas/core": "0.1.13"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"typecheck": "tsc --noEmit",
|