specatlas 0.1.3 → 0.1.5
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 +16 -16
- package/package.json +2 -2
- package/workflow/phases/specify.md +2 -2
package/dist/bin.js
CHANGED
|
@@ -11845,7 +11845,7 @@ async function generatePresentation(opts) {
|
|
|
11845
11845
|
language,
|
|
11846
11846
|
labels,
|
|
11847
11847
|
title: change.meta?.title ?? change.slug,
|
|
11848
|
-
domain: change.meta?.domain ?? "\
|
|
11848
|
+
domain: change.meta?.domain ?? "\u2014",
|
|
11849
11849
|
lane: change.meta?.lane ?? config.lanes.default,
|
|
11850
11850
|
project: config.project.name,
|
|
11851
11851
|
version: change.delta.sectionsFound.length,
|
|
@@ -11872,7 +11872,7 @@ async function copyMockups(root, change, destDir) {
|
|
|
11872
11872
|
for (const screen of manifest.screens) {
|
|
11873
11873
|
const src = path12.join(dir, screen.file);
|
|
11874
11874
|
if (!await exists(src)) {
|
|
11875
|
-
diagnostics.push(diag("ATLAS-PRESENT-002", "warning", `El mockup ${screen.file} no existe y no se incluir\
|
|
11875
|
+
diagnostics.push(diag("ATLAS-PRESENT-002", "warning", `El mockup ${screen.file} no existe y no se incluir\xE1`, { path: src }));
|
|
11876
11876
|
continue;
|
|
11877
11877
|
}
|
|
11878
11878
|
await copyFile(src, path12.join(destDir, screen.file));
|
|
@@ -11923,15 +11923,15 @@ function labelsFor(language) {
|
|
|
11923
11923
|
return {
|
|
11924
11924
|
kicker: "Propuesta",
|
|
11925
11925
|
summary: "Resumen de negocio",
|
|
11926
|
-
criteria: "Criterios de aceptaci\
|
|
11926
|
+
criteria: "Criterios de aceptaci\xF3n",
|
|
11927
11927
|
requirements: "Requisitos y escenarios",
|
|
11928
11928
|
mockups: "Mockups",
|
|
11929
|
-
approve: "Aprobaci\
|
|
11929
|
+
approve: "Aprobaci\xF3n",
|
|
11930
11930
|
approveText: "Esta propuesta se aprueba firmando la spec (hash + autor). Cualquier cambio posterior invalida la firma.",
|
|
11931
11931
|
command: "Comando",
|
|
11932
11932
|
hash: "Hash",
|
|
11933
11933
|
generated: "Generado",
|
|
11934
|
-
noProposal: "La propuesta est\
|
|
11934
|
+
noProposal: "La propuesta est\xE1 vac\xEDa.",
|
|
11935
11935
|
added: "agregado",
|
|
11936
11936
|
modified: "modificado",
|
|
11937
11937
|
scenario: "Escenario",
|
|
@@ -11986,13 +11986,13 @@ footer { color: var(--muted); font-size: 13px; text-align:center; }
|
|
|
11986
11986
|
function page(input) {
|
|
11987
11987
|
const l = input.labels;
|
|
11988
11988
|
const reqHtml = input.requirements.map(({ req, kind }) => {
|
|
11989
|
-
const rules = req.rules.map((r) => `<li><code>${esc(r.id)}</code> \
|
|
11989
|
+
const rules = req.rules.map((r) => `<li><code>${esc(r.id)}</code> \u2014 ${inline(r.text)}</li>`).join("");
|
|
11990
11990
|
const scenarios = req.scenarios.map((s) => {
|
|
11991
11991
|
const when = s.when.map((w) => `<div class="when">CUANDO ${inline(w)}</div>`).join("");
|
|
11992
11992
|
const then = s.then.map((t) => `<div class="then">ENTONCES ${inline(t)}</div>`).join("");
|
|
11993
|
-
return `<div class="scenario"><h4>${esc(s.id)} \
|
|
11993
|
+
return `<div class="scenario"><h4>${esc(s.id)} \u2014 ${esc(s.title)}</h4>${when}${then}</div>`;
|
|
11994
11994
|
}).join("");
|
|
11995
|
-
return `<div class="req"><h3>${esc(req.id)} \
|
|
11995
|
+
return `<div class="req"><h3>${esc(req.id)} \u2014 ${esc(req.title)}<span class="badge">${kind === "added" ? l.added : l.modified}</span></h3><p>${inline(req.prose)}</p>${rules ? `<ul class="rules">${rules}</ul>` : ""}${scenarios}</div>`;
|
|
11996
11996
|
}).join("");
|
|
11997
11997
|
const criteriaRows = input.requirements.flatMap(({ req }) => req.scenarios).map((s) => {
|
|
11998
11998
|
const status = input.evidence.get(s.id);
|
|
@@ -12001,7 +12001,7 @@ function page(input) {
|
|
|
12001
12001
|
return `<tr><td><code>${esc(s.id)}</code></td><td>${esc(s.title)}</td><td><span class="pill ${cls}">${esc(label)}</span></td></tr>`;
|
|
12002
12002
|
}).join("");
|
|
12003
12003
|
const mockupHtml = input.mockups.length === 0 ? `<p><em>${l.noMockups}</em></p>` : `<div class="mockups">${input.mockups.map(
|
|
12004
|
-
(m) => `<div class="mockup ${m.platform === "mobile" ? "phone" : ""}"><header>${esc(m.title)} \
|
|
12004
|
+
(m) => `<div class="mockup ${m.platform === "mobile" ? "phone" : ""}"><header>${esc(m.title)} \u2014 ${esc(m.file)}</header><iframe src="${esc(m.file)}" loading="lazy" title="${esc(m.title)}"></iframe></div>`
|
|
12005
12005
|
).join("")}</div>`;
|
|
12006
12006
|
const shotsHtml = input.screenshots.length === 0 ? "" : `<h3>${l.screenshots}</h3><div class="grid-shots">${input.screenshots.map((s) => `<img src="${esc(s)}" alt="${esc(s)}" loading="lazy">`).join("")}</div>`;
|
|
12007
12007
|
return `<!doctype html>
|
|
@@ -12009,15 +12009,15 @@ function page(input) {
|
|
|
12009
12009
|
<head>
|
|
12010
12010
|
<meta charset="utf-8">
|
|
12011
12011
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
12012
|
-
<title>${esc(l.kicker)} \
|
|
12012
|
+
<title>${esc(l.kicker)} \u2014 ${esc(input.title)}</title>
|
|
12013
12013
|
<style>${CSS}</style>
|
|
12014
12014
|
</head>
|
|
12015
12015
|
<body>
|
|
12016
12016
|
<div class="wrap">
|
|
12017
12017
|
<header class="hero">
|
|
12018
|
-
<p class="kicker">${esc(l.kicker)} \
|
|
12018
|
+
<p class="kicker">${esc(l.kicker)} \xB7 ${esc(input.domain)} \xB7 ${esc(input.lane)}</p>
|
|
12019
12019
|
<h1>${esc(input.title)}</h1>
|
|
12020
|
-
<p class="meta">${esc(input.project)} \
|
|
12020
|
+
<p class="meta">${esc(input.project)} \xB7 ${esc(l.hash)} ${esc(shortHash(input.hash))} \xB7 ${esc(l.generated)} ${esc(input.generatedAt)}</p>
|
|
12021
12021
|
</header>
|
|
12022
12022
|
|
|
12023
12023
|
<section>
|
|
@@ -12047,7 +12047,7 @@ function page(input) {
|
|
|
12047
12047
|
<p>${esc(l.command)}: <code>${esc(input.approveHint)}</code></p>
|
|
12048
12048
|
</section>
|
|
12049
12049
|
|
|
12050
|
-
<footer>SpecAtlas \
|
|
12050
|
+
<footer>SpecAtlas \xB7 ${esc(input.project)} \xB7 ${esc(input.generatedAt)}</footer>
|
|
12051
12051
|
</div>
|
|
12052
12052
|
</body>
|
|
12053
12053
|
</html>
|
|
@@ -13443,9 +13443,9 @@ async function runArchive(ctx) {
|
|
|
13443
13443
|
diagnostics: [
|
|
13444
13444
|
{
|
|
13445
13445
|
code: "ATLAS-ARCHIVE-001",
|
|
13446
|
-
severity: "
|
|
13447
|
-
message: `
|
|
13448
|
-
suggestion:
|
|
13446
|
+
severity: "warning",
|
|
13447
|
+
message: `Confirmaci\xF3n requerida: archivar "${slug}" pliega sus deltas en la spec viva y mueve el cambio al hist\xF3rico.`,
|
|
13448
|
+
suggestion: `Revisa primero con \`satlas archive ${slug} --dry-run\` y confirma con \`satlas archive ${slug} --yes\``
|
|
13449
13449
|
}
|
|
13450
13450
|
]
|
|
13451
13451
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specatlas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
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.2"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"typecheck": "tsc --noEmit",
|
|
@@ -26,14 +26,14 @@ El contenido se escribe en **{{LANGUAGE_NAME}}**.
|
|
|
26
26
|
|
|
27
27
|
1. Lee `.sdd/constitution.md`, `.sdd/glossary.md` y las specs vivas de `.sdd/specs/**/spec.md` que toquen el dominio.
|
|
28
28
|
2. Si hay código existente relacionado, inspecciónalo solo para entender el comportamiento actual (AS-IS); no lo describas con tecnología en la spec.
|
|
29
|
-
3. Si falta información de negocio, **pregunta** (máximo 5 preguntas concretas) antes de escribir. No inventes reglas.
|
|
29
|
+
3. Si falta información de negocio, **pregunta** (máximo 5 preguntas concretas) antes de escribir: incluye la **historia de usuario** («como <rol>, quiero <acción>, para <beneficio>») cuando no esté clara. No inventes reglas.
|
|
30
30
|
4. Redacta el delta con las secciones canónicas:
|
|
31
31
|
- `## Requisitos agregados` (`ADDED`), `## Requisitos modificados` (`MODIFIED`), `## Requisitos eliminados` (`REMOVED`), `## Requisitos renombrados` (`RENAMED`).
|
|
32
32
|
- Cada requisito: `### Requisito: REQ-<DOMINIO>-NNN — Título` (ids inmutables), prosa de negocio, reglas `- Regla BR-<DOMINIO>-NNN: ...` y escenarios `#### Escenario: REQ-<DOMINIO>-NNN-S1 — Título` con `- **CUANDO** ...` / `- **ENTONCES** ...`.
|
|
33
33
|
- Incluye siempre escenarios de error, vacío, sin permiso y límites.
|
|
34
34
|
- `MODIFIED` copia el bloque **completo** del requisito tal como está en la spec viva y lo edita.
|
|
35
35
|
- `REMOVED` declara `- Motivo:` y `- Migración:`.
|
|
36
|
-
5. Completa `.sdd/changes/{{SLUG}}/proposal.md` en lenguaje de negocio (sin tecnología y sin dejar los textos entre paréntesis de la plantilla): **Por qué** (problema u oportunidad), **Qué cambia** (alcance funcional), **Fuera de alcance** (lo que no se hará) y **Cómo se mide el éxito** (indicadores observables).
|
|
36
|
+
5. Completa `.sdd/changes/{{SLUG}}/proposal.md` en lenguaje de negocio (sin tecnología y sin dejar los textos entre paréntesis de la plantilla): **Por qué** (problema u oportunidad, con la historia de usuario), **Qué cambia** (alcance funcional), **Fuera de alcance** (lo que no se hará) y **Cómo se mide el éxito** (indicadores observables).
|
|
37
37
|
6. Verifica con el CLI y corrige hasta que no haya errores:
|
|
38
38
|
|
|
39
39
|
```
|