@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,1793 @@
1
+ #!/usr/bin/env node
2
+
3
+ // scripts/cli/openlag.ts
4
+ import { execFileSync as execFileSync2 } from "child_process";
5
+ import path8 from "path";
6
+ import { fileURLToPath as fileURLToPath3 } from "url";
7
+ import chalk6 from "chalk";
8
+ import { Command } from "commander";
9
+
10
+ // scripts/cli/build.ts
11
+ import { execFileSync } from "child_process";
12
+ import path4 from "path";
13
+ import { fileURLToPath } from "url";
14
+ import chalk2 from "chalk";
15
+
16
+ // scripts/cli/generate.ts
17
+ import fs2 from "fs";
18
+ import path2 from "path";
19
+
20
+ // scripts/core/parser/scanner.ts
21
+ import fs from "fs";
22
+ import path from "path";
23
+ function scanDocs(docsDir) {
24
+ const documents = [];
25
+ const traverse = (dir) => {
26
+ if (!fs.existsSync(dir)) return;
27
+ const items = fs.readdirSync(dir);
28
+ for (const item of items) {
29
+ const fullPath = path.join(dir, item);
30
+ const stat = fs.statSync(fullPath);
31
+ if (stat.isDirectory()) {
32
+ traverse(fullPath);
33
+ } else if (item.endsWith(".md")) {
34
+ const content = fs.readFileSync(fullPath, "utf-8");
35
+ documents.push({
36
+ file: fullPath,
37
+ content
38
+ });
39
+ }
40
+ }
41
+ };
42
+ traverse(docsDir);
43
+ return documents;
44
+ }
45
+
46
+ // scripts/core/parser/schemas.ts
47
+ import { z } from "zod";
48
+ var ArtifactSchema = z.object({
49
+ id: z.string(),
50
+ type: z.string(),
51
+ subType: z.string().optional(),
52
+ title: z.string(),
53
+ version: z.string(),
54
+ description: z.string(),
55
+ systemVersionId: z.string().optional(),
56
+ status: z.enum(["draft", "in_progress", "ready", "closed", "deprecated"]).optional(),
57
+ layer: z.string().optional(),
58
+ ownership: z.object({
59
+ owner: z.string().optional(),
60
+ team: z.string().optional(),
61
+ domain: z.string().optional(),
62
+ maintainers: z.array(z.string()).optional(),
63
+ reviewers: z.array(z.string()).optional(),
64
+ steward: z.string().optional()
65
+ }).optional(),
66
+ file: z.string(),
67
+ schemaVersion: z.string().optional()
68
+ });
69
+
70
+ // src/core/semantic/artifact-layers.ts
71
+ var LayerInferenceRules = {
72
+ PROJECT: "BUSINESS",
73
+ EPIC: "BUSINESS",
74
+ FEATURE: "BUSINESS",
75
+ REQUIREMENT: "BUSINESS",
76
+ BUSINESS_RULE: "BUSINESS",
77
+ USE_CASE: "BUSINESS",
78
+ DESIGN: "ARCHITECTURE",
79
+ DECISION: "ARCHITECTURE",
80
+ COMPONENT: "ARCHITECTURE",
81
+ API: "ARCHITECTURE",
82
+ CODE_ENTITY: "IMPLEMENTATION",
83
+ DATABASE_ENTITY: "IMPLEMENTATION",
84
+ TEST_CASE: "IMPLEMENTATION",
85
+ TEST: "IMPLEMENTATION",
86
+ CHANGE: "IMPLEMENTATION",
87
+ BUG: "IMPLEMENTATION",
88
+ RISK: "IMPLEMENTATION",
89
+ INCIDENT: "OPERATIONS",
90
+ INFRASTRUCTURE: "OPERATIONS",
91
+ DEPLOYMENT: "OPERATIONS",
92
+ MONITORING: "OPERATIONS",
93
+ MAINTENANCE: "OPERATIONS",
94
+ SYSTEM_VERSION: "OPERATIONS",
95
+ GLOSSARY_TERM: "DOCUMENTATION",
96
+ DOCUMENTATION: "DOCUMENTATION",
97
+ VERSION: "DOCUMENTATION",
98
+ LIBRARY: "IMPLEMENTATION",
99
+ ENVIRONMENT: "OPERATIONS",
100
+ CHECK: "OPERATIONS",
101
+ PROCESS: "OPERATIONS",
102
+ PIPELINE: "OPERATIONS"
103
+ };
104
+ function inferLayer(artifactType) {
105
+ return LayerInferenceRules[artifactType];
106
+ }
107
+
108
+ // scripts/core/parser/normalizer.ts
109
+ function normalizeArtifact(parsed, fullPath, body) {
110
+ const p = { ...parsed };
111
+ if (!p.schemaVersion) {
112
+ p.schemaVersion = "1.0.0";
113
+ }
114
+ const typeValue = p.type || p.Type;
115
+ return {
116
+ id: String(p.id || p.ID || ""),
117
+ type: typeValue,
118
+ subType: p.subType || p.subtype || p.SubType,
119
+ title: String(p.title || p.Title || (p.id || p.ID || "")),
120
+ version: String(p.version || p.Version || "v-1"),
121
+ description: body,
122
+ systemVersionId: p.systemVersionId || p.systemversionid,
123
+ component: p.component,
124
+ releaseDate: p.releaseDate || p.timestamp,
125
+ status: p.status,
126
+ layer: inferLayer(typeValue),
127
+ ownership: p.ownership || p.owner ? { owner: p.owner, ...p.ownership } : void 0,
128
+ file: fullPath,
129
+ schemaVersion: p.schemaVersion
130
+ };
131
+ }
132
+
133
+ // scripts/core/parser/diagnostic.ts
134
+ var DiagnosticEngine = class {
135
+ constructor() {
136
+ this.diagnostics = [];
137
+ }
138
+ add(file, message, severity) {
139
+ this.diagnostics.push({ file, message, severity });
140
+ }
141
+ getDiagnostics() {
142
+ return this.diagnostics;
143
+ }
144
+ getErrors() {
145
+ return this.diagnostics.map((d) => ({ file: d.file, message: `[${d.severity}] ${d.message}` }));
146
+ }
147
+ hasCritical() {
148
+ return this.diagnostics.some((d) => d.severity === "CRITICAL" /* CRITICAL */);
149
+ }
150
+ };
151
+
152
+ // src/core/generated/relation-definitions.ts
153
+ var GENERATED_RELATIONS = [
154
+ {
155
+ "type": "BLOCKS",
156
+ "description": "Descripci\xF3n de impedimentos directos.",
157
+ "category": "DEPENDENCY",
158
+ "allowedFrom": [
159
+ "BUG",
160
+ "RISK",
161
+ "INCIDENT",
162
+ "CHANGE",
163
+ "DECISION",
164
+ "REQUIREMENT",
165
+ "FEATURE",
166
+ "EPIC"
167
+ ],
168
+ "allowedTo": [
169
+ "PROJECT",
170
+ "EPIC",
171
+ "FEATURE",
172
+ "REQUIREMENT",
173
+ "BUG",
174
+ "CHANGE",
175
+ "DEPLOYMENT",
176
+ "DEPLOYMENT"
177
+ ],
178
+ "multiplicity": {
179
+ "from": "many",
180
+ "to": "many"
181
+ },
182
+ "validation": {
183
+ "severity": "error"
184
+ },
185
+ "strength": "STRONG"
186
+ },
187
+ {
188
+ "type": "BREAKS",
189
+ "description": "Aver\xEDas o rupturas confirmadas.",
190
+ "category": "OPERATIONAL",
191
+ "allowedFrom": [
192
+ "CHANGE",
193
+ "CODE_ENTITY",
194
+ "COMPONENT",
195
+ "SYSTEM_VERSION"
196
+ ],
197
+ "allowedTo": [
198
+ "TEST_CASE",
199
+ "TEST",
200
+ "API",
201
+ "COMPONENT",
202
+ "REQUIREMENT",
203
+ "FEATURE"
204
+ ],
205
+ "multiplicity": {
206
+ "from": "many",
207
+ "to": "many"
208
+ },
209
+ "validation": {
210
+ "severity": "error"
211
+ },
212
+ "strength": "STRONG"
213
+ },
214
+ {
215
+ "type": "CALLS",
216
+ "description": "Trazabilidad de invocaci\xF3n a nivel c\xF3digo.",
217
+ "category": "STRUCTURAL",
218
+ "allowedFrom": [
219
+ "CODE_ENTITY"
220
+ ],
221
+ "allowedTo": [
222
+ "CODE_ENTITY",
223
+ "API"
224
+ ],
225
+ "multiplicity": {
226
+ "from": "many",
227
+ "to": "many"
228
+ },
229
+ "validation": {
230
+ "severity": "warn"
231
+ },
232
+ "strength": "MEDIUM"
233
+ },
234
+ {
235
+ "type": "DEFINES",
236
+ "description": "Entidades que instauran glosarios o normas.",
237
+ "category": "SEMANTIC",
238
+ "allowedFrom": [
239
+ "BUSINESS_RULE",
240
+ "DECISION",
241
+ "DOCUMENTATION",
242
+ "GLOSSARY_TERM"
243
+ ],
244
+ "allowedTo": [
245
+ "REQUIREMENT",
246
+ "FEATURE",
247
+ "DESIGN",
248
+ "PROJECT",
249
+ "COMPONENT",
250
+ "API",
251
+ "DATABASE_ENTITY"
252
+ ],
253
+ "multiplicity": {
254
+ "from": "many",
255
+ "to": "many"
256
+ },
257
+ "validation": {
258
+ "severity": "info"
259
+ },
260
+ "strength": "WEAK"
261
+ },
262
+ {
263
+ "type": "DEPENDS_ON",
264
+ "description": "Acoplamiento est\xE1tico arquitect\xF3nico o de empaquetado.",
265
+ "category": "STRUCTURAL",
266
+ "allowedFrom": [
267
+ "CODE_ENTITY",
268
+ "COMPONENT",
269
+ "API",
270
+ "DATABASE_ENTITY",
271
+ "LIBRARY",
272
+ "VERSION",
273
+ "SYSTEM_VERSION"
274
+ ],
275
+ "allowedTo": [
276
+ "CODE_ENTITY",
277
+ "COMPONENT",
278
+ "API",
279
+ "DATABASE_ENTITY",
280
+ "LIBRARY",
281
+ "VERSION",
282
+ "SYSTEM_VERSION"
283
+ ],
284
+ "multiplicity": {
285
+ "from": "many",
286
+ "to": "many"
287
+ },
288
+ "validation": {
289
+ "severity": "warn"
290
+ },
291
+ "strength": "MEDIUM"
292
+ },
293
+ {
294
+ "type": "DEPLOYS",
295
+ "description": "Instanciaci\xF3n de componentes o release en infraestructura.",
296
+ "category": "OPERATIONAL",
297
+ "allowedFrom": [
298
+ "DEPLOYMENT",
299
+ "PIPELINE",
300
+ "SYSTEM_VERSION"
301
+ ],
302
+ "allowedTo": [
303
+ "COMPONENT",
304
+ "INFRASTRUCTURE",
305
+ "ENVIRONMENT",
306
+ "DATABASE_ENTITY"
307
+ ],
308
+ "multiplicity": {
309
+ "from": "many",
310
+ "to": "many"
311
+ },
312
+ "validation": {
313
+ "severity": "error"
314
+ },
315
+ "strength": "STRONG"
316
+ },
317
+ {
318
+ "type": "DERIVES_FROM",
319
+ "description": "Evoluci\xF3n conceptual gen\xE9rica.",
320
+ "category": "SEMANTIC",
321
+ "allowedFrom": [
322
+ "REQUIREMENT",
323
+ "FEATURE",
324
+ "DESIGN",
325
+ "BUSINESS_RULE",
326
+ "DECISION",
327
+ "USE_CASE"
328
+ ],
329
+ "allowedTo": [
330
+ "REQUIREMENT",
331
+ "FEATURE",
332
+ "DESIGN",
333
+ "BUSINESS_RULE",
334
+ "DECISION",
335
+ "USE_CASE"
336
+ ],
337
+ "multiplicity": {
338
+ "from": "many",
339
+ "to": "many"
340
+ },
341
+ "validation": {
342
+ "severity": "info"
343
+ },
344
+ "strength": "WEAK"
345
+ },
346
+ {
347
+ "type": "DOCUMENTS",
348
+ "description": "Conecta documentaci\xF3n con el artefacto descrito.",
349
+ "category": "SEMANTIC",
350
+ "allowedFrom": [
351
+ "DOCUMENTATION",
352
+ "GLOSSARY_TERM"
353
+ ],
354
+ "allowedTo": [
355
+ "PROJECT",
356
+ "EPIC",
357
+ "FEATURE",
358
+ "REQUIREMENT",
359
+ "BUSINESS_RULE",
360
+ "USE_CASE",
361
+ "DESIGN",
362
+ "DECISION",
363
+ "CODE_ENTITY",
364
+ "TEST_CASE",
365
+ "CHANGE",
366
+ "BUG",
367
+ "RISK",
368
+ "GLOSSARY_TERM",
369
+ "COMPONENT",
370
+ "API",
371
+ "DATABASE_ENTITY",
372
+ "TEST",
373
+ "DOCUMENTATION",
374
+ "INCIDENT",
375
+ "INFRASTRUCTURE",
376
+ "DEPLOYMENT",
377
+ "MONITORING",
378
+ "MAINTENANCE",
379
+ "SYSTEM_VERSION",
380
+ "VERSION"
381
+ ],
382
+ "multiplicity": {
383
+ "from": "many",
384
+ "to": "many"
385
+ },
386
+ "validation": {
387
+ "severity": "info"
388
+ },
389
+ "strength": "WEAK"
390
+ },
391
+ {
392
+ "type": "FIXES",
393
+ "description": "Conecta correcciones con bugs o incidentes.",
394
+ "category": "TRACEABILITY",
395
+ "allowedFrom": [
396
+ "CHANGE",
397
+ "CODE_ENTITY",
398
+ "COMPONENT",
399
+ "SYSTEM_VERSION"
400
+ ],
401
+ "allowedTo": [
402
+ "BUG",
403
+ "INCIDENT",
404
+ "RISK"
405
+ ],
406
+ "multiplicity": {
407
+ "from": "many",
408
+ "to": "many"
409
+ },
410
+ "validation": {
411
+ "severity": "error"
412
+ },
413
+ "strength": "STRONG"
414
+ },
415
+ {
416
+ "type": "IMPACTS",
417
+ "description": "Descripci\xF3n de posibles efectos colaterales.",
418
+ "category": "SEMANTIC",
419
+ "allowedFrom": [
420
+ "CHANGE",
421
+ "RISK",
422
+ "BUG",
423
+ "INCIDENT",
424
+ "DECISION"
425
+ ],
426
+ "allowedTo": [
427
+ "PROJECT",
428
+ "EPIC",
429
+ "FEATURE",
430
+ "REQUIREMENT",
431
+ "DESIGN",
432
+ "CODE_ENTITY",
433
+ "COMPONENT",
434
+ "API",
435
+ "DATABASE_ENTITY",
436
+ "SYSTEM_VERSION"
437
+ ],
438
+ "multiplicity": {
439
+ "from": "many",
440
+ "to": "many"
441
+ },
442
+ "validation": {
443
+ "severity": "warn"
444
+ },
445
+ "strength": "MEDIUM"
446
+ },
447
+ {
448
+ "type": "IMPLEMENTS",
449
+ "description": "Conecta implementaci\xF3n con necesidad funcional/t\xE9cnica.",
450
+ "category": "TRACEABILITY",
451
+ "allowedFrom": [
452
+ "CODE_ENTITY",
453
+ "COMPONENT",
454
+ "API",
455
+ "DATABASE_ENTITY",
456
+ "SYSTEM_VERSION"
457
+ ],
458
+ "allowedTo": [
459
+ "REQUIREMENT",
460
+ "FEATURE",
461
+ "EPIC",
462
+ "DESIGN",
463
+ "USE_CASE",
464
+ "BUSINESS_RULE"
465
+ ],
466
+ "multiplicity": {
467
+ "from": "many",
468
+ "to": "many"
469
+ },
470
+ "validation": {
471
+ "severity": "error"
472
+ },
473
+ "strength": "STRONG"
474
+ },
475
+ {
476
+ "type": "IMPORTS",
477
+ "description": "Trazabilidad de importaci\xF3n est\xE1tica a nivel de c\xF3digo.",
478
+ "category": "STRUCTURAL",
479
+ "allowedFrom": [
480
+ "CODE_ENTITY"
481
+ ],
482
+ "allowedTo": [
483
+ "CODE_ENTITY",
484
+ "LIBRARY"
485
+ ],
486
+ "multiplicity": {
487
+ "from": "many",
488
+ "to": "many"
489
+ },
490
+ "validation": {
491
+ "severity": "warn"
492
+ },
493
+ "strength": "MEDIUM"
494
+ },
495
+ {
496
+ "type": "JUSTIFIES",
497
+ "description": "Conecta decisiones con aquello que justifican.",
498
+ "category": "SEMANTIC",
499
+ "allowedFrom": [
500
+ "DECISION",
501
+ "BUSINESS_RULE",
502
+ "DOCUMENTATION",
503
+ "RISK"
504
+ ],
505
+ "allowedTo": [
506
+ "DESIGN",
507
+ "REQUIREMENT",
508
+ "FEATURE",
509
+ "EPIC",
510
+ "PROJECT",
511
+ "CODE_ENTITY",
512
+ "COMPONENT",
513
+ "INFRASTRUCTURE",
514
+ "DEPLOYMENT",
515
+ "MAINTENANCE"
516
+ ],
517
+ "multiplicity": {
518
+ "from": "many",
519
+ "to": "many"
520
+ },
521
+ "validation": {
522
+ "severity": "warn"
523
+ },
524
+ "strength": "MEDIUM"
525
+ },
526
+ {
527
+ "type": "MONITORS",
528
+ "description": "Relaci\xF3n de observabilidad.",
529
+ "category": "OPERATIONAL",
530
+ "allowedFrom": [
531
+ "MONITORING",
532
+ "CHECK"
533
+ ],
534
+ "allowedTo": [
535
+ "COMPONENT",
536
+ "INFRASTRUCTURE",
537
+ "DEPLOYMENT",
538
+ "DATABASE_ENTITY",
539
+ "API"
540
+ ],
541
+ "multiplicity": {
542
+ "from": "many",
543
+ "to": "many"
544
+ },
545
+ "validation": {
546
+ "severity": "info"
547
+ },
548
+ "strength": "WEAK"
549
+ },
550
+ {
551
+ "type": "REFINES",
552
+ "description": "Descompone artefactos en otros m\xE1s concretos.",
553
+ "category": "TRACEABILITY",
554
+ "allowedFrom": [
555
+ "FEATURE",
556
+ "REQUIREMENT",
557
+ "BUG",
558
+ "RISK",
559
+ "DESIGN"
560
+ ],
561
+ "allowedTo": [
562
+ "EPIC",
563
+ "FEATURE",
564
+ "PROJECT",
565
+ "BUSINESS_RULE",
566
+ "REQUIREMENT",
567
+ "DESIGN"
568
+ ],
569
+ "multiplicity": {
570
+ "from": "many",
571
+ "to": "many"
572
+ },
573
+ "validation": {
574
+ "severity": "warn"
575
+ },
576
+ "strength": "MEDIUM"
577
+ },
578
+ {
579
+ "type": "RELATES_TO",
580
+ "description": 'Uso gen\xE9rico propenso a poluci\xF3n sem\xE1ntica. (DISCOURAGED)\nPara mantener un grafo limpio, solo \xFAsala aportando rationale expl\xEDcito:\n\nrelations:\n - to: mi-otro-artefacto\n type: RELATES_TO\n rationale: "No encaja con USES o DEPENDS_ON debido al contexto X."\n',
581
+ "category": "SEMANTIC",
582
+ "allowedFrom": [
583
+ "PROJECT",
584
+ "EPIC",
585
+ "FEATURE",
586
+ "REQUIREMENT",
587
+ "BUSINESS_RULE",
588
+ "USE_CASE",
589
+ "DESIGN",
590
+ "DECISION",
591
+ "CODE_ENTITY",
592
+ "TEST_CASE",
593
+ "CHANGE",
594
+ "BUG",
595
+ "RISK",
596
+ "GLOSSARY_TERM",
597
+ "COMPONENT",
598
+ "API",
599
+ "DATABASE_ENTITY",
600
+ "TEST",
601
+ "DOCUMENTATION",
602
+ "INCIDENT",
603
+ "INFRASTRUCTURE",
604
+ "DEPLOYMENT",
605
+ "MONITORING",
606
+ "MAINTENANCE",
607
+ "SYSTEM_VERSION",
608
+ "VERSION"
609
+ ],
610
+ "allowedTo": [
611
+ "PROJECT",
612
+ "EPIC",
613
+ "FEATURE",
614
+ "REQUIREMENT",
615
+ "BUSINESS_RULE",
616
+ "USE_CASE",
617
+ "DESIGN",
618
+ "DECISION",
619
+ "CODE_ENTITY",
620
+ "TEST_CASE",
621
+ "CHANGE",
622
+ "BUG",
623
+ "RISK",
624
+ "GLOSSARY_TERM",
625
+ "COMPONENT",
626
+ "API",
627
+ "DATABASE_ENTITY",
628
+ "TEST",
629
+ "DOCUMENTATION",
630
+ "INCIDENT",
631
+ "INFRASTRUCTURE",
632
+ "DEPLOYMENT",
633
+ "MONITORING",
634
+ "MAINTENANCE",
635
+ "SYSTEM_VERSION",
636
+ "VERSION"
637
+ ],
638
+ "multiplicity": {
639
+ "from": "many",
640
+ "to": "many"
641
+ },
642
+ "validation": {
643
+ "severity": "warn"
644
+ },
645
+ "strength": "MEDIUM"
646
+ },
647
+ {
648
+ "type": "REPLACES",
649
+ "description": "Evoluci\xF3n e hist\xF3rico, deprecando versiones anteriores.",
650
+ "category": "EVOLUTIONARY",
651
+ "allowedFrom": [
652
+ "COMPONENT",
653
+ "API",
654
+ "SYSTEM_VERSION",
655
+ "VERSION",
656
+ "REQUIREMENT",
657
+ "FEATURE",
658
+ "DESIGN",
659
+ "DECISION"
660
+ ],
661
+ "allowedTo": [
662
+ "COMPONENT",
663
+ "API",
664
+ "SYSTEM_VERSION",
665
+ "VERSION",
666
+ "REQUIREMENT",
667
+ "FEATURE",
668
+ "DESIGN",
669
+ "DECISION"
670
+ ],
671
+ "multiplicity": {
672
+ "from": "many",
673
+ "to": "one"
674
+ },
675
+ "validation": {
676
+ "severity": "info"
677
+ },
678
+ "strength": "WEAK"
679
+ },
680
+ {
681
+ "type": "TESTS",
682
+ "description": "Conecta tests con comportamiento validado.",
683
+ "category": "TRACEABILITY",
684
+ "allowedFrom": [
685
+ "TEST_CASE",
686
+ "TEST"
687
+ ],
688
+ "allowedTo": [
689
+ "REQUIREMENT",
690
+ "FEATURE",
691
+ "EPIC",
692
+ "CODE_ENTITY",
693
+ "COMPONENT",
694
+ "API",
695
+ "DATABASE_ENTITY",
696
+ "BUG",
697
+ "INCIDENT"
698
+ ],
699
+ "multiplicity": {
700
+ "from": "many",
701
+ "to": "many"
702
+ },
703
+ "validation": {
704
+ "severity": "error"
705
+ },
706
+ "strength": "STRONG"
707
+ },
708
+ {
709
+ "type": "USES",
710
+ "description": "Llamada funcional, invocaci\xF3n o flujo en tiempo de ejecuci\xF3n.",
711
+ "category": "OPERATIONAL",
712
+ "allowedFrom": [
713
+ "CODE_ENTITY",
714
+ "COMPONENT",
715
+ "API",
716
+ "FEATURE",
717
+ "USE_CASE"
718
+ ],
719
+ "allowedTo": [
720
+ "CODE_ENTITY",
721
+ "COMPONENT",
722
+ "API",
723
+ "SYSTEM_VERSION"
724
+ ],
725
+ "multiplicity": {
726
+ "from": "many",
727
+ "to": "many"
728
+ },
729
+ "validation": {
730
+ "severity": "warn"
731
+ },
732
+ "strength": "MEDIUM"
733
+ },
734
+ {
735
+ "type": "VALIDATES",
736
+ "description": "Validaci\xF3n emp\xEDrica/humana (QA Manual).",
737
+ "category": "TRACEABILITY",
738
+ "allowedFrom": [
739
+ "PROCESS",
740
+ "CHECK",
741
+ "DOCUMENTATION"
742
+ ],
743
+ "allowedTo": [
744
+ "REQUIREMENT",
745
+ "FEATURE",
746
+ "USE_CASE",
747
+ "DEPLOYMENT"
748
+ ],
749
+ "multiplicity": {
750
+ "from": "many",
751
+ "to": "many"
752
+ },
753
+ "validation": {
754
+ "severity": "info"
755
+ },
756
+ "strength": "WEAK"
757
+ }
758
+ ];
759
+
760
+ // src/core/registry/RelationRegistry.ts
761
+ var RelationRegistry = class {
762
+ static {
763
+ this.relationsMap = new Map(
764
+ GENERATED_RELATIONS.map((rel) => [rel.type, rel])
765
+ );
766
+ }
767
+ static getValidTypes() {
768
+ return Array.from(this.relationsMap.keys());
769
+ }
770
+ static getContract(type) {
771
+ return this.relationsMap.get(type);
772
+ }
773
+ static isValid(type) {
774
+ return this.relationsMap.has(type);
775
+ }
776
+ static getRelationsByCategory(category) {
777
+ return GENERATED_RELATIONS.filter((rel) => rel.category === category);
778
+ }
779
+ static getAllContracts() {
780
+ return GENERATED_RELATIONS;
781
+ }
782
+ };
783
+
784
+ // scripts/core/parser.ts
785
+ import yaml from "js-yaml";
786
+ function parseOpenLagDocs(docsDir) {
787
+ const diag = new DiagnosticEngine();
788
+ const state = {
789
+ versions: [],
790
+ systemVersions: [],
791
+ changes: [],
792
+ artifacts: [],
793
+ relations: [],
794
+ errors: []
795
+ };
796
+ const documents = scanDocs(docsDir);
797
+ for (const doc of documents) {
798
+ const { content, file: fullPath } = doc;
799
+ const sections = content.split(/---+\r?\n/);
800
+ let i = 0;
801
+ if (content.trim().startsWith("---")) i = 1;
802
+ for (; i < sections.length; i += 1) {
803
+ const section = sections[i].trim();
804
+ if (section.length < 5) continue;
805
+ let parsed;
806
+ try {
807
+ const yamlCandidate = sections[i].split("\n").map((l) => l.replace(/^##\s?/, "")).join("\n").replace(/---$/, "").trim();
808
+ parsed = yaml.load(yamlCandidate);
809
+ } catch (e) {
810
+ throw new Error(`CRITICAL: Invalid YAML block in ${fullPath}: ${e.message}`, { cause: e });
811
+ }
812
+ if (parsed && typeof parsed === "object" && (parsed.id || parsed.ID) && (parsed.type || parsed.Type)) {
813
+ const body = i + 1 < sections.length ? sections[i + 1].trim() : "";
814
+ if (i + 1 < sections.length) i++;
815
+ const normalized = normalizeArtifact(parsed, fullPath, body);
816
+ try {
817
+ ArtifactSchema.parse(normalized);
818
+ const artifact = normalized;
819
+ state.artifacts.push(artifact);
820
+ const typeValue = artifact.type;
821
+ if (typeValue === "VERSION") {
822
+ state.versions.push({
823
+ id: artifact.id,
824
+ name: String(parsed.name || ""),
825
+ timestamp: String(parsed.timestamp || ""),
826
+ parentVersion: parsed.parentVersion || null
827
+ });
828
+ } else if (typeValue === "SYSTEM_VERSION") {
829
+ state.systemVersions.push({
830
+ id: artifact.id,
831
+ component: String(parsed.component || ""),
832
+ version: String(parsed.version || ""),
833
+ releaseDate: String(parsed.releaseDate || "")
834
+ });
835
+ } else if (typeValue === "CHANGE") {
836
+ state.changes.push({
837
+ id: artifact.id,
838
+ type: parsed.changeType || "FEATURE",
839
+ title: artifact.title,
840
+ description: artifact.description,
841
+ affects: Array.isArray(parsed.affects) ? parsed.affects : [],
842
+ versionFrom: String(parsed.versionFrom || ""),
843
+ versionTo: String(parsed.versionTo || "")
844
+ });
845
+ }
846
+ const rels = parsed.relations || parsed.Relations;
847
+ if (rels) {
848
+ const relArray = Array.isArray(rels) ? rels : [rels];
849
+ relArray.forEach((rel, idx) => {
850
+ const to = typeof rel === "string" ? rel : rel.to || rel.id || rel.ID;
851
+ if (to) {
852
+ const relType = rel.type;
853
+ if (!relType) {
854
+ diag.add(fullPath, `Relation targeting ${to} missing 'type' in artifact ${artifact.id}`, "WARNING" /* WARNING */);
855
+ return;
856
+ }
857
+ const contract = RelationRegistry.getContract(relType);
858
+ state.relations.push({
859
+ id: `rel-${artifact.id}-${idx}`,
860
+ from: artifact.id,
861
+ to: String(to),
862
+ type: relType,
863
+ category: contract?.category,
864
+ strength: contract?.strength,
865
+ file: fullPath
866
+ });
867
+ }
868
+ });
869
+ }
870
+ } catch (e) {
871
+ diag.add(fullPath, `Schema validation error: ${e.message}`, "INVALID" /* INVALID */);
872
+ }
873
+ } else if (parsed && typeof parsed === "object") {
874
+ if (!(parsed.id || parsed.ID)) {
875
+ diag.add(fullPath, `Missing ID in artifact`, "INVALID" /* INVALID */);
876
+ } else if (!(parsed.type || parsed.Type)) {
877
+ diag.add(fullPath, `Missing Type in artifact`, "INVALID" /* INVALID */);
878
+ }
879
+ }
880
+ }
881
+ }
882
+ state.errors = diag.getErrors();
883
+ return state;
884
+ }
885
+
886
+ // scripts/cli/generate.ts
887
+ import chokidar from "chokidar";
888
+ import chalk from "chalk";
889
+ function isDescendant(currentVersionId, artifactVersionId, versions) {
890
+ const artifactVersion = versions.find((v) => v.id === artifactVersionId);
891
+ if (!artifactVersion) return false;
892
+ let temp = versions.find((v) => v.id === currentVersionId);
893
+ let depth = 0;
894
+ while (temp && temp.parentVersion) {
895
+ depth++;
896
+ if (depth > 50) return false;
897
+ if (temp.parentVersion === artifactVersionId) return true;
898
+ temp = versions.find((v) => v.id === temp.parentVersion);
899
+ }
900
+ return false;
901
+ }
902
+ function generateData(docsDir, outputDir, silent = false) {
903
+ if (!silent) console.log(chalk.blue("\u{1F680} Generating OpenLAG Static Data..."));
904
+ const parsedData = parseOpenLagDocs(docsDir);
905
+ const state = {
906
+ versions: parsedData.versions,
907
+ systemVersions: parsedData.systemVersions,
908
+ graphs: {},
909
+ changes: parsedData.changes
910
+ };
911
+ const allArtifacts = parsedData.artifacts;
912
+ const allRelations = parsedData.relations;
913
+ state.versions.forEach((v) => {
914
+ state.graphs[v.id] = {
915
+ artifacts: allArtifacts.filter((a) => a.type === "SYSTEM_VERSION" || a.type === "VERSION" || a.version === v.id || isDescendant(v.id, a.version, state.versions)),
916
+ relations: allRelations.filter((r) => {
917
+ const fromArt = allArtifacts.find((a) => a.id === r.from);
918
+ return fromArt && (fromArt.type === "SYSTEM_VERSION" || fromArt.type === "VERSION" || fromArt.version === v.id || isDescendant(v.id, fromArt.version, state.versions));
919
+ })
920
+ };
921
+ });
922
+ if (!fs2.existsSync(outputDir)) fs2.mkdirSync(outputDir, { recursive: true });
923
+ fs2.writeFileSync(
924
+ path2.join(outputDir, "graph-data.json"),
925
+ JSON.stringify(state, null, 2)
926
+ );
927
+ if (!silent) console.log(chalk.green("\u2705 Data generated at"), chalk.cyan(path2.join(outputDir, "graph-data.json")));
928
+ }
929
+ function watchData(docsDir, outputDir) {
930
+ console.log(chalk.yellow("\u{1F440} Watching for changes in"), chalk.cyan(docsDir));
931
+ const watcher = chokidar.watch(docsDir, {
932
+ ignoreInitial: true,
933
+ persistent: true
934
+ });
935
+ const runCleanly = () => {
936
+ try {
937
+ generateData(docsDir, outputDir, true);
938
+ console.log(chalk.dim(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] `) + chalk.green("Regenerated graph-data.json"));
939
+ } catch (e) {
940
+ console.error(chalk.red("\u274C Error during regeneration:"), e);
941
+ }
942
+ };
943
+ let timeout;
944
+ const debouncedRun = () => {
945
+ clearTimeout(timeout);
946
+ timeout = setTimeout(runCleanly, 300);
947
+ };
948
+ watcher.on("all", (event, path9) => {
949
+ debouncedRun();
950
+ });
951
+ }
952
+
953
+ // scripts/cli/vite-bin.ts
954
+ import path3 from "path";
955
+ import { createRequire } from "module";
956
+ function resolveViteBin(importMetaUrl) {
957
+ const require2 = createRequire(importMetaUrl);
958
+ const viteEntry = require2.resolve("vite");
959
+ return path3.resolve(path3.dirname(viteEntry), "../../bin/vite.js");
960
+ }
961
+
962
+ // scripts/cli/build.ts
963
+ function buildPortal() {
964
+ const packageRoot2 = path4.resolve(path4.dirname(fileURLToPath(import.meta.url)), "../..");
965
+ const viteBin = resolveViteBin(import.meta.url);
966
+ const viteConfig = path4.join(packageRoot2, "vite.config.ts");
967
+ const docsDir = path4.join(process.cwd(), "docs");
968
+ const outputDir = path4.join(process.cwd(), "public");
969
+ generateData(docsDir, outputDir);
970
+ console.log(chalk2.blue("Building OpenLAG portal..."));
971
+ try {
972
+ execFileSync(process.execPath, [viteBin, "build", "--config", viteConfig], {
973
+ cwd: packageRoot2,
974
+ env: {
975
+ ...process.env,
976
+ OPENLAG_PROJECT_ROOT: process.cwd()
977
+ },
978
+ stdio: "inherit"
979
+ });
980
+ console.log(chalk2.green("Portal build complete."));
981
+ } catch {
982
+ console.error(chalk2.red("Build failed."));
983
+ process.exit(1);
984
+ }
985
+ }
986
+
987
+ // scripts/cli/dev.ts
988
+ import { spawn } from "child_process";
989
+ import path5 from "path";
990
+ import { fileURLToPath as fileURLToPath2 } from "url";
991
+ import chalk3 from "chalk";
992
+ function runDevServer() {
993
+ const packageRoot2 = path5.resolve(path5.dirname(fileURLToPath2(import.meta.url)), "../..");
994
+ const viteBin = resolveViteBin(import.meta.url);
995
+ const viteConfig = path5.join(packageRoot2, "vite.config.ts");
996
+ const projectRoot = process.cwd();
997
+ const docsDir = path5.join(projectRoot, "docs");
998
+ const outputDir = path5.join(projectRoot, "public");
999
+ generateData(docsDir, outputDir);
1000
+ watchData(docsDir, outputDir);
1001
+ console.log(chalk3.blue("Starting OpenLAG portal dev server..."));
1002
+ const vite = spawn(process.execPath, [viteBin, "--config", viteConfig], {
1003
+ cwd: packageRoot2,
1004
+ env: {
1005
+ ...process.env,
1006
+ OPENLAG_PROJECT_ROOT: projectRoot
1007
+ },
1008
+ stdio: "inherit"
1009
+ });
1010
+ vite.on("close", (code) => {
1011
+ process.exit(code || 0);
1012
+ });
1013
+ }
1014
+
1015
+ // scripts/cli/init.ts
1016
+ import fs3 from "fs";
1017
+ import path6 from "path";
1018
+ import chalk4 from "chalk";
1019
+ async function initProject(projectName, projectDesc, includeAllRelations) {
1020
+ const name = projectName || process.env.PROJECT_NAME || "My OpenLAG Project";
1021
+ const desc = projectDesc || process.env.PROJECT_DESCRIPTION || "Living Architecture documentation for my system.";
1022
+ const ROOT_DIR = process.cwd();
1023
+ console.log(chalk4.blue(`\u{1F6E0}\uFE0F Initializing OpenLAG for: `) + chalk4.bold(name));
1024
+ const metadataPath = path6.join(ROOT_DIR, "metadata.json");
1025
+ if (fs3.existsSync(metadataPath)) {
1026
+ const metadata = JSON.parse(fs3.readFileSync(metadataPath, "utf-8"));
1027
+ metadata.name = name;
1028
+ metadata.description = desc;
1029
+ fs3.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
1030
+ console.log(chalk4.green("\u2705 Updated metadata.json"));
1031
+ }
1032
+ const htmlPath = path6.join(ROOT_DIR, "index.html");
1033
+ if (fs3.existsSync(htmlPath)) {
1034
+ let html = fs3.readFileSync(htmlPath, "utf-8");
1035
+ html = html.replace(/<title>.*?<\/title>/, `<title>${name} | OpenLAG</title>`);
1036
+ fs3.writeFileSync(htmlPath, html);
1037
+ console.log(chalk4.green("\u2705 Updated index.html title"));
1038
+ }
1039
+ const docsDir = path6.join(ROOT_DIR, "docs");
1040
+ if (!fs3.existsSync(docsDir)) {
1041
+ fs3.mkdirSync(docsDir);
1042
+ console.log(chalk4.green("\u2705 Created /docs directory"));
1043
+ }
1044
+ const relationsDir = path6.join(docsDir, "relations");
1045
+ if (!fs3.existsSync(relationsDir)) {
1046
+ fs3.mkdirSync(relationsDir);
1047
+ console.log(chalk4.green("\u2705 Created /docs/relations directory"));
1048
+ } else {
1049
+ const files = fs3.readdirSync(relationsDir);
1050
+ for (const file of files) {
1051
+ if (file.endsWith(".yaml")) {
1052
+ fs3.unlinkSync(path6.join(relationsDir, file));
1053
+ }
1054
+ }
1055
+ }
1056
+ const mandatoryRelations = [
1057
+ {
1058
+ name: "IMPLEMENTS.yaml",
1059
+ content: `relation: IMPLEMENTS
1060
+ description: "Conecta implementaci\xF3n con necesidad funcional/t\xE9cnica."
1061
+ category: TRACEABILITY
1062
+ allowedFrom: [CODE_ENTITY, COMPONENT, API, DATABASE_ENTITY, SYSTEM_VERSION]
1063
+ allowedTo: [REQUIREMENT, FEATURE, EPIC, DESIGN, USE_CASE, BUSINESS_RULE]
1064
+ multiplicity:
1065
+ from: many
1066
+ to: many
1067
+ validation:
1068
+ severity: error`
1069
+ },
1070
+ {
1071
+ name: "TESTS.yaml",
1072
+ content: `relation: TESTS
1073
+ description: "Conecta tests con comportamiento validado."
1074
+ category: TRACEABILITY
1075
+ allowedFrom: [TEST_CASE, TEST]
1076
+ allowedTo: [REQUIREMENT, FEATURE, EPIC, CODE_ENTITY, COMPONENT, API, DATABASE_ENTITY, BUG, INCIDENT]
1077
+ multiplicity:
1078
+ from: many
1079
+ to: many
1080
+ validation:
1081
+ severity: error`
1082
+ },
1083
+ {
1084
+ name: "REFINES.yaml",
1085
+ content: `relation: REFINES
1086
+ description: "Descompone artefactos en otros m\xE1s concretos."
1087
+ category: TRACEABILITY
1088
+ allowedFrom: [FEATURE, REQUIREMENT, BUG, RISK, DESIGN]
1089
+ allowedTo: [EPIC, FEATURE, PROJECT, BUSINESS_RULE, REQUIREMENT, DESIGN]
1090
+ multiplicity:
1091
+ from: many
1092
+ to: many
1093
+ validation:
1094
+ severity: warn`
1095
+ },
1096
+ {
1097
+ name: "FIXES.yaml",
1098
+ content: `relation: FIXES
1099
+ description: "Conecta correcciones con bugs o incidentes."
1100
+ category: TRACEABILITY
1101
+ allowedFrom: [CHANGE, CODE_ENTITY, COMPONENT, SYSTEM_VERSION]
1102
+ allowedTo: [BUG, INCIDENT, RISK]
1103
+ multiplicity:
1104
+ from: many
1105
+ to: many
1106
+ validation:
1107
+ severity: error`
1108
+ },
1109
+ {
1110
+ name: "DOCUMENTS.yaml",
1111
+ content: `relation: DOCUMENTS
1112
+ description: "Conecta documentaci\xF3n con el artefacto descrito."
1113
+ category: SEMANTIC
1114
+ allowedFrom: [DOCUMENTATION, GLOSSARY_TERM]
1115
+ 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]
1116
+ multiplicity:
1117
+ from: many
1118
+ to: many
1119
+ validation:
1120
+ severity: info`
1121
+ },
1122
+ {
1123
+ name: "JUSTIFIES.yaml",
1124
+ content: `relation: JUSTIFIES
1125
+ description: "Conecta decisiones con aquello que justifican."
1126
+ category: SEMANTIC
1127
+ allowedFrom: [DECISION, BUSINESS_RULE, DOCUMENTATION, RISK]
1128
+ allowedTo: [DESIGN, REQUIREMENT, FEATURE, EPIC, PROJECT, CODE_ENTITY, COMPONENT, INFRASTRUCTURE, DEPLOYMENT, MAINTENANCE]
1129
+ multiplicity:
1130
+ from: many
1131
+ to: many
1132
+ validation:
1133
+ severity: warn`
1134
+ }
1135
+ ];
1136
+ mandatoryRelations.forEach((rel) => {
1137
+ fs3.writeFileSync(path6.join(relationsDir, rel.name), rel.content);
1138
+ });
1139
+ console.log(chalk4.green("\u2705 Created Mandatory Core Relations (IMPLEMENTS, TESTS, REFINES, FIXES, DOCUMENTS, JUSTIFIES)"));
1140
+ if (includeAllRelations) {
1141
+ const optionalRelations = [
1142
+ {
1143
+ name: "DEPENDS_ON.yaml",
1144
+ content: `relation: DEPENDS_ON
1145
+ description: "Acoplamiento est\xE1tico arquitect\xF3nico o de empaquetado."
1146
+ category: STRUCTURAL
1147
+ allowedFrom: [CODE_ENTITY, COMPONENT, API, DATABASE_ENTITY, LIBRARY, VERSION, SYSTEM_VERSION]
1148
+ allowedTo: [CODE_ENTITY, COMPONENT, API, DATABASE_ENTITY, LIBRARY, VERSION, SYSTEM_VERSION]
1149
+ multiplicity:
1150
+ from: many
1151
+ to: many
1152
+ validation:
1153
+ severity: warn`
1154
+ },
1155
+ {
1156
+ name: "USES.yaml",
1157
+ content: `relation: USES
1158
+ description: "Llamada funcional, invocaci\xF3n o flujo en tiempo de ejecuci\xF3n."
1159
+ category: OPERATIONAL
1160
+ allowedFrom: [CODE_ENTITY, COMPONENT, API, FEATURE, USE_CASE]
1161
+ allowedTo: [CODE_ENTITY, COMPONENT, API, SYSTEM_VERSION]
1162
+ multiplicity:
1163
+ from: many
1164
+ to: many
1165
+ validation:
1166
+ severity: warn`
1167
+ },
1168
+ {
1169
+ name: "DEPLOYS.yaml",
1170
+ content: `relation: DEPLOYS
1171
+ description: "Instanciaci\xF3n de componentes o release en infraestructura."
1172
+ category: OPERATIONAL
1173
+ allowedFrom: [DEPLOYMENT, PIPELINE, SYSTEM_VERSION]
1174
+ allowedTo: [COMPONENT, INFRASTRUCTURE, ENVIRONMENT, DATABASE_ENTITY]
1175
+ multiplicity:
1176
+ from: many
1177
+ to: many
1178
+ validation:
1179
+ severity: error`
1180
+ },
1181
+ {
1182
+ name: "MONITORS.yaml",
1183
+ content: `relation: MONITORS
1184
+ description: "Relaci\xF3n de observabilidad."
1185
+ category: OPERATIONAL
1186
+ allowedFrom: [MONITORING, CHECK]
1187
+ allowedTo: [COMPONENT, INFRASTRUCTURE, DEPLOYMENT, DATABASE_ENTITY, API]
1188
+ multiplicity:
1189
+ from: many
1190
+ to: many
1191
+ validation:
1192
+ severity: info`
1193
+ },
1194
+ {
1195
+ name: "IMPACTS.yaml",
1196
+ content: `relation: IMPACTS
1197
+ description: "Descripci\xF3n de posibles efectos colaterales."
1198
+ category: SEMANTIC
1199
+ allowedFrom: [CHANGE, RISK, BUG, INCIDENT, DECISION]
1200
+ allowedTo: [PROJECT, EPIC, FEATURE, REQUIREMENT, DESIGN, CODE_ENTITY, COMPONENT, API, DATABASE_ENTITY, SYSTEM_VERSION]
1201
+ multiplicity:
1202
+ from: many
1203
+ to: many
1204
+ validation:
1205
+ severity: warn`
1206
+ },
1207
+ {
1208
+ name: "BLOCKS.yaml",
1209
+ content: `relation: BLOCKS
1210
+ description: "Descripci\xF3n de impedimentos directos."
1211
+ category: DEPENDENCY
1212
+ allowedFrom: [BUG, RISK, INCIDENT, CHANGE, DECISION, REQUIREMENT, FEATURE, EPIC]
1213
+ allowedTo: [PROJECT, EPIC, FEATURE, REQUIREMENT, BUG, CHANGE, DEPLOYMENT, DEPLOYMENT]
1214
+ multiplicity:
1215
+ from: many
1216
+ to: many
1217
+ validation:
1218
+ severity: error`
1219
+ },
1220
+ {
1221
+ name: "BREAKS.yaml",
1222
+ content: `relation: BREAKS
1223
+ description: "Aver\xEDas o rupturas confirmadas."
1224
+ category: OPERATIONAL
1225
+ allowedFrom: [CHANGE, CODE_ENTITY, COMPONENT, SYSTEM_VERSION]
1226
+ allowedTo: [TEST_CASE, TEST, API, COMPONENT, REQUIREMENT, FEATURE]
1227
+ multiplicity:
1228
+ from: many
1229
+ to: many
1230
+ validation:
1231
+ severity: error`
1232
+ },
1233
+ {
1234
+ name: "REPLACES.yaml",
1235
+ content: `relation: REPLACES
1236
+ description: "Evoluci\xF3n e hist\xF3rico, deprecando versiones anteriores."
1237
+ category: EVOLUTIONARY
1238
+ allowedFrom: [COMPONENT, API, SYSTEM_VERSION, VERSION, REQUIREMENT, FEATURE, DESIGN, DECISION]
1239
+ allowedTo: [COMPONENT, API, SYSTEM_VERSION, VERSION, REQUIREMENT, FEATURE, DESIGN, DECISION]
1240
+ multiplicity:
1241
+ from: many
1242
+ to: one
1243
+ validation:
1244
+ severity: info`
1245
+ },
1246
+ {
1247
+ name: "DERIVES_FROM.yaml",
1248
+ content: `relation: DERIVES_FROM
1249
+ description: "Evoluci\xF3n conceptual gen\xE9rica."
1250
+ category: SEMANTIC
1251
+ allowedFrom: [REQUIREMENT, FEATURE, DESIGN, BUSINESS_RULE, DECISION, USE_CASE]
1252
+ allowedTo: [REQUIREMENT, FEATURE, DESIGN, BUSINESS_RULE, DECISION, USE_CASE]
1253
+ multiplicity:
1254
+ from: many
1255
+ to: many
1256
+ validation:
1257
+ severity: info`
1258
+ },
1259
+ {
1260
+ name: "VALIDATES.yaml",
1261
+ content: `relation: VALIDATES
1262
+ description: "Validaci\xF3n emp\xEDrica/humana (QA Manual)."
1263
+ category: TRACEABILITY
1264
+ allowedFrom: [PROCESS, CHECK, DOCUMENTATION]
1265
+ allowedTo: [REQUIREMENT, FEATURE, USE_CASE, DEPLOYMENT]
1266
+ multiplicity:
1267
+ from: many
1268
+ to: many
1269
+ validation:
1270
+ severity: info`
1271
+ },
1272
+ {
1273
+ name: "DEFINES.yaml",
1274
+ content: `relation: DEFINES
1275
+ description: "Entidades que instauran glosarios o normas."
1276
+ category: SEMANTIC
1277
+ allowedFrom: [BUSINESS_RULE, DECISION, DOCUMENTATION, GLOSSARY_TERM]
1278
+ allowedTo: [REQUIREMENT, FEATURE, DESIGN, PROJECT, COMPONENT, API, DATABASE_ENTITY]
1279
+ multiplicity:
1280
+ from: many
1281
+ to: many
1282
+ validation:
1283
+ severity: info`
1284
+ },
1285
+ {
1286
+ name: "CALLS.yaml",
1287
+ content: `relation: CALLS
1288
+ description: "Trazabilidad de invocaci\xF3n a nivel c\xF3digo."
1289
+ category: STRUCTURAL
1290
+ allowedFrom: [CODE_ENTITY]
1291
+ allowedTo: [CODE_ENTITY, API]
1292
+ multiplicity:
1293
+ from: many
1294
+ to: many
1295
+ validation:
1296
+ severity: warn`
1297
+ },
1298
+ {
1299
+ name: "IMPORTS.yaml",
1300
+ content: `relation: IMPORTS
1301
+ description: "Trazabilidad de importaci\xF3n est\xE1tica a nivel de c\xF3digo."
1302
+ category: STRUCTURAL
1303
+ allowedFrom: [CODE_ENTITY]
1304
+ allowedTo: [CODE_ENTITY, LIBRARY]
1305
+ multiplicity:
1306
+ from: many
1307
+ to: many
1308
+ validation:
1309
+ severity: warn`
1310
+ },
1311
+ {
1312
+ name: "RELATES_TO.yaml",
1313
+ content: `relation: RELATES_TO
1314
+ description: |
1315
+ Uso gen\xE9rico propenso a poluci\xF3n sem\xE1ntica. (DISCOURAGED)
1316
+ Para mantener un grafo limpio, solo \xFAsala aportando rationale expl\xEDcito:
1317
+
1318
+ relations:
1319
+ - to: mi-otro-artefacto
1320
+ type: RELATES_TO
1321
+ rationale: "No encaja con USES o DEPENDS_ON debido al contexto X."
1322
+ category: SEMANTIC
1323
+ 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]
1324
+ 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]
1325
+ multiplicity:
1326
+ from: many
1327
+ to: many
1328
+ validation:
1329
+ severity: warn`
1330
+ }
1331
+ ];
1332
+ optionalRelations.forEach((rel) => {
1333
+ fs3.writeFileSync(path6.join(relationsDir, rel.name), rel.content);
1334
+ });
1335
+ console.log(chalk4.green("\u2705 Created Official Optional Relations"));
1336
+ }
1337
+ const versionsDir = path6.join(docsDir, "versions");
1338
+ if (!fs3.existsSync(versionsDir)) {
1339
+ fs3.mkdirSync(versionsDir);
1340
+ console.log(chalk4.green("\u2705 Created /docs/versions directory"));
1341
+ }
1342
+ const versionPath = path6.join(versionsDir, "v-1.0.0.md");
1343
+ if (!fs3.existsSync(versionPath)) {
1344
+ const versionsContent = `---
1345
+ id: v-1.0.0
1346
+ type: VERSION
1347
+ name: "Baseline"
1348
+ timestamp: "${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}"
1349
+ parentVersion: null
1350
+ layer: DOCUMENTATION
1351
+ title: "Project Release v1.0.0"
1352
+ description: "Initial release"
1353
+ ownership:
1354
+ owner: architecture
1355
+ team: architecture
1356
+ relations: []
1357
+ ---
1358
+ `;
1359
+ fs3.writeFileSync(versionPath, versionsContent);
1360
+ console.log(chalk4.green("\u2705 Created initial docs/versions/v-1.0.0.md"));
1361
+ }
1362
+ const componentsVersionsPath = path6.join(versionsDir, "sys-core-1.0.md");
1363
+ if (!fs3.existsSync(componentsVersionsPath)) {
1364
+ const cvContent = `---
1365
+ id: sys-core-1.0
1366
+ type: SYSTEM_VERSION
1367
+ component: "Core System"
1368
+ version: "1.0.0"
1369
+ releaseDate: "${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}"
1370
+ layer: OPERATIONS
1371
+ title: "Core System v1.0"
1372
+ description: "Base framework."
1373
+ ownership:
1374
+ owner: architecture
1375
+ team: architecture
1376
+ relations: []
1377
+ ---
1378
+ `;
1379
+ fs3.writeFileSync(componentsVersionsPath, cvContent);
1380
+ console.log(chalk4.green("\u2705 Created initial docs/versions/sys-core-1.0.md"));
1381
+ }
1382
+ const architectureDir = path6.join(docsDir, "architecture");
1383
+ if (!fs3.existsSync(architectureDir)) {
1384
+ fs3.mkdirSync(architectureDir);
1385
+ console.log(chalk4.green("\u2705 Created /docs/architecture directory"));
1386
+ }
1387
+ const sampleDocPath = path6.join(architectureDir, "architecture-overview.md");
1388
+ if (!fs3.existsSync(sampleDocPath)) {
1389
+ const sampleContent = `---
1390
+ id: arch-overview
1391
+ type: DOCUMENT
1392
+ status: draft
1393
+ title: "Architecture Overview"
1394
+ description: "High-level description of the system architecture."
1395
+ ---
1396
+
1397
+ # Architecture Overview
1398
+
1399
+ This document describes the high-level architecture of ${name}.
1400
+
1401
+ ## Key Principles
1402
+ - Traceability first.
1403
+ - Documentation as Code.
1404
+ - Graph-based relationships.
1405
+ `;
1406
+ fs3.writeFileSync(sampleDocPath, sampleContent);
1407
+ console.log(chalk4.green("\u2705 Created initial docs/architecture/architecture-overview.md"));
1408
+ }
1409
+ console.log("\n" + chalk4.cyan("\u{1F680} Project initialized successfully!"));
1410
+ console.log("Next steps:");
1411
+ console.log("1. Edit " + chalk4.cyan("docs/") + " to reflect your architecture.");
1412
+ console.log("2. Run " + chalk4.cyan("openlag dev") + " to see your portal.");
1413
+ }
1414
+
1415
+ // scripts/cli/lint.ts
1416
+ import path7 from "path";
1417
+
1418
+ // scripts/lint/lint-engine.ts
1419
+ import fs4 from "fs";
1420
+ import yaml2 from "js-yaml";
1421
+ import chalk5 from "chalk";
1422
+
1423
+ // src/core/registry/ArtifactRegistry.ts
1424
+ var CORE_ARTIFACT_TYPES = [
1425
+ "PROJECT",
1426
+ "EPIC",
1427
+ "FEATURE",
1428
+ "REQUIREMENT",
1429
+ "BUSINESS_RULE",
1430
+ "USE_CASE",
1431
+ "DESIGN",
1432
+ "DECISION",
1433
+ "CODE_ENTITY",
1434
+ "TEST_CASE",
1435
+ "CHANGE",
1436
+ "BUG",
1437
+ "RISK",
1438
+ "GLOSSARY_TERM",
1439
+ "COMPONENT",
1440
+ "API",
1441
+ "DATABASE_ENTITY",
1442
+ "TEST",
1443
+ "DOCUMENTATION",
1444
+ "INCIDENT",
1445
+ "INFRASTRUCTURE",
1446
+ "DEPLOYMENT",
1447
+ "MONITORING",
1448
+ "MAINTENANCE",
1449
+ "SYSTEM_VERSION",
1450
+ "VERSION",
1451
+ "LIBRARY",
1452
+ "ENVIRONMENT",
1453
+ "CHECK",
1454
+ "PROCESS",
1455
+ "PIPELINE"
1456
+ ];
1457
+ var ArtifactRegistry = class {
1458
+ static getValidTypes() {
1459
+ return CORE_ARTIFACT_TYPES;
1460
+ }
1461
+ static isValid(type) {
1462
+ return CORE_ARTIFACT_TYPES.includes(type);
1463
+ }
1464
+ };
1465
+
1466
+ // scripts/lint/lint-rules.ts
1467
+ function runLintRules(data, profile) {
1468
+ const issues = [];
1469
+ const getSeverity = (rule, artifactStatus) => {
1470
+ let severity = profile[rule];
1471
+ if (!severity || severity === "off") return "off";
1472
+ if (artifactStatus === "draft") {
1473
+ if (rule !== "brokenRelation" && rule !== "invalidYaml" && rule !== "duplicateId") {
1474
+ severity = "info";
1475
+ }
1476
+ } else if (artifactStatus === "in_progress") {
1477
+ if (rule !== "brokenRelation" && rule !== "invalidYaml" && rule !== "duplicateId") {
1478
+ if (severity === "error") severity = "warning";
1479
+ }
1480
+ }
1481
+ return severity;
1482
+ };
1483
+ const addIssue = (rule, message, file, artifactId, artifactStatus) => {
1484
+ const severity = getSeverity(rule, artifactStatus);
1485
+ if (severity && severity !== "off") {
1486
+ issues.push({ severity, rule, message, file, artifactId });
1487
+ }
1488
+ };
1489
+ for (const error of data.errors) {
1490
+ addIssue("invalidYaml", error.message, error.file);
1491
+ }
1492
+ const artifactMap = /* @__PURE__ */ new Map();
1493
+ for (const artifact of data.artifacts) {
1494
+ const list = artifactMap.get(artifact.id) || [];
1495
+ list.push(artifact);
1496
+ artifactMap.set(artifact.id, list);
1497
+ }
1498
+ for (const [id, artifacts] of artifactMap.entries()) {
1499
+ if (artifacts.length > 1) {
1500
+ addIssue("duplicateId", `${id} appears in ${artifacts.length} files`, artifacts[0].file, id);
1501
+ }
1502
+ }
1503
+ for (const artifact of data.artifacts) {
1504
+ if (!ArtifactRegistry.isValid(artifact.type)) {
1505
+ addIssue("invalidArtifactType", `Invalid artifact type: ${artifact.type}`, artifact.file, artifact.id, artifact.status);
1506
+ }
1507
+ if (!artifact.type || !artifact.title) {
1508
+ addIssue("missingRequiredFields", `Artifact missing type or title`, artifact.file, artifact.id, artifact.status);
1509
+ }
1510
+ }
1511
+ const targets = new Set(data.artifacts.map((a) => a.id));
1512
+ const implementationsByReq = /* @__PURE__ */ new Map();
1513
+ const testsByReq = /* @__PURE__ */ new Map();
1514
+ const reqsByCode = /* @__PURE__ */ new Map();
1515
+ const reqsByTest = /* @__PURE__ */ new Map();
1516
+ for (const relation of data.relations) {
1517
+ if (!RelationRegistry.isValid(relation.type)) {
1518
+ addIssue("invalidRelationType", `Invalid relation type: ${relation.type}`, relation.file, relation.from);
1519
+ }
1520
+ if (!targets.has(relation.to)) {
1521
+ addIssue("brokenRelation", `${relation.from} -> ${relation.to} target does not exist`, relation.file, relation.from);
1522
+ }
1523
+ if (relation.type === "IMPLEMENTS") {
1524
+ const list = implementationsByReq.get(relation.to) || [];
1525
+ list.push(relation);
1526
+ implementationsByReq.set(relation.to, list);
1527
+ const listCode = reqsByCode.get(relation.from) || [];
1528
+ listCode.push(relation);
1529
+ reqsByCode.set(relation.from, listCode);
1530
+ }
1531
+ if (relation.type === "TESTS" || relation.type === "VALIDATES") {
1532
+ const list = testsByReq.get(relation.to) || [];
1533
+ list.push(relation);
1534
+ testsByReq.set(relation.to, list);
1535
+ const listTest = reqsByTest.get(relation.from) || [];
1536
+ listTest.push(relation);
1537
+ reqsByTest.set(relation.from, listTest);
1538
+ }
1539
+ }
1540
+ for (const artifact of data.artifacts) {
1541
+ const isDraft = artifact.status === "draft";
1542
+ const isClosed = artifact.status === "closed";
1543
+ const isDeprecated = artifact.status === "deprecated";
1544
+ if (isDeprecated) continue;
1545
+ if (artifact.type === "REQUIREMENT") {
1546
+ const hasImplementation = implementationsByReq.has(artifact.id);
1547
+ const hasTest = testsByReq.has(artifact.id);
1548
+ if (!hasImplementation) {
1549
+ addIssue("requirementWithoutImplementation", `${artifact.id} lacks implementation`, artifact.file, artifact.id, artifact.status);
1550
+ }
1551
+ if (!hasTest) {
1552
+ addIssue("requirementWithoutTest", `${artifact.id} has no tests linked`, artifact.file, artifact.id, artifact.status);
1553
+ }
1554
+ }
1555
+ if (artifact.type === "CODE_ENTITY") {
1556
+ const hasReq = reqsByCode.has(artifact.id);
1557
+ if (!hasReq) {
1558
+ addIssue("codeWithoutRequirement", `${artifact.id} has no requirement associated`, artifact.file, artifact.id, artifact.status);
1559
+ }
1560
+ }
1561
+ if (artifact.type === "TEST") {
1562
+ const hasReq = reqsByTest.has(artifact.id);
1563
+ if (!hasReq) {
1564
+ addIssue("orphanArtifact", `${artifact.id} is a test without associated requirement`, artifact.file, artifact.id, artifact.status);
1565
+ }
1566
+ }
1567
+ if (isClosed) {
1568
+ const outgoing = data.relations.filter((r) => r.from === artifact.id);
1569
+ for (const rel of outgoing) {
1570
+ const targetArts = artifactMap.get(rel.to);
1571
+ if (targetArts && targetArts[0]) {
1572
+ const targetStatus = targetArts[0].status;
1573
+ if (targetStatus === "draft" || targetStatus === "in_progress") {
1574
+ if (rel.type !== "RELATES_TO" && rel.type !== "DOCUMENTS" && rel.type !== "JUSTIFIES") {
1575
+ addIssue("closedArtifactWithPendingRelations", `${artifact.id} is closed but links to ${targetStatus} artifact ${rel.to} via ${rel.type}`, artifact.file, artifact.id, artifact.status);
1576
+ }
1577
+ }
1578
+ }
1579
+ }
1580
+ if (!artifact.ownership || Object.keys(artifact.ownership).length === 0) {
1581
+ addIssue("missingOwnership", `${artifact.id} is closed but has no ownership defined`, artifact.file, artifact.id, artifact.status);
1582
+ }
1583
+ }
1584
+ if (artifact.type === "API" && (!artifact.ownership || Object.keys(artifact.ownership).length === 0)) {
1585
+ addIssue("missingOwnership", `API ${artifact.id} should have ownership defined`, artifact.file, artifact.id, artifact.status);
1586
+ }
1587
+ if (artifact.layer === "BUSINESS") {
1588
+ const outgoing = data.relations.filter((r) => r.from === artifact.id);
1589
+ for (const rel of outgoing) {
1590
+ const relSemantics = rel.category;
1591
+ if (relSemantics === "OPERATIONAL") {
1592
+ addIssue("invalidLayerRelation", `Business layer artifact ${artifact.id} should not have OPERATIONAL relations (${rel.type})`, artifact.file, artifact.id, artifact.status);
1593
+ }
1594
+ }
1595
+ }
1596
+ }
1597
+ return issues;
1598
+ }
1599
+
1600
+ // scripts/lint/lint-profiles.ts
1601
+ var defaultProfiles = {
1602
+ feature: {
1603
+ duplicateId: "error",
1604
+ invalidYaml: "error",
1605
+ brokenRelation: "error",
1606
+ missingRequiredFields: "warning",
1607
+ requirementWithoutImplementation: "info",
1608
+ requirementWithoutTest: "info",
1609
+ codeWithoutRequirement: "info",
1610
+ closedArtifactWithPendingRelations: "warning",
1611
+ orphanArtifact: "info",
1612
+ invalidRelationType: "error",
1613
+ invalidArtifactType: "error",
1614
+ invalidLayerRelation: "info",
1615
+ missingOwnership: "info"
1616
+ },
1617
+ develop: {
1618
+ duplicateId: "error",
1619
+ invalidYaml: "error",
1620
+ brokenRelation: "error",
1621
+ missingRequiredFields: "error",
1622
+ requirementWithoutImplementation: "warning",
1623
+ requirementWithoutTest: "warning",
1624
+ codeWithoutRequirement: "warning",
1625
+ closedArtifactWithPendingRelations: "warning",
1626
+ orphanArtifact: "warning",
1627
+ invalidRelationType: "error",
1628
+ invalidArtifactType: "error",
1629
+ invalidLayerRelation: "warning",
1630
+ missingOwnership: "warning"
1631
+ },
1632
+ release: {
1633
+ duplicateId: "error",
1634
+ invalidYaml: "error",
1635
+ brokenRelation: "error",
1636
+ missingRequiredFields: "error",
1637
+ requirementWithoutImplementation: "error",
1638
+ requirementWithoutTest: "error",
1639
+ codeWithoutRequirement: "error",
1640
+ closedArtifactWithPendingRelations: "error",
1641
+ orphanArtifact: "error",
1642
+ invalidRelationType: "error",
1643
+ invalidArtifactType: "error",
1644
+ invalidLayerRelation: "error",
1645
+ missingOwnership: "error"
1646
+ }
1647
+ };
1648
+
1649
+ // scripts/lint/lint-engine.ts
1650
+ function loadConfig(configPath) {
1651
+ const defaultConfig = {
1652
+ defaultProfile: "develop",
1653
+ failOnWarnings: false,
1654
+ profiles: {}
1655
+ };
1656
+ if (fs4.existsSync(configPath)) {
1657
+ try {
1658
+ const fileContent = fs4.readFileSync(configPath, "utf8");
1659
+ const parsed = yaml2.load(fileContent);
1660
+ if (parsed && parsed.lint) {
1661
+ return {
1662
+ ...defaultConfig,
1663
+ ...parsed.lint
1664
+ };
1665
+ }
1666
+ } catch (e) {
1667
+ console.warn("\u26A0\uFE0F Could not parse openlag.config.yml, using defaults.");
1668
+ }
1669
+ }
1670
+ return defaultConfig;
1671
+ }
1672
+ function runLint(docsDir, configPath, profileName) {
1673
+ const config = loadConfig(configPath);
1674
+ const selectedProfileName = profileName || config.defaultProfile;
1675
+ const baseProfile = defaultProfiles[selectedProfileName] || defaultProfiles["develop"];
1676
+ const customProfileOverrides = config.profiles[selectedProfileName] || {};
1677
+ const activeProfile = { ...baseProfile, ...customProfileOverrides };
1678
+ const parsedData = parseOpenLagDocs(docsDir);
1679
+ const issues = runLintRules(parsedData, activeProfile);
1680
+ const summary = {
1681
+ errors: 0,
1682
+ warnings: 0,
1683
+ info: 0
1684
+ };
1685
+ for (const issue of issues) {
1686
+ if (issue.severity === "error") summary.errors++;
1687
+ if (issue.severity === "warning") summary.warnings++;
1688
+ if (issue.severity === "info") summary.info++;
1689
+ }
1690
+ return {
1691
+ profile: selectedProfileName,
1692
+ summary,
1693
+ issues
1694
+ };
1695
+ }
1696
+ function printHumanReport(report) {
1697
+ console.log(`
1698
+ ` + chalk5.bold(`OpenLAG Lint Report`));
1699
+ console.log(chalk5.dim(`Profile: ${report.profile}
1700
+ `));
1701
+ if (report.issues.length === 0) {
1702
+ console.log(chalk5.green(`\u2705 No issues found!
1703
+ `));
1704
+ } else {
1705
+ for (const issue of report.issues) {
1706
+ const sevColor = issue.severity === "error" ? chalk5.red : issue.severity === "warning" ? chalk5.yellow : chalk5.cyan;
1707
+ const severityLabel = issue.severity.toUpperCase().padEnd(7);
1708
+ const ruleLabel = issue.rule.padEnd(30);
1709
+ console.log(`${sevColor(severityLabel)} ${chalk5.dim(ruleLabel)} ${issue.message}`);
1710
+ }
1711
+ }
1712
+ console.log(`
1713
+ ` + chalk5.bold(`Summary:`));
1714
+ console.log(chalk5.red(`Errors: ${report.summary.errors}`));
1715
+ console.log(chalk5.yellow(`Warnings: ${report.summary.warnings}`));
1716
+ console.log(chalk5.cyan(`Info: ${report.summary.info}
1717
+ `));
1718
+ }
1719
+
1720
+ // scripts/cli/lint.ts
1721
+ function lintDocs(profile, jsonOutput = false, strictWarnings = false) {
1722
+ const docsDir = path7.join(process.cwd(), "docs");
1723
+ const configPath = path7.join(process.cwd(), "openlag.config.yml");
1724
+ const config = loadConfig(configPath);
1725
+ const report = runLint(docsDir, configPath, profile);
1726
+ if (jsonOutput) {
1727
+ console.log(JSON.stringify(report, null, 2));
1728
+ } else {
1729
+ printHumanReport(report);
1730
+ }
1731
+ const failOnWarnings = strictWarnings || config.failOnWarnings;
1732
+ let hasErrors = report.summary.errors > 0;
1733
+ if (failOnWarnings && report.summary.warnings > 0) {
1734
+ hasErrors = true;
1735
+ }
1736
+ if (hasErrors) {
1737
+ process.exit(1);
1738
+ }
1739
+ }
1740
+
1741
+ // scripts/cli/openlag.ts
1742
+ var program = new Command();
1743
+ var packageRoot = path8.resolve(path8.dirname(fileURLToPath3(import.meta.url)), "../..");
1744
+ function runVitePreview() {
1745
+ const viteBin = resolveViteBin(import.meta.url);
1746
+ execFileSync2(process.execPath, [viteBin, "preview", "--outDir", path8.join(process.cwd(), "dist")], {
1747
+ cwd: packageRoot,
1748
+ env: {
1749
+ ...process.env,
1750
+ OPENLAG_PROJECT_ROOT: process.cwd()
1751
+ },
1752
+ stdio: "inherit"
1753
+ });
1754
+ }
1755
+ program.name("openlag").description("Architecture as Code traceability graph generator").version("0.1.0");
1756
+ program.command("init").description("Initialize a new OpenLAG project").option("-n, --name <name>", "Project name").option("-d, --desc <description>", "Project description").option("--all", "Include optional synthetic relations").action((options) => {
1757
+ initProject(options.name, options.desc, options.all);
1758
+ });
1759
+ program.command("generate").description("Generate static graph data from markdown docs").option("-w, --watch", "Watch mode").action((options) => {
1760
+ const docsDir = path8.join(process.cwd(), "docs");
1761
+ const outputDir = path8.join(process.cwd(), "public");
1762
+ if (options.watch) {
1763
+ watchData(docsDir, outputDir);
1764
+ } else {
1765
+ generateData(docsDir, outputDir);
1766
+ }
1767
+ });
1768
+ program.command("dev").description("Start development server with live data refresh").action(() => {
1769
+ runDevServer();
1770
+ });
1771
+ program.command("build").description("Build the OpenLAG portal for production").action(() => {
1772
+ buildPortal();
1773
+ });
1774
+ program.command("lint").description("Validate architecture documentation").option("-p, --profile <profile>", "Lint profile (develop, feature, release)", "develop").option("--json", "Output report in JSON format").option("--strict", "Fail on warnings").action((options) => {
1775
+ lintDocs(options.profile, options.json, options.strict);
1776
+ });
1777
+ program.command("preview").description("Preview the production build").action(() => {
1778
+ runVitePreview();
1779
+ });
1780
+ program.command("check").description("Generate graph data and validate architecture documentation").option("-p, --profile <profile>", "Lint profile (develop, feature, release)", "develop").option("--strict", "Fail on warnings").action((options) => {
1781
+ console.log(chalk6.blue("Running OpenLAG checks..."));
1782
+ const docsDir = path8.join(process.cwd(), "docs");
1783
+ const outputDir = path8.join(process.cwd(), "public");
1784
+ try {
1785
+ generateData(docsDir, outputDir);
1786
+ lintDocs(options.profile, false, options.strict);
1787
+ console.log(chalk6.green("\nOpenLAG checks passed."));
1788
+ } catch {
1789
+ console.error(chalk6.red("\nOpenLAG checks failed."));
1790
+ process.exit(1);
1791
+ }
1792
+ });
1793
+ program.parse();