@specatlas/core 0.1.12 → 0.1.14
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/index.d.ts +11 -1
- package/dist/index.js +149 -12
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { rename, cp, rm } from 'node:fs/promises';
|
|
2
3
|
export { defaultTokens, renderDocument, renderStyles } from '@specatlas/render';
|
|
3
4
|
|
|
4
5
|
declare const CORE_VERSION = "0.0.1";
|
|
@@ -809,6 +810,7 @@ declare function lintRequirement(req: Requirement, path: string, opts?: LintOpti
|
|
|
809
810
|
declare function lintDelta(delta: Delta, livingRequirements: Map<string, Requirement>, path: string, opts?: LintOptions): Diagnostic[];
|
|
810
811
|
declare function lintTasks(_tasks: TasksFile): Diagnostic[];
|
|
811
812
|
declare function lintVerify(_verify: VerifyFile): Diagnostic[];
|
|
813
|
+
declare function lintPlan(planText: string, path: string): Diagnostic[];
|
|
812
814
|
declare function lintSpec(spec: SpecFile, opts?: LintOptions): Diagnostic[];
|
|
813
815
|
|
|
814
816
|
interface TraceNode {
|
|
@@ -1643,6 +1645,14 @@ interface FoldOutcome {
|
|
|
1643
1645
|
diagnostics: Diagnostic[];
|
|
1644
1646
|
}
|
|
1645
1647
|
declare function foldDelta(livingBody: string, delta: Delta, language?: Language): FoldOutcome;
|
|
1648
|
+
interface MoveOps {
|
|
1649
|
+
rename?: typeof rename;
|
|
1650
|
+
cp?: typeof cp;
|
|
1651
|
+
rm?: typeof rm;
|
|
1652
|
+
}
|
|
1653
|
+
declare function moveDirectory(from: string, to: string, ops?: MoveOps): Promise<{
|
|
1654
|
+
strategy: 'rename' | 'copy';
|
|
1655
|
+
}>;
|
|
1646
1656
|
interface ArchiveOptions {
|
|
1647
1657
|
root: string;
|
|
1648
1658
|
slug: string;
|
|
@@ -1700,4 +1710,4 @@ declare function livingRequirementsMap(specs: Array<{
|
|
|
1700
1710
|
}>): Map<string, Requirement>;
|
|
1701
1711
|
declare function runCiGate(opts: CiOptions): Promise<CiResult>;
|
|
1702
1712
|
|
|
1703
|
-
export { type AdoptDomain, type AdoptOptions, type AdoptResult, type AgingBucket, type AnalyzeOptions, type AnalyzePackSummary, type AnalyzeResult, type Approval, type ApprovalStatus, type ApprovalsFile, type ApprovalsIndex, type ApproveFromGithubOptions, type ApproveFromGithubResult, type ArchiveOptions, type ArchiveResult, type AtlasConfig, type AttentionItem, BLOCK_HEAD_RE, BUILTIN_PACKS, type BlockWavePlan, CONFIG_FILE, CORE_VERSION, type CaptureResult, type Change, type ChangeMeta, type ChangeMetrics, type ChangeState, type CiCheck, type CiExtraCheck, type CiOptions, type CiResult, type Delta, type DeltaOp, type DeriveInput, type DerivedState, type DetectionResult, type Diagnostic, type DoctorReport, type Domain, type Evidence, type EvidenceMethod, type EvidenceResult, type ExecOptions, type ExecResult, type FoldOutcome, type FrontmatterResult, type GhRunner, type GitHubRepo, type InitOptions, type InitResult, type IssueBodyInput, type Lane, type Language, type LinkedIssue, type LintOptions, type LoadedConfig, type MockupCheckResult, type MockupManifest, type MockupPlan, type MockupPlanScreen, type MockupScreen, type NewChangeOptions, type NewChangeResult, type NextAction, type Override, type Pack, type PackCheck, type PackCheckResult, type PackCheckType, type PackEvaluation, type PresentOptions, type PresentResult, type ProfileMatch, REQ_HEAD_RE, REQ_ID_RE, RULE_ID_RE, RULE_RE, RUN_EVENT_TYPES, type RecordEvidenceOptions, type RecordEvidenceResult, type Rename, type Requirement, type RiskLevel, type Rule, type RunEvent, type RunEventType, type RunRecord, type RunState, type RunStatus, SCENARIO_HEAD_RE, SCENARIO_ID_RE, SDD_DIR, SLUG_RE, type Scenario, type Severity, type SignApprovalOptions, type SignApprovalResult, type SpecFile, type SpecRef, type StackProfile, type SyncGithubOptions, type SyncGithubResult, TASK_ID_RE, TASK_LINE_RE, type Task, type TaskBlock, type TasksFile, type TemplateSet, type TraceEdge, type TraceFinding, type TraceGraph, type TraceInput, type TraceNode, type TraceResult, type VerifyFile, type WalkEntry, type WavePlan, type Workspace, type WorkspaceMetrics, adoptWorkspace, appendRunEvent, approvalsSchema, approveFromGithub, archiveChange, artifactHash, atlasConfigSchema, buildTraceGraph, canonicalizeMarkdown, captureMockups, changeMarker, changeMetaSchema, changeMetaYaml, checkMockups, checkTrace, collectMetrics, commentIssue, compareTaskIds, computeInputsHash, configToYaml, copyFile, countBySeverity, createChange, createIssue, createRun, defaultConfig, deriveState, detectProfiles, detectRepo, detectionToYaml, diag, editIssue, emitFrontmatter, ensureDir, ensureSddDirs, esc, evaluatePacks, evidenceSummary, exists, findLinkedIssue, findWorkspaceRoot, firstToken, foldDelta, generatePresentation, generateRunId, getNumber, getString, ghAuthStatus, ghAvailable, hasErrors, hasShellMetacharacters, indexMarkdown, initWorkspace, inline, isCommandAllowed, isDirectory, issueBody, issueLabels, laneOrDefault, lintDelta, lintMockupHtml, lintMockupManifest, lintRequirement, lintSpec, lintTasks, lintVerify, listChangeSlugs, listDir, listDirs, listRuns, livingRequirementsMap, loadActiveProfile, loadApprovals, loadChange, loadConfig, loadDetectedBest, loadProfileFile, loadProfilesFromDir, loadProjectPacks, loadSpecs, loadWorkspace, localCompact, localDate, localMonth, localOffset, localStamp, matchGlob, mockupManifestSchema, mockupsDir, mockupsReady, packFindings, parseApprovals, parseChangeMeta, parseConfig, parseDelta, parseFrontmatter, parseGitHubRemote, parseIssueUrl, parseRequirementBlocks, parseSpecFile, parseTasksFile, parseVerifyFile, patchChangeMeta, planBlock, planMockups, planWaves, profileSchema, readMockupManifest, readRun, readText, readTextIfExists, recordEvidence, regenerateIndex, renderMarkdown, renderRequirement, renderTemplate, requiresMockups, resolvePacks, runAnalyze, runCiGate, runDoctor, runProcess, setMockupRequirement, sha256, shortHash, signApproval, specHashOf, splitCommand, stateLabel, syncGithubIssue, templatesFor, toPosix, tokensFile, updateMockupScreenshots, updateRunStatus, verifyApproval, walkFiles, writeConfig, writeMockupManifest, writeMockupPlan, writeText };
|
|
1713
|
+
export { type AdoptDomain, type AdoptOptions, type AdoptResult, type AgingBucket, type AnalyzeOptions, type AnalyzePackSummary, type AnalyzeResult, type Approval, type ApprovalStatus, type ApprovalsFile, type ApprovalsIndex, type ApproveFromGithubOptions, type ApproveFromGithubResult, type ArchiveOptions, type ArchiveResult, type AtlasConfig, type AttentionItem, BLOCK_HEAD_RE, BUILTIN_PACKS, type BlockWavePlan, CONFIG_FILE, CORE_VERSION, type CaptureResult, type Change, type ChangeMeta, type ChangeMetrics, type ChangeState, type CiCheck, type CiExtraCheck, type CiOptions, type CiResult, type Delta, type DeltaOp, type DeriveInput, type DerivedState, type DetectionResult, type Diagnostic, type DoctorReport, type Domain, type Evidence, type EvidenceMethod, type EvidenceResult, type ExecOptions, type ExecResult, type FoldOutcome, type FrontmatterResult, type GhRunner, type GitHubRepo, type InitOptions, type InitResult, type IssueBodyInput, type Lane, type Language, type LinkedIssue, type LintOptions, type LoadedConfig, type MockupCheckResult, type MockupManifest, type MockupPlan, type MockupPlanScreen, type MockupScreen, type MoveOps, type NewChangeOptions, type NewChangeResult, type NextAction, type Override, type Pack, type PackCheck, type PackCheckResult, type PackCheckType, type PackEvaluation, type PresentOptions, type PresentResult, type ProfileMatch, REQ_HEAD_RE, REQ_ID_RE, RULE_ID_RE, RULE_RE, RUN_EVENT_TYPES, type RecordEvidenceOptions, type RecordEvidenceResult, type Rename, type Requirement, type RiskLevel, type Rule, type RunEvent, type RunEventType, type RunRecord, type RunState, type RunStatus, SCENARIO_HEAD_RE, SCENARIO_ID_RE, SDD_DIR, SLUG_RE, type Scenario, type Severity, type SignApprovalOptions, type SignApprovalResult, type SpecFile, type SpecRef, type StackProfile, type SyncGithubOptions, type SyncGithubResult, TASK_ID_RE, TASK_LINE_RE, type Task, type TaskBlock, type TasksFile, type TemplateSet, type TraceEdge, type TraceFinding, type TraceGraph, type TraceInput, type TraceNode, type TraceResult, type VerifyFile, type WalkEntry, type WavePlan, type Workspace, type WorkspaceMetrics, adoptWorkspace, appendRunEvent, approvalsSchema, approveFromGithub, archiveChange, artifactHash, atlasConfigSchema, buildTraceGraph, canonicalizeMarkdown, captureMockups, changeMarker, changeMetaSchema, changeMetaYaml, checkMockups, checkTrace, collectMetrics, commentIssue, compareTaskIds, computeInputsHash, configToYaml, copyFile, countBySeverity, createChange, createIssue, createRun, defaultConfig, deriveState, detectProfiles, detectRepo, detectionToYaml, diag, editIssue, emitFrontmatter, ensureDir, ensureSddDirs, esc, evaluatePacks, evidenceSummary, exists, findLinkedIssue, findWorkspaceRoot, firstToken, foldDelta, generatePresentation, generateRunId, getNumber, getString, ghAuthStatus, ghAvailable, hasErrors, hasShellMetacharacters, indexMarkdown, initWorkspace, inline, isCommandAllowed, isDirectory, issueBody, issueLabels, laneOrDefault, lintDelta, lintMockupHtml, lintMockupManifest, lintPlan, lintRequirement, lintSpec, lintTasks, lintVerify, listChangeSlugs, listDir, listDirs, listRuns, livingRequirementsMap, loadActiveProfile, loadApprovals, loadChange, loadConfig, loadDetectedBest, loadProfileFile, loadProfilesFromDir, loadProjectPacks, loadSpecs, loadWorkspace, localCompact, localDate, localMonth, localOffset, localStamp, matchGlob, mockupManifestSchema, mockupsDir, mockupsReady, moveDirectory, packFindings, parseApprovals, parseChangeMeta, parseConfig, parseDelta, parseFrontmatter, parseGitHubRemote, parseIssueUrl, parseRequirementBlocks, parseSpecFile, parseTasksFile, parseVerifyFile, patchChangeMeta, planBlock, planMockups, planWaves, profileSchema, readMockupManifest, readRun, readText, readTextIfExists, recordEvidence, regenerateIndex, renderMarkdown, renderRequirement, renderTemplate, requiresMockups, resolvePacks, runAnalyze, runCiGate, runDoctor, runProcess, setMockupRequirement, sha256, shortHash, signApproval, specHashOf, splitCommand, stateLabel, syncGithubIssue, templatesFor, toPosix, tokensFile, updateMockupScreenshots, updateRunStatus, verifyApproval, walkFiles, writeConfig, writeMockupManifest, writeMockupPlan, writeText };
|
package/dist/index.js
CHANGED
|
@@ -716,12 +716,12 @@ function lintDelta(delta, livingRequirements, path19, opts = {}) {
|
|
|
716
716
|
out.push(diag("TRACE-007", "error", `REMOVED ${req.id} no existe en la spec viva`, { path: path19, line: req.line }));
|
|
717
717
|
}
|
|
718
718
|
}
|
|
719
|
-
for (const
|
|
720
|
-
if (
|
|
721
|
-
out.push(diag("LINT-DLT-003", "error", `RENAMED cambia el id (${
|
|
719
|
+
for (const rename2 of delta.renamed) {
|
|
720
|
+
if (rename2.from.id !== rename2.to.id) {
|
|
721
|
+
out.push(diag("LINT-DLT-003", "error", `RENAMED cambia el id (${rename2.from.id} \u2192 ${rename2.to.id}); los ids son inmutables`, { path: path19, line: rename2.line }));
|
|
722
722
|
}
|
|
723
|
-
if (!livingRequirements.has(
|
|
724
|
-
out.push(diag("TRACE-007", "error", `RENAMED ${
|
|
723
|
+
if (!livingRequirements.has(rename2.from.id)) {
|
|
724
|
+
out.push(diag("TRACE-007", "error", `RENAMED ${rename2.from.id} no existe en la spec viva`, { path: path19, line: rename2.line }));
|
|
725
725
|
}
|
|
726
726
|
}
|
|
727
727
|
return out;
|
|
@@ -732,6 +732,71 @@ function lintTasks(_tasks) {
|
|
|
732
732
|
function lintVerify(_verify) {
|
|
733
733
|
return [];
|
|
734
734
|
}
|
|
735
|
+
var MERMAID_KEYWORDS = [
|
|
736
|
+
"flowchart",
|
|
737
|
+
"graph",
|
|
738
|
+
"sequenceDiagram",
|
|
739
|
+
"stateDiagram-v2",
|
|
740
|
+
"stateDiagram",
|
|
741
|
+
"classDiagram",
|
|
742
|
+
"erDiagram",
|
|
743
|
+
"journey",
|
|
744
|
+
"gantt",
|
|
745
|
+
"pie",
|
|
746
|
+
"mindmap",
|
|
747
|
+
"timeline",
|
|
748
|
+
"quadrantChart",
|
|
749
|
+
"xychart-beta",
|
|
750
|
+
"block-beta",
|
|
751
|
+
"architecture-beta"
|
|
752
|
+
];
|
|
753
|
+
var MERMAID_BLOCKS = /^\s*(alt|loop|opt|par|rect|critical|break|subgraph)\b/;
|
|
754
|
+
function lintPlan(planText, path19) {
|
|
755
|
+
const out = [];
|
|
756
|
+
const blocks = [...planText.matchAll(/```mermaid\r?\n([\s\S]*?)```/g)];
|
|
757
|
+
for (const [index, block] of blocks.entries()) {
|
|
758
|
+
const code = (block[1] ?? "").replace(/\r\n?/g, "\n");
|
|
759
|
+
const lines = code.split("\n");
|
|
760
|
+
const first = (lines.find((line) => line.trim().length > 0) ?? "").trim();
|
|
761
|
+
if (!MERMAID_KEYWORDS.some((keyword) => first.startsWith(keyword))) {
|
|
762
|
+
out.push(
|
|
763
|
+
diag("LINT-PLN-002", "error", `Diagrama mermaid ${index + 1}: la primera l\xEDnea debe declarar el tipo (${MERMAID_KEYWORDS.slice(0, 5).join(", ")}\u2026) y empieza por "${first.slice(0, 30)}"`, {
|
|
764
|
+
path: path19,
|
|
765
|
+
suggestion: "Corrige el tipo del diagrama o elimina el bloque"
|
|
766
|
+
})
|
|
767
|
+
);
|
|
768
|
+
continue;
|
|
769
|
+
}
|
|
770
|
+
let open = 0;
|
|
771
|
+
for (const line of lines) {
|
|
772
|
+
if (MERMAID_BLOCKS.test(line)) open += 1;
|
|
773
|
+
else if (/^\s*end\b/.test(line)) open -= 1;
|
|
774
|
+
}
|
|
775
|
+
if (open !== 0) {
|
|
776
|
+
out.push(
|
|
777
|
+
diag("LINT-PLN-002", "error", `Diagrama mermaid ${index + 1}: faltan ${Math.abs(open)} \`end\` (bloques alt/loop/subgraph sin cerrar)`, {
|
|
778
|
+
path: path19,
|
|
779
|
+
suggestion: "Cierra cada bloque alt/loop/opt/par/rect/subgraph con `end`"
|
|
780
|
+
})
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
if (first.startsWith("sequenceDiagram")) {
|
|
784
|
+
for (const line of lines) {
|
|
785
|
+
if (!/^\s*[^\s:]+-{1,2}>{1,2}[^\s:]*\s*:\s*/.test(line)) continue;
|
|
786
|
+
const message = line.slice(line.indexOf(":") + 1);
|
|
787
|
+
if (message.includes(";")) {
|
|
788
|
+
out.push(
|
|
789
|
+
diag("LINT-PLN-003", "error", `Diagrama mermaid ${index + 1}: el mensaje "${message.trim().slice(0, 40)}\u2026" usa \`;\` y mermaid lo interpreta como fin de sentencia`, {
|
|
790
|
+
path: path19,
|
|
791
|
+
suggestion: "Sustituye `;` por `\xB7` o `,` en los mensajes de sequenceDiagram"
|
|
792
|
+
})
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
return out;
|
|
799
|
+
}
|
|
735
800
|
function lintSpec(spec, opts = {}) {
|
|
736
801
|
const out = [...spec.diagnostics];
|
|
737
802
|
for (const req of spec.requirements) {
|
|
@@ -2903,6 +2968,10 @@ async function runAnalyze(opts) {
|
|
|
2903
2968
|
if (lane !== "fix" && !change.planPath) {
|
|
2904
2969
|
findings.push(diag("ATLAS-ANALYZE-001", "warning", "El cambio no tiene plan.md (plan t\xE9cnico)", { suggestion: "Ejecuta la fase /satlas-plan" }));
|
|
2905
2970
|
}
|
|
2971
|
+
if (change.planPath) {
|
|
2972
|
+
const planText = await readTextIfExists(change.planPath) ?? "";
|
|
2973
|
+
findings.push(...lintPlan(planText, change.planPath));
|
|
2974
|
+
}
|
|
2906
2975
|
const deltaScenarios = [...change.delta?.added ?? [], ...change.delta?.modified ?? []].flatMap((r) => r.scenarios);
|
|
2907
2976
|
const passed = new Set((change.verify?.evidence ?? []).filter((e) => e.result === "pass").map((e) => e.scenario));
|
|
2908
2977
|
const evidence = { done: deltaScenarios.filter((s) => passed.has(s.id)).length, total: deltaScenarios.length };
|
|
@@ -3700,6 +3769,7 @@ async function createChange(opts) {
|
|
|
3700
3769
|
|
|
3701
3770
|
// src/archive.ts
|
|
3702
3771
|
import { promises as fs } from "fs";
|
|
3772
|
+
import { cp, rename, rm } from "fs/promises";
|
|
3703
3773
|
import path16 from "path";
|
|
3704
3774
|
var REQ_HEADER_RE = /^###\s+(?:Requisito|Requirement):\s+(REQ-[A-Z0-9-]+)\s*(?:—|-|–)\s*(.*)$/;
|
|
3705
3775
|
function foldDelta(livingBody, delta, language = "es") {
|
|
@@ -3744,16 +3814,16 @@ function foldDelta(livingBody, delta, language = "es") {
|
|
|
3744
3814
|
lines = [...lines.slice(0, range.start), ...lines.slice(range.end)];
|
|
3745
3815
|
applied.removed.push(req.id);
|
|
3746
3816
|
}
|
|
3747
|
-
for (const
|
|
3748
|
-
const range = findRange(
|
|
3817
|
+
for (const rename2 of delta.renamed) {
|
|
3818
|
+
const range = findRange(rename2.from.id);
|
|
3749
3819
|
if (!range) {
|
|
3750
|
-
diagnostics.push(diag("TRACE-007", "error", `No se puede renombrar ${
|
|
3820
|
+
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 }));
|
|
3751
3821
|
continue;
|
|
3752
3822
|
}
|
|
3753
3823
|
const header = lines[range.start] ?? "";
|
|
3754
3824
|
const label = /Requirement/i.test(header) ? "Requirement" : "Requisito";
|
|
3755
|
-
lines[range.start] = header.replace(REQ_HEADER_RE, (_match, id) => `### ${label}: ${id} \u2014 ${
|
|
3756
|
-
applied.renamed.push(
|
|
3825
|
+
lines[range.start] = header.replace(REQ_HEADER_RE, (_match, id) => `### ${label}: ${id} \u2014 ${rename2.to.title}`);
|
|
3826
|
+
applied.renamed.push(rename2.from.id);
|
|
3757
3827
|
}
|
|
3758
3828
|
for (const req of delta.added) {
|
|
3759
3829
|
const rendered = renderRequirement(req, language);
|
|
@@ -3768,6 +3838,46 @@ function trimTrailingBlanks(lines) {
|
|
|
3768
3838
|
while (out.length > 0 && (out[out.length - 1] ?? "").trim() === "") out.pop();
|
|
3769
3839
|
return out;
|
|
3770
3840
|
}
|
|
3841
|
+
var TRANSIENT_MOVE_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "ENOTEMPTY", "EACCES"]);
|
|
3842
|
+
function delay(ms) {
|
|
3843
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3844
|
+
}
|
|
3845
|
+
async function moveDirectory(from, to, ops = {}) {
|
|
3846
|
+
const doRename = ops.rename ?? rename;
|
|
3847
|
+
const doCopy = ops.cp ?? cp;
|
|
3848
|
+
const doRemove = ops.rm ?? rm;
|
|
3849
|
+
let lastError;
|
|
3850
|
+
for (let attempt = 1; attempt <= 3; attempt += 1) {
|
|
3851
|
+
try {
|
|
3852
|
+
await doRename(from, to);
|
|
3853
|
+
return { strategy: "rename" };
|
|
3854
|
+
} catch (error) {
|
|
3855
|
+
lastError = error;
|
|
3856
|
+
const code = error.code ?? "";
|
|
3857
|
+
if (!TRANSIENT_MOVE_CODES.has(code)) throw error;
|
|
3858
|
+
await delay(250 * attempt);
|
|
3859
|
+
}
|
|
3860
|
+
}
|
|
3861
|
+
await doCopy(from, to, { recursive: true, force: true });
|
|
3862
|
+
for (let attempt = 1; attempt <= 3; attempt += 1) {
|
|
3863
|
+
try {
|
|
3864
|
+
await doRemove(from, { recursive: true, force: true, maxRetries: 2 });
|
|
3865
|
+
return { strategy: "copy" };
|
|
3866
|
+
} catch (error) {
|
|
3867
|
+
lastError = error;
|
|
3868
|
+
await delay(350 * attempt);
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
await doRemove(to, { recursive: true, force: true }).catch(() => void 0);
|
|
3872
|
+
throw lastError;
|
|
3873
|
+
}
|
|
3874
|
+
async function restoreFile(file, previous) {
|
|
3875
|
+
try {
|
|
3876
|
+
if (previous === void 0) await fs.rm(file, { force: true });
|
|
3877
|
+
else await writeText(file, previous);
|
|
3878
|
+
} catch {
|
|
3879
|
+
}
|
|
3880
|
+
}
|
|
3771
3881
|
async function archiveChange(opts) {
|
|
3772
3882
|
const root = path16.resolve(opts.root);
|
|
3773
3883
|
const diagnostics = [];
|
|
@@ -3792,7 +3902,17 @@ async function archiveChange(opts) {
|
|
|
3792
3902
|
}
|
|
3793
3903
|
if (!opts.dryRun) {
|
|
3794
3904
|
await ensureDir(path16.dirname(targetFix));
|
|
3795
|
-
|
|
3905
|
+
try {
|
|
3906
|
+
await moveDirectory(change.dir, targetFix);
|
|
3907
|
+
} catch (error) {
|
|
3908
|
+
diagnostics.push(
|
|
3909
|
+
diag("ATLAS-ARCH-004", "error", `No se pudo mover el cambio al hist\xF3rico: ${error.message}`, {
|
|
3910
|
+
path: change.dir,
|
|
3911
|
+
suggestion: "Cierra las pesta\xF1as con archivos de este cambio (y espera unos segundos si OneDrive est\xE1 sincronizando) y vuelve a intentar"
|
|
3912
|
+
})
|
|
3913
|
+
);
|
|
3914
|
+
return { slug: opts.slug, fold: emptyFold, diagnostics, dryRun: false };
|
|
3915
|
+
}
|
|
3796
3916
|
await regenerateIndex(root, config);
|
|
3797
3917
|
}
|
|
3798
3918
|
return { slug: opts.slug, archivedTo: targetFix, fold: emptyFold, diagnostics, dryRun: opts.dryRun ?? false };
|
|
@@ -3845,7 +3965,18 @@ ${body}`;
|
|
|
3845
3965
|
if (!opts.dryRun) {
|
|
3846
3966
|
await writeText(specFile, nextContent);
|
|
3847
3967
|
await ensureDir(archiveDir);
|
|
3848
|
-
|
|
3968
|
+
try {
|
|
3969
|
+
await moveDirectory(change.dir, target);
|
|
3970
|
+
} catch (error) {
|
|
3971
|
+
await restoreFile(specFile, existing);
|
|
3972
|
+
diagnostics.push(
|
|
3973
|
+
diag("ATLAS-ARCH-004", "error", `No se pudo mover el cambio al hist\xF3rico: ${error.message}`, {
|
|
3974
|
+
path: change.dir,
|
|
3975
|
+
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"
|
|
3976
|
+
})
|
|
3977
|
+
);
|
|
3978
|
+
return { slug: opts.slug, domain, fold, diagnostics, dryRun: false };
|
|
3979
|
+
}
|
|
3849
3980
|
await regenerateIndex(root, config, now);
|
|
3850
3981
|
}
|
|
3851
3982
|
return { slug: opts.slug, domain, archivedTo: target, fold, diagnostics, dryRun: opts.dryRun ?? false };
|
|
@@ -3954,6 +4085,10 @@ async function runCiGate(opts) {
|
|
|
3954
4085
|
requireEvidence: config.gates.verify.mode !== "off" && config.gates.verify.require_evidence
|
|
3955
4086
|
});
|
|
3956
4087
|
const changeDiags = [...lintFindings, ...trace.findings];
|
|
4088
|
+
if (change.planPath) {
|
|
4089
|
+
const planText = await readTextIfExists(change.planPath) ?? "";
|
|
4090
|
+
changeDiags.push(...lintPlan(planText, change.planPath));
|
|
4091
|
+
}
|
|
3957
4092
|
if (change.tasks && change.tasks.counts.total > 0) {
|
|
3958
4093
|
const plan = planWaves(change.tasks, { maxParallel: config.waves.max_parallel });
|
|
3959
4094
|
changeDiags.push(...plan.blocks.flatMap((block) => block.diagnostics));
|
|
@@ -4065,6 +4200,7 @@ export {
|
|
|
4065
4200
|
lintDelta,
|
|
4066
4201
|
lintMockupHtml,
|
|
4067
4202
|
lintMockupManifest,
|
|
4203
|
+
lintPlan,
|
|
4068
4204
|
lintRequirement,
|
|
4069
4205
|
lintSpec,
|
|
4070
4206
|
lintTasks,
|
|
@@ -4093,6 +4229,7 @@ export {
|
|
|
4093
4229
|
mockupManifestSchema,
|
|
4094
4230
|
mockupsDir,
|
|
4095
4231
|
mockupsReady,
|
|
4232
|
+
moveDirectory,
|
|
4096
4233
|
packFindings,
|
|
4097
4234
|
parseApprovals,
|
|
4098
4235
|
parseChangeMeta,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@specatlas/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "Kernel determinista de SpecAtlas: parsing, validación, trazabilidad, olas y ciclo de vida",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@specatlas/render": "0.1.
|
|
37
|
+
"@specatlas/render": "0.1.3",
|
|
38
38
|
"yaml": "^2.6.1",
|
|
39
39
|
"zod": "^3.24.1"
|
|
40
40
|
},
|