docviz-builder 0.1.0
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/AGENTS.md +371 -0
- package/LICENSE +21 -0
- package/README.md +837 -0
- package/bin/docviz-mcp.mjs +10 -0
- package/bin/docviz.mjs +11 -0
- package/dist/build/builder.d.ts +62 -0
- package/dist/build/builder.d.ts.map +1 -0
- package/dist/build/builder.js +337 -0
- package/dist/build/builder.js.map +1 -0
- package/dist/build/diff.d.ts +64 -0
- package/dist/build/diff.d.ts.map +1 -0
- package/dist/build/diff.js +156 -0
- package/dist/build/diff.js.map +1 -0
- package/dist/build/doctor.d.ts +39 -0
- package/dist/build/doctor.d.ts.map +1 -0
- package/dist/build/doctor.js +190 -0
- package/dist/build/doctor.js.map +1 -0
- package/dist/build/init.d.ts +28 -0
- package/dist/build/init.d.ts.map +1 -0
- package/dist/build/init.js +274 -0
- package/dist/build/init.js.map +1 -0
- package/dist/build/preview.d.ts +13 -0
- package/dist/build/preview.d.ts.map +1 -0
- package/dist/build/preview.js +277 -0
- package/dist/build/preview.js.map +1 -0
- package/dist/build/skill.d.ts +41 -0
- package/dist/build/skill.d.ts.map +1 -0
- package/dist/build/skill.js +63 -0
- package/dist/build/skill.js.map +1 -0
- package/dist/build/verify.d.ts +26 -0
- package/dist/build/verify.d.ts.map +1 -0
- package/dist/build/verify.js +99 -0
- package/dist/build/verify.js.map +1 -0
- package/dist/cli.d.ts +20 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +427 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/load.d.ts +32 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/load.js +279 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/types.d.ts +89 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +5 -0
- package/dist/config/types.js.map +1 -0
- package/dist/core/cache.d.ts +32 -0
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +69 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/errors.d.ts +115 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +164 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/hash.d.ts +57 -0
- package/dist/core/hash.d.ts.map +1 -0
- package/dist/core/hash.js +0 -0
- package/dist/core/hash.js.map +1 -0
- package/dist/core/package-version.d.ts +9 -0
- package/dist/core/package-version.d.ts.map +1 -0
- package/dist/core/package-version.js +44 -0
- package/dist/core/package-version.js.map +1 -0
- package/dist/core/paths.d.ts +46 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +105 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/registry.d.ts +24 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +72 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/types.d.ts +78 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +11 -0
- package/dist/core/types.js.map +1 -0
- package/dist/dsl/architecture.d.ts +15 -0
- package/dist/dsl/architecture.d.ts.map +1 -0
- package/dist/dsl/architecture.js +242 -0
- package/dist/dsl/architecture.js.map +1 -0
- package/dist/dsl/catalog.d.ts +62 -0
- package/dist/dsl/catalog.d.ts.map +1 -0
- package/dist/dsl/catalog.en.d.ts +18 -0
- package/dist/dsl/catalog.en.d.ts.map +1 -0
- package/dist/dsl/catalog.en.js +299 -0
- package/dist/dsl/catalog.en.js.map +1 -0
- package/dist/dsl/catalog.js +1082 -0
- package/dist/dsl/catalog.js.map +1 -0
- package/dist/dsl/chart.d.ts +14 -0
- package/dist/dsl/chart.d.ts.map +1 -0
- package/dist/dsl/chart.js +435 -0
- package/dist/dsl/chart.js.map +1 -0
- package/dist/dsl/compile.d.ts +31 -0
- package/dist/dsl/compile.d.ts.map +1 -0
- package/dist/dsl/compile.js +120 -0
- package/dist/dsl/compile.js.map +1 -0
- package/dist/dsl/diagram-bpmn.d.ts +13 -0
- package/dist/dsl/diagram-bpmn.d.ts.map +1 -0
- package/dist/dsl/diagram-bpmn.js +215 -0
- package/dist/dsl/diagram-bpmn.js.map +1 -0
- package/dist/dsl/diagram-product.d.ts +15 -0
- package/dist/dsl/diagram-product.d.ts.map +1 -0
- package/dist/dsl/diagram-product.js +291 -0
- package/dist/dsl/diagram-product.js.map +1 -0
- package/dist/dsl/diagram-technical.d.ts +28 -0
- package/dist/dsl/diagram-technical.d.ts.map +1 -0
- package/dist/dsl/diagram-technical.js +365 -0
- package/dist/dsl/diagram-technical.js.map +1 -0
- package/dist/dsl/diagram.d.ts +22 -0
- package/dist/dsl/diagram.d.ts.map +1 -0
- package/dist/dsl/diagram.js +542 -0
- package/dist/dsl/diagram.js.map +1 -0
- package/dist/dsl/fallbacks-d2.d.ts +27 -0
- package/dist/dsl/fallbacks-d2.d.ts.map +1 -0
- package/dist/dsl/fallbacks-d2.js +265 -0
- package/dist/dsl/fallbacks-d2.js.map +1 -0
- package/dist/dsl/fallbacks.d.ts +25 -0
- package/dist/dsl/fallbacks.d.ts.map +1 -0
- package/dist/dsl/fallbacks.js +264 -0
- package/dist/dsl/fallbacks.js.map +1 -0
- package/dist/dsl/fields.d.ts +93 -0
- package/dist/dsl/fields.d.ts.map +1 -0
- package/dist/dsl/fields.js +233 -0
- package/dist/dsl/fields.js.map +1 -0
- package/dist/dsl/index.d.ts +50 -0
- package/dist/dsl/index.d.ts.map +1 -0
- package/dist/dsl/index.js +114 -0
- package/dist/dsl/index.js.map +1 -0
- package/dist/dsl/util.d.ts +105 -0
- package/dist/dsl/util.d.ts.map +1 -0
- package/dist/dsl/util.js +261 -0
- package/dist/dsl/util.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/markdown/scan.d.ts +73 -0
- package/dist/markdown/scan.d.ts.map +1 -0
- package/dist/markdown/scan.js +150 -0
- package/dist/markdown/scan.js.map +1 -0
- package/dist/markdown/transform.d.ts +28 -0
- package/dist/markdown/transform.d.ts.map +1 -0
- package/dist/markdown/transform.js +38 -0
- package/dist/markdown/transform.js.map +1 -0
- package/dist/mcp/server.d.ts +18 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +118 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +118 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +573 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/renderers/base.d.ts +18 -0
- package/dist/renderers/base.d.ts.map +1 -0
- package/dist/renderers/base.js +59 -0
- package/dist/renderers/base.js.map +1 -0
- package/dist/renderers/bpmn.d.ts +68 -0
- package/dist/renderers/bpmn.d.ts.map +1 -0
- package/dist/renderers/bpmn.js +158 -0
- package/dist/renderers/bpmn.js.map +1 -0
- package/dist/renderers/browser.d.ts +30 -0
- package/dist/renderers/browser.d.ts.map +1 -0
- package/dist/renderers/browser.js +143 -0
- package/dist/renderers/browser.js.map +1 -0
- package/dist/renderers/color-scheme.d.ts +40 -0
- package/dist/renderers/color-scheme.d.ts.map +1 -0
- package/dist/renderers/color-scheme.js +122 -0
- package/dist/renderers/color-scheme.js.map +1 -0
- package/dist/renderers/d2.d.ts +37 -0
- package/dist/renderers/d2.d.ts.map +1 -0
- package/dist/renderers/d2.js +108 -0
- package/dist/renderers/d2.js.map +1 -0
- package/dist/renderers/graphviz.d.ts +33 -0
- package/dist/renderers/graphviz.d.ts.map +1 -0
- package/dist/renderers/graphviz.js +88 -0
- package/dist/renderers/graphviz.js.map +1 -0
- package/dist/renderers/in-page.d.ts +33 -0
- package/dist/renderers/in-page.d.ts.map +1 -0
- package/dist/renderers/in-page.js +76 -0
- package/dist/renderers/in-page.js.map +1 -0
- package/dist/renderers/index.d.ts +20 -0
- package/dist/renderers/index.d.ts.map +1 -0
- package/dist/renderers/index.js +94 -0
- package/dist/renderers/index.js.map +1 -0
- package/dist/renderers/kroki.d.ts +38 -0
- package/dist/renderers/kroki.d.ts.map +1 -0
- package/dist/renderers/kroki.js +151 -0
- package/dist/renderers/kroki.js.map +1 -0
- package/dist/renderers/likec4-svg.d.ts +82 -0
- package/dist/renderers/likec4-svg.d.ts.map +1 -0
- package/dist/renderers/likec4-svg.js +435 -0
- package/dist/renderers/likec4-svg.js.map +1 -0
- package/dist/renderers/likec4.d.ts +22 -0
- package/dist/renderers/likec4.d.ts.map +1 -0
- package/dist/renderers/likec4.js +77 -0
- package/dist/renderers/likec4.js.map +1 -0
- package/dist/renderers/mermaid.d.ts +64 -0
- package/dist/renderers/mermaid.d.ts.map +1 -0
- package/dist/renderers/mermaid.js +196 -0
- package/dist/renderers/mermaid.js.map +1 -0
- package/dist/renderers/plantuml.d.ts +56 -0
- package/dist/renderers/plantuml.d.ts.map +1 -0
- package/dist/renderers/plantuml.js +195 -0
- package/dist/renderers/plantuml.js.map +1 -0
- package/dist/renderers/svg-utils.d.ts +46 -0
- package/dist/renderers/svg-utils.d.ts.map +1 -0
- package/dist/renderers/svg-utils.js +439 -0
- package/dist/renderers/svg-utils.js.map +1 -0
- package/dist/renderers/svgbob.d.ts +26 -0
- package/dist/renderers/svgbob.d.ts.map +1 -0
- package/dist/renderers/svgbob.js +70 -0
- package/dist/renderers/svgbob.js.map +1 -0
- package/dist/renderers/vega-lite.d.ts +18 -0
- package/dist/renderers/vega-lite.d.ts.map +1 -0
- package/dist/renderers/vega-lite.js +94 -0
- package/dist/renderers/vega-lite.js.map +1 -0
- package/dist/themes/index.d.ts +17 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/index.js +419 -0
- package/dist/themes/index.js.map +1 -0
- package/dist/themes/types.d.ts +99 -0
- package/dist/themes/types.d.ts.map +1 -0
- package/dist/themes/types.js +9 -0
- package/dist/themes/types.js.map +1 -0
- package/eval/casos.json +513 -0
- package/package.json +114 -0
- package/scripts/capture-preview.mjs +101 -0
- package/scripts/check-github.mjs +128 -0
- package/scripts/eval.d.mts +8 -0
- package/scripts/eval.mjs +284 -0
- package/scripts/fetch-plantuml.mjs +122 -0
- package/scripts/generate-catalog-doc.mjs +106 -0
- package/scripts/rasterize.mjs +68 -0
- package/scripts/sync-docs.mjs +158 -0
- package/skills/docviz/SKILL.md +111 -0
- package/vendor/.gitkeep +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instalacion del contrato de DocViz como skill de agente.
|
|
3
|
+
*
|
|
4
|
+
* `docviz init` deja un `AGENTS.md` en el proyecto, y eso basta para los
|
|
5
|
+
* agentes que lo leen solos. Pero un agente solo abre `AGENTS.md` si ya esta
|
|
6
|
+
* trabajando en ese repositorio: no hay forma de que sepa que DocViz existe
|
|
7
|
+
* antes de eso. Un skill instalado —en el proyecto o en el perfil del usuario—
|
|
8
|
+
* lo pone en su radar desde el primer mensaje.
|
|
9
|
+
*/
|
|
10
|
+
import { copyFile, mkdir, readFile } from 'node:fs/promises';
|
|
11
|
+
import { existsSync } from 'node:fs';
|
|
12
|
+
import { homedir } from 'node:os';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
import { DocVizError, ERROR_CODES } from '../core/errors.js';
|
|
16
|
+
/** Fuente del skill dentro del propio paquete. */
|
|
17
|
+
export function skillSourcePath() {
|
|
18
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
// dist/build/skill.js -> raiz del paquete
|
|
20
|
+
return path.resolve(here, '..', '..', 'skills', 'docviz', 'SKILL.md');
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Directorio donde el agente busca sus skills.
|
|
24
|
+
*
|
|
25
|
+
* Se admite `dir` explicito porque cada agente elige el suyo y esa lista
|
|
26
|
+
* cambia mas rapido que este paquete: fijarla aqui garantizaria quedarse
|
|
27
|
+
* desactualizado.
|
|
28
|
+
*/
|
|
29
|
+
export function skillTargetDir(options) {
|
|
30
|
+
if (options.dir !== undefined)
|
|
31
|
+
return path.resolve(options.cwd, options.dir);
|
|
32
|
+
const base = options.global === true ? homedir() : options.cwd;
|
|
33
|
+
return path.join(base, '.claude', 'skills');
|
|
34
|
+
}
|
|
35
|
+
export async function installSkill(options) {
|
|
36
|
+
const origen = skillSourcePath();
|
|
37
|
+
if (!existsSync(origen)) {
|
|
38
|
+
throw new DocVizError('el paquete no incluye el skill', {}, `se esperaba en ${origen}`, ERROR_CODES.CONFIG);
|
|
39
|
+
}
|
|
40
|
+
const destino = path.join(skillTargetDir(options), 'docviz', 'SKILL.md');
|
|
41
|
+
if (existsSync(destino) && options.force !== true) {
|
|
42
|
+
return { destino, escrito: false, motivo: 'ya existe' };
|
|
43
|
+
}
|
|
44
|
+
await mkdir(path.dirname(destino), { recursive: true });
|
|
45
|
+
await copyFile(origen, destino);
|
|
46
|
+
return { destino, escrito: true };
|
|
47
|
+
}
|
|
48
|
+
/** Informe legible de la instalacion. */
|
|
49
|
+
export function formatearSkill(result) {
|
|
50
|
+
if (!result.escrito) {
|
|
51
|
+
return (`\nel skill ya estaba instalado en ${result.destino}\n` +
|
|
52
|
+
' (usa --force para sobrescribirlo)\n\n');
|
|
53
|
+
}
|
|
54
|
+
return (`\nskill instalado en ${result.destino}\n\n` +
|
|
55
|
+
'A partir de ahora tu agente sabe que DocViz existe y como usarlo.\n' +
|
|
56
|
+
'Para el catalogo completo de los 57 tipos, ejecuta `docviz init` en el\n' +
|
|
57
|
+
'proyecto: deja un AGENTS.md con las tablas de decision.\n\n');
|
|
58
|
+
}
|
|
59
|
+
/** Contenido del skill, para comprobar que sigue siendo valido. */
|
|
60
|
+
export async function readSkill() {
|
|
61
|
+
return readFile(skillSourcePath(), 'utf8');
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.js","sourceRoot":"","sources":["../../src/build/skill.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAoB7D,kDAAkD;AAClD,MAAM,UAAU,eAAe;IAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,0CAA0C;IAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;AACxE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,OAAqB;IAClD,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7E,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IAC/D,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAqB;IACtD,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,WAAW,CACnB,gCAAgC,EAChC,EAAE,EACF,kBAAkB,MAAM,EAAE,EAC1B,WAAW,CAAC,MAAM,CACnB,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IACzE,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QAClD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAC1D,CAAC;IAED,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACpC,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,cAAc,CAAC,MAAmB;IAChD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CACL,qCAAqC,MAAM,CAAC,OAAO,IAAI;YACvD,yCAAyC,CAC1C,CAAC;IACJ,CAAC;IACD,OAAO,CACL,wBAAwB,MAAM,CAAC,OAAO,MAAM;QAC5C,qEAAqE;QACrE,0EAA0E;QAC1E,6DAA6D,CAC9D,CAAC;AACJ,CAAC;AAED,mEAAmE;AACnE,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,OAAO,QAAQ,CAAC,eAAe,EAAE,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verificacion del Markdown ya compilado.
|
|
3
|
+
*
|
|
4
|
+
* Responde a la pregunta del criterio de aceptacion "no hay imagenes rotas":
|
|
5
|
+
* cada referencia de imagen del documento debe existir en disco, ser relativa y
|
|
6
|
+
* quedar dentro del directorio de salida.
|
|
7
|
+
*/
|
|
8
|
+
export interface VerifyIssue {
|
|
9
|
+
file: string;
|
|
10
|
+
line: number;
|
|
11
|
+
url: string;
|
|
12
|
+
reason: string;
|
|
13
|
+
}
|
|
14
|
+
export interface VerifyResult {
|
|
15
|
+
documents: number;
|
|
16
|
+
images: number;
|
|
17
|
+
/** Bloques declarativos que quedaron sin compilar en la salida. */
|
|
18
|
+
residualBlocks: Array<{
|
|
19
|
+
file: string;
|
|
20
|
+
line: number;
|
|
21
|
+
lang: string;
|
|
22
|
+
}>;
|
|
23
|
+
issues: VerifyIssue[];
|
|
24
|
+
}
|
|
25
|
+
export declare function verify(outputDir: string): Promise<VerifyResult>;
|
|
26
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/build/verify.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,cAAc,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpE,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAqBD,wBAAsB,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAwErE"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verificacion del Markdown ya compilado.
|
|
3
|
+
*
|
|
4
|
+
* Responde a la pregunta del criterio de aceptacion "no hay imagenes rotas":
|
|
5
|
+
* cada referencia de imagen del documento debe existir en disco, ser relativa y
|
|
6
|
+
* quedar dentro del directorio de salida.
|
|
7
|
+
*/
|
|
8
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { visit } from 'unist-util-visit';
|
|
11
|
+
import { parseMarkdown } from '../markdown/scan.js';
|
|
12
|
+
import { collectMarkdown } from './builder.js';
|
|
13
|
+
import { toPosix } from '../core/paths.js';
|
|
14
|
+
const DECLARATIVE_LANGS = new Set([
|
|
15
|
+
'plantuml',
|
|
16
|
+
'puml',
|
|
17
|
+
'uml',
|
|
18
|
+
'mermaid',
|
|
19
|
+
'mmd',
|
|
20
|
+
'd2',
|
|
21
|
+
'graphviz',
|
|
22
|
+
'dot',
|
|
23
|
+
'vega-lite',
|
|
24
|
+
'vegalite',
|
|
25
|
+
'vl',
|
|
26
|
+
'likec4',
|
|
27
|
+
'c4',
|
|
28
|
+
'diagram',
|
|
29
|
+
'chart',
|
|
30
|
+
'architecture',
|
|
31
|
+
]);
|
|
32
|
+
export async function verify(outputDir) {
|
|
33
|
+
const files = await collectMarkdown(outputDir);
|
|
34
|
+
const result = { documents: files.length, images: 0, residualBlocks: [], issues: [] };
|
|
35
|
+
for (const file of files) {
|
|
36
|
+
const relative = toPosix(path.relative(outputDir, file));
|
|
37
|
+
const text = await readFile(file, 'utf8');
|
|
38
|
+
const tree = parseMarkdown(text);
|
|
39
|
+
const images = [];
|
|
40
|
+
visit(tree, 'image', (node) => {
|
|
41
|
+
images.push({ url: node.url, line: node.position?.start.line ?? 0, alt: node.alt ?? null });
|
|
42
|
+
});
|
|
43
|
+
visit(tree, 'code', (node) => {
|
|
44
|
+
const lang = (node.lang ?? '').trim().toLowerCase();
|
|
45
|
+
if (DECLARATIVE_LANGS.has(lang)) {
|
|
46
|
+
result.residualBlocks.push({ file: relative, line: node.position?.start.line ?? 0, lang });
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
for (const image of images) {
|
|
50
|
+
result.images += 1;
|
|
51
|
+
const { url } = image;
|
|
52
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(url)) {
|
|
53
|
+
if (!url.startsWith('data:')) {
|
|
54
|
+
result.issues.push({
|
|
55
|
+
file: relative,
|
|
56
|
+
line: image.line,
|
|
57
|
+
url,
|
|
58
|
+
reason: 'la imagen usa una URL absoluta en lugar de una ruta relativa',
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (url.startsWith('/')) {
|
|
64
|
+
result.issues.push({
|
|
65
|
+
file: relative,
|
|
66
|
+
line: image.line,
|
|
67
|
+
url,
|
|
68
|
+
reason: 'la ruta de la imagen es absoluta; el documento dejaria de funcionar al moverlo',
|
|
69
|
+
});
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const clean = decodeURIComponent(url.replace(/^<|>$/g, '').split('#')[0].split('?')[0]);
|
|
73
|
+
const target = path.resolve(path.dirname(file), clean);
|
|
74
|
+
if (path.relative(outputDir, target).startsWith('..')) {
|
|
75
|
+
result.issues.push({
|
|
76
|
+
file: relative,
|
|
77
|
+
line: image.line,
|
|
78
|
+
url,
|
|
79
|
+
reason: 'la imagen apunta fuera del directorio de salida',
|
|
80
|
+
});
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const info = await stat(target);
|
|
85
|
+
if (!info.isFile() || info.size === 0) {
|
|
86
|
+
result.issues.push({ file: relative, line: image.line, url, reason: 'el recurso existe pero esta vacio' });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
result.issues.push({ file: relative, line: image.line, url, reason: 'el recurso no existe' });
|
|
91
|
+
}
|
|
92
|
+
if (image.alt === null || image.alt.trim() === '') {
|
|
93
|
+
result.issues.push({ file: relative, line: image.line, url, reason: 'la imagen no tiene texto alternativo' });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/build/verify.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interfaz de linea de comandos (seccion 17).
|
|
3
|
+
*
|
|
4
|
+
* docviz build <source> --output <target> [--theme ...] [--clean] ...
|
|
5
|
+
* docviz check <source>
|
|
6
|
+
* docviz diff <base> <head>
|
|
7
|
+
* docviz setup
|
|
8
|
+
* docviz skill
|
|
9
|
+
* docviz fix <archivo>
|
|
10
|
+
* docviz verify <output>
|
|
11
|
+
* docviz preview <output>
|
|
12
|
+
* docviz types
|
|
13
|
+
*/
|
|
14
|
+
import { Command } from 'commander';
|
|
15
|
+
export declare function createProgram(): Command;
|
|
16
|
+
/** Ficha legible de un tipo, con su ejemplo listo para copiar. */
|
|
17
|
+
/** Idiomas en los que se puede leer el catalogo. */
|
|
18
|
+
export type Idioma = 'es' | 'en';
|
|
19
|
+
export declare function run(argv?: readonly string[]): Promise<number>;
|
|
20
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2BpC,wBAAgB,aAAa,IAAI,OAAO,CAkXvC;AAED,kEAAkE;AAClE,oDAAoD;AACpD,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;AAgEjC,wBAAsB,GAAG,CAAC,IAAI,GAAE,SAAS,MAAM,EAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBjF"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interfaz de linea de comandos (seccion 17).
|
|
3
|
+
*
|
|
4
|
+
* docviz build <source> --output <target> [--theme ...] [--clean] ...
|
|
5
|
+
* docviz check <source>
|
|
6
|
+
* docviz diff <base> <head>
|
|
7
|
+
* docviz setup
|
|
8
|
+
* docviz skill
|
|
9
|
+
* docviz fix <archivo>
|
|
10
|
+
* docviz verify <output>
|
|
11
|
+
* docviz preview <output>
|
|
12
|
+
* docviz types
|
|
13
|
+
*/
|
|
14
|
+
import { execFile } from 'node:child_process';
|
|
15
|
+
import { readFile } from 'node:fs/promises';
|
|
16
|
+
import path from 'node:path';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
import { promisify } from 'node:util';
|
|
19
|
+
import { Command } from 'commander';
|
|
20
|
+
import { build, check } from './build/builder.js';
|
|
21
|
+
import { diff, formatDiff, hasChanges } from './build/diff.js';
|
|
22
|
+
import { diagnosticar, formatearDiagnostico } from './build/doctor.js';
|
|
23
|
+
import { init, formatearInit } from './build/init.js';
|
|
24
|
+
import { startPreview } from './build/preview.js';
|
|
25
|
+
import { installSkill, formatearSkill } from './build/skill.js';
|
|
26
|
+
import { fixBlock } from './mcp/tools.js';
|
|
27
|
+
import { verify } from './build/verify.js';
|
|
28
|
+
import { loadConfig, resolveFromRoot } from './config/load.js';
|
|
29
|
+
import { BuildFailedError, DocVizError } from './core/errors.js';
|
|
30
|
+
import { dslCatalog, findType, TYPE_CATALOG } from './dsl/index.js';
|
|
31
|
+
import { suggestType } from './mcp/tools.js';
|
|
32
|
+
import { themeNames } from './themes/index.js';
|
|
33
|
+
const VERSION = '0.1.0';
|
|
34
|
+
const ejecutar = promisify(execFile);
|
|
35
|
+
/** Lee el bloque de la entrada estandar, para encadenarlo con otro comando. */
|
|
36
|
+
async function leerEntrada() {
|
|
37
|
+
const trozos = [];
|
|
38
|
+
for await (const trozo of process.stdin)
|
|
39
|
+
trozos.push(Buffer.from(trozo));
|
|
40
|
+
return Buffer.concat(trozos).toString('utf8');
|
|
41
|
+
}
|
|
42
|
+
export function createProgram() {
|
|
43
|
+
const program = new Command();
|
|
44
|
+
program
|
|
45
|
+
.name('docviz')
|
|
46
|
+
.description('Compila bloques declarativos de diagramas dentro de Markdown a imagenes SVG/PNG.')
|
|
47
|
+
.version(VERSION);
|
|
48
|
+
program
|
|
49
|
+
.command('build')
|
|
50
|
+
.description('compila los documentos de <source> hacia el directorio de salida')
|
|
51
|
+
.argument('[source]', 'directorio de documentos fuente')
|
|
52
|
+
.option('-o, --output <dir>', 'directorio de salida')
|
|
53
|
+
.option('-t, --theme <name>', `tema visual (${themeNames().join(', ')})`)
|
|
54
|
+
.option('-c, --config <file>', 'archivo de configuracion')
|
|
55
|
+
.option('--clean', 'borra el directorio de salida antes de compilar', false)
|
|
56
|
+
.option('--verbose', 'muestra cada diagrama procesado', false)
|
|
57
|
+
.option('--no-cache', 'ignora el cache y vuelve a renderizar todo')
|
|
58
|
+
.option('--renderer-url <url>', 'URL de una instancia Kroki self-hosted')
|
|
59
|
+
.option('--backend <backend>', 'backend por defecto: local | kroki')
|
|
60
|
+
.option('--continue-on-error', 'no aborta ante un diagrama invalido', false)
|
|
61
|
+
.action(async (source, opts) => {
|
|
62
|
+
const config = await loadConfig({
|
|
63
|
+
configPath: opts.config,
|
|
64
|
+
overrides: {
|
|
65
|
+
...(source !== undefined ? { source } : {}),
|
|
66
|
+
...(opts.output !== undefined ? { output: opts.output } : {}),
|
|
67
|
+
...(opts.theme !== undefined ? { theme: opts.theme } : {}),
|
|
68
|
+
...(opts.cache === false ? { cacheEnabled: false } : {}),
|
|
69
|
+
...(opts.rendererUrl !== undefined ? { krokiUrl: opts.rendererUrl } : {}),
|
|
70
|
+
...(opts.backend !== undefined ? { backend: opts.backend } : {}),
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
const started = Date.now();
|
|
74
|
+
const result = await build(config, {
|
|
75
|
+
clean: opts.clean,
|
|
76
|
+
verbose: opts.verbose,
|
|
77
|
+
continueOnError: opts.continueOnError,
|
|
78
|
+
onLog: (m) => process.stdout.write(`${m}\n`),
|
|
79
|
+
});
|
|
80
|
+
const elapsed = ((Date.now() - started) / 1000).toFixed(1);
|
|
81
|
+
process.stdout.write([
|
|
82
|
+
'',
|
|
83
|
+
`documentos: ${result.stats.documents}`,
|
|
84
|
+
`diagramas: ${result.stats.blocks}`,
|
|
85
|
+
`regenerados: ${result.stats.generated}`,
|
|
86
|
+
`cache hits: ${result.stats.cacheHits}`,
|
|
87
|
+
`salida: ${path.relative(process.cwd(), resolveFromRoot(config, config.output))}`,
|
|
88
|
+
`tema: ${config.theme.name}`,
|
|
89
|
+
`tiempo: ${elapsed}s`,
|
|
90
|
+
'',
|
|
91
|
+
].join('\n'));
|
|
92
|
+
escribirAvisos(result.warnings);
|
|
93
|
+
if (result.errors.length > 0) {
|
|
94
|
+
process.stderr.write(`\n${result.errors.map((e) => e.format()).join('\n\n')}\n`);
|
|
95
|
+
process.stderr.write(`\n${result.errors.length} diagrama(s) fallaron (--continue-on-error activo)\n`);
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
program
|
|
100
|
+
.command('check')
|
|
101
|
+
.description('valida los bloques declarativos sin renderizar')
|
|
102
|
+
.argument('[source]', 'directorio de documentos fuente')
|
|
103
|
+
.option('-c, --config <file>', 'archivo de configuracion')
|
|
104
|
+
.option('--verbose', 'lista cada bloque detectado', false)
|
|
105
|
+
.action(async (source, opts) => {
|
|
106
|
+
const config = await loadConfig({
|
|
107
|
+
configPath: opts.config,
|
|
108
|
+
overrides: source !== undefined ? { source } : {},
|
|
109
|
+
});
|
|
110
|
+
const result = await check(config);
|
|
111
|
+
if (opts.verbose === true) {
|
|
112
|
+
for (const f of result.findings) {
|
|
113
|
+
process.stdout.write(` ${f.file}:${f.line} ${f.lang} -> ${f.rendererType} "${f.title}"\n`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// El conteo distingue los bloques que compilan de los que no: decir
|
|
117
|
+
// "bloques: 0" cuando habia tres rotos oculta justo lo que hay que ver.
|
|
118
|
+
const invalidos = result.invalidBlocks > 0 ? ` (${result.invalidBlocks} invalido(s))` : '';
|
|
119
|
+
process.stdout.write(`\ndocumentos: ${result.documents}\nbloques: ${result.blocks}${invalidos}\n` +
|
|
120
|
+
`avisos: ${result.warnings.length}\nerrores: ${result.errors.length}\n`);
|
|
121
|
+
escribirAvisos(result.warnings);
|
|
122
|
+
if (result.errors.length > 0) {
|
|
123
|
+
process.stderr.write(`\n${result.errors.map((e) => e.format()).join('\n\n')}\n`);
|
|
124
|
+
process.exitCode = 1;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
process.stdout.write('\ncheck OK\n');
|
|
128
|
+
});
|
|
129
|
+
program
|
|
130
|
+
.command('diff')
|
|
131
|
+
.description('compara los diagramas de dos versiones de la documentacion')
|
|
132
|
+
.argument('<base>', 'directorio de la version anterior')
|
|
133
|
+
.argument('<head>', 'directorio de la version nueva')
|
|
134
|
+
.option('-c, --config <file>', 'archivo de configuracion')
|
|
135
|
+
.option('--all', 'incluye tambien los diagramas que no cambiaron', false)
|
|
136
|
+
.option('--json', 'salida en JSON', false)
|
|
137
|
+
.option('--exit-code', 'termina con codigo 1 si algo cambio, como git diff', false)
|
|
138
|
+
.action(async (base, head, opts) => {
|
|
139
|
+
const config = await loadConfig(opts.config !== undefined ? { configPath: opts.config } : {});
|
|
140
|
+
const result = await diff(config, path.resolve(base), path.resolve(head));
|
|
141
|
+
process.stdout.write(opts.json === true ? `${JSON.stringify(result, null, 2)}\n` : formatDiff(result, { all: opts.all }));
|
|
142
|
+
if (opts.exitCode === true && hasChanges(result))
|
|
143
|
+
process.exitCode = 1;
|
|
144
|
+
});
|
|
145
|
+
program
|
|
146
|
+
.command('verify')
|
|
147
|
+
.description('comprueba que el Markdown compilado no tenga imagenes rotas')
|
|
148
|
+
.argument('[output]', 'directorio de salida a verificar')
|
|
149
|
+
.option('-c, --config <file>', 'archivo de configuracion')
|
|
150
|
+
.action(async (output, opts) => {
|
|
151
|
+
const config = await loadConfig({
|
|
152
|
+
configPath: opts.config,
|
|
153
|
+
overrides: output !== undefined ? { output } : {},
|
|
154
|
+
});
|
|
155
|
+
const dir = resolveFromRoot(config, config.output);
|
|
156
|
+
const result = await verify(dir);
|
|
157
|
+
process.stdout.write(`\ndocumentos: ${result.documents}\nimagenes: ${result.images}\nproblemas: ${result.issues.length}\n`);
|
|
158
|
+
for (const block of result.residualBlocks) {
|
|
159
|
+
process.stderr.write(`AVISO ${block.file}:${block.line} quedo un bloque "${block.lang}" sin compilar en la salida\n`);
|
|
160
|
+
}
|
|
161
|
+
if (result.issues.length > 0) {
|
|
162
|
+
for (const issue of result.issues) {
|
|
163
|
+
process.stderr.write(`ERROR ${issue.file}:${issue.line} ${issue.url} -> ${issue.reason}\n`);
|
|
164
|
+
}
|
|
165
|
+
process.exitCode = 1;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (result.residualBlocks.length > 0) {
|
|
169
|
+
process.exitCode = 1;
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
process.stdout.write('\nverify OK\n');
|
|
173
|
+
});
|
|
174
|
+
program
|
|
175
|
+
.command('preview')
|
|
176
|
+
.description('sirve el Markdown compilado para revisarlo visualmente')
|
|
177
|
+
.argument('[output]', 'directorio de salida a servir')
|
|
178
|
+
.option('-c, --config <file>', 'archivo de configuracion')
|
|
179
|
+
.option('-p, --port <port>', 'puerto', '4321')
|
|
180
|
+
.action(async (output, opts) => {
|
|
181
|
+
const config = await loadConfig({
|
|
182
|
+
configPath: opts.config,
|
|
183
|
+
overrides: output !== undefined ? { output } : {},
|
|
184
|
+
});
|
|
185
|
+
const dir = resolveFromRoot(config, config.output);
|
|
186
|
+
const server = await startPreview(dir, Number.parseInt(opts.port, 10));
|
|
187
|
+
process.stdout.write(`previsualizacion en ${server.url}\npulsa Ctrl+C para detener\n`);
|
|
188
|
+
await new Promise((resolve) => {
|
|
189
|
+
process.on('SIGINT', () => {
|
|
190
|
+
void server.close().then(resolve);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
program
|
|
195
|
+
.command('init')
|
|
196
|
+
.description('prepara este proyecto para usar DocViz')
|
|
197
|
+
.option('-t, --theme <name>', `tema inicial (${themeNames().join(', ')})`, 'default')
|
|
198
|
+
.option('--force', 'sobrescribe los archivos que ya existan', false)
|
|
199
|
+
.action(async (opts) => {
|
|
200
|
+
if (!themeNames().includes(opts.theme)) {
|
|
201
|
+
process.stderr.write(`el tema "${opts.theme}" no existe\ntemas: ${themeNames().join(', ')}\n`);
|
|
202
|
+
process.exitCode = 1;
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const result = await init({ cwd: process.cwd(), theme: opts.theme, force: opts.force === true });
|
|
206
|
+
process.stdout.write(formatearInit(result, opts.theme));
|
|
207
|
+
});
|
|
208
|
+
program
|
|
209
|
+
.command('fix')
|
|
210
|
+
.description('corrige las erratas de un bloque que no compila')
|
|
211
|
+
.argument('<archivo>', 'archivo con el bloque, o - para leer de la entrada estandar')
|
|
212
|
+
.option('-l, --lang <valla>', 'valla del bloque: diagram | chart | architecture', 'diagram')
|
|
213
|
+
.option('--json', 'salida en JSON', false)
|
|
214
|
+
.action(async (archivo, opts) => {
|
|
215
|
+
const source = archivo === '-' ? await leerEntrada() : await readFile(path.resolve(archivo), 'utf8');
|
|
216
|
+
const result = fixBlock({ source, ...(opts.lang !== undefined ? { lang: opts.lang } : {}) });
|
|
217
|
+
if (opts.json === true) {
|
|
218
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
219
|
+
if (!result.ok)
|
|
220
|
+
process.exitCode = 1;
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
for (const c of (result['aplicado'] ?? [])) {
|
|
224
|
+
process.stderr.write(`corregido: "${c.de}" -> "${c.a}"\n`);
|
|
225
|
+
}
|
|
226
|
+
process.stdout.write(`${String(result['source'] ?? source)}\n`);
|
|
227
|
+
if (!result.ok) {
|
|
228
|
+
process.stderr.write(`\n${String(result['detail'] ?? result['error'] ?? 'sigue sin compilar')}\n`);
|
|
229
|
+
for (const p2 of (result['pendientes'] ?? []))
|
|
230
|
+
process.stderr.write(` ${p2}\n`);
|
|
231
|
+
process.exitCode = 1;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
program
|
|
235
|
+
.command('setup')
|
|
236
|
+
.description('descarga plantuml.jar dentro del paquete (unica operacion de red)')
|
|
237
|
+
.argument('[version]', 'version de PlantUML a descargar')
|
|
238
|
+
.action(async (version) => {
|
|
239
|
+
// Instalado como dependencia, `npm run setup` no existe: los scripts del
|
|
240
|
+
// paquete no son los del proyecto. Sin este comando, los 12 tipos de
|
|
241
|
+
// PlantUML quedan muertos tras un `npm install` y nadie sabe por que.
|
|
242
|
+
const script = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'scripts', 'fetch-plantuml.mjs');
|
|
243
|
+
try {
|
|
244
|
+
const { stdout, stderr } = await ejecutar(process.execPath, version !== undefined ? [script, version] : [script], { timeout: 300_000, maxBuffer: 4 * 1024 * 1024 });
|
|
245
|
+
process.stdout.write(stdout);
|
|
246
|
+
if (stderr !== '')
|
|
247
|
+
process.stderr.write(stderr);
|
|
248
|
+
}
|
|
249
|
+
catch (err) {
|
|
250
|
+
const salida = err;
|
|
251
|
+
if (salida.stdout)
|
|
252
|
+
process.stdout.write(salida.stdout);
|
|
253
|
+
process.stderr.write(salida.stderr ?? `${salida.message ?? String(err)}\n`);
|
|
254
|
+
process.exitCode = 1;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
program
|
|
258
|
+
.command('skill')
|
|
259
|
+
.description('instala el contrato de DocViz como skill de tu agente')
|
|
260
|
+
.option('-g, --global', 'instala en tu perfil en lugar de en el proyecto', false)
|
|
261
|
+
.option('-d, --dir <dir>', 'directorio de skills de otro agente')
|
|
262
|
+
.option('--force', 'sobrescribe una instalacion anterior', false)
|
|
263
|
+
.action(async (opts) => {
|
|
264
|
+
const result = await installSkill({
|
|
265
|
+
cwd: process.cwd(),
|
|
266
|
+
global: opts.global === true,
|
|
267
|
+
force: opts.force === true,
|
|
268
|
+
...(opts.dir !== undefined ? { dir: opts.dir } : {}),
|
|
269
|
+
});
|
|
270
|
+
process.stdout.write(formatearSkill(result));
|
|
271
|
+
});
|
|
272
|
+
program
|
|
273
|
+
.command('doctor')
|
|
274
|
+
.description('comprueba el entorno y que tipos se pueden dibujar')
|
|
275
|
+
.option('-c, --config <file>', 'archivo de configuracion')
|
|
276
|
+
.option('--json', 'salida en JSON', false)
|
|
277
|
+
.action(async (opts) => {
|
|
278
|
+
const config = await loadConfig(opts.config !== undefined ? { configPath: opts.config } : {});
|
|
279
|
+
const diagnostico = await diagnosticar(config);
|
|
280
|
+
process.stdout.write(opts.json === true ? `${JSON.stringify(diagnostico, null, 2)}\n` : formatearDiagnostico(diagnostico));
|
|
281
|
+
// Falta de entorno es un fallo: en un pipeline conviene enterarse antes de
|
|
282
|
+
// compilar, no a mitad del build.
|
|
283
|
+
if (!diagnostico.ok)
|
|
284
|
+
process.exitCode = 1;
|
|
285
|
+
});
|
|
286
|
+
program
|
|
287
|
+
.command('types')
|
|
288
|
+
.description('lista los tipos del DSL con su proposito y su ejemplo')
|
|
289
|
+
.argument('[type]', 'muestra la ficha completa de un tipo concreto')
|
|
290
|
+
.option('--short', 'solo los nombres, sin metadatos', false)
|
|
291
|
+
.option('--json', 'salida en JSON, para consumirla desde otro programa', false)
|
|
292
|
+
.option('-l, --lang <idioma>', 'idioma de las fichas: es | en', 'es')
|
|
293
|
+
.action((type, opts) => {
|
|
294
|
+
const idioma = opts.lang === 'en' ? 'en' : 'es';
|
|
295
|
+
if (type !== undefined) {
|
|
296
|
+
const spec = findType(type);
|
|
297
|
+
if (spec === undefined) {
|
|
298
|
+
process.stderr.write(`el tipo "${type}" no existe\n\ntipos disponibles:\n ${TYPE_CATALOG.map((s) => s.type).sort().join(', ')}\n`);
|
|
299
|
+
process.exitCode = 1;
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
process.stdout.write(opts.json === true ? `${JSON.stringify(spec, null, 2)}\n` : ficha(spec, idioma));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (opts.json === true) {
|
|
306
|
+
process.stdout.write(`${JSON.stringify({ types: TYPE_CATALOG, themes: themeNames() }, null, 2)}\n`);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (opts.short === true) {
|
|
310
|
+
for (const [lang, types] of Object.entries(dslCatalog())) {
|
|
311
|
+
process.stdout.write(`\n\`\`\`${lang}\`\`\`\n`);
|
|
312
|
+
for (const t of types)
|
|
313
|
+
process.stdout.write(` - ${t}\n`);
|
|
314
|
+
}
|
|
315
|
+
process.stdout.write(`\ntemas: ${themeNames().join(', ')}\n`);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
// Por defecto se muestra el proposito de cada tipo: una lista de nombres
|
|
319
|
+
// obliga a adivinar, que es justo lo que el catalogo existe para evitar.
|
|
320
|
+
for (const lang of ['diagram', 'chart', 'architecture']) {
|
|
321
|
+
const specs = TYPE_CATALOG.filter((s) => s.lang === lang);
|
|
322
|
+
process.stdout.write(`\n\`\`\`${lang}\`\`\`\n`);
|
|
323
|
+
const ancho = Math.max(...specs.map((s) => s.type.length));
|
|
324
|
+
for (const spec of specs) {
|
|
325
|
+
const proposito = idioma === 'en' && spec.en !== undefined ? spec.en.purpose : spec.purpose;
|
|
326
|
+
process.stdout.write(` ${spec.type.padEnd(ancho)} ${proposito}\n`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
process.stdout.write(`\ntemas: ${themeNames().join(', ')}\n` +
|
|
330
|
+
`\ndocviz types <tipo> ficha completa con ejemplo\n` +
|
|
331
|
+
`docviz suggest "..." recomendacion a partir de una frase\n`);
|
|
332
|
+
});
|
|
333
|
+
program
|
|
334
|
+
.command('suggest')
|
|
335
|
+
.description('recomienda un tipo a partir de lo que quieres explicar')
|
|
336
|
+
.argument('<necesidad...>', 'que quieres explicar, en una frase')
|
|
337
|
+
.option('-n, --limit <n>', 'numero de sugerencias', '3')
|
|
338
|
+
.option('--json', 'salida en JSON', false)
|
|
339
|
+
.action((palabras, opts) => {
|
|
340
|
+
const need = palabras.join(' ');
|
|
341
|
+
const result = suggestType({ need, limit: Number.parseInt(opts.limit, 10) });
|
|
342
|
+
if (opts.json === true) {
|
|
343
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
344
|
+
if (result.ok !== true)
|
|
345
|
+
process.exitCode = 1;
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (result.ok !== true) {
|
|
349
|
+
process.stderr.write(`${String(result['error'])}\n`);
|
|
350
|
+
process.exitCode = 1;
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const matches = result['matches'];
|
|
354
|
+
if (matches.length === 0) {
|
|
355
|
+
process.stdout.write(`${String(result['advice'])}\n`);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
for (const match of matches) {
|
|
359
|
+
process.stdout.write(`\n${match['type']} (${match['lang']}, ${match['engine']})\n` +
|
|
360
|
+
` ${match['purpose']}\n` +
|
|
361
|
+
` cuando: ${match['whenToUse']}\n` +
|
|
362
|
+
` cuando no: ${match['whenNotToUse']}\n\n` +
|
|
363
|
+
`${match['block'].split('\n').map((l) => ` ${l}`).join('\n')}\n`);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
return program;
|
|
367
|
+
}
|
|
368
|
+
const ETIQUETAS = {
|
|
369
|
+
es: { usar: 'cuando usarlo:', evitar: 'cuando no: ', alias: 'alias: ', respaldo: 'respaldo: ' },
|
|
370
|
+
en: { usar: 'when to use: ', evitar: 'when not to: ', alias: 'aliases: ', respaldo: 'fallbacks: ' },
|
|
371
|
+
};
|
|
372
|
+
/** Ficha legible de un tipo, con su ejemplo listo para copiar. */
|
|
373
|
+
function ficha(spec, idioma = 'es') {
|
|
374
|
+
const texto = idioma === 'en' && spec.en !== undefined ? spec.en : spec;
|
|
375
|
+
const et = ETIQUETAS[idioma];
|
|
376
|
+
const lineas = [
|
|
377
|
+
'',
|
|
378
|
+
`${spec.type} (${spec.lang}, ${spec.engine})`,
|
|
379
|
+
'',
|
|
380
|
+
` ${texto.purpose}`,
|
|
381
|
+
'',
|
|
382
|
+
` ${et.usar} ${texto.whenToUse}`,
|
|
383
|
+
` ${et.evitar} ${texto.whenNotToUse}`,
|
|
384
|
+
];
|
|
385
|
+
if (spec.aliases !== undefined && spec.aliases.length > 0) {
|
|
386
|
+
lineas.push(` ${et.alias} ${spec.aliases.join(', ')}`);
|
|
387
|
+
}
|
|
388
|
+
if (spec.fallbacks !== undefined && spec.fallbacks.length > 0) {
|
|
389
|
+
lineas.push(` ${et.respaldo} ${spec.fallbacks.join(', ')}`);
|
|
390
|
+
}
|
|
391
|
+
lineas.push('', ` \`\`\`${spec.lang}`);
|
|
392
|
+
for (const l of spec.example.split('\n'))
|
|
393
|
+
lineas.push(` ${l}`);
|
|
394
|
+
lineas.push(' ```', '');
|
|
395
|
+
return `${lineas.join('\n')}\n`;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Los avisos van a stderr y no cambian el codigo de salida.
|
|
399
|
+
*
|
|
400
|
+
* Un campo ignorado no rompe el documento, pero si se mezcla con la salida
|
|
401
|
+
* normal nadie lo lee; y si fallara el build, corregir una errata seria
|
|
402
|
+
* obligatorio antes de publicar cualquier cosa.
|
|
403
|
+
*/
|
|
404
|
+
function escribirAvisos(warnings) {
|
|
405
|
+
for (const w of warnings) {
|
|
406
|
+
process.stderr.write(`AVISO ${w.file}:${w.line} [${w.code}] ${w.message}\n`);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
export async function run(argv = process.argv) {
|
|
410
|
+
try {
|
|
411
|
+
await createProgram().parseAsync([...argv]);
|
|
412
|
+
return typeof process.exitCode === 'number' ? process.exitCode : 0;
|
|
413
|
+
}
|
|
414
|
+
catch (err) {
|
|
415
|
+
if (err instanceof BuildFailedError) {
|
|
416
|
+
process.stderr.write(`\n${err.format()}\n\n${err.message}\n`);
|
|
417
|
+
return 1;
|
|
418
|
+
}
|
|
419
|
+
if (err instanceof DocVizError) {
|
|
420
|
+
process.stderr.write(`\n${err.format()}\n`);
|
|
421
|
+
return 1;
|
|
422
|
+
}
|
|
423
|
+
process.stderr.write(`\nERROR inesperado\n${err instanceof Error ? (err.stack ?? err.message) : String(err)}\n`);
|
|
424
|
+
return 1;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=cli.js.map
|