@specatlas/core 0.1.26 → 0.1.27
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 +82 -2
- package/dist/index.js +271 -25
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -195,6 +195,17 @@ interface MockupManifest {
|
|
|
195
195
|
tokens?: string;
|
|
196
196
|
screens: MockupScreen[];
|
|
197
197
|
}
|
|
198
|
+
interface ClarifyItem {
|
|
199
|
+
text: string;
|
|
200
|
+
line: number;
|
|
201
|
+
answer?: string;
|
|
202
|
+
}
|
|
203
|
+
interface ClarifyFile {
|
|
204
|
+
path: string;
|
|
205
|
+
open: ClarifyItem[];
|
|
206
|
+
resolved: ClarifyItem[];
|
|
207
|
+
diagnostics: Diagnostic[];
|
|
208
|
+
}
|
|
198
209
|
interface Change {
|
|
199
210
|
slug: string;
|
|
200
211
|
dir: string;
|
|
@@ -204,6 +215,9 @@ interface Change {
|
|
|
204
215
|
verify?: VerifyFile;
|
|
205
216
|
fix?: VerifyFile;
|
|
206
217
|
fixCovers?: string[];
|
|
218
|
+
clarify?: ClarifyFile;
|
|
219
|
+
clarifyPath?: string;
|
|
220
|
+
docsPaths?: string[];
|
|
207
221
|
planPath?: string;
|
|
208
222
|
reviewPath?: string;
|
|
209
223
|
presentationPath?: string;
|
|
@@ -295,6 +309,20 @@ declare const atlasConfigSchema: z.ZodObject<{
|
|
|
295
309
|
}, {
|
|
296
310
|
mode?: "off" | "advisory" | "blocking" | undefined;
|
|
297
311
|
}>>;
|
|
312
|
+
clarify: z.ZodDefault<z.ZodObject<{
|
|
313
|
+
mode: z.ZodDefault<z.ZodEnum<["off", "advisory", "blocking"]>>;
|
|
314
|
+
}, "strip", z.ZodTypeAny, {
|
|
315
|
+
mode: "off" | "advisory" | "blocking";
|
|
316
|
+
}, {
|
|
317
|
+
mode?: "off" | "advisory" | "blocking" | undefined;
|
|
318
|
+
}>>;
|
|
319
|
+
docs: z.ZodDefault<z.ZodObject<{
|
|
320
|
+
mode: z.ZodDefault<z.ZodEnum<["off", "advisory", "blocking"]>>;
|
|
321
|
+
}, "strip", z.ZodTypeAny, {
|
|
322
|
+
mode: "off" | "advisory" | "blocking";
|
|
323
|
+
}, {
|
|
324
|
+
mode?: "off" | "advisory" | "blocking" | undefined;
|
|
325
|
+
}>>;
|
|
298
326
|
mockup: z.ZodDefault<z.ZodObject<{
|
|
299
327
|
require_approval: z.ZodDefault<z.ZodBoolean>;
|
|
300
328
|
compare_in_verify: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -319,6 +347,12 @@ declare const atlasConfigSchema: z.ZodObject<{
|
|
|
319
347
|
review: {
|
|
320
348
|
mode: "off" | "advisory" | "blocking";
|
|
321
349
|
};
|
|
350
|
+
clarify: {
|
|
351
|
+
mode: "off" | "advisory" | "blocking";
|
|
352
|
+
};
|
|
353
|
+
docs: {
|
|
354
|
+
mode: "off" | "advisory" | "blocking";
|
|
355
|
+
};
|
|
322
356
|
mockup: {
|
|
323
357
|
require_approval: boolean;
|
|
324
358
|
compare_in_verify: boolean;
|
|
@@ -337,6 +371,12 @@ declare const atlasConfigSchema: z.ZodObject<{
|
|
|
337
371
|
review?: {
|
|
338
372
|
mode?: "off" | "advisory" | "blocking" | undefined;
|
|
339
373
|
} | undefined;
|
|
374
|
+
clarify?: {
|
|
375
|
+
mode?: "off" | "advisory" | "blocking" | undefined;
|
|
376
|
+
} | undefined;
|
|
377
|
+
docs?: {
|
|
378
|
+
mode?: "off" | "advisory" | "blocking" | undefined;
|
|
379
|
+
} | undefined;
|
|
340
380
|
mockup?: {
|
|
341
381
|
require_approval?: boolean | undefined;
|
|
342
382
|
compare_in_verify?: boolean | undefined;
|
|
@@ -452,6 +492,12 @@ declare const atlasConfigSchema: z.ZodObject<{
|
|
|
452
492
|
review: {
|
|
453
493
|
mode: "off" | "advisory" | "blocking";
|
|
454
494
|
};
|
|
495
|
+
clarify: {
|
|
496
|
+
mode: "off" | "advisory" | "blocking";
|
|
497
|
+
};
|
|
498
|
+
docs: {
|
|
499
|
+
mode: "off" | "advisory" | "blocking";
|
|
500
|
+
};
|
|
455
501
|
mockup: {
|
|
456
502
|
require_approval: boolean;
|
|
457
503
|
compare_in_verify: boolean;
|
|
@@ -515,6 +561,12 @@ declare const atlasConfigSchema: z.ZodObject<{
|
|
|
515
561
|
review?: {
|
|
516
562
|
mode?: "off" | "advisory" | "blocking" | undefined;
|
|
517
563
|
} | undefined;
|
|
564
|
+
clarify?: {
|
|
565
|
+
mode?: "off" | "advisory" | "blocking" | undefined;
|
|
566
|
+
} | undefined;
|
|
567
|
+
docs?: {
|
|
568
|
+
mode?: "off" | "advisory" | "blocking" | undefined;
|
|
569
|
+
} | undefined;
|
|
518
570
|
mockup?: {
|
|
519
571
|
require_approval?: boolean | undefined;
|
|
520
572
|
compare_in_verify?: boolean | undefined;
|
|
@@ -803,6 +855,8 @@ declare function parseApprovals(raw: string, filePath: string): {
|
|
|
803
855
|
diagnostics: Diagnostic[];
|
|
804
856
|
};
|
|
805
857
|
|
|
858
|
+
declare function parseClarify(content: string, filePath: string): ClarifyFile;
|
|
859
|
+
|
|
806
860
|
interface GlossaryTerm {
|
|
807
861
|
term: string;
|
|
808
862
|
definition: string;
|
|
@@ -910,7 +964,7 @@ declare function planWaves(tasks: TasksFile, opts?: {
|
|
|
910
964
|
}): WavePlan;
|
|
911
965
|
declare function planBlock(block: TaskBlock, maxParallel: number): BlockWavePlan;
|
|
912
966
|
|
|
913
|
-
type ChangeState = 'draft' | 'spec_draft' | 'awaiting_mockups' | 'awaiting_approval' | 'approved' | 'planned' | 'building' | 'built' | 'verified' | 'ready' | 'archived';
|
|
967
|
+
type ChangeState = 'draft' | 'spec_draft' | 'awaiting_mockups' | 'awaiting_approval' | 'approved' | 'planned' | 'building' | 'built' | 'verified' | 'reviewed' | 'ready' | 'archived';
|
|
914
968
|
interface NextAction {
|
|
915
969
|
command: string;
|
|
916
970
|
description: string;
|
|
@@ -946,6 +1000,9 @@ interface DeriveInput {
|
|
|
946
1000
|
specContent?: string;
|
|
947
1001
|
}
|
|
948
1002
|
declare function requiresMockups(meta: ChangeMeta | undefined, cfg: AtlasConfig): boolean;
|
|
1003
|
+
declare function docsReady(change: Change): boolean;
|
|
1004
|
+
declare function clarifyAdvisory(change: Change, cfg: AtlasConfig): Diagnostic[];
|
|
1005
|
+
declare function docsAdvisory(change: Change, cfg: AtlasConfig): Diagnostic[];
|
|
949
1006
|
declare function deriveState(input: DeriveInput): DerivedState;
|
|
950
1007
|
declare function stateLabel(state: ChangeState): string;
|
|
951
1008
|
|
|
@@ -1125,6 +1182,8 @@ interface TemplateSet {
|
|
|
1125
1182
|
tasks: string;
|
|
1126
1183
|
verify: string;
|
|
1127
1184
|
fix: string;
|
|
1185
|
+
docTecnica: string;
|
|
1186
|
+
docManual: string;
|
|
1128
1187
|
}
|
|
1129
1188
|
declare function templatesFor(language: Language): TemplateSet;
|
|
1130
1189
|
declare function renderTemplate(template: string, vars: Record<string, string>): string;
|
|
@@ -1829,6 +1888,27 @@ interface WriteLivingFixResult {
|
|
|
1829
1888
|
}
|
|
1830
1889
|
declare function writeLivingFix(root: string, input: WriteLivingFixInput): Promise<WriteLivingFixResult>;
|
|
1831
1890
|
|
|
1891
|
+
type DocsTipo = 'tecnica' | 'manual' | 'all';
|
|
1892
|
+
declare const DOCS_MARKER_START = "<!-- specatlas:generado:inicio -->";
|
|
1893
|
+
declare const DOCS_MARKER_END = "<!-- specatlas:generado:fin -->";
|
|
1894
|
+
interface GenerateDocsOptions {
|
|
1895
|
+
root: string;
|
|
1896
|
+
slug: string;
|
|
1897
|
+
tipo?: DocsTipo;
|
|
1898
|
+
now?: Date;
|
|
1899
|
+
}
|
|
1900
|
+
interface GeneratedDoc {
|
|
1901
|
+
tipo: 'tecnica' | 'manual';
|
|
1902
|
+
path: string;
|
|
1903
|
+
created: boolean;
|
|
1904
|
+
}
|
|
1905
|
+
interface GenerateDocsResult {
|
|
1906
|
+
slug: string;
|
|
1907
|
+
files: GeneratedDoc[];
|
|
1908
|
+
diagnostics: Diagnostic[];
|
|
1909
|
+
}
|
|
1910
|
+
declare function generateDocs(opts: GenerateDocsOptions): Promise<GenerateDocsResult>;
|
|
1911
|
+
|
|
1832
1912
|
declare const SARIF_SCHEMA = "https://json.schemastore.org/sarif-2.1.0.json";
|
|
1833
1913
|
declare const SARIF_VERSION = "2.1.0";
|
|
1834
1914
|
declare const TOOL_NAME = "SpecAtlas";
|
|
@@ -1928,4 +2008,4 @@ declare function livingRequirementsMap(specs: Array<{
|
|
|
1928
2008
|
}>): Map<string, Requirement>;
|
|
1929
2009
|
declare function runCiGate(opts: CiOptions): Promise<CiResult>;
|
|
1930
2010
|
|
|
1931
|
-
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, BACKUP_DIRNAME, BACKUP_POINTER, 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 GlossaryTerm, type ImpactEvidence, type ImpactReport, type ImpactTask, type InitOptions, type InitResult, type IssueBodyInput, LIVING_FIXES_DIR, type Lane, type Language, type LinkedIssue, type LintOptions, type LivingFix, type LoadedConfig, type MigrationSpec, 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 ParsedGlossary, 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, SARIF_SCHEMA, SARIF_VERSION, SCENARIO_HEAD_RE, SCENARIO_ID_RE, SCHEMA_MIGRATIONS, SCHEMA_VERSION, SDD_DIR, SLUG_RE, type SarifLocation, type SarifOptions, type SarifReport, type SarifResult, type SarifRule, type Scenario, type Severity, type SignApprovalOptions, type SignApprovalResult, type SpecFile, type SpecRef, type StackProfile, type SyncGithubOptions, type SyncGithubResult, TASK_ID_RE, TASK_LINE_RE, TOOL_NAME, TOOL_URL, type Task, type TaskBlock, type TasksFile, type TemplateSet, type TraceEdge, type TraceFinding, type TraceGraph, type TraceInput, type TraceNode, type TraceResult, type UpgradeAdvisory, type UpgradeApplyReport, type UpgradeBackupInfo, type UpgradeIssue, type UpgradeItem, type UpgradePlan, type UpgradeRollbackReport, type VerifyFile, type WalkEntry, type WavePlan, type Workspace, type WorkspaceMetrics, type WriteLivingFixInput, type WriteLivingFixResult, adoptWorkspace, appendRunEvent, applyUpgrade, approvalsSchema, approveFromGithub, archiveChange, artifactHash, atlasConfigSchema, buildTraceGraph, canonicalizeMarkdown, captureMockups, changeMarker, changeMetaSchema, changeMetaYaml, checkMockups, checkTrace, collectMetrics, collectVersionedArtifacts, 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, impactOfFile, impactOfRequirement, 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, loadLivingFixes, loadProfileFile, loadProfilesFromDir, loadProjectPacks, loadSpecs, loadWorkspace, localCompact, localDate, localMonth, localOffset, localStamp, matchGlob, mockupManifestSchema, mockupsDir, mockupsReady, moveDirectory, packFindings, parseApprovals, parseChangeMeta, parseConfig, parseDelta, parseFixCovers, parseFrontmatter, parseGitHubRemote, parseGlossary, parseIssueUrl, parseLivingFix, parseRequirementBlocks, parseSpecFile, parseTasksFile, parseVerifyFile, patchChangeMeta, planBlock, planMockups, planUpgrade, planWaves, profileSchema, readArtifactVersion, readMockupManifest, readRun, readText, readTextIfExists, recordEvidence, regenerateIndex, renderMarkdown, renderRequirement, renderTemplate, requiresMockups, resolvePacks, rollbackUpgrade, ruleDescription, runAnalyze, runCiGate, runDoctor, runProcess, sarifLevel, setMockupRequirement, sha256, shortHash, signApproval, specHashOf, splitCommand, stampSchemaVersion, stateLabel, syncGithubIssue, templatesFor, toPosix, toSarifReport, toSarifText, tokensFile, updateMockupScreenshots, updateRunStatus, upgradeAdvisory, verifyApproval, walkFiles, writeConfig, writeLivingFix, writeMockupManifest, writeMockupPlan, writeText };
|
|
2011
|
+
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, BACKUP_DIRNAME, BACKUP_POINTER, 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 ClarifyFile, type ClarifyItem, DOCS_MARKER_END, DOCS_MARKER_START, type Delta, type DeltaOp, type DeriveInput, type DerivedState, type DetectionResult, type Diagnostic, type DocsTipo, type DoctorReport, type Domain, type Evidence, type EvidenceMethod, type EvidenceResult, type ExecOptions, type ExecResult, type FoldOutcome, type FrontmatterResult, type GenerateDocsOptions, type GenerateDocsResult, type GeneratedDoc, type GhRunner, type GitHubRepo, type GlossaryTerm, type ImpactEvidence, type ImpactReport, type ImpactTask, type InitOptions, type InitResult, type IssueBodyInput, LIVING_FIXES_DIR, type Lane, type Language, type LinkedIssue, type LintOptions, type LivingFix, type LoadedConfig, type MigrationSpec, 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 ParsedGlossary, 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, SARIF_SCHEMA, SARIF_VERSION, SCENARIO_HEAD_RE, SCENARIO_ID_RE, SCHEMA_MIGRATIONS, SCHEMA_VERSION, SDD_DIR, SLUG_RE, type SarifLocation, type SarifOptions, type SarifReport, type SarifResult, type SarifRule, type Scenario, type Severity, type SignApprovalOptions, type SignApprovalResult, type SpecFile, type SpecRef, type StackProfile, type SyncGithubOptions, type SyncGithubResult, TASK_ID_RE, TASK_LINE_RE, TOOL_NAME, TOOL_URL, type Task, type TaskBlock, type TasksFile, type TemplateSet, type TraceEdge, type TraceFinding, type TraceGraph, type TraceInput, type TraceNode, type TraceResult, type UpgradeAdvisory, type UpgradeApplyReport, type UpgradeBackupInfo, type UpgradeIssue, type UpgradeItem, type UpgradePlan, type UpgradeRollbackReport, type VerifyFile, type WalkEntry, type WavePlan, type Workspace, type WorkspaceMetrics, type WriteLivingFixInput, type WriteLivingFixResult, adoptWorkspace, appendRunEvent, applyUpgrade, approvalsSchema, approveFromGithub, archiveChange, artifactHash, atlasConfigSchema, buildTraceGraph, canonicalizeMarkdown, captureMockups, changeMarker, changeMetaSchema, changeMetaYaml, checkMockups, checkTrace, clarifyAdvisory, collectMetrics, collectVersionedArtifacts, commentIssue, compareTaskIds, computeInputsHash, configToYaml, copyFile, countBySeverity, createChange, createIssue, createRun, defaultConfig, deriveState, detectProfiles, detectRepo, detectionToYaml, diag, docsAdvisory, docsReady, editIssue, emitFrontmatter, ensureDir, ensureSddDirs, esc, evaluatePacks, evidenceSummary, exists, findLinkedIssue, findWorkspaceRoot, firstToken, foldDelta, generateDocs, generatePresentation, generateRunId, getNumber, getString, ghAuthStatus, ghAvailable, hasErrors, hasShellMetacharacters, impactOfFile, impactOfRequirement, 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, loadLivingFixes, loadProfileFile, loadProfilesFromDir, loadProjectPacks, loadSpecs, loadWorkspace, localCompact, localDate, localMonth, localOffset, localStamp, matchGlob, mockupManifestSchema, mockupsDir, mockupsReady, moveDirectory, packFindings, parseApprovals, parseChangeMeta, parseClarify, parseConfig, parseDelta, parseFixCovers, parseFrontmatter, parseGitHubRemote, parseGlossary, parseIssueUrl, parseLivingFix, parseRequirementBlocks, parseSpecFile, parseTasksFile, parseVerifyFile, patchChangeMeta, planBlock, planMockups, planUpgrade, planWaves, profileSchema, readArtifactVersion, readMockupManifest, readRun, readText, readTextIfExists, recordEvidence, regenerateIndex, renderMarkdown, renderRequirement, renderTemplate, requiresMockups, resolvePacks, rollbackUpgrade, ruleDescription, runAnalyze, runCiGate, runDoctor, runProcess, sarifLevel, setMockupRequirement, sha256, shortHash, signApproval, specHashOf, splitCommand, stampSchemaVersion, stateLabel, syncGithubIssue, templatesFor, toPosix, toSarifReport, toSarifText, tokensFile, updateMockupScreenshots, updateRunStatus, upgradeAdvisory, verifyApproval, walkFiles, writeConfig, writeLivingFix, writeMockupManifest, writeMockupPlan, writeText };
|
package/dist/index.js
CHANGED
|
@@ -61,6 +61,8 @@ var atlasConfigSchema = z.object({
|
|
|
61
61
|
analyze: z.object({ mode: z.enum(["off", "advisory", "blocking"]).default("blocking"), min_severity: z.enum(["low", "medium", "high"]).default("medium") }).default({}),
|
|
62
62
|
verify: z.object({ mode: z.enum(["off", "advisory", "blocking"]).default("blocking"), require_evidence: z.boolean().default(true) }).default({}),
|
|
63
63
|
review: z.object({ mode: z.enum(["off", "advisory", "blocking"]).default("advisory") }).default({}),
|
|
64
|
+
clarify: z.object({ mode: z.enum(["off", "advisory", "blocking"]).default("advisory") }).default({}),
|
|
65
|
+
docs: z.object({ mode: z.enum(["off", "advisory", "blocking"]).default("blocking") }).default({}),
|
|
64
66
|
mockup: z.object({ require_approval: z.boolean().default(false), compare_in_verify: z.boolean().default(false) }).default({})
|
|
65
67
|
}).default({}),
|
|
66
68
|
trace: z.object({ mode: z.enum(["off", "advisory", "blocking"]).default("blocking"), prefix: z.string().default("REQ") }).default({}),
|
|
@@ -640,6 +642,35 @@ function findScenarioHeading(lines, blockLineIndex) {
|
|
|
640
642
|
return void 0;
|
|
641
643
|
}
|
|
642
644
|
|
|
645
|
+
// src/parse/clarify.ts
|
|
646
|
+
var OPEN_RE = /^\s*-\s*\[\s\]\s+(.+?)\s*$/;
|
|
647
|
+
var DONE_RE = /^\s*-\s*\[[xX]\]\s+(.+?)\s*$/;
|
|
648
|
+
var ANSWER_SEPARATOR = " \u2014 ";
|
|
649
|
+
function splitAnswer(raw) {
|
|
650
|
+
const index = raw.indexOf(ANSWER_SEPARATOR);
|
|
651
|
+
if (index === -1) return { text: raw.trim() };
|
|
652
|
+
return { text: raw.slice(0, index).trim(), answer: raw.slice(index + ANSWER_SEPARATOR.length).trim() };
|
|
653
|
+
}
|
|
654
|
+
function parseClarify(content, filePath) {
|
|
655
|
+
const fm = parseFrontmatter(content, filePath);
|
|
656
|
+
const lines = fm.body.replace(/\r\n?/g, "\n").split("\n");
|
|
657
|
+
const open = [];
|
|
658
|
+
const resolved = [];
|
|
659
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
660
|
+
const line = lines[i] ?? "";
|
|
661
|
+
const lineNo = fm.bodyStartLine + i;
|
|
662
|
+
const done = DONE_RE.exec(line);
|
|
663
|
+
if (done) {
|
|
664
|
+
const item = splitAnswer(done[1] ?? "");
|
|
665
|
+
resolved.push({ text: item.text, line: lineNo, ...item.answer !== void 0 ? { answer: item.answer } : {} });
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
668
|
+
const pending = OPEN_RE.exec(line);
|
|
669
|
+
if (pending) open.push({ text: pending[1] ?? "", line: lineNo });
|
|
670
|
+
}
|
|
671
|
+
return { path: filePath, open, resolved, diagnostics: [] };
|
|
672
|
+
}
|
|
673
|
+
|
|
643
674
|
// src/parse/glossary.ts
|
|
644
675
|
var HEADER_KEYS = /* @__PURE__ */ new Set(["t\xE9rmino", "termino", "term", "definici\xF3n", "definicion", "definition", "sin\xF3nimos", "sinonimos", "synonyms"]);
|
|
645
676
|
var SEPARATOR_RE = /^:?-{2,}:?$/;
|
|
@@ -794,14 +825,14 @@ function wordBoundary(text, term) {
|
|
|
794
825
|
const re = new RegExp(`(?<![\\p{L}\\p{N}])${escaped}(?![\\p{L}\\p{N}])`, "iu");
|
|
795
826
|
return re.test(text);
|
|
796
827
|
}
|
|
797
|
-
function lintText(text, code, terms, label,
|
|
828
|
+
function lintText(text, code, terms, label, path23, line) {
|
|
798
829
|
const out = [];
|
|
799
830
|
const lower = text.toLowerCase();
|
|
800
831
|
for (const term of terms) {
|
|
801
832
|
if (wordBoundary(lower, term)) {
|
|
802
833
|
out.push(
|
|
803
834
|
diag(code, "error", `${label}: "${term}"`, {
|
|
804
|
-
path:
|
|
835
|
+
path: path23,
|
|
805
836
|
line,
|
|
806
837
|
suggestion: "La especificaci\xF3n es funcional y de negocio: describe comportamiento, no tecnolog\xEDa ni adjetivos vagos"
|
|
807
838
|
})
|
|
@@ -810,7 +841,7 @@ function lintText(text, code, terms, label, path22, line) {
|
|
|
810
841
|
}
|
|
811
842
|
return out;
|
|
812
843
|
}
|
|
813
|
-
function lintRequirement(req,
|
|
844
|
+
function lintRequirement(req, path23, opts = {}) {
|
|
814
845
|
const out = [];
|
|
815
846
|
const vague = opts.language === "en" ? VAGUE_EN : VAGUE_ES;
|
|
816
847
|
const tech = opts.language === "en" ? TECH_EN : TECH_ES;
|
|
@@ -821,32 +852,32 @@ function lintRequirement(req, path22, opts = {}) {
|
|
|
821
852
|
...req.scenarios.flatMap((s) => [...s.when.map((w) => ({ text: w, line: s.line })), ...s.then.map((t) => ({ text: t, line: s.line }))])
|
|
822
853
|
];
|
|
823
854
|
for (const part of parts) {
|
|
824
|
-
out.push(...lintText(part.text, "LINT-BIZ-002", vague, "Palabra vaga en la especificaci\xF3n",
|
|
855
|
+
out.push(...lintText(part.text, "LINT-BIZ-002", vague, "Palabra vaga en la especificaci\xF3n", path23, part.line));
|
|
825
856
|
if (opts.businessOnly !== false) {
|
|
826
|
-
out.push(...lintText(part.text, "LINT-BIZ-001", tech, "Jerga t\xE9cnica en la especificaci\xF3n de negocio",
|
|
857
|
+
out.push(...lintText(part.text, "LINT-BIZ-001", tech, "Jerga t\xE9cnica en la especificaci\xF3n de negocio", path23, part.line));
|
|
827
858
|
}
|
|
828
859
|
}
|
|
829
860
|
if (req.scenarios.length === 0) {
|
|
830
|
-
out.push(diag("TRACE-001", "error", `El requisito ${req.id} no tiene ning\xFAn escenario`, { path:
|
|
861
|
+
out.push(diag("TRACE-001", "error", `El requisito ${req.id} no tiene ning\xFAn escenario`, { path: path23, line: req.line, suggestion: "A\xF1ade al menos un escenario CUANDO/ENTONCES" }));
|
|
831
862
|
}
|
|
832
863
|
return out;
|
|
833
864
|
}
|
|
834
|
-
function lintDelta(delta, livingRequirements,
|
|
865
|
+
function lintDelta(delta, livingRequirements, path23, opts = {}) {
|
|
835
866
|
const out = [...delta.diagnostics];
|
|
836
867
|
for (const req of [...delta.added, ...delta.modified]) {
|
|
837
|
-
out.push(...lintRequirement(req,
|
|
868
|
+
out.push(...lintRequirement(req, path23, opts));
|
|
838
869
|
}
|
|
839
870
|
for (const req of delta.modified) {
|
|
840
871
|
const living = livingRequirements.get(req.id);
|
|
841
872
|
if (!living) {
|
|
842
|
-
out.push(diag("TRACE-007", "error", `MODIFIED ${req.id} no existe en la spec viva; usa ADDED`, { path:
|
|
873
|
+
out.push(diag("TRACE-007", "error", `MODIFIED ${req.id} no existe en la spec viva; usa ADDED`, { path: path23, line: req.line }));
|
|
843
874
|
continue;
|
|
844
875
|
}
|
|
845
876
|
for (const existing of living.scenarios) {
|
|
846
877
|
if (!req.scenarios.some((s) => s.id === existing.id)) {
|
|
847
878
|
out.push(
|
|
848
879
|
diag("TRACE-007", "error", `MODIFIED ${req.id} pierde el escenario ${existing.id}: copia el bloque completo`, {
|
|
849
|
-
path:
|
|
880
|
+
path: path23,
|
|
850
881
|
line: req.line,
|
|
851
882
|
suggestion: "Copia el bloque completo de la spec viva y ed\xEDtalo; para quitarlo, decl\xE1ralo en REMOVED"
|
|
852
883
|
})
|
|
@@ -857,15 +888,15 @@ function lintDelta(delta, livingRequirements, path22, opts = {}) {
|
|
|
857
888
|
for (const req of delta.removed) {
|
|
858
889
|
const living = livingRequirements.get(req.id);
|
|
859
890
|
if (!living) {
|
|
860
|
-
out.push(diag("TRACE-007", "error", `REMOVED ${req.id} no existe en la spec viva`, { path:
|
|
891
|
+
out.push(diag("TRACE-007", "error", `REMOVED ${req.id} no existe en la spec viva`, { path: path23, line: req.line }));
|
|
861
892
|
}
|
|
862
893
|
}
|
|
863
894
|
for (const rename2 of delta.renamed) {
|
|
864
895
|
if (rename2.from.id !== rename2.to.id) {
|
|
865
|
-
out.push(diag("LINT-DLT-003", "error", `RENAMED cambia el id (${rename2.from.id} \u2192 ${rename2.to.id}); los ids son inmutables`, { path:
|
|
896
|
+
out.push(diag("LINT-DLT-003", "error", `RENAMED cambia el id (${rename2.from.id} \u2192 ${rename2.to.id}); los ids son inmutables`, { path: path23, line: rename2.line }));
|
|
866
897
|
}
|
|
867
898
|
if (!livingRequirements.has(rename2.from.id)) {
|
|
868
|
-
out.push(diag("TRACE-007", "error", `RENAMED ${rename2.from.id} no existe en la spec viva`, { path:
|
|
899
|
+
out.push(diag("TRACE-007", "error", `RENAMED ${rename2.from.id} no existe en la spec viva`, { path: path23, line: rename2.line }));
|
|
869
900
|
}
|
|
870
901
|
}
|
|
871
902
|
return out;
|
|
@@ -895,7 +926,7 @@ var MERMAID_KEYWORDS = [
|
|
|
895
926
|
"architecture-beta"
|
|
896
927
|
];
|
|
897
928
|
var MERMAID_BLOCKS = /^\s*(alt|loop|opt|par|rect|critical|break|subgraph)\b/;
|
|
898
|
-
function lintPlan(planText,
|
|
929
|
+
function lintPlan(planText, path23) {
|
|
899
930
|
const out = [];
|
|
900
931
|
const blocks = [...planText.matchAll(/```mermaid\r?\n([\s\S]*?)```/g)];
|
|
901
932
|
for (const [index, block] of blocks.entries()) {
|
|
@@ -905,7 +936,7 @@ function lintPlan(planText, path22) {
|
|
|
905
936
|
if (!MERMAID_KEYWORDS.some((keyword) => first.startsWith(keyword))) {
|
|
906
937
|
out.push(
|
|
907
938
|
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)}"`, {
|
|
908
|
-
path:
|
|
939
|
+
path: path23,
|
|
909
940
|
suggestion: "Corrige el tipo del diagrama o elimina el bloque"
|
|
910
941
|
})
|
|
911
942
|
);
|
|
@@ -919,7 +950,7 @@ function lintPlan(planText, path22) {
|
|
|
919
950
|
if (open !== 0) {
|
|
920
951
|
out.push(
|
|
921
952
|
diag("LINT-PLN-002", "error", `Diagrama mermaid ${index + 1}: faltan ${Math.abs(open)} \`end\` (bloques alt/loop/subgraph sin cerrar)`, {
|
|
922
|
-
path:
|
|
953
|
+
path: path23,
|
|
923
954
|
suggestion: "Cierra cada bloque alt/loop/opt/par/rect/subgraph con `end`"
|
|
924
955
|
})
|
|
925
956
|
);
|
|
@@ -931,7 +962,7 @@ function lintPlan(planText, path22) {
|
|
|
931
962
|
if (message.includes(";")) {
|
|
932
963
|
out.push(
|
|
933
964
|
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`, {
|
|
934
|
-
path:
|
|
965
|
+
path: path23,
|
|
935
966
|
suggestion: "Sustituye `;` por `\xB7` o `,` en los mensajes de sequenceDiagram"
|
|
936
967
|
})
|
|
937
968
|
);
|
|
@@ -1240,6 +1271,29 @@ function requiresMockups(meta, cfg) {
|
|
|
1240
1271
|
function mockupOverride(change) {
|
|
1241
1272
|
return (change.meta?.overrides ?? []).some((override) => override.gate === "mockup");
|
|
1242
1273
|
}
|
|
1274
|
+
function docsReady(change) {
|
|
1275
|
+
const paths = change.docsPaths ?? [];
|
|
1276
|
+
return paths.some((p) => p.endsWith("tecnica.md")) && paths.some((p) => p.endsWith("manual.md"));
|
|
1277
|
+
}
|
|
1278
|
+
function clarifyAdvisory(change, cfg) {
|
|
1279
|
+
const open = change.clarify?.open.length ?? 0;
|
|
1280
|
+
if (cfg.gates.clarify.mode !== "advisory" || open === 0) return [];
|
|
1281
|
+
return [
|
|
1282
|
+
diag("ATLAS-CLARIFY-001", "warning", `El cambio "${change.slug}" tiene ${open} pregunta(s) sin aclarar`, {
|
|
1283
|
+
...change.clarifyPath !== void 0 ? { path: change.clarifyPath } : {},
|
|
1284
|
+
suggestion: `Aclara antes de planificar: /satlas.clarify ${change.slug} (o satlas clarify ${change.slug})`
|
|
1285
|
+
})
|
|
1286
|
+
];
|
|
1287
|
+
}
|
|
1288
|
+
function docsAdvisory(change, cfg) {
|
|
1289
|
+
const lane = change.meta?.lane ?? cfg.lanes.default;
|
|
1290
|
+
if (lane !== "full" || cfg.gates.docs.mode !== "advisory" || docsReady(change)) return [];
|
|
1291
|
+
return [
|
|
1292
|
+
diag("ATLAS-DOCS-001", "warning", `El cambio "${change.slug}" (carril completo) no tiene su documentaci\xF3n t\xE9cnica y manual`, {
|
|
1293
|
+
suggestion: `Genera la documentaci\xF3n: satlas docs ${change.slug} (o /satlas.docs ${change.slug})`
|
|
1294
|
+
})
|
|
1295
|
+
];
|
|
1296
|
+
}
|
|
1243
1297
|
function deriveState(input) {
|
|
1244
1298
|
const { change, cfg, approval, blockingFindings } = input;
|
|
1245
1299
|
const lane = change.meta?.lane ?? cfg.lanes.default;
|
|
@@ -1302,6 +1356,16 @@ function deriveState(input) {
|
|
|
1302
1356
|
};
|
|
1303
1357
|
}
|
|
1304
1358
|
if (!change.planPath && !change.tasks) {
|
|
1359
|
+
const openQuestions = change.clarify?.open.length ?? 0;
|
|
1360
|
+
if (openQuestions > 0 && cfg.gates.clarify.mode === "blocking") {
|
|
1361
|
+
blockedBy.push(`aclaraci\xF3n pendiente (${openQuestions})`);
|
|
1362
|
+
return {
|
|
1363
|
+
state: "approved",
|
|
1364
|
+
blockedBy,
|
|
1365
|
+
nextAction: next(`/satlas.clarify ${change.slug}`, `Aclarar ${openQuestions} pregunta(s) antes de planificar`, true),
|
|
1366
|
+
progress
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1305
1369
|
return { state: "approved", blockedBy, nextAction: next(`/satlas.plan ${change.slug}`, "Crear el plan t\xE9cnico y las tareas", true), progress };
|
|
1306
1370
|
}
|
|
1307
1371
|
if (tasksTotal > 0 && tasksDone < tasksTotal) {
|
|
@@ -1315,6 +1379,10 @@ function deriveState(input) {
|
|
|
1315
1379
|
blockedBy.push("review pendiente");
|
|
1316
1380
|
return { state: "verified", blockedBy, nextAction: next(`/satlas.review ${change.slug}`, "Revisi\xF3n de c\xF3digo", true), progress };
|
|
1317
1381
|
}
|
|
1382
|
+
if (lane === "full" && cfg.gates.docs.mode === "blocking" && !docsReady(change)) {
|
|
1383
|
+
blockedBy.push("documentaci\xF3n pendiente");
|
|
1384
|
+
return { state: "reviewed", blockedBy, nextAction: next(`/satlas.docs ${change.slug}`, "Generar la documentaci\xF3n t\xE9cnica y manual del cambio", true), progress };
|
|
1385
|
+
}
|
|
1318
1386
|
return { state: "ready", blockedBy, nextAction: next(`satlas archive ${change.slug}`, "Archivar el cambio y plegar los deltas"), progress };
|
|
1319
1387
|
}
|
|
1320
1388
|
function stateLabel(state) {
|
|
@@ -1328,6 +1396,7 @@ function stateLabel(state) {
|
|
|
1328
1396
|
building: "construyendo",
|
|
1329
1397
|
built: "construido",
|
|
1330
1398
|
verified: "verificado",
|
|
1399
|
+
reviewed: "revisado",
|
|
1331
1400
|
ready: "listo para archivar",
|
|
1332
1401
|
archived: "archivado"
|
|
1333
1402
|
};
|
|
@@ -1668,6 +1737,19 @@ async function loadChange(root, slug, relDir) {
|
|
|
1668
1737
|
diagnostics.push(...change.fix.diagnostics);
|
|
1669
1738
|
change.fixCovers = parseFixCovers(fixRaw);
|
|
1670
1739
|
}
|
|
1740
|
+
const clarifyFile = path5.join(dir, "clarify.md");
|
|
1741
|
+
const clarifyRaw = await readTextIfExists(clarifyFile);
|
|
1742
|
+
if (clarifyRaw !== void 0) {
|
|
1743
|
+
change.clarify = parseClarify(clarifyRaw, clarifyFile);
|
|
1744
|
+
change.clarifyPath = clarifyFile;
|
|
1745
|
+
diagnostics.push(...change.clarify.diagnostics);
|
|
1746
|
+
}
|
|
1747
|
+
const docsPaths = [];
|
|
1748
|
+
for (const name of ["tecnica.md", "manual.md"]) {
|
|
1749
|
+
const docFile = path5.join(dir, "docs", name);
|
|
1750
|
+
if (await exists(docFile)) docsPaths.push(docFile);
|
|
1751
|
+
}
|
|
1752
|
+
if (docsPaths.length > 0) change.docsPaths = docsPaths;
|
|
1671
1753
|
const mockupManifest = path5.join(dir, "mockups", "manifest.yaml");
|
|
1672
1754
|
if (await exists(mockupManifest)) change.mockupManifestPath = mockupManifest;
|
|
1673
1755
|
return change;
|
|
@@ -1884,6 +1966,44 @@ satlas verify <slug> --file fix --scenario REQ-DOMINIO-001-S1 --command "<comand
|
|
|
1884
1966
|
o, si es manual:
|
|
1885
1967
|
satlas verify <slug> --file fix --scenario REQ-DOMINIO-001-S1 --method manual --result pass --by "<nombre>" --notes "<c\xF3mo se comprob\xF3>"
|
|
1886
1968
|
-->
|
|
1969
|
+
`,
|
|
1970
|
+
docTecnica: `# Documentaci\xF3n t\xE9cnica \u2014 {{TITLE}}
|
|
1971
|
+
|
|
1972
|
+
## Resumen del cambio
|
|
1973
|
+
|
|
1974
|
+
- **Cambio**: \`{{SLUG}}\` \xB7 dominio \`{{DOMAIN}}\` \xB7 carril \`{{LANE}}\`
|
|
1975
|
+
- **Actualizado**: {{DATE}}
|
|
1976
|
+
- **Tareas**: {{TASKS}}
|
|
1977
|
+
|
|
1978
|
+
## Requisitos y escenarios
|
|
1979
|
+
|
|
1980
|
+
{{REQUIREMENTS}}
|
|
1981
|
+
|
|
1982
|
+
## Evidencia registrada
|
|
1983
|
+
|
|
1984
|
+
{{EVIDENCE}}
|
|
1985
|
+
|
|
1986
|
+
## Pendiente de evidencia
|
|
1987
|
+
|
|
1988
|
+
{{PENDING}}
|
|
1989
|
+
`,
|
|
1990
|
+
docManual: `# Manual \u2014 {{TITLE}}
|
|
1991
|
+
|
|
1992
|
+
## Qu\xE9 hace este cambio
|
|
1993
|
+
|
|
1994
|
+
{{TITLE}} \u2014 dominio \`{{DOMAIN}}\` (cambio \`{{SLUG}}\`, carril \`{{LANE}}\`).
|
|
1995
|
+
|
|
1996
|
+
## C\xF3mo se usa
|
|
1997
|
+
|
|
1998
|
+
{{SCENARIOS}}
|
|
1999
|
+
|
|
2000
|
+
## C\xF3mo se comprob\xF3
|
|
2001
|
+
|
|
2002
|
+
{{EVIDENCE}}
|
|
2003
|
+
|
|
2004
|
+
## Pendiente de comprobar
|
|
2005
|
+
|
|
2006
|
+
{{PENDING}}
|
|
1887
2007
|
`
|
|
1888
2008
|
};
|
|
1889
2009
|
var EN = {
|
|
@@ -2009,6 +2129,44 @@ Cubre: REQ-DOMAIN-001
|
|
|
2009
2129
|
<!-- Register real evidence with:
|
|
2010
2130
|
satlas verify <slug> --file fix --scenario REQ-DOMAIN-001-S1 --command "<command>" --by "<name>"
|
|
2011
2131
|
-->
|
|
2132
|
+
`,
|
|
2133
|
+
docTecnica: `# Technical documentation \u2014 {{TITLE}}
|
|
2134
|
+
|
|
2135
|
+
## Change summary
|
|
2136
|
+
|
|
2137
|
+
- **Change**: \`{{SLUG}}\` \xB7 domain \`{{DOMAIN}}\` \xB7 lane \`{{LANE}}\`
|
|
2138
|
+
- **Updated**: {{DATE}}
|
|
2139
|
+
- **Tasks**: {{TASKS}}
|
|
2140
|
+
|
|
2141
|
+
## Requirements and scenarios
|
|
2142
|
+
|
|
2143
|
+
{{REQUIREMENTS}}
|
|
2144
|
+
|
|
2145
|
+
## Recorded evidence
|
|
2146
|
+
|
|
2147
|
+
{{EVIDENCE}}
|
|
2148
|
+
|
|
2149
|
+
## Pending evidence
|
|
2150
|
+
|
|
2151
|
+
{{PENDING}}
|
|
2152
|
+
`,
|
|
2153
|
+
docManual: `# Manual \u2014 {{TITLE}}
|
|
2154
|
+
|
|
2155
|
+
## What this change does
|
|
2156
|
+
|
|
2157
|
+
{{TITLE}} \u2014 domain \`{{DOMAIN}}\` (change \`{{SLUG}}\`, lane \`{{LANE}}\`).
|
|
2158
|
+
|
|
2159
|
+
## How to use it
|
|
2160
|
+
|
|
2161
|
+
{{SCENARIOS}}
|
|
2162
|
+
|
|
2163
|
+
## How it was verified
|
|
2164
|
+
|
|
2165
|
+
{{EVIDENCE}}
|
|
2166
|
+
|
|
2167
|
+
## Pending verification
|
|
2168
|
+
|
|
2169
|
+
{{PENDING}}
|
|
2012
2170
|
`
|
|
2013
2171
|
};
|
|
2014
2172
|
function templatesFor(language) {
|
|
@@ -4600,8 +4758,89 @@ async function upgradeAdvisory(root) {
|
|
|
4600
4758
|
return { plan, diagnostics };
|
|
4601
4759
|
}
|
|
4602
4760
|
|
|
4603
|
-
// src/
|
|
4761
|
+
// src/docs.ts
|
|
4604
4762
|
import path19 from "path";
|
|
4763
|
+
var DOCS_MARKER_START = "<!-- specatlas:generado:inicio -->";
|
|
4764
|
+
var DOCS_MARKER_END = "<!-- specatlas:generado:fin -->";
|
|
4765
|
+
function docData(change, language, now) {
|
|
4766
|
+
const es = language !== "en";
|
|
4767
|
+
const requirements = [...change.delta?.added ?? [], ...change.delta?.modified ?? []];
|
|
4768
|
+
const evidence = change.verify?.evidence ?? [];
|
|
4769
|
+
const passed = new Set(evidence.filter((entry) => entry.result === "pass").map((entry) => entry.scenario));
|
|
4770
|
+
const requirementsText = requirements.length === 0 ? es ? "_Sin requisitos en el delta._" : "_No requirements in the delta._" : requirements.map((requirement) => {
|
|
4771
|
+
const lines = [`### ${requirement.id} \u2014 ${requirement.title}`, ""];
|
|
4772
|
+
for (const scenario of requirement.scenarios) lines.push(`- \`${scenario.id}\` \u2014 ${scenario.title}`);
|
|
4773
|
+
return lines.join("\n");
|
|
4774
|
+
}).join("\n\n");
|
|
4775
|
+
const scenarioList = requirements.flatMap((requirement) => requirement.scenarios);
|
|
4776
|
+
const scenariosText = scenarioList.length === 0 ? es ? "_Sin escenarios._" : "_No scenarios._" : scenarioList.map((scenario) => `- \`${scenario.id}\` \u2014 ${scenario.title}`).join("\n");
|
|
4777
|
+
const evidenceText = evidence.length === 0 ? es ? "_Sin evidencia registrada._" : "_No evidence recorded._" : evidence.map((entry) => `- \`${entry.scenario}\` \u2014 ${entry.method} \xB7 ${entry.result}${entry.date ? ` \xB7 ${entry.date}` : ""}`).join("\n");
|
|
4778
|
+
const pending = scenarioList.filter((scenario) => !passed.has(scenario.id));
|
|
4779
|
+
const pendingText = pending.length === 0 ? es ? "_Nada pendiente: todos los escenarios tienen evidencia en pass._" : "_Nothing pending: every scenario has passing evidence._" : pending.map((scenario) => `- \`${scenario.id}\` \u2014 ${scenario.title}`).join("\n");
|
|
4780
|
+
return {
|
|
4781
|
+
TITLE: change.meta?.title ?? change.slug,
|
|
4782
|
+
SLUG: change.slug,
|
|
4783
|
+
DOMAIN: change.meta?.domain ?? "\u2014",
|
|
4784
|
+
LANE: change.meta?.lane ?? "standard",
|
|
4785
|
+
DATE: localDate(now),
|
|
4786
|
+
TASKS: change.tasks ? `${change.tasks.counts.done}/${change.tasks.counts.total}` : es ? "sin tareas" : "no tasks",
|
|
4787
|
+
REQUIREMENTS: requirementsText,
|
|
4788
|
+
SCENARIOS: scenariosText,
|
|
4789
|
+
EVIDENCE: evidenceText,
|
|
4790
|
+
PENDING: pendingText
|
|
4791
|
+
};
|
|
4792
|
+
}
|
|
4793
|
+
function mergeManaged(existing, block, language) {
|
|
4794
|
+
const managed = `${DOCS_MARKER_START}
|
|
4795
|
+
${block.trimEnd()}
|
|
4796
|
+
${DOCS_MARKER_END}`;
|
|
4797
|
+
if (existing === void 0) {
|
|
4798
|
+
const notes = language === "en" ? "## Notes\n\n(Write here whatever you want to keep across regenerations.)" : "## Notas\n\n(Escribe aqu\xED lo que quieras conservar entre regeneraciones.)";
|
|
4799
|
+
return `${managed}
|
|
4800
|
+
|
|
4801
|
+
${notes}
|
|
4802
|
+
`;
|
|
4803
|
+
}
|
|
4804
|
+
const start = existing.indexOf(DOCS_MARKER_START);
|
|
4805
|
+
const end = existing.indexOf(DOCS_MARKER_END);
|
|
4806
|
+
if (start >= 0 && end > start) {
|
|
4807
|
+
const before = existing.slice(0, start);
|
|
4808
|
+
const after = existing.slice(end + DOCS_MARKER_END.length);
|
|
4809
|
+
return `${before}${managed}${after}`;
|
|
4810
|
+
}
|
|
4811
|
+
return `${managed}
|
|
4812
|
+
|
|
4813
|
+
${existing}`;
|
|
4814
|
+
}
|
|
4815
|
+
async function generateDocs(opts) {
|
|
4816
|
+
const root = path19.resolve(opts.root);
|
|
4817
|
+
const { config } = await loadWorkspace(root);
|
|
4818
|
+
const change = await loadChange(root, opts.slug);
|
|
4819
|
+
if (!change.meta) {
|
|
4820
|
+
return {
|
|
4821
|
+
slug: opts.slug,
|
|
4822
|
+
files: [],
|
|
4823
|
+
diagnostics: [diag("ATLAS-DOCS-002", "error", `No existe el cambio "${opts.slug}"`, { suggestion: "Comprueba el nombre del cambio" })]
|
|
4824
|
+
};
|
|
4825
|
+
}
|
|
4826
|
+
const language = config.project.language;
|
|
4827
|
+
const tipo = opts.tipo ?? "all";
|
|
4828
|
+
const tipos = tipo === "all" ? ["tecnica", "manual"] : [tipo];
|
|
4829
|
+
const templates = templatesFor(language);
|
|
4830
|
+
const data = docData(change, language, opts.now ?? /* @__PURE__ */ new Date());
|
|
4831
|
+
const files = [];
|
|
4832
|
+
for (const current of tipos) {
|
|
4833
|
+
const file = path19.join(change.dir, "docs", `${current}.md`);
|
|
4834
|
+
const block = renderTemplate(current === "tecnica" ? templates.docTecnica : templates.docManual, data);
|
|
4835
|
+
const existing = await readTextIfExists(file);
|
|
4836
|
+
await writeText(file, mergeManaged(existing, block, language));
|
|
4837
|
+
files.push({ tipo: current, path: file, created: existing === void 0 });
|
|
4838
|
+
}
|
|
4839
|
+
return { slug: opts.slug, files, diagnostics: [] };
|
|
4840
|
+
}
|
|
4841
|
+
|
|
4842
|
+
// src/sarif.ts
|
|
4843
|
+
import path20 from "path";
|
|
4605
4844
|
var SARIF_SCHEMA = "https://json.schemastore.org/sarif-2.1.0.json";
|
|
4606
4845
|
var SARIF_VERSION = "2.1.0";
|
|
4607
4846
|
var TOOL_NAME = "SpecAtlas";
|
|
@@ -4639,7 +4878,7 @@ function resultOf(diagnostic, root) {
|
|
|
4639
4878
|
message: { text: diagnostic.message }
|
|
4640
4879
|
};
|
|
4641
4880
|
if (diagnostic.path) {
|
|
4642
|
-
const rel =
|
|
4881
|
+
const rel = path20.relative(root, diagnostic.path);
|
|
4643
4882
|
if (rel !== "") {
|
|
4644
4883
|
const physicalLocation = {
|
|
4645
4884
|
artifactLocation: { uri: toPosix(rel) },
|
|
@@ -4689,7 +4928,7 @@ function toSarifText(opts) {
|
|
|
4689
4928
|
}
|
|
4690
4929
|
|
|
4691
4930
|
// src/doctor.ts
|
|
4692
|
-
import
|
|
4931
|
+
import path21 from "path";
|
|
4693
4932
|
async function runDoctor(root) {
|
|
4694
4933
|
const findings = [];
|
|
4695
4934
|
const { workspace, config } = await loadWorkspace(root);
|
|
@@ -4697,7 +4936,7 @@ async function runDoctor(root) {
|
|
|
4697
4936
|
const approvals = await loadApprovals(workspace.sddDir);
|
|
4698
4937
|
findings.push(...approvals.diagnostics);
|
|
4699
4938
|
for (const change of workspace.changes) {
|
|
4700
|
-
const deltaPath =
|
|
4939
|
+
const deltaPath = path21.join(change.dir, "spec.md");
|
|
4701
4940
|
const deltaContent = await readTextIfExists(deltaPath);
|
|
4702
4941
|
const approval = verifyApproval(change, approvals.byArtifact, config, deltaContent ?? void 0);
|
|
4703
4942
|
if ((change.planPath || change.tasks) && (approval.status === "missing" || approval.status === "stale")) {
|
|
@@ -4719,7 +4958,7 @@ async function runDoctor(root) {
|
|
|
4719
4958
|
}
|
|
4720
4959
|
for (const override of change.meta?.overrides ?? []) {
|
|
4721
4960
|
if (!override.reason.trim() || !override.by.trim()) {
|
|
4722
|
-
findings.push(diag("ATLAS-LIFECYCLE-004", "error", `Override del gate "${override.gate}" sin motivo o autor`, { path:
|
|
4961
|
+
findings.push(diag("ATLAS-LIFECYCLE-004", "error", `Override del gate "${override.gate}" sin motivo o autor`, { path: path21.join(change.dir, "meta.yaml") }));
|
|
4723
4962
|
}
|
|
4724
4963
|
}
|
|
4725
4964
|
}
|
|
@@ -4742,7 +4981,7 @@ async function specHashOf(filePath) {
|
|
|
4742
4981
|
}
|
|
4743
4982
|
|
|
4744
4983
|
// src/gate.ts
|
|
4745
|
-
import
|
|
4984
|
+
import path22 from "path";
|
|
4746
4985
|
var UI_DOMAINS2 = /* @__PURE__ */ new Set(["frontend", "mobile", "fullstack"]);
|
|
4747
4986
|
function count(name, diagnostics) {
|
|
4748
4987
|
return {
|
|
@@ -4759,7 +4998,7 @@ function livingRequirementsMap(specs) {
|
|
|
4759
4998
|
return map;
|
|
4760
4999
|
}
|
|
4761
5000
|
async function runCiGate(opts) {
|
|
4762
|
-
const root =
|
|
5001
|
+
const root = path22.resolve(opts.root);
|
|
4763
5002
|
const { workspace, config } = await loadWorkspace(root);
|
|
4764
5003
|
const diagnostics = [];
|
|
4765
5004
|
const checks = [];
|
|
@@ -4770,7 +5009,7 @@ async function runCiGate(opts) {
|
|
|
4770
5009
|
let changesErrors = 0;
|
|
4771
5010
|
let changesWarnings = 0;
|
|
4772
5011
|
for (const change of workspace.changes) {
|
|
4773
|
-
const lintFindings = change.delta ? lintDelta(change.delta, living,
|
|
5012
|
+
const lintFindings = change.delta ? lintDelta(change.delta, living, path22.join(change.dir, "spec.md"), { language: config.spec.language }) : [];
|
|
4774
5013
|
const trace = checkTrace({
|
|
4775
5014
|
specs: workspace.specs,
|
|
4776
5015
|
change,
|
|
@@ -4820,6 +5059,8 @@ export {
|
|
|
4820
5059
|
BUILTIN_PACKS,
|
|
4821
5060
|
CONFIG_FILE,
|
|
4822
5061
|
CORE_VERSION,
|
|
5062
|
+
DOCS_MARKER_END,
|
|
5063
|
+
DOCS_MARKER_START,
|
|
4823
5064
|
LIVING_FIXES_DIR,
|
|
4824
5065
|
REQ_HEAD_RE,
|
|
4825
5066
|
REQ_ID_RE,
|
|
@@ -4854,6 +5095,7 @@ export {
|
|
|
4854
5095
|
changeMetaYaml,
|
|
4855
5096
|
checkMockups,
|
|
4856
5097
|
checkTrace,
|
|
5098
|
+
clarifyAdvisory,
|
|
4857
5099
|
collectMetrics,
|
|
4858
5100
|
collectVersionedArtifacts,
|
|
4859
5101
|
commentIssue,
|
|
@@ -4872,6 +5114,8 @@ export {
|
|
|
4872
5114
|
detectRepo,
|
|
4873
5115
|
detectionToYaml,
|
|
4874
5116
|
diag,
|
|
5117
|
+
docsAdvisory,
|
|
5118
|
+
docsReady,
|
|
4875
5119
|
editIssue,
|
|
4876
5120
|
emitFrontmatter,
|
|
4877
5121
|
ensureDir,
|
|
@@ -4884,6 +5128,7 @@ export {
|
|
|
4884
5128
|
findWorkspaceRoot,
|
|
4885
5129
|
firstToken,
|
|
4886
5130
|
foldDelta,
|
|
5131
|
+
generateDocs,
|
|
4887
5132
|
generatePresentation,
|
|
4888
5133
|
generateRunId,
|
|
4889
5134
|
getNumber,
|
|
@@ -4939,6 +5184,7 @@ export {
|
|
|
4939
5184
|
packFindings,
|
|
4940
5185
|
parseApprovals,
|
|
4941
5186
|
parseChangeMeta,
|
|
5187
|
+
parseClarify,
|
|
4942
5188
|
parseConfig,
|
|
4943
5189
|
parseDelta,
|
|
4944
5190
|
parseFixCovers,
|