@donartcha/openlag 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.
Files changed (99) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +82 -0
  3. package/bin/openlag.js +2 -0
  4. package/dist/assets/arc-4YUHkXo3.js +1 -0
  5. package/dist/assets/architectureDiagram-3BPJPVTR-WeGmL7HM.js +36 -0
  6. package/dist/assets/blockDiagram-GPEHLZMM-CtV7ubAx.js +132 -0
  7. package/dist/assets/c4Diagram-AAUBKEIU-DqYDW5c3.js +10 -0
  8. package/dist/assets/channel-Tsel3-MK.js +1 -0
  9. package/dist/assets/chunk-2J33WTMH-BE8P9tjh.js +1 -0
  10. package/dist/assets/chunk-4BX2VUAB-Bi7oLGF5.js +1 -0
  11. package/dist/assets/chunk-55IACEB6-D9Xhxp_r.js +1 -0
  12. package/dist/assets/chunk-727SXJPM-Dz8jKE60.js +206 -0
  13. package/dist/assets/chunk-AQP2D5EJ-BzmM0IeH.js +231 -0
  14. package/dist/assets/chunk-FMBD7UC4-Cvl5dpcx.js +15 -0
  15. package/dist/assets/chunk-ND2GUHAM-Dz2efqnq.js +1 -0
  16. package/dist/assets/chunk-QZHKN3VN-CwblgSnQ.js +1 -0
  17. package/dist/assets/classDiagram-4FO5ZUOK-Bgm-_cW8.js +1 -0
  18. package/dist/assets/classDiagram-v2-Q7XG4LA2-Bgm-_cW8.js +1 -0
  19. package/dist/assets/cose-bilkent-S5V4N54A-h_A3nZUx.js +1 -0
  20. package/dist/assets/cytoscape.esm-D_LviqZs.js +331 -0
  21. package/dist/assets/dagre-BM42HDAG-CN_B2Doz.js +4 -0
  22. package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  23. package/dist/assets/diagram-2AECGRRQ-C9TAFwjG.js +43 -0
  24. package/dist/assets/diagram-5GNKFQAL-BThljQLo.js +10 -0
  25. package/dist/assets/diagram-KO2AKTUF-bRPq25Se.js +3 -0
  26. package/dist/assets/diagram-LMA3HP47-BubLCIus.js +24 -0
  27. package/dist/assets/diagram-OG6HWLK6-CJpfhIsS.js +24 -0
  28. package/dist/assets/erDiagram-TEJ5UH35-6Xkza9wL.js +85 -0
  29. package/dist/assets/flowDiagram-I6XJVG4X-Bq_to3hX.js +162 -0
  30. package/dist/assets/ganttDiagram-6RSMTGT7-C3CmvYl7.js +292 -0
  31. package/dist/assets/gitGraphDiagram-PVQCEYII-C93LTfrl.js +106 -0
  32. package/dist/assets/graph-CAnANduQ.js +1 -0
  33. package/dist/assets/index-0RMQQ34p.css +1 -0
  34. package/dist/assets/index-ByxguSZe.js +729 -0
  35. package/dist/assets/infoDiagram-5YYISTIA-CMfuwygl.js +2 -0
  36. package/dist/assets/init-Gi6I4Gst.js +1 -0
  37. package/dist/assets/ishikawaDiagram-YF4QCWOH-CbJ5ojDF.js +70 -0
  38. package/dist/assets/journeyDiagram-JHISSGLW-C_Xz8YyT.js +139 -0
  39. package/dist/assets/kanban-definition-UN3LZRKU-GVv_iRMq.js +89 -0
  40. package/dist/assets/katex-DkKDou_j.js +257 -0
  41. package/dist/assets/layout-DGIYPm2g.js +1 -0
  42. package/dist/assets/linear-BNEtUH2J.js +1 -0
  43. package/dist/assets/mindmap-definition-RKZ34NQL-DIsL0XSF.js +96 -0
  44. package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  45. package/dist/assets/pieDiagram-4H26LBE5-CSCTSOjk.js +30 -0
  46. package/dist/assets/quadrantDiagram-W4KKPZXB-CQQ9OaFY.js +7 -0
  47. package/dist/assets/requirementDiagram-4Y6WPE33-Cjn3la_S.js +84 -0
  48. package/dist/assets/sankeyDiagram-5OEKKPKP-DoVspvVc.js +40 -0
  49. package/dist/assets/sequenceDiagram-3UESZ5HK-UsoGmL4w.js +162 -0
  50. package/dist/assets/stateDiagram-AJRCARHV-DLmf7Dc8.js +1 -0
  51. package/dist/assets/stateDiagram-v2-BHNVJYJU-jkiDZ_3u.js +1 -0
  52. package/dist/assets/timeline-definition-PNZ67QCA-HfyRxZ8p.js +120 -0
  53. package/dist/assets/vennDiagram-CIIHVFJN-B6pM3L33.js +34 -0
  54. package/dist/assets/wardley-L42UT6IY-B-LdKtrI.js +173 -0
  55. package/dist/assets/wardleyDiagram-YWT4CUSO-BD45zhOu.js +78 -0
  56. package/dist/assets/xychartDiagram-2RQKCTM6-zsDMbUiS.js +7 -0
  57. package/dist/cli/openlag.js +1793 -0
  58. package/dist/index.html +14 -0
  59. package/index.html +13 -0
  60. package/package.json +84 -0
  61. package/scripts/cli/build.ts +34 -0
  62. package/scripts/cli/dev.ts +35 -0
  63. package/scripts/cli/generate.ts +92 -0
  64. package/scripts/cli/init.ts +427 -0
  65. package/scripts/cli/lint.ts +29 -0
  66. package/scripts/cli/openlag.ts +110 -0
  67. package/scripts/cli/vite-bin.ts +8 -0
  68. package/scripts/core/parser/diagnostic.ts +34 -0
  69. package/scripts/core/parser/normalizer.ts +27 -0
  70. package/scripts/core/parser/scanner.ts +30 -0
  71. package/scripts/core/parser/schemas.ts +23 -0
  72. package/scripts/core/parser/types.ts +30 -0
  73. package/scripts/core/parser.ts +127 -0
  74. package/scripts/generate-relations.ts +53 -0
  75. package/scripts/lint/lint-engine.ts +85 -0
  76. package/scripts/lint/lint-profiles.ts +49 -0
  77. package/scripts/lint/lint-rules.ts +174 -0
  78. package/scripts/lint/lint-types.ts +43 -0
  79. package/src/App.tsx +164 -0
  80. package/src/components/DocumentationView.tsx +905 -0
  81. package/src/components/GraphView.tsx +529 -0
  82. package/src/components/GuideView.tsx +535 -0
  83. package/src/components/ImpactView.tsx +365 -0
  84. package/src/components/MarkdownRenderer.tsx +120 -0
  85. package/src/components/OrphansView.tsx +360 -0
  86. package/src/components/SettingsView.tsx +146 -0
  87. package/src/core/generated/relation-definitions.ts +622 -0
  88. package/src/core/graph/GraphQueryLayer.ts +194 -0
  89. package/src/core/registry/ArtifactRegistry.ts +19 -0
  90. package/src/core/registry/RelationRegistry.ts +27 -0
  91. package/src/core/semantic/artifact-layers.ts +43 -0
  92. package/src/core/semantic/ownership-rules.ts +13 -0
  93. package/src/core/semantic/types.ts +11 -0
  94. package/src/index.css +121 -0
  95. package/src/lib/reportUtils.ts +59 -0
  96. package/src/main.tsx +10 -0
  97. package/src/store.ts +146 -0
  98. package/src/types.ts +77 -0
  99. package/vite.config.ts +31 -0
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>My OpenLAG Project | OpenLAG</title>
7
+ <script type="module" crossorigin src="/assets/index-ByxguSZe.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-0RMQQ34p.css">
9
+ </head>
10
+ <body>
11
+ <div id="root"></div>
12
+ </body>
13
+ </html>
14
+
package/index.html ADDED
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>My OpenLAG Project | OpenLAG</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
13
+
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "@donartcha/openlag",
3
+ "version": "0.1.0",
4
+ "description": "Architecture as Code traceability graph generator",
5
+ "type": "module",
6
+ "license": "MPL-2.0",
7
+ "bin": {
8
+ "openlag": "./bin/openlag.js"
9
+ },
10
+ "files": [
11
+ "bin",
12
+ "scripts",
13
+ "src",
14
+ "dist",
15
+ "index.html",
16
+ "vite.config.ts",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "dev": "tsx scripts/cli/openlag.ts dev",
22
+ "build": "npm run generate-relations && npm run build:web && npm run build:cli",
23
+ "build:web": "vite build",
24
+ "build:cli": "tsup scripts/cli/openlag.ts --format esm --platform node --target node18 --out-dir dist/cli --clean false",
25
+ "check": "npm run typecheck && npm run lint && npm run test && npm run pack:dry-run",
26
+ "generate": "tsx scripts/cli/openlag.ts generate",
27
+ "generate-relations": "tsx scripts/generate-relations.ts",
28
+ "lint": "eslint .",
29
+ "typecheck": "tsc --noEmit",
30
+ "test": "node --import tsx --test tests/*.test.ts",
31
+ "test:watch": "node --import tsx --test --watch tests/*.test.ts",
32
+ "pack:dry-run": "npm pack --dry-run",
33
+ "clean": "rimraf dist public/graph-data.json",
34
+ "prepack": "npm run build"
35
+ },
36
+ "dependencies": {
37
+ "@tailwindcss/vite": "^4.1.14",
38
+ "@vitejs/plugin-react": "^5.0.4",
39
+ "@xyflow/react": "^12.10.2",
40
+ "chalk": "^5.4.1",
41
+ "chokidar": "^5.0.0",
42
+ "clsx": "^2.1.1",
43
+ "commander": "^14.0.3",
44
+ "dagre": "^0.8.5",
45
+ "gray-matter": "^4.0.3",
46
+ "html-to-image": "^1.11.13",
47
+ "html2canvas": "^1.4.1",
48
+ "js-yaml": "^4.1.1",
49
+ "jspdf": "^4.2.1",
50
+ "lucide-react": "^0.546.0",
51
+ "mermaid": "^11.15.0",
52
+ "motion": "^12.23.24",
53
+ "ora": "^8.2.0",
54
+ "react": "^19.0.1",
55
+ "react-dom": "^19.0.1",
56
+ "react-markdown": "^10.1.0",
57
+ "tailwind-merge": "^3.6.0",
58
+ "vite": "^6.2.3",
59
+ "zod": "^4.4.3",
60
+ "zustand": "^5.0.13"
61
+ },
62
+ "devDependencies": {
63
+ "@eslint/js": "^10.0.1",
64
+ "@types/dagre": "^0.7.54",
65
+ "@types/js-yaml": "^4.0.9",
66
+ "@types/node": "^22.14.0",
67
+ "@typescript-eslint/eslint-plugin": "^8.59.3",
68
+ "@typescript-eslint/parser": "^8.59.3",
69
+ "autoprefixer": "^10.4.21",
70
+ "dotenv": "^17.2.3",
71
+ "esbuild": "^0.25.0",
72
+ "eslint": "^10.4.0",
73
+ "globals": "^17.6.0",
74
+ "rimraf": "^6.1.3",
75
+ "tailwindcss": "^4.1.14",
76
+ "tsup": "^8.5.1",
77
+ "tsx": "^4.21.0",
78
+ "typescript": "~5.8.2",
79
+ "vitest": "^4.1.6"
80
+ },
81
+ "engines": {
82
+ "node": ">=18"
83
+ }
84
+ }
@@ -0,0 +1,34 @@
1
+ import { execFileSync } from 'child_process';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ import chalk from 'chalk';
6
+
7
+ import { generateData } from './generate.js';
8
+ import { resolveViteBin } from './vite-bin.js';
9
+
10
+ export function buildPortal() {
11
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
12
+ const viteBin = resolveViteBin(import.meta.url);
13
+ const viteConfig = path.join(packageRoot, 'vite.config.ts');
14
+ const docsDir = path.join(process.cwd(), 'docs');
15
+ const outputDir = path.join(process.cwd(), 'public');
16
+
17
+ generateData(docsDir, outputDir);
18
+
19
+ console.log(chalk.blue('Building OpenLAG portal...'));
20
+ try {
21
+ execFileSync(process.execPath, [viteBin, 'build', '--config', viteConfig], {
22
+ cwd: packageRoot,
23
+ env: {
24
+ ...process.env,
25
+ OPENLAG_PROJECT_ROOT: process.cwd(),
26
+ },
27
+ stdio: 'inherit',
28
+ });
29
+ console.log(chalk.green('Portal build complete.'));
30
+ } catch {
31
+ console.error(chalk.red('Build failed.'));
32
+ process.exit(1);
33
+ }
34
+ }
@@ -0,0 +1,35 @@
1
+ import { spawn } from 'child_process';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ import chalk from 'chalk';
6
+
7
+ import { generateData, watchData } from './generate.js';
8
+ import { resolveViteBin } from './vite-bin.js';
9
+
10
+ export function runDevServer() {
11
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
12
+ const viteBin = resolveViteBin(import.meta.url);
13
+ const viteConfig = path.join(packageRoot, 'vite.config.ts');
14
+ const projectRoot = process.cwd();
15
+ const docsDir = path.join(projectRoot, 'docs');
16
+ const outputDir = path.join(projectRoot, 'public');
17
+
18
+ generateData(docsDir, outputDir);
19
+ watchData(docsDir, outputDir);
20
+
21
+ console.log(chalk.blue('Starting OpenLAG portal dev server...'));
22
+
23
+ const vite = spawn(process.execPath, [viteBin, '--config', viteConfig], {
24
+ cwd: packageRoot,
25
+ env: {
26
+ ...process.env,
27
+ OPENLAG_PROJECT_ROOT: projectRoot,
28
+ },
29
+ stdio: 'inherit',
30
+ });
31
+
32
+ vite.on('close', (code) => {
33
+ process.exit(code || 0);
34
+ });
35
+ }
@@ -0,0 +1,92 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { parseOpenLagDocs } from "../core/parser.js";
4
+ import { Version, Change, SystemVersion, GraphSnapshot } from "../../src/types.js";
5
+ import chokidar from "chokidar";
6
+ import chalk from "chalk";
7
+
8
+ interface StaticState {
9
+ versions: Version[];
10
+ systemVersions: SystemVersion[];
11
+ graphs: Record<string, GraphSnapshot>;
12
+ changes: Change[];
13
+ }
14
+
15
+ function isDescendant(currentVersionId: string, artifactVersionId: string, versions: Version[]): boolean {
16
+ const artifactVersion = versions.find(v => v.id === artifactVersionId);
17
+ if (!artifactVersion) return false;
18
+
19
+ let temp = versions.find(v => v.id === currentVersionId);
20
+ let depth = 0;
21
+ while (temp && temp.parentVersion) {
22
+ depth++;
23
+ if (depth > 50) return false;
24
+ if (temp.parentVersion === artifactVersionId) return true;
25
+ temp = versions.find(v => v.id === temp!.parentVersion);
26
+ }
27
+ return false;
28
+ }
29
+
30
+ export function generateData(docsDir: string, outputDir: string, silent = false) {
31
+ if (!silent) console.log(chalk.blue("🚀 Generating OpenLAG Static Data..."));
32
+
33
+ const parsedData = parseOpenLagDocs(docsDir);
34
+
35
+ const state: StaticState = {
36
+ versions: parsedData.versions,
37
+ systemVersions: parsedData.systemVersions,
38
+ graphs: {},
39
+ changes: parsedData.changes
40
+ };
41
+
42
+ const allArtifacts = parsedData.artifacts;
43
+ const allRelations = parsedData.relations;
44
+
45
+ state.versions.forEach(v => {
46
+ state.graphs[v.id] = {
47
+ artifacts: allArtifacts.filter(a => a.type === 'SYSTEM_VERSION' || a.type === 'VERSION' || a.version === v.id || isDescendant(v.id, a.version, state.versions)),
48
+ relations: allRelations.filter(r => {
49
+ const fromArt = allArtifacts.find(a => a.id === r.from);
50
+ return fromArt && (fromArt.type === 'SYSTEM_VERSION' || fromArt.type === 'VERSION' || fromArt.version === v.id || isDescendant(v.id, fromArt.version, state.versions));
51
+ })
52
+ };
53
+ });
54
+
55
+ if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir, { recursive: true });
56
+
57
+ fs.writeFileSync(
58
+ path.join(outputDir, 'graph-data.json'),
59
+ JSON.stringify(state, null, 2)
60
+ );
61
+
62
+ if (!silent) console.log(chalk.green("✅ Data generated at"), chalk.cyan(path.join(outputDir, 'graph-data.json')));
63
+ }
64
+
65
+ export function watchData(docsDir: string, outputDir: string) {
66
+ console.log(chalk.yellow("👀 Watching for changes in"), chalk.cyan(docsDir));
67
+
68
+ const watcher = chokidar.watch(docsDir, {
69
+ ignoreInitial: true,
70
+ persistent: true
71
+ });
72
+
73
+ const runCleanly = () => {
74
+ try {
75
+ generateData(docsDir, outputDir, true);
76
+ console.log(chalk.dim(`[${new Date().toLocaleTimeString()}] `) + chalk.green("Regenerated graph-data.json"));
77
+ } catch (e) {
78
+ console.error(chalk.red("❌ Error during regeneration:"), e);
79
+ }
80
+ };
81
+
82
+ // Debounce to avoid multiple rapid regenerations
83
+ let timeout: NodeJS.Timeout;
84
+ const debouncedRun = () => {
85
+ clearTimeout(timeout);
86
+ timeout = setTimeout(runCleanly, 300);
87
+ };
88
+
89
+ watcher.on('all', (event, path) => {
90
+ debouncedRun();
91
+ });
92
+ }
@@ -0,0 +1,427 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+
5
+ /**
6
+ * OpenLAG Project Initializer
7
+ * Purpose: Configures the OpenLAG portal for a specific project.
8
+ */
9
+
10
+ export async function initProject(projectName?: string, projectDesc?: string, includeAllRelations?: boolean) {
11
+ const name = projectName || process.env.PROJECT_NAME || 'My OpenLAG Project';
12
+ const desc = projectDesc || process.env.PROJECT_DESCRIPTION || 'Living Architecture documentation for my system.';
13
+
14
+ const ROOT_DIR = process.cwd();
15
+
16
+ console.log(chalk.blue(`🛠️ Initializing OpenLAG for: `) + chalk.bold(name));
17
+
18
+ // 1. Update metadata.json
19
+ const metadataPath = path.join(ROOT_DIR, 'metadata.json');
20
+ if (fs.existsSync(metadataPath)) {
21
+ const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf-8'));
22
+ metadata.name = name;
23
+ metadata.description = desc;
24
+ fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
25
+ console.log(chalk.green('✅ Updated metadata.json'));
26
+ }
27
+
28
+ // 2. Update index.html title
29
+ const htmlPath = path.join(ROOT_DIR, 'index.html');
30
+ if (fs.existsSync(htmlPath)) {
31
+ let html = fs.readFileSync(htmlPath, 'utf-8');
32
+ html = html.replace(/<title>.*?<\/title>/, `<title>${name} | OpenLAG</title>`);
33
+ fs.writeFileSync(htmlPath, html);
34
+ console.log(chalk.green('✅ Updated index.html title'));
35
+ }
36
+
37
+ // 3. Initialize /docs if empty or missing
38
+ const docsDir = path.join(ROOT_DIR, 'docs');
39
+ if (!fs.existsSync(docsDir)) {
40
+ fs.mkdirSync(docsDir);
41
+ console.log(chalk.green('✅ Created /docs directory'));
42
+ }
43
+
44
+ // 3.1 Initialize /docs/relations with Mandatory Core Relations
45
+ const relationsDir = path.join(docsDir, 'relations');
46
+ if (!fs.existsSync(relationsDir)) {
47
+ fs.mkdirSync(relationsDir);
48
+ console.log(chalk.green('✅ Created /docs/relations directory'));
49
+ } else {
50
+ // Purge existing relations to ensure only mandatory ones exist on init
51
+ const files = fs.readdirSync(relationsDir);
52
+ for (const file of files) {
53
+ if (file.endsWith('.yaml')) {
54
+ fs.unlinkSync(path.join(relationsDir, file));
55
+ }
56
+ }
57
+ }
58
+
59
+ const mandatoryRelations = [
60
+ {
61
+ name: 'IMPLEMENTS.yaml',
62
+ content: `relation: IMPLEMENTS
63
+ description: "Conecta implementación con necesidad funcional/técnica."
64
+ category: TRACEABILITY
65
+ allowedFrom: [CODE_ENTITY, COMPONENT, API, DATABASE_ENTITY, SYSTEM_VERSION]
66
+ allowedTo: [REQUIREMENT, FEATURE, EPIC, DESIGN, USE_CASE, BUSINESS_RULE]
67
+ multiplicity:
68
+ from: many
69
+ to: many
70
+ validation:
71
+ severity: error`
72
+ },
73
+ {
74
+ name: 'TESTS.yaml',
75
+ content: `relation: TESTS
76
+ description: "Conecta tests con comportamiento validado."
77
+ category: TRACEABILITY
78
+ allowedFrom: [TEST_CASE, TEST]
79
+ allowedTo: [REQUIREMENT, FEATURE, EPIC, CODE_ENTITY, COMPONENT, API, DATABASE_ENTITY, BUG, INCIDENT]
80
+ multiplicity:
81
+ from: many
82
+ to: many
83
+ validation:
84
+ severity: error`
85
+ },
86
+ {
87
+ name: 'REFINES.yaml',
88
+ content: `relation: REFINES
89
+ description: "Descompone artefactos en otros más concretos."
90
+ category: TRACEABILITY
91
+ allowedFrom: [FEATURE, REQUIREMENT, BUG, RISK, DESIGN]
92
+ allowedTo: [EPIC, FEATURE, PROJECT, BUSINESS_RULE, REQUIREMENT, DESIGN]
93
+ multiplicity:
94
+ from: many
95
+ to: many
96
+ validation:
97
+ severity: warn`
98
+ },
99
+ {
100
+ name: 'FIXES.yaml',
101
+ content: `relation: FIXES
102
+ description: "Conecta correcciones con bugs o incidentes."
103
+ category: TRACEABILITY
104
+ allowedFrom: [CHANGE, CODE_ENTITY, COMPONENT, SYSTEM_VERSION]
105
+ allowedTo: [BUG, INCIDENT, RISK]
106
+ multiplicity:
107
+ from: many
108
+ to: many
109
+ validation:
110
+ severity: error`
111
+ },
112
+ {
113
+ name: 'DOCUMENTS.yaml',
114
+ content: `relation: DOCUMENTS
115
+ description: "Conecta documentación con el artefacto descrito."
116
+ category: SEMANTIC
117
+ allowedFrom: [DOCUMENTATION, GLOSSARY_TERM]
118
+ allowedTo: [PROJECT, EPIC, FEATURE, REQUIREMENT, BUSINESS_RULE, USE_CASE, DESIGN, DECISION, CODE_ENTITY, TEST_CASE, CHANGE, BUG, RISK, GLOSSARY_TERM, COMPONENT, API, DATABASE_ENTITY, TEST, DOCUMENTATION, INCIDENT, INFRASTRUCTURE, DEPLOYMENT, MONITORING, MAINTENANCE, SYSTEM_VERSION, VERSION]
119
+ multiplicity:
120
+ from: many
121
+ to: many
122
+ validation:
123
+ severity: info`
124
+ },
125
+ {
126
+ name: 'JUSTIFIES.yaml',
127
+ content: `relation: JUSTIFIES
128
+ description: "Conecta decisiones con aquello que justifican."
129
+ category: SEMANTIC
130
+ allowedFrom: [DECISION, BUSINESS_RULE, DOCUMENTATION, RISK]
131
+ allowedTo: [DESIGN, REQUIREMENT, FEATURE, EPIC, PROJECT, CODE_ENTITY, COMPONENT, INFRASTRUCTURE, DEPLOYMENT, MAINTENANCE]
132
+ multiplicity:
133
+ from: many
134
+ to: many
135
+ validation:
136
+ severity: warn`
137
+ }
138
+ ];
139
+
140
+ mandatoryRelations.forEach(rel => {
141
+ fs.writeFileSync(path.join(relationsDir, rel.name), rel.content);
142
+ });
143
+ console.log(chalk.green('✅ Created Mandatory Core Relations (IMPLEMENTS, TESTS, REFINES, FIXES, DOCUMENTS, JUSTIFIES)'));
144
+
145
+ if (includeAllRelations) {
146
+ const optionalRelations = [
147
+ {
148
+ name: 'DEPENDS_ON.yaml',
149
+ content: `relation: DEPENDS_ON
150
+ description: "Acoplamiento estático arquitectónico o de empaquetado."
151
+ category: STRUCTURAL
152
+ allowedFrom: [CODE_ENTITY, COMPONENT, API, DATABASE_ENTITY, LIBRARY, VERSION, SYSTEM_VERSION]
153
+ allowedTo: [CODE_ENTITY, COMPONENT, API, DATABASE_ENTITY, LIBRARY, VERSION, SYSTEM_VERSION]
154
+ multiplicity:
155
+ from: many
156
+ to: many
157
+ validation:
158
+ severity: warn`
159
+ },
160
+ {
161
+ name: 'USES.yaml',
162
+ content: `relation: USES
163
+ description: "Llamada funcional, invocación o flujo en tiempo de ejecución."
164
+ category: OPERATIONAL
165
+ allowedFrom: [CODE_ENTITY, COMPONENT, API, FEATURE, USE_CASE]
166
+ allowedTo: [CODE_ENTITY, COMPONENT, API, SYSTEM_VERSION]
167
+ multiplicity:
168
+ from: many
169
+ to: many
170
+ validation:
171
+ severity: warn`
172
+ },
173
+ {
174
+ name: 'DEPLOYS.yaml',
175
+ content: `relation: DEPLOYS
176
+ description: "Instanciación de componentes o release en infraestructura."
177
+ category: OPERATIONAL
178
+ allowedFrom: [DEPLOYMENT, PIPELINE, SYSTEM_VERSION]
179
+ allowedTo: [COMPONENT, INFRASTRUCTURE, ENVIRONMENT, DATABASE_ENTITY]
180
+ multiplicity:
181
+ from: many
182
+ to: many
183
+ validation:
184
+ severity: error`
185
+ },
186
+ {
187
+ name: 'MONITORS.yaml',
188
+ content: `relation: MONITORS
189
+ description: "Relación de observabilidad."
190
+ category: OPERATIONAL
191
+ allowedFrom: [MONITORING, CHECK]
192
+ allowedTo: [COMPONENT, INFRASTRUCTURE, DEPLOYMENT, DATABASE_ENTITY, API]
193
+ multiplicity:
194
+ from: many
195
+ to: many
196
+ validation:
197
+ severity: info`
198
+ },
199
+ {
200
+ name: 'IMPACTS.yaml',
201
+ content: `relation: IMPACTS
202
+ description: "Descripción de posibles efectos colaterales."
203
+ category: SEMANTIC
204
+ allowedFrom: [CHANGE, RISK, BUG, INCIDENT, DECISION]
205
+ allowedTo: [PROJECT, EPIC, FEATURE, REQUIREMENT, DESIGN, CODE_ENTITY, COMPONENT, API, DATABASE_ENTITY, SYSTEM_VERSION]
206
+ multiplicity:
207
+ from: many
208
+ to: many
209
+ validation:
210
+ severity: warn`
211
+ },
212
+ {
213
+ name: 'BLOCKS.yaml',
214
+ content: `relation: BLOCKS
215
+ description: "Descripción de impedimentos directos."
216
+ category: DEPENDENCY
217
+ allowedFrom: [BUG, RISK, INCIDENT, CHANGE, DECISION, REQUIREMENT, FEATURE, EPIC]
218
+ allowedTo: [PROJECT, EPIC, FEATURE, REQUIREMENT, BUG, CHANGE, DEPLOYMENT, DEPLOYMENT]
219
+ multiplicity:
220
+ from: many
221
+ to: many
222
+ validation:
223
+ severity: error`
224
+ },
225
+ {
226
+ name: 'BREAKS.yaml',
227
+ content: `relation: BREAKS
228
+ description: "Averías o rupturas confirmadas."
229
+ category: OPERATIONAL
230
+ allowedFrom: [CHANGE, CODE_ENTITY, COMPONENT, SYSTEM_VERSION]
231
+ allowedTo: [TEST_CASE, TEST, API, COMPONENT, REQUIREMENT, FEATURE]
232
+ multiplicity:
233
+ from: many
234
+ to: many
235
+ validation:
236
+ severity: error`
237
+ },
238
+ {
239
+ name: 'REPLACES.yaml',
240
+ content: `relation: REPLACES
241
+ description: "Evolución e histórico, deprecando versiones anteriores."
242
+ category: EVOLUTIONARY
243
+ allowedFrom: [COMPONENT, API, SYSTEM_VERSION, VERSION, REQUIREMENT, FEATURE, DESIGN, DECISION]
244
+ allowedTo: [COMPONENT, API, SYSTEM_VERSION, VERSION, REQUIREMENT, FEATURE, DESIGN, DECISION]
245
+ multiplicity:
246
+ from: many
247
+ to: one
248
+ validation:
249
+ severity: info`
250
+ },
251
+ {
252
+ name: 'DERIVES_FROM.yaml',
253
+ content: `relation: DERIVES_FROM
254
+ description: "Evolución conceptual genérica."
255
+ category: SEMANTIC
256
+ allowedFrom: [REQUIREMENT, FEATURE, DESIGN, BUSINESS_RULE, DECISION, USE_CASE]
257
+ allowedTo: [REQUIREMENT, FEATURE, DESIGN, BUSINESS_RULE, DECISION, USE_CASE]
258
+ multiplicity:
259
+ from: many
260
+ to: many
261
+ validation:
262
+ severity: info`
263
+ },
264
+ {
265
+ name: 'VALIDATES.yaml',
266
+ content: `relation: VALIDATES
267
+ description: "Validación empírica/humana (QA Manual)."
268
+ category: TRACEABILITY
269
+ allowedFrom: [PROCESS, CHECK, DOCUMENTATION]
270
+ allowedTo: [REQUIREMENT, FEATURE, USE_CASE, DEPLOYMENT]
271
+ multiplicity:
272
+ from: many
273
+ to: many
274
+ validation:
275
+ severity: info`
276
+ },
277
+ {
278
+ name: 'DEFINES.yaml',
279
+ content: `relation: DEFINES
280
+ description: "Entidades que instauran glosarios o normas."
281
+ category: SEMANTIC
282
+ allowedFrom: [BUSINESS_RULE, DECISION, DOCUMENTATION, GLOSSARY_TERM]
283
+ allowedTo: [REQUIREMENT, FEATURE, DESIGN, PROJECT, COMPONENT, API, DATABASE_ENTITY]
284
+ multiplicity:
285
+ from: many
286
+ to: many
287
+ validation:
288
+ severity: info`
289
+ },
290
+ {
291
+ name: 'CALLS.yaml',
292
+ content: `relation: CALLS
293
+ description: "Trazabilidad de invocación a nivel código."
294
+ category: STRUCTURAL
295
+ allowedFrom: [CODE_ENTITY]
296
+ allowedTo: [CODE_ENTITY, API]
297
+ multiplicity:
298
+ from: many
299
+ to: many
300
+ validation:
301
+ severity: warn`
302
+ },
303
+ {
304
+ name: 'IMPORTS.yaml',
305
+ content: `relation: IMPORTS
306
+ description: "Trazabilidad de importación estática a nivel de código."
307
+ category: STRUCTURAL
308
+ allowedFrom: [CODE_ENTITY]
309
+ allowedTo: [CODE_ENTITY, LIBRARY]
310
+ multiplicity:
311
+ from: many
312
+ to: many
313
+ validation:
314
+ severity: warn`
315
+ },
316
+ {
317
+ name: 'RELATES_TO.yaml',
318
+ content: `relation: RELATES_TO
319
+ description: |
320
+ Uso genérico propenso a polución semántica. (DISCOURAGED)
321
+ Para mantener un grafo limpio, solo úsala aportando rationale explícito:
322
+
323
+ relations:
324
+ - to: mi-otro-artefacto
325
+ type: RELATES_TO
326
+ rationale: "No encaja con USES o DEPENDS_ON debido al contexto X."
327
+ category: SEMANTIC
328
+ allowedFrom: [PROJECT, EPIC, FEATURE, REQUIREMENT, BUSINESS_RULE, USE_CASE, DESIGN, DECISION, CODE_ENTITY, TEST_CASE, CHANGE, BUG, RISK, GLOSSARY_TERM, COMPONENT, API, DATABASE_ENTITY, TEST, DOCUMENTATION, INCIDENT, INFRASTRUCTURE, DEPLOYMENT, MONITORING, MAINTENANCE, SYSTEM_VERSION, VERSION]
329
+ allowedTo: [PROJECT, EPIC, FEATURE, REQUIREMENT, BUSINESS_RULE, USE_CASE, DESIGN, DECISION, CODE_ENTITY, TEST_CASE, CHANGE, BUG, RISK, GLOSSARY_TERM, COMPONENT, API, DATABASE_ENTITY, TEST, DOCUMENTATION, INCIDENT, INFRASTRUCTURE, DEPLOYMENT, MONITORING, MAINTENANCE, SYSTEM_VERSION, VERSION]
330
+ multiplicity:
331
+ from: many
332
+ to: many
333
+ validation:
334
+ severity: warn`
335
+ }
336
+ ];
337
+
338
+ optionalRelations.forEach(rel => {
339
+ fs.writeFileSync(path.join(relationsDir, rel.name), rel.content);
340
+ });
341
+ console.log(chalk.green('✅ Created Official Optional Relations'));
342
+ }
343
+
344
+
345
+ const versionsDir = path.join(docsDir, 'versions');
346
+ if (!fs.existsSync(versionsDir)) {
347
+ fs.mkdirSync(versionsDir);
348
+ console.log(chalk.green('✅ Created /docs/versions directory'));
349
+ }
350
+
351
+ const versionPath = path.join(versionsDir, 'v-1.0.0.md');
352
+ if (!fs.existsSync(versionPath)) {
353
+ const versionsContent = `---
354
+ id: v-1.0.0
355
+ type: VERSION
356
+ name: "Baseline"
357
+ timestamp: "${new Date().toISOString().split('T')[0]}"
358
+ parentVersion: null
359
+ layer: DOCUMENTATION
360
+ title: "Project Release v1.0.0"
361
+ description: "Initial release"
362
+ ownership:
363
+ owner: architecture
364
+ team: architecture
365
+ relations: []
366
+ ---
367
+ `;
368
+ fs.writeFileSync(versionPath, versionsContent);
369
+ console.log(chalk.green('✅ Created initial docs/versions/v-1.0.0.md'));
370
+ }
371
+
372
+ const componentsVersionsPath = path.join(versionsDir, 'sys-core-1.0.md');
373
+ if (!fs.existsSync(componentsVersionsPath)) {
374
+ const cvContent = `---
375
+ id: sys-core-1.0
376
+ type: SYSTEM_VERSION
377
+ component: "Core System"
378
+ version: "1.0.0"
379
+ releaseDate: "${new Date().toISOString().split('T')[0]}"
380
+ layer: OPERATIONS
381
+ title: "Core System v1.0"
382
+ description: "Base framework."
383
+ ownership:
384
+ owner: architecture
385
+ team: architecture
386
+ relations: []
387
+ ---
388
+ `;
389
+ fs.writeFileSync(componentsVersionsPath, cvContent);
390
+ console.log(chalk.green('✅ Created initial docs/versions/sys-core-1.0.md'));
391
+ }
392
+
393
+ // 4. Create a sample doc if empty
394
+ const architectureDir = path.join(docsDir, 'architecture');
395
+ if (!fs.existsSync(architectureDir)) {
396
+ fs.mkdirSync(architectureDir);
397
+ console.log(chalk.green('✅ Created /docs/architecture directory'));
398
+ }
399
+
400
+ const sampleDocPath = path.join(architectureDir, 'architecture-overview.md');
401
+ if (!fs.existsSync(sampleDocPath)) {
402
+ const sampleContent = `---
403
+ id: arch-overview
404
+ type: DOCUMENT
405
+ status: draft
406
+ title: "Architecture Overview"
407
+ description: "High-level description of the system architecture."
408
+ ---
409
+
410
+ # Architecture Overview
411
+
412
+ This document describes the high-level architecture of ${name}.
413
+
414
+ ## Key Principles
415
+ - Traceability first.
416
+ - Documentation as Code.
417
+ - Graph-based relationships.
418
+ `;
419
+ fs.writeFileSync(sampleDocPath, sampleContent);
420
+ console.log(chalk.green('✅ Created initial docs/architecture/architecture-overview.md'));
421
+ }
422
+
423
+ console.log('\n' + chalk.cyan('🚀 Project initialized successfully!'));
424
+ console.log('Next steps:');
425
+ console.log('1. Edit ' + chalk.cyan('docs/') + ' to reflect your architecture.');
426
+ console.log('2. Run ' + chalk.cyan('openlag dev') + ' to see your portal.');
427
+ }