@documentation-robotics/cli 0.1.0 → 0.1.7

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 (510) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +466 -693
  3. package/dist/analysis/data-model-analyzer.js +189 -0
  4. package/dist/analysis/data-model-analyzer.js.map +7 -0
  5. package/dist/analysis/index.js +3 -0
  6. package/dist/analysis/index.js.map +7 -0
  7. package/dist/analysis/relationship-classifier.js +181 -0
  8. package/dist/analysis/relationship-classifier.js.map +7 -0
  9. package/dist/analyzers/base-analyzer.js +1 -0
  10. package/dist/analyzers/base-analyzer.js.map +7 -0
  11. package/dist/analyzers/call-graph-utils.js +39 -0
  12. package/dist/analyzers/call-graph-utils.js.map +7 -0
  13. package/dist/analyzers/cbm-analyzer.js +1205 -0
  14. package/dist/analyzers/cbm-analyzer.js.map +7 -0
  15. package/dist/analyzers/heuristic-utils.js +55 -0
  16. package/dist/analyzers/heuristic-utils.js.map +7 -0
  17. package/dist/analyzers/mapping-loader.js +146 -0
  18. package/dist/analyzers/mapping-loader.js.map +7 -0
  19. package/dist/analyzers/registry.js +124 -0
  20. package/dist/analyzers/registry.js.map +7 -0
  21. package/dist/analyzers/session-state.js +176 -0
  22. package/dist/analyzers/session-state.js.map +7 -0
  23. package/dist/analyzers/stdio-client.js +208 -0
  24. package/dist/analyzers/stdio-client.js.map +7 -0
  25. package/dist/analyzers/types.js +15 -0
  26. package/dist/analyzers/types.js.map +7 -0
  27. package/dist/analyzers/verify-engine.js +209 -0
  28. package/dist/analyzers/verify-engine.js.map +7 -0
  29. package/dist/analyzers/verify-ignore.js +130 -0
  30. package/dist/analyzers/verify-ignore.js.map +7 -0
  31. package/dist/analyzers/version.js +8 -0
  32. package/dist/analyzers/version.js.map +7 -0
  33. package/dist/audit/ai/runner.js +41 -0
  34. package/dist/audit/ai/runner.js.map +7 -0
  35. package/dist/audit/differential-analyzer.js +183 -0
  36. package/dist/audit/differential-analyzer.js.map +7 -0
  37. package/dist/audit/index.js +32 -0
  38. package/dist/audit/index.js.map +7 -0
  39. package/dist/audit/nodes/ai/evaluator.js +49 -0
  40. package/dist/audit/nodes/ai/evaluator.js.map +7 -0
  41. package/dist/audit/nodes/ai/parser.js +55 -0
  42. package/dist/audit/nodes/ai/parser.js.map +7 -0
  43. package/dist/audit/nodes/ai/prompts.js +103 -0
  44. package/dist/audit/nodes/ai/prompts.js.map +7 -0
  45. package/dist/audit/nodes/analysis/node-completeness-checker.js +32 -0
  46. package/dist/audit/nodes/analysis/node-completeness-checker.js.map +7 -0
  47. package/dist/audit/nodes/analysis/node-definition-analyzer.js +47 -0
  48. package/dist/audit/nodes/analysis/node-definition-analyzer.js.map +7 -0
  49. package/dist/audit/nodes/analysis/node-overlap-detector.js +79 -0
  50. package/dist/audit/nodes/analysis/node-overlap-detector.js.map +7 -0
  51. package/dist/audit/nodes/model/orchestrator.js +82 -0
  52. package/dist/audit/nodes/model/orchestrator.js.map +7 -0
  53. package/dist/audit/nodes/spec/loader.js +116 -0
  54. package/dist/audit/nodes/spec/loader.js.map +7 -0
  55. package/dist/audit/nodes/spec/orchestrator.js +68 -0
  56. package/dist/audit/nodes/spec/orchestrator.js.map +7 -0
  57. package/dist/audit/nodes/types.js +1 -0
  58. package/dist/audit/nodes/types.js.map +7 -0
  59. package/dist/audit/pipeline/index.js +5 -0
  60. package/dist/audit/pipeline/index.js.map +7 -0
  61. package/dist/audit/pipeline/pipeline-orchestrator.js +218 -0
  62. package/dist/audit/pipeline/pipeline-orchestrator.js.map +7 -0
  63. package/dist/audit/relationships/ai/evaluator.js +235 -0
  64. package/dist/audit/relationships/ai/evaluator.js.map +7 -0
  65. package/dist/audit/relationships/ai/parser.js +197 -0
  66. package/dist/audit/relationships/ai/parser.js.map +7 -0
  67. package/dist/audit/relationships/ai/prompts.js +274 -0
  68. package/dist/audit/relationships/ai/prompts.js.map +7 -0
  69. package/dist/audit/relationships/analysis/balance-assessor.js +115 -0
  70. package/dist/audit/relationships/analysis/balance-assessor.js.map +7 -0
  71. package/dist/audit/relationships/analysis/coverage-analyzer.js +99 -0
  72. package/dist/audit/relationships/analysis/coverage-analyzer.js.map +7 -0
  73. package/dist/audit/relationships/analysis/duplicate-detector.js +95 -0
  74. package/dist/audit/relationships/analysis/duplicate-detector.js.map +7 -0
  75. package/dist/audit/relationships/analysis/gap-analyzer.js +99 -0
  76. package/dist/audit/relationships/analysis/gap-analyzer.js.map +7 -0
  77. package/dist/audit/relationships/analysis/layer-templates.js +294 -0
  78. package/dist/audit/relationships/analysis/layer-templates.js.map +7 -0
  79. package/dist/audit/relationships/graph/connectivity.js +129 -0
  80. package/dist/audit/relationships/graph/connectivity.js.map +7 -0
  81. package/dist/audit/relationships/graph/relationship-graph.js +179 -0
  82. package/dist/audit/relationships/graph/relationship-graph.js.map +7 -0
  83. package/dist/audit/relationships/model/balance-assessor.js +49 -0
  84. package/dist/audit/relationships/model/balance-assessor.js.map +7 -0
  85. package/dist/audit/relationships/model/coverage-analyzer.js +34 -0
  86. package/dist/audit/relationships/model/coverage-analyzer.js.map +7 -0
  87. package/dist/audit/relationships/model/duplicate-detector.js +68 -0
  88. package/dist/audit/relationships/model/duplicate-detector.js.map +7 -0
  89. package/dist/audit/relationships/model/gap-analyzer.js +41 -0
  90. package/dist/audit/relationships/model/gap-analyzer.js.map +7 -0
  91. package/dist/audit/relationships/model/orchestrator.js +126 -0
  92. package/dist/audit/relationships/model/orchestrator.js.map +7 -0
  93. package/dist/audit/relationships/spec/orchestrator.js +157 -0
  94. package/dist/audit/relationships/spec/orchestrator.js.map +7 -0
  95. package/dist/audit/reports/index.js +5 -0
  96. package/dist/audit/reports/index.js.map +7 -0
  97. package/dist/audit/reports/report-generator.js +118 -0
  98. package/dist/audit/reports/report-generator.js.map +7 -0
  99. package/dist/audit/snapshot-storage.js +163 -0
  100. package/dist/audit/snapshot-storage.js.map +7 -0
  101. package/dist/audit/types.js +21 -0
  102. package/dist/audit/types.js.map +7 -0
  103. package/dist/cli.js +223 -92
  104. package/dist/cli.js.map +3 -3
  105. package/dist/coding-agents/agents/claude-code.js +147 -0
  106. package/dist/coding-agents/agents/claude-code.js.map +7 -0
  107. package/dist/coding-agents/agents/index.js +5 -0
  108. package/dist/coding-agents/agents/index.js.map +7 -0
  109. package/dist/coding-agents/agents/types.js +1 -0
  110. package/dist/coding-agents/agents/types.js.map +7 -0
  111. package/dist/coding-agents/base-chat-client.js +45 -0
  112. package/dist/coding-agents/base-chat-client.js.map +7 -0
  113. package/dist/coding-agents/chat-utils.js +23 -0
  114. package/dist/coding-agents/chat-utils.js.map +7 -0
  115. package/dist/coding-agents/claude-code-client.js +246 -0
  116. package/dist/coding-agents/claude-code-client.js.map +7 -0
  117. package/dist/coding-agents/copilot-client.js +209 -0
  118. package/dist/coding-agents/copilot-client.js.map +7 -0
  119. package/dist/commands/add.js +95 -33
  120. package/dist/commands/add.js.map +2 -2
  121. package/dist/commands/analyzer.js +511 -0
  122. package/dist/commands/analyzer.js.map +7 -0
  123. package/dist/commands/audit-diff.js +49 -0
  124. package/dist/commands/audit-diff.js.map +7 -0
  125. package/dist/commands/audit-snapshots.js +62 -0
  126. package/dist/commands/audit-snapshots.js.map +7 -0
  127. package/dist/commands/audit.js +81 -0
  128. package/dist/commands/audit.js.map +7 -0
  129. package/dist/commands/catalog.js +248 -0
  130. package/dist/commands/catalog.js.map +7 -0
  131. package/dist/commands/changeset.js +577 -66
  132. package/dist/commands/changeset.js.map +2 -2
  133. package/dist/commands/chat.js +106 -83
  134. package/dist/commands/chat.js.map +2 -2
  135. package/dist/commands/claude.js +74 -0
  136. package/dist/commands/claude.js.map +7 -0
  137. package/dist/commands/conformance.js +71 -68
  138. package/dist/commands/conformance.js.map +2 -2
  139. package/dist/commands/copilot.js +75 -0
  140. package/dist/commands/copilot.js.map +7 -0
  141. package/dist/commands/delete.js +125 -11
  142. package/dist/commands/delete.js.map +3 -3
  143. package/dist/commands/discover-logic.js +44 -0
  144. package/dist/commands/discover-logic.js.map +7 -0
  145. package/dist/commands/docs.js +87 -0
  146. package/dist/commands/docs.js.map +7 -0
  147. package/dist/commands/element.js +14 -20
  148. package/dist/commands/element.js.map +2 -2
  149. package/dist/commands/export.js +13 -3
  150. package/dist/commands/export.js.map +2 -2
  151. package/dist/commands/import.js +51 -0
  152. package/dist/commands/import.js.map +7 -0
  153. package/dist/commands/info.js +30 -24
  154. package/dist/commands/info.js.map +2 -2
  155. package/dist/commands/init.js +27 -11
  156. package/dist/commands/init.js.map +2 -2
  157. package/dist/commands/list.js +63 -13
  158. package/dist/commands/list.js.map +3 -3
  159. package/dist/commands/relationship.js +225 -37
  160. package/dist/commands/relationship.js.map +2 -2
  161. package/dist/commands/report.js +54 -0
  162. package/dist/commands/report.js.map +7 -0
  163. package/dist/commands/reports.js +45 -0
  164. package/dist/commands/reports.js.map +7 -0
  165. package/dist/commands/schema.js +135 -0
  166. package/dist/commands/schema.js.map +7 -0
  167. package/dist/commands/search.js +40 -12
  168. package/dist/commands/search.js.map +2 -2
  169. package/dist/commands/show.js +58 -27
  170. package/dist/commands/show.js.map +2 -2
  171. package/dist/commands/stats.js +35 -0
  172. package/dist/commands/stats.js.map +7 -0
  173. package/dist/commands/trace.js +39 -16
  174. package/dist/commands/trace.js.map +2 -2
  175. package/dist/commands/update.js +141 -14
  176. package/dist/commands/update.js.map +2 -2
  177. package/dist/commands/upgrade.js +210 -46
  178. package/dist/commands/upgrade.js.map +3 -3
  179. package/dist/commands/validate.js +142 -23
  180. package/dist/commands/validate.js.map +3 -3
  181. package/dist/commands/version.js +8 -12
  182. package/dist/commands/version.js.map +2 -2
  183. package/dist/commands/visualize.js +162 -25
  184. package/dist/commands/visualize.js.map +2 -2
  185. package/dist/core/base-snapshot-manager.js +84 -0
  186. package/dist/core/base-snapshot-manager.js.map +7 -0
  187. package/dist/core/changeset-exporter.js +305 -0
  188. package/dist/core/changeset-exporter.js.map +7 -0
  189. package/dist/core/changeset-validator.js +41 -0
  190. package/dist/core/changeset-validator.js.map +7 -0
  191. package/dist/core/changeset.js +88 -173
  192. package/dist/core/changeset.js.map +2 -2
  193. package/dist/core/dependency-tracker.js +4 -2
  194. package/dist/core/dependency-tracker.js.map +2 -2
  195. package/dist/core/element.js +98 -27
  196. package/dist/core/element.js.map +2 -2
  197. package/dist/core/golden-copy-cache.js +290 -0
  198. package/dist/core/golden-copy-cache.js.map +7 -0
  199. package/dist/core/graph-model.js +266 -0
  200. package/dist/core/graph-model.js.map +7 -0
  201. package/dist/core/layer.js +159 -16
  202. package/dist/core/layer.js.map +2 -2
  203. package/dist/core/layers.js +32 -0
  204. package/dist/core/layers.js.map +7 -0
  205. package/dist/core/manifest.js +32 -11
  206. package/dist/core/manifest.js.map +2 -2
  207. package/dist/core/migration-registry.js +56 -1
  208. package/dist/core/migration-registry.js.map +2 -2
  209. package/dist/core/model.js +424 -217
  210. package/dist/core/model.js.map +3 -3
  211. package/dist/core/mutation-handler.js +179 -0
  212. package/dist/core/mutation-handler.js.map +7 -0
  213. package/dist/core/reference-registry.js +29 -21
  214. package/dist/core/reference-registry.js.map +2 -2
  215. package/dist/core/relationship-catalog.js +189 -0
  216. package/dist/core/relationship-catalog.js.map +7 -0
  217. package/dist/core/relationship-registry.js.map +2 -2
  218. package/dist/core/relationships.js.map +1 -1
  219. package/dist/core/report-data-model.js +285 -0
  220. package/dist/core/report-data-model.js.map +7 -0
  221. package/dist/core/spec-data-service.js +185 -0
  222. package/dist/core/spec-data-service.js.map +7 -0
  223. package/dist/core/spec-loader-types.js +1 -0
  224. package/dist/core/spec-loader-types.js.map +7 -0
  225. package/dist/core/spec-loader.js +234 -0
  226. package/dist/core/spec-loader.js.map +7 -0
  227. package/dist/core/staged-changeset-storage.js +282 -0
  228. package/dist/core/staged-changeset-storage.js.map +7 -0
  229. package/dist/core/staging-area.js +1002 -0
  230. package/dist/core/staging-area.js.map +7 -0
  231. package/dist/core/stats-collector.js +169 -0
  232. package/dist/core/stats-collector.js.map +7 -0
  233. package/dist/core/virtual-projection.js +443 -0
  234. package/dist/core/virtual-projection.js.map +7 -0
  235. package/dist/export/archimate-exporter.js +99 -60
  236. package/dist/export/archimate-exporter.js.map +2 -2
  237. package/dist/export/audit-formatters.js +479 -0
  238. package/dist/export/audit-formatters.js.map +7 -0
  239. package/dist/export/diff-formatters.js +99 -0
  240. package/dist/export/diff-formatters.js.map +7 -0
  241. package/dist/export/export-manager.js.map +2 -2
  242. package/dist/export/graphml-exporter.js +44 -27
  243. package/dist/export/graphml-exporter.js.map +2 -2
  244. package/dist/export/index.js +4 -0
  245. package/dist/export/index.js.map +2 -2
  246. package/dist/export/json-schema-exporter.js +55 -42
  247. package/dist/export/json-schema-exporter.js.map +2 -2
  248. package/dist/export/markdown-exporter.js +92 -70
  249. package/dist/export/markdown-exporter.js.map +2 -2
  250. package/dist/export/markdown-generator.js +248 -0
  251. package/dist/export/markdown-generator.js.map +7 -0
  252. package/dist/export/markdown-utils.js +30 -0
  253. package/dist/export/markdown-utils.js.map +7 -0
  254. package/dist/export/mermaid-markdown-exporter.js +37 -0
  255. package/dist/export/mermaid-markdown-exporter.js.map +7 -0
  256. package/dist/export/openapi-exporter.js +119 -71
  257. package/dist/export/openapi-exporter.js.map +2 -2
  258. package/dist/export/plantuml-exporter.js +104 -39
  259. package/dist/export/plantuml-exporter.js.map +2 -2
  260. package/dist/export/report-formatters.js +111 -0
  261. package/dist/export/report-formatters.js.map +7 -0
  262. package/dist/export/stats-formatters.js +98 -0
  263. package/dist/export/stats-formatters.js.map +7 -0
  264. package/dist/export/types.js +2 -14
  265. package/dist/export/types.js.map +2 -2
  266. package/dist/export/verify-formatters.js +153 -0
  267. package/dist/export/verify-formatters.js.map +7 -0
  268. package/dist/generated/compiled-validators.js +17 -0
  269. package/dist/generated/compiled-validators.js.map +7 -0
  270. package/dist/generated/index.js +31 -0
  271. package/dist/generated/index.js.map +7 -0
  272. package/dist/generated/layer-registry.js +190 -0
  273. package/dist/generated/layer-registry.js.map +7 -0
  274. package/dist/generated/layer-types.js +7 -0
  275. package/dist/generated/layer-types.js.map +7 -0
  276. package/dist/generated/node-types.js +1719 -0
  277. package/dist/generated/node-types.js.map +7 -0
  278. package/dist/generated/relationship-index.js +14552 -0
  279. package/dist/generated/relationship-index.js.map +7 -0
  280. package/dist/import/archimate-importer.js +166 -0
  281. package/dist/import/archimate-importer.js.map +7 -0
  282. package/dist/import/index.js +47 -0
  283. package/dist/import/index.js.map +7 -0
  284. package/dist/import/openapi-importer.js +143 -0
  285. package/dist/import/openapi-importer.js.map +7 -0
  286. package/dist/import/types.js +1 -0
  287. package/dist/import/types.js.map +7 -0
  288. package/dist/integrations/base-manager.js +311 -0
  289. package/dist/integrations/base-manager.js.map +7 -0
  290. package/dist/integrations/claude-manager.js +360 -0
  291. package/dist/integrations/claude-manager.js.map +7 -0
  292. package/dist/integrations/claude_code/agents/dr-advisor.md +253 -0
  293. package/dist/integrations/claude_code/agents/dr-architect.md +278 -0
  294. package/dist/integrations/claude_code/agents/dr-extractor.md +286 -0
  295. package/dist/integrations/claude_code/commands/dr-changeset.md +657 -0
  296. package/dist/integrations/claude_code/commands/dr-design.md +373 -0
  297. package/dist/integrations/claude_code/commands/dr-info.md +132 -0
  298. package/dist/integrations/claude_code/commands/dr-init.md +251 -0
  299. package/dist/integrations/claude_code/commands/dr-map.md +936 -0
  300. package/dist/integrations/claude_code/commands/dr-model.md +493 -0
  301. package/dist/integrations/claude_code/commands/dr-relate.md +814 -0
  302. package/dist/integrations/claude_code/commands/dr-sync.md +279 -0
  303. package/dist/integrations/claude_code/commands/dr-validate.md +654 -0
  304. package/dist/integrations/claude_code/commands/dr-verify.md +559 -0
  305. package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +903 -0
  306. package/dist/integrations/claude_code/docs/QUICK_START.md +271 -0
  307. package/dist/integrations/claude_code/docs/README.md +347 -0
  308. package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +550 -0
  309. package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +620 -0
  310. package/dist/integrations/claude_code/skills/dr_03_security_layer/SKILL.md +642 -0
  311. package/dist/integrations/claude_code/skills/dr_04_application_layer/SKILL.md +911 -0
  312. package/dist/integrations/claude_code/skills/dr_05_technology_layer/SKILL.md +836 -0
  313. package/dist/integrations/claude_code/skills/dr_06_api_layer/SKILL.md +933 -0
  314. package/dist/integrations/claude_code/skills/dr_07_data_model_layer/SKILL.md +210 -0
  315. package/dist/integrations/claude_code/skills/dr_08_dataset_layer/SKILL.md +319 -0
  316. package/dist/integrations/claude_code/skills/dr_09_ux_layer/SKILL.md +319 -0
  317. package/dist/integrations/claude_code/skills/dr_10_navigation_layer/SKILL.md +318 -0
  318. package/dist/integrations/claude_code/skills/dr_11_apm_layer/SKILL.md +273 -0
  319. package/dist/integrations/claude_code/skills/dr_12_testing_layer/SKILL.md +273 -0
  320. package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +187 -0
  321. package/dist/integrations/claude_code/skills/dr_codebase_memory/SKILL.md +590 -0
  322. package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +295 -0
  323. package/dist/integrations/copilot-manager.js +328 -0
  324. package/dist/integrations/copilot-manager.js.map +7 -0
  325. package/dist/integrations/github_copilot/agents/dr-advisor.md +243 -0
  326. package/dist/integrations/github_copilot/agents/dr-architect.md +1567 -0
  327. package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +491 -0
  328. package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +539 -0
  329. package/dist/integrations/github_copilot/skills/dr_03_security_layer/SKILL.md +667 -0
  330. package/dist/integrations/github_copilot/skills/dr_04_application_layer/SKILL.md +670 -0
  331. package/dist/integrations/github_copilot/skills/dr_05_technology_layer/SKILL.md +660 -0
  332. package/dist/integrations/github_copilot/skills/dr_06_api_layer/SKILL.md +855 -0
  333. package/dist/integrations/github_copilot/skills/dr_07_data_model_layer/SKILL.md +171 -0
  334. package/dist/integrations/github_copilot/skills/dr_08_dataset_layer/SKILL.md +216 -0
  335. package/dist/integrations/github_copilot/skills/dr_09_ux_layer/SKILL.md +230 -0
  336. package/dist/integrations/github_copilot/skills/dr_10_navigation_layer/SKILL.md +228 -0
  337. package/dist/integrations/github_copilot/skills/dr_11_apm_layer/SKILL.md +234 -0
  338. package/dist/integrations/github_copilot/skills/dr_12_testing_layer/SKILL.md +230 -0
  339. package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +187 -0
  340. package/dist/integrations/hash-utils.js +51 -0
  341. package/dist/integrations/hash-utils.js.map +7 -0
  342. package/dist/integrations/types.js +16 -0
  343. package/dist/integrations/types.js.map +7 -0
  344. package/dist/reports/model-layer-report-generator.js +278 -0
  345. package/dist/reports/model-layer-report-generator.js.map +7 -0
  346. package/dist/reports/model-report-data.js +57 -0
  347. package/dist/reports/model-report-data.js.map +7 -0
  348. package/dist/reports/model-report-orchestrator.js +103 -0
  349. package/dist/reports/model-report-orchestrator.js.map +7 -0
  350. package/dist/schemas/bundled/analyzers/cbm.json +595 -0
  351. package/dist/schemas/bundled/analyzers/manifest.json +9 -0
  352. package/dist/schemas/bundled/api.json +3411 -0
  353. package/dist/schemas/bundled/apm.json +2371 -0
  354. package/dist/schemas/bundled/application.json +1253 -0
  355. package/dist/schemas/bundled/base.json +1622 -0
  356. package/dist/schemas/bundled/business.json +1279 -0
  357. package/dist/schemas/bundled/data-model.json +1298 -0
  358. package/dist/schemas/bundled/data-store.json +2025 -0
  359. package/dist/schemas/bundled/manifest.json +93 -0
  360. package/dist/schemas/bundled/motivation.json +1360 -0
  361. package/dist/schemas/bundled/navigation.json +1874 -0
  362. package/dist/schemas/bundled/security.json +3488 -0
  363. package/dist/schemas/bundled/technology.json +2067 -0
  364. package/dist/schemas/bundled/testing.json +3120 -0
  365. package/dist/schemas/bundled/ux.json +3592 -0
  366. package/dist/server/schemas.js +202 -0
  367. package/dist/server/schemas.js.map +7 -0
  368. package/dist/server/server.js +1336 -252
  369. package/dist/server/server.js.map +3 -3
  370. package/dist/server/telemetry-middleware.js +22 -15
  371. package/dist/server/telemetry-middleware.js.map +2 -2
  372. package/dist/server-entry.js +65 -0
  373. package/dist/server-entry.js.map +7 -0
  374. package/dist/telemetry/config.js +89 -0
  375. package/dist/telemetry/config.js.map +7 -0
  376. package/dist/telemetry/console-interceptor.js.map +1 -1
  377. package/dist/telemetry/detect.js +24 -0
  378. package/dist/telemetry/detect.js.map +7 -0
  379. package/dist/telemetry/fetch-otlp-exporter.js +112 -0
  380. package/dist/telemetry/fetch-otlp-exporter.js.map +7 -0
  381. package/dist/telemetry/index.js +153 -3
  382. package/dist/telemetry/index.js.map +2 -2
  383. package/dist/telemetry/resilient-exporter.js +22 -8
  384. package/dist/telemetry/resilient-exporter.js.map +2 -2
  385. package/dist/telemetry/resilient-log-exporter.js +17 -8
  386. package/dist/telemetry/resilient-log-exporter.js.map +2 -2
  387. package/dist/telemetry/test-instrumentation.js.map +2 -2
  388. package/dist/types/index.js +84 -0
  389. package/dist/types/index.js.map +3 -3
  390. package/dist/types/source-reference.js +1 -0
  391. package/dist/types/source-reference.js.map +7 -0
  392. package/dist/utils/chat-logger.js +292 -0
  393. package/dist/utils/chat-logger.js.map +7 -0
  394. package/dist/utils/claude-stream.js +8 -0
  395. package/dist/utils/claude-stream.js.map +7 -0
  396. package/dist/utils/date-utils.js +7 -0
  397. package/dist/utils/date-utils.js.map +7 -0
  398. package/dist/utils/element-utils.js.map +1 -1
  399. package/dist/utils/errors.js +88 -15
  400. package/dist/utils/errors.js.map +3 -3
  401. package/dist/utils/export-python-annotations.js +82 -0
  402. package/dist/utils/export-python-annotations.js.map +7 -0
  403. package/dist/utils/file-io.js +7 -2
  404. package/dist/utils/file-io.js.map +2 -2
  405. package/dist/utils/file-lock.js +156 -0
  406. package/dist/utils/file-lock.js.map +7 -0
  407. package/dist/utils/id-generator.js +18 -0
  408. package/dist/utils/id-generator.js.map +7 -0
  409. package/dist/utils/layer-name-formatter.js +16 -0
  410. package/dist/utils/layer-name-formatter.js.map +7 -0
  411. package/dist/utils/markdown-anchor.js +7 -0
  412. package/dist/utils/markdown-anchor.js.map +7 -0
  413. package/dist/utils/markdown-link.js +12 -0
  414. package/dist/utils/markdown-link.js.map +7 -0
  415. package/dist/utils/markdown-table.js +17 -0
  416. package/dist/utils/markdown-table.js.map +7 -0
  417. package/dist/utils/mermaid-utils.js +11 -0
  418. package/dist/utils/mermaid-utils.js.map +7 -0
  419. package/dist/utils/project-paths.js.map +2 -2
  420. package/dist/utils/source-reference.js +52 -0
  421. package/dist/utils/source-reference.js.map +7 -0
  422. package/dist/utils/spec-installer.js +40 -53
  423. package/dist/utils/spec-installer.js.map +2 -2
  424. package/dist/utils/spec-version.js +5 -1
  425. package/dist/utils/spec-version.js.map +2 -2
  426. package/dist/utils/string-utils.js +12 -0
  427. package/dist/utils/string-utils.js.map +7 -0
  428. package/dist/utils/table-formatting.js +19 -0
  429. package/dist/utils/table-formatting.js.map +7 -0
  430. package/dist/validators/index.js +4 -0
  431. package/dist/validators/index.js.map +2 -2
  432. package/dist/validators/naming-validator.js +20 -23
  433. package/dist/validators/naming-validator.js.map +2 -2
  434. package/dist/validators/reference-validator.js +23 -38
  435. package/dist/validators/reference-validator.js.map +2 -2
  436. package/dist/validators/relationship-schema-validator.js +243 -0
  437. package/dist/validators/relationship-schema-validator.js.map +7 -0
  438. package/dist/validators/schema-validator.js +168 -68
  439. package/dist/validators/schema-validator.js.map +2 -2
  440. package/dist/validators/semantic-validator.js +36 -60
  441. package/dist/validators/semantic-validator.js.map +2 -2
  442. package/dist/validators/types.js.map +2 -2
  443. package/dist/validators/validation-formatter.js +159 -0
  444. package/dist/validators/validation-formatter.js.map +7 -0
  445. package/dist/validators/validator.js +24 -38
  446. package/dist/validators/validator.js.map +2 -2
  447. package/dist/viewer/README.md +139 -0
  448. package/dist/viewer/assets/main-CY0Xufuj.css +1 -0
  449. package/dist/viewer/assets/main-DtgErnwF.js +81 -0
  450. package/dist/viewer/assets/vendor-CxKvDp2x.js +17 -0
  451. package/dist/viewer/favicon.svg +11 -0
  452. package/dist/viewer/fonts/inter/Inter-Black.woff2 +0 -0
  453. package/dist/viewer/fonts/inter/Inter-Bold.woff2 +0 -0
  454. package/dist/viewer/fonts/inter/Inter-ExtraBold.woff2 +0 -0
  455. package/dist/viewer/fonts/inter/Inter-Light.woff2 +0 -0
  456. package/dist/viewer/fonts/inter/Inter-Medium.woff2 +0 -0
  457. package/dist/viewer/fonts/inter/Inter-Regular.woff2 +0 -0
  458. package/dist/viewer/fonts/inter/Inter-SemiBold.woff2 +0 -0
  459. package/dist/viewer/fonts/jetbrains-mono/JetBrainsMono-Medium.woff2 +0 -0
  460. package/dist/viewer/fonts/jetbrains-mono/JetBrainsMono-Regular.woff2 +0 -0
  461. package/dist/viewer/fonts/jetbrains-mono/JetBrainsMono-SemiBold.woff2 +0 -0
  462. package/dist/viewer/index.html +15 -0
  463. package/dist/viewer/manifest.json +99 -0
  464. package/dist/viewer/version.json +1 -0
  465. package/package.json +42 -16
  466. package/PYTHON_CLI_PARITY.md +0 -265
  467. package/PYTHON_CLI_STRUCTURE_UPDATE.md +0 -246
  468. package/biome.json +0 -42
  469. package/bunfig.toml +0 -3
  470. package/dist/ai/claude-client.js +0 -71
  471. package/dist/ai/claude-client.js.map +0 -7
  472. package/dist/ai/context-provider.js +0 -129
  473. package/dist/ai/context-provider.js.map +0 -7
  474. package/dist/ai/tools.js +0 -231
  475. package/dist/ai/tools.js.map +0 -7
  476. package/dist/commands/migrate.js +0 -36
  477. package/dist/commands/migrate.js.map +0 -7
  478. package/dist/commands/project.js +0 -74
  479. package/dist/commands/project.js.map +0 -7
  480. package/dist/core/active-changeset.js +0 -52
  481. package/dist/core/active-changeset.js.map +0 -7
  482. package/dist/core/projection-engine.js +0 -288
  483. package/dist/core/projection-engine.js.map +0 -7
  484. package/dist/schemas/bundled/01-motivation-layer.schema.json +0 -942
  485. package/dist/schemas/bundled/02-business-layer.schema.json +0 -1293
  486. package/dist/schemas/bundled/03-security-layer.schema.json +0 -2177
  487. package/dist/schemas/bundled/04-application-layer.schema.json +0 -1328
  488. package/dist/schemas/bundled/05-technology-layer.schema.json +0 -1465
  489. package/dist/schemas/bundled/06-api-layer.schema.json +0 -1743
  490. package/dist/schemas/bundled/07-data-model-layer.schema.json +0 -1253
  491. package/dist/schemas/bundled/08-datastore-layer.schema.json +0 -892
  492. package/dist/schemas/bundled/09-ux-layer.schema.json +0 -1506
  493. package/dist/schemas/bundled/10-navigation-layer.schema.json +0 -843
  494. package/dist/schemas/bundled/11-apm-observability-layer.schema.json +0 -1430
  495. package/dist/schemas/bundled/12-testing-layer.schema.json +0 -1091
  496. package/dist/schemas/bundled/common/layer-extensions.schema.json +0 -266
  497. package/dist/schemas/bundled/common/predicates.schema.json +0 -493
  498. package/dist/schemas/bundled/common/relationships.schema.json +0 -791
  499. package/dist/schemas/bundled/common/source-references.schema.json +0 -71
  500. package/dist/schemas/bundled/link-registry.json +0 -1839
  501. package/dist/schemas/bundled/link-registry.schema.json +0 -339
  502. package/dist/schemas/bundled/relationship-catalog.json +0 -1302
  503. package/dist/schemas/bundled/relationship-type.schema.json +0 -221
  504. package/dist/utils/model-path.js +0 -22
  505. package/dist/utils/model-path.js.map +0 -7
  506. package/docs/TEST-INSTRUMENTATION.md +0 -405
  507. package/docs/telemetry.md +0 -427
  508. package/test-debug.js +0 -33
  509. package/test-special.mjs +0 -46
  510. package/test_runner.ts +0 -7
@@ -1,79 +1,66 @@
1
1
  import { ensureDir, writeFile } from "./file-io.js";
2
- import { join } from "path";
2
+ import { join, dirname } from "path";
3
+ import { fileURLToPath } from "url";
3
4
  import { getCliBundledSpecVersion } from "./spec-version.js";
4
5
  import fs from "fs/promises";
6
+ import { existsSync } from "fs";
7
+ function getBundledSpecDir() {
8
+ const currentDir = dirname(fileURLToPath(import.meta.url)), installPath = join(currentDir, "..", "schemas", "bundled");
9
+ if (existsSync(join(installPath, "manifest.json")))
10
+ return installPath;
11
+ const devDistPath = join(currentDir, "../../../spec/dist");
12
+ if (existsSync(join(devDistPath, "manifest.json")))
13
+ return devDistPath;
14
+ throw new Error("Cannot find bundled spec schemas. Run 'npm run build' first.");
15
+ }
5
16
  async function installSpecReference(projectRoot, _force = !1) {
6
17
  const drPath = join(projectRoot, ".dr"), specVersion = getCliBundledSpecVersion();
7
- await ensureDir(drPath), await ensureDir(join(drPath, "schemas")), await ensureDir(join(drPath, "schemas", "common")), await ensureDir(join(drPath, "changesets"));
8
- const manifestPath = join(drPath, "manifest.json"), manifest = {
18
+ await ensureDir(drPath), await ensureDir(join(drPath, "changesets"));
19
+ const bundledDir = getBundledSpecDir(), specDestDir = join(drPath, "spec");
20
+ await fs.rm(specDestDir, { recursive: !0, force: !0 }), await ensureDir(specDestDir);
21
+ const specFiles = await fs.readdir(bundledDir);
22
+ await Promise.all(specFiles.filter((f) => f.endsWith(".json")).map((f) => fs.copyFile(join(bundledDir, f), join(specDestDir, f))));
23
+ const manifest = {
9
24
  specVersion,
10
25
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
11
26
  };
12
- await writeFile(manifestPath, JSON.stringify(manifest, null, 2));
13
- const schemaSourceDir = new URL("../schemas/bundled", import.meta.url).pathname, layerSchemas = [
14
- "01-motivation-layer.schema.json",
15
- "02-business-layer.schema.json",
16
- "03-security-layer.schema.json",
17
- "04-application-layer.schema.json",
18
- "05-technology-layer.schema.json",
19
- "06-api-layer.schema.json",
20
- "07-data-model-layer.schema.json",
21
- "08-datastore-layer.schema.json",
22
- "09-ux-layer.schema.json",
23
- "10-navigation-layer.schema.json",
24
- "11-apm-observability-layer.schema.json",
25
- "12-testing-layer.schema.json"
26
- ];
27
- for (const schema of layerSchemas) {
28
- const sourcePath = join(schemaSourceDir, schema), targetPath = join(drPath, "schemas", schema);
29
- await fs.copyFile(sourcePath, targetPath);
30
- }
31
- const catalogFiles = [
32
- "relationship-catalog.json",
33
- "link-registry.json",
34
- "link-registry.schema.json",
35
- "relationship-type.schema.json"
36
- ];
37
- for (const file of catalogFiles) {
38
- const sourcePath = join(schemaSourceDir, file), targetPath = join(drPath, "schemas", file);
39
- await fs.copyFile(sourcePath, targetPath);
40
- }
41
- const commonSchemas = [
42
- "layer-extensions.schema.json",
43
- "predicates.schema.json",
44
- "relationships.schema.json",
45
- "source-references.schema.json"
46
- ];
47
- for (const schema of commonSchemas) {
48
- const sourcePath = join(schemaSourceDir, "common", schema), targetPath = join(drPath, "schemas", "common", schema);
49
- await fs.copyFile(sourcePath, targetPath);
50
- }
51
- const readmePath = join(drPath, "README.md"), readme = `# Documentation Robotics - Spec Reference
27
+ await writeFile(join(drPath, "manifest.json"), JSON.stringify(manifest, null, 2));
28
+ const readme = `# Documentation Robotics - Spec Reference
52
29
 
53
- This directory contains the specification reference for Documentation Robotics.
30
+ This directory is managed by the Documentation Robotics CLI.
54
31
 
55
32
  **Spec Version:** ${specVersion}
56
33
  **Installed:** ${(/* @__PURE__ */ new Date()).toISOString()}
57
34
 
58
35
  ## Structure
59
36
 
60
- - \`manifest.json\` - Spec version information
61
- - \`schemas/\` - JSON Schema definitions for all layers
62
- - \`changesets/\` - Model changesets (active and saved)
37
+ - \`spec/\` \u2014 Compiled spec files (14 JSON files: manifest, base, one per layer)
38
+ - \`manifest.json\` \u2014 Spec version information
39
+ - \`changesets/\` \u2014 Model changesets (active and saved)
40
+
41
+ ## Spec Files
42
+
43
+ The \`spec/\` directory contains the complete compiled specification:
63
44
 
64
- ## Important
45
+ - \`manifest.json\` \u2014 Layer index with node type and relationship counts
46
+ - \`base.json\` \u2014 Base schemas and predicate definitions
47
+ - \`{layer}.json\` \u2014 One file per layer (12 total), each containing:
48
+ - \`layer\` \u2014 Layer metadata (id, name, description, node_types)
49
+ - \`nodeSchemas\` \u2014 JSON Schema definitions for all node types in the layer
50
+ - \`relationshipSchemas\` \u2014 Flat relationship definitions for all relationships in the layer
65
51
 
66
- This directory is ephemeral and should be git-ignored. It will be recreated
67
- automatically by the CLI when needed.
52
+ These files are regenerated on \`dr init\` and \`dr upgrade\` to match the
53
+ current CLI version. Do not manually edit them.
68
54
 
69
- Do not manually edit files in this directory.
55
+ This directory should be git-ignored.
70
56
  `;
71
- await writeFile(readmePath, readme);
57
+ await writeFile(join(drPath, "README.md"), readme);
72
58
  }
73
59
  async function needsSpecReferenceInstall(projectRoot) {
74
60
  const manifestPath = join(projectRoot, ".dr", "manifest.json");
75
61
  try {
76
- return await (await import("fs/promises")).access(manifestPath), !1;
62
+ const content = await fs.readFile(manifestPath, "utf-8");
63
+ return JSON.parse(content).specVersion !== getCliBundledSpecVersion();
77
64
  } catch {
78
65
  return !0;
79
66
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/spec-installer.ts"],
4
- "sourcesContent": ["/**\n * Spec Reference Installer\n *\n * Manages the .dr/ folder which contains the spec reference (schemas, etc.)\n * This is an ephemeral folder that should be git-ignored\n */\n\nimport { ensureDir, writeFile } from './file-io.js';\nimport { join } from 'path';\nimport { getCliBundledSpecVersion } from './spec-version.js';\nimport fs from 'fs/promises';\n\n/**\n * Install or update the .dr/ spec reference folder\n *\n * Creates:\n * - .dr/manifest.json with spec version\n * - .dr/schemas/ with all bundled schemas\n * - .dr/changesets/ directory\n * - .dr/README.md\n *\n * @param projectRoot - Path to project root\n * @param _force - If true, overwrite existing files (reserved for future use)\n */\nexport async function installSpecReference(\n projectRoot: string,\n _force: boolean = false\n): Promise<void> {\n const drPath = join(projectRoot, '.dr');\n const specVersion = getCliBundledSpecVersion();\n\n // Create .dr directory structure\n await ensureDir(drPath);\n await ensureDir(join(drPath, 'schemas'));\n await ensureDir(join(drPath, 'schemas', 'common'));\n await ensureDir(join(drPath, 'changesets'));\n\n // Write manifest.json\n const manifestPath = join(drPath, 'manifest.json');\n const manifest = {\n specVersion: specVersion,\n installedAt: new Date().toISOString(),\n };\n await writeFile(manifestPath, JSON.stringify(manifest, null, 2));\n\n // Copy bundled schemas\n const schemaSourceDir = new URL('../schemas/bundled', import.meta.url).pathname;\n\n // Copy layer schemas\n const layerSchemas = [\n '01-motivation-layer.schema.json',\n '02-business-layer.schema.json',\n '03-security-layer.schema.json',\n '04-application-layer.schema.json',\n '05-technology-layer.schema.json',\n '06-api-layer.schema.json',\n '07-data-model-layer.schema.json',\n '08-datastore-layer.schema.json',\n '09-ux-layer.schema.json',\n '10-navigation-layer.schema.json',\n '11-apm-observability-layer.schema.json',\n '12-testing-layer.schema.json',\n ];\n\n for (const schema of layerSchemas) {\n const sourcePath = join(schemaSourceDir, schema);\n const targetPath = join(drPath, 'schemas', schema);\n await fs.copyFile(sourcePath, targetPath);\n }\n\n // Copy catalog and registry files\n const catalogFiles = [\n 'relationship-catalog.json',\n 'link-registry.json',\n 'link-registry.schema.json',\n 'relationship-type.schema.json',\n ];\n\n for (const file of catalogFiles) {\n const sourcePath = join(schemaSourceDir, file);\n const targetPath = join(drPath, 'schemas', file);\n await fs.copyFile(sourcePath, targetPath);\n }\n\n // Copy common schemas\n const commonSchemas = [\n 'layer-extensions.schema.json',\n 'predicates.schema.json',\n 'relationships.schema.json',\n 'source-references.schema.json',\n ];\n\n for (const schema of commonSchemas) {\n const sourcePath = join(schemaSourceDir, 'common', schema);\n const targetPath = join(drPath, 'schemas', 'common', schema);\n await fs.copyFile(sourcePath, targetPath);\n }\n\n // Create README.md\n const readmePath = join(drPath, 'README.md');\n const readme = `# Documentation Robotics - Spec Reference\n\nThis directory contains the specification reference for Documentation Robotics.\n\n**Spec Version:** ${specVersion}\n**Installed:** ${new Date().toISOString()}\n\n## Structure\n\n- \\`manifest.json\\` - Spec version information\n- \\`schemas/\\` - JSON Schema definitions for all layers\n- \\`changesets/\\` - Model changesets (active and saved)\n\n## Important\n\nThis directory is ephemeral and should be git-ignored. It will be recreated\nautomatically by the CLI when needed.\n\nDo not manually edit files in this directory.\n`;\n await writeFile(readmePath, readme);\n}\n\n/**\n * Check if spec reference needs to be installed or updated\n *\n * @param projectRoot - Path to project root\n * @returns True if installation/update is needed\n */\nexport async function needsSpecReferenceInstall(projectRoot: string): Promise<boolean> {\n const manifestPath = join(projectRoot, '.dr', 'manifest.json');\n\n try {\n const fs = await import('fs/promises');\n await fs.access(manifestPath);\n return false;\n } catch {\n return true;\n }\n}\n"],
5
- "mappings": "AAOA,SAAS,WAAW,iBAAiB;AACrC,SAAS,YAAY;AACrB,SAAS,gCAAgC;AACzC,OAAO,QAAQ;AAcf,eAAsB,qBACpB,aACA,SAAkB,IAAK;AAEvB,QAAM,SAAS,KAAK,aAAa,KAAK,GAChC,cAAc,yBAAwB;AAG5C,QAAM,UAAU,MAAM,GACtB,MAAM,UAAU,KAAK,QAAQ,SAAS,CAAC,GACvC,MAAM,UAAU,KAAK,QAAQ,WAAW,QAAQ,CAAC,GACjD,MAAM,UAAU,KAAK,QAAQ,YAAY,CAAC;AAG1C,QAAM,eAAe,KAAK,QAAQ,eAAe,GAC3C,WAAW;IACf;IACA,cAAa,oBAAI,KAAI,GAAG,YAAW;;AAErC,QAAM,UAAU,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAG/D,QAAM,kBAAkB,IAAI,IAAI,sBAAsB,YAAY,GAAG,EAAE,UAGjE,eAAe;IACnB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;AAGF,aAAW,UAAU,cAAc;AACjC,UAAM,aAAa,KAAK,iBAAiB,MAAM,GACzC,aAAa,KAAK,QAAQ,WAAW,MAAM;AACjD,UAAM,GAAG,SAAS,YAAY,UAAU;EAC1C;AAGA,QAAM,eAAe;IACnB;IACA;IACA;IACA;;AAGF,aAAW,QAAQ,cAAc;AAC/B,UAAM,aAAa,KAAK,iBAAiB,IAAI,GACvC,aAAa,KAAK,QAAQ,WAAW,IAAI;AAC/C,UAAM,GAAG,SAAS,YAAY,UAAU;EAC1C;AAGA,QAAM,gBAAgB;IACpB;IACA;IACA;IACA;;AAGF,aAAW,UAAU,eAAe;AAClC,UAAM,aAAa,KAAK,iBAAiB,UAAU,MAAM,GACnD,aAAa,KAAK,QAAQ,WAAW,UAAU,MAAM;AAC3D,UAAM,GAAG,SAAS,YAAY,UAAU;EAC1C;AAGA,QAAM,aAAa,KAAK,QAAQ,WAAW,GACrC,SAAS;;;;oBAIG,WAAW;kBACd,oBAAI,KAAI,GAAG,YAAW,CAAE;;;;;;;;;;;;;;;AAevC,QAAM,UAAU,YAAY,MAAM;AACpC;AAQA,eAAsB,0BAA0B,aAAmB;AACjE,QAAM,eAAe,KAAK,aAAa,OAAO,eAAe;AAE7D,MAAI;AAEF,kBADW,MAAM,OAAO,aAAa,GAC5B,OAAO,YAAY,GACrB;EACT,QAAQ;AACN,WAAO;EACT;AACF;",
4
+ "sourcesContent": ["/**\n * Spec Reference Installer\n *\n * Manages the .dr/ folder, which stores:\n * - The 14 compiled spec files in .dr/spec/ for agent and user access\n * - The installed spec version in .dr/manifest.json\n * - Changesets in .dr/changesets/\n *\n * The spec files in .dr/spec/ are the same 14 compiled JSON files bundled\n * with the CLI (manifest.json, base.json, {layer}.json x12). They are copied\n * from the CLI's bundled schemas on every install/upgrade so agents, skills,\n * and end users can read the spec directly from the project directory.\n */\n\nimport { ensureDir, writeFile } from \"./file-io.js\";\nimport { join, dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { getCliBundledSpecVersion } from \"./spec-version.js\";\nimport fs from \"fs/promises\";\nimport { existsSync } from \"fs\";\n\n/**\n * Resolve the directory containing the CLI's bundled compiled spec files.\n * Mirrors the logic in SpecDataLoader.getDefaultBundledDir().\n */\nfunction getBundledSpecDir(): string {\n const currentDir = dirname(fileURLToPath(import.meta.url));\n\n // CLI installation: dist/utils \u2192 dist/schemas/bundled\n const installPath = join(currentDir, \"..\", \"schemas\", \"bundled\");\n if (existsSync(join(installPath, \"manifest.json\"))) {\n return installPath;\n }\n\n // Development monorepo: spec/dist/\n const devDistPath = join(currentDir, \"../../../spec/dist\");\n if (existsSync(join(devDistPath, \"manifest.json\"))) {\n return devDistPath;\n }\n\n throw new Error(\"Cannot find bundled spec schemas. Run 'npm run build' first.\");\n}\n\n/**\n * Install or update the .dr/ spec reference folder.\n *\n * Creates:\n * - .dr/spec/ \u2014 14 compiled spec files (manifest.json, base.json, {layer}.json x12)\n * - .dr/manifest.json \u2014 installed spec version record\n * - .dr/changesets/ \u2014 directory for model changesets\n * - .dr/README.md \u2014 informational readme\n *\n * @param projectRoot - Path to project root\n * @param _force - Reserved; kept for API compatibility\n */\nexport async function installSpecReference(\n projectRoot: string,\n _force: boolean = false\n): Promise<void> {\n const drPath = join(projectRoot, \".dr\");\n const specVersion = getCliBundledSpecVersion();\n\n await ensureDir(drPath);\n await ensureDir(join(drPath, \"changesets\"));\n\n // Copy the 14 bundled compiled spec files to .dr/spec/\n // This gives agents, skills, and end users direct file access to the spec.\n // Remove first to clear any stale files or subdirectories from old formats.\n const bundledDir = getBundledSpecDir();\n const specDestDir = join(drPath, \"spec\");\n await fs.rm(specDestDir, { recursive: true, force: true });\n await ensureDir(specDestDir);\n\n const specFiles = await fs.readdir(bundledDir);\n await Promise.all(\n specFiles\n .filter((f) => f.endsWith(\".json\"))\n .map((f) => fs.copyFile(join(bundledDir, f), join(specDestDir, f)))\n );\n\n // Write manifest.json\n const manifest = {\n specVersion: specVersion,\n installedAt: new Date().toISOString(),\n };\n await writeFile(join(drPath, \"manifest.json\"), JSON.stringify(manifest, null, 2));\n\n // Write README.md\n const readme = `# Documentation Robotics - Spec Reference\n\nThis directory is managed by the Documentation Robotics CLI.\n\n**Spec Version:** ${specVersion}\n**Installed:** ${new Date().toISOString()}\n\n## Structure\n\n- \\`spec/\\` \u2014 Compiled spec files (14 JSON files: manifest, base, one per layer)\n- \\`manifest.json\\` \u2014 Spec version information\n- \\`changesets/\\` \u2014 Model changesets (active and saved)\n\n## Spec Files\n\nThe \\`spec/\\` directory contains the complete compiled specification:\n\n- \\`manifest.json\\` \u2014 Layer index with node type and relationship counts\n- \\`base.json\\` \u2014 Base schemas and predicate definitions\n- \\`{layer}.json\\` \u2014 One file per layer (12 total), each containing:\n - \\`layer\\` \u2014 Layer metadata (id, name, description, node_types)\n - \\`nodeSchemas\\` \u2014 JSON Schema definitions for all node types in the layer\n - \\`relationshipSchemas\\` \u2014 Flat relationship definitions for all relationships in the layer\n\nThese files are regenerated on \\`dr init\\` and \\`dr upgrade\\` to match the\ncurrent CLI version. Do not manually edit them.\n\nThis directory should be git-ignored.\n`;\n await writeFile(join(drPath, \"README.md\"), readme);\n}\n\n/**\n * Check if spec reference needs to be installed or updated.\n *\n * Returns true if .dr/manifest.json is missing, unreadable, or records a\n * specVersion that doesn't match the CLI's bundled spec version.\n */\nexport async function needsSpecReferenceInstall(projectRoot: string): Promise<boolean> {\n const manifestPath = join(projectRoot, \".dr\", \"manifest.json\");\n\n try {\n const content = await fs.readFile(manifestPath, \"utf-8\");\n const manifest = JSON.parse(content) as { specVersion?: string };\n return manifest.specVersion !== getCliBundledSpecVersion();\n } catch {\n return true; // manifest missing or unreadable\n }\n}\n"],
5
+ "mappings": "AAcA,SAAS,WAAW,iBAAiB;AACrC,SAAS,MAAM,eAAe;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,gCAAgC;AACzC,OAAO,QAAQ;AACf,SAAS,kBAAkB;AAM3B,SAAS,oBAAiB;AACxB,QAAM,aAAa,QAAQ,cAAc,YAAY,GAAG,CAAC,GAGnD,cAAc,KAAK,YAAY,MAAM,WAAW,SAAS;AAC/D,MAAI,WAAW,KAAK,aAAa,eAAe,CAAC;AAC/C,WAAO;AAIT,QAAM,cAAc,KAAK,YAAY,oBAAoB;AACzD,MAAI,WAAW,KAAK,aAAa,eAAe,CAAC;AAC/C,WAAO;AAGT,QAAM,IAAI,MAAM,8DAA8D;AAChF;AAcA,eAAsB,qBACpB,aACA,SAAkB,IAAK;AAEvB,QAAM,SAAS,KAAK,aAAa,KAAK,GAChC,cAAc,yBAAwB;AAE5C,QAAM,UAAU,MAAM,GACtB,MAAM,UAAU,KAAK,QAAQ,YAAY,CAAC;AAK1C,QAAM,aAAa,kBAAiB,GAC9B,cAAc,KAAK,QAAQ,MAAM;AACvC,QAAM,GAAG,GAAG,aAAa,EAAE,WAAW,IAAM,OAAO,GAAI,CAAE,GACzD,MAAM,UAAU,WAAW;AAE3B,QAAM,YAAY,MAAM,GAAG,QAAQ,UAAU;AAC7C,QAAM,QAAQ,IACZ,UACG,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO,CAAC,EACjC,IAAI,CAAC,MAAM,GAAG,SAAS,KAAK,YAAY,CAAC,GAAG,KAAK,aAAa,CAAC,CAAC,CAAC,CAAC;AAIvE,QAAM,WAAW;IACf;IACA,cAAa,oBAAI,KAAI,GAAG,YAAW;;AAErC,QAAM,UAAU,KAAK,QAAQ,eAAe,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAGhF,QAAM,SAAS;;;;oBAIG,WAAW;kBACd,oBAAI,KAAI,GAAG,YAAW,CAAE;;;;;;;;;;;;;;;;;;;;;;;;AAwBvC,QAAM,UAAU,KAAK,QAAQ,WAAW,GAAG,MAAM;AACnD;AAQA,eAAsB,0BAA0B,aAAmB;AACjE,QAAM,eAAe,KAAK,aAAa,OAAO,eAAe;AAE7D,MAAI;AACF,UAAM,UAAU,MAAM,GAAG,SAAS,cAAc,OAAO;AAEvD,WADiB,KAAK,MAAM,OAAO,EACnB,gBAAgB,yBAAwB;EAC1D,QAAQ;AACN,WAAO;EACT;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,9 @@
1
1
  import { readJSON, fileExists } from "./file-io.js";
2
2
  import { join } from "path";
3
- const BUNDLED_SPEC_VERSION = "0.7.0";
3
+ const CLI_VERSION = "0.1.3", BUNDLED_SPEC_VERSION = "0.8.4";
4
+ function getCliVersion() {
5
+ return CLI_VERSION;
6
+ }
4
7
  function getCliBundledSpecVersion() {
5
8
  return BUNDLED_SPEC_VERSION;
6
9
  }
@@ -27,6 +30,7 @@ async function getModelSpecVersion(modelPath) {
27
30
  }
28
31
  export {
29
32
  getCliBundledSpecVersion,
33
+ getCliVersion,
30
34
  getInstalledSpecVersion,
31
35
  getModelSpecVersion
32
36
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/spec-version.ts"],
4
- "sourcesContent": ["/**\n * Spec Version Utilities\n *\n * Manages spec version information for the CLI\n */\n\nimport { readJSON, fileExists } from './file-io.js';\nimport { join } from 'path';\n\n/**\n * Bundled spec version\n * This should match the version in ../../../spec/VERSION\n * Updated during build process\n */\nconst BUNDLED_SPEC_VERSION = '0.7.0';\n\n/**\n * Get the CLI's bundled spec version\n *\n * This is the version of the DR specification that is bundled with this CLI.\n * It represents what version of the spec this CLI supports.\n *\n * @returns Bundled spec version string\n */\nexport function getCliBundledSpecVersion(): string {\n return BUNDLED_SPEC_VERSION;\n}\n\n/**\n * Read spec version from .dr/manifest.json (installed spec reference)\n *\n * @param drPath - Path to .dr/ directory\n * @returns Spec version from .dr/manifest.json, or null if not found\n */\nexport async function getInstalledSpecVersion(drPath: string): Promise<string | null> {\n const manifestPath = join(drPath, 'manifest.json');\n\n if (!(await fileExists(manifestPath))) {\n return null;\n }\n\n try {\n const manifest = await readJSON<{ specVersion?: string }>(manifestPath);\n return manifest.specVersion || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Read spec version from documentation_robotics/model/manifest.yaml\n *\n * @param modelPath - Path to model directory\n * @returns Spec version from model manifest, or null if not found\n */\nexport async function getModelSpecVersion(modelPath: string): Promise<string | null> {\n const manifestPath = join(modelPath, 'manifest.yaml');\n\n if (!(await fileExists(manifestPath))) {\n return null;\n }\n\n try {\n // Use YAML parser\n const yaml = await import('yaml');\n const fs = await import('fs/promises');\n const content = await fs.readFile(manifestPath, 'utf-8');\n const manifest = yaml.parse(content) as { spec_version?: string; specVersion?: string };\n // Check snake_case first (Python CLI format), then camelCase (legacy)\n return manifest.spec_version || manifest.specVersion || null;\n } catch {\n return null;\n }\n}\n"],
5
- "mappings": "AAMA,SAAS,UAAU,kBAAkB;AACrC,SAAS,YAAY;AAOrB,MAAM,uBAAuB;AAUvB,SAAU,2BAAwB;AACtC,SAAO;AACT;AAQA,eAAsB,wBAAwB,QAAc;AAC1D,QAAM,eAAe,KAAK,QAAQ,eAAe;AAEjD,MAAI,CAAE,MAAM,WAAW,YAAY;AACjC,WAAO;AAGT,MAAI;AAEF,YADiB,MAAM,SAAmC,YAAY,GACtD,eAAe;EACjC,QAAQ;AACN,WAAO;EACT;AACF;AAQA,eAAsB,oBAAoB,WAAiB;AACzD,QAAM,eAAe,KAAK,WAAW,eAAe;AAEpD,MAAI,CAAE,MAAM,WAAW,YAAY;AACjC,WAAO;AAGT,MAAI;AAEF,UAAM,OAAO,MAAM,OAAO,MAAM,GAE1B,UAAU,OADL,MAAM,OAAO,aAAa,GACZ,SAAS,cAAc,OAAO,GACjD,WAAW,KAAK,MAAM,OAAO;AAEnC,WAAO,SAAS,gBAAgB,SAAS,eAAe;EAC1D,QAAQ;AACN,WAAO;EACT;AACF;",
4
+ "sourcesContent": ["/**\n * Spec Version Utilities\n *\n * Manages spec version information for the CLI\n */\n\nimport { readJSON, fileExists } from \"./file-io.js\";\nimport { join } from \"path\";\n\n/**\n * CLI version\n * This should match the version in ../package.json\n * Updated during release process\n */\nconst CLI_VERSION = \"0.1.3\";\n\n/**\n * Bundled spec version\n * This should match the version in ../../../spec/VERSION\n * Updated during build process\n */\nconst BUNDLED_SPEC_VERSION = \"0.8.4\";\n\n/**\n * Get the CLI version\n *\n * @returns CLI version string\n */\nexport function getCliVersion(): string {\n return CLI_VERSION;\n}\n\n/**\n * Get the CLI's bundled spec version\n *\n * This is the version of the DR specification that is bundled with this CLI.\n * It represents what version of the spec this CLI supports.\n *\n * @returns Bundled spec version string\n */\nexport function getCliBundledSpecVersion(): string {\n return BUNDLED_SPEC_VERSION;\n}\n\n/**\n * Read spec version from .dr/manifest.json (installed spec reference)\n *\n * @param drPath - Path to .dr/ directory\n * @returns Spec version from .dr/manifest.json, or null if not found\n */\nexport async function getInstalledSpecVersion(drPath: string): Promise<string | null> {\n const manifestPath = join(drPath, \"manifest.json\");\n\n if (!(await fileExists(manifestPath))) {\n return null;\n }\n\n try {\n const manifest = await readJSON<{ specVersion?: string }>(manifestPath);\n return manifest.specVersion || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Read spec version from documentation_robotics/model/manifest.yaml\n *\n * @param modelPath - Path to model directory\n * @returns Spec version from model manifest, or null if not found\n */\nexport async function getModelSpecVersion(modelPath: string): Promise<string | null> {\n const manifestPath = join(modelPath, \"manifest.yaml\");\n\n if (!(await fileExists(manifestPath))) {\n return null;\n }\n\n try {\n // Use YAML parser\n const yaml = await import(\"yaml\");\n const fs = await import(\"fs/promises\");\n const content = await fs.readFile(manifestPath, \"utf-8\");\n const manifest = yaml.parse(content) as { spec_version?: string; specVersion?: string };\n // Check snake_case first (Python CLI format), then camelCase (legacy)\n return manifest.spec_version || manifest.specVersion || null;\n } catch {\n return null;\n }\n}\n"],
5
+ "mappings": "AAMA,SAAS,UAAU,kBAAkB;AACrC,SAAS,YAAY;AAOrB,MAAM,cAAc,SAOd,uBAAuB;AAOvB,SAAU,gBAAa;AAC3B,SAAO;AACT;AAUM,SAAU,2BAAwB;AACtC,SAAO;AACT;AAQA,eAAsB,wBAAwB,QAAc;AAC1D,QAAM,eAAe,KAAK,QAAQ,eAAe;AAEjD,MAAI,CAAE,MAAM,WAAW,YAAY;AACjC,WAAO;AAGT,MAAI;AAEF,YADiB,MAAM,SAAmC,YAAY,GACtD,eAAe;EACjC,QAAQ;AACN,WAAO;EACT;AACF;AAQA,eAAsB,oBAAoB,WAAiB;AACzD,QAAM,eAAe,KAAK,WAAW,eAAe;AAEpD,MAAI,CAAE,MAAM,WAAW,YAAY;AACjC,WAAO;AAGT,MAAI;AAEF,UAAM,OAAO,MAAM,OAAO,MAAM,GAE1B,UAAU,OADL,MAAM,OAAO,aAAa,GACZ,SAAS,cAAc,OAAO,GACjD,WAAW,KAAK,MAAM,OAAO;AAEnC,WAAO,SAAS,gBAAgB,SAAS,eAAe;EAC1D,QAAQ;AACN,WAAO;EACT;AACF;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,12 @@
1
+ function truncateToWidth(text, width) {
2
+ const maxLength = width - 1;
3
+ return text.length >= width ? text.substring(0, maxLength).padEnd(width) : text.padEnd(width);
4
+ }
5
+ function safeTruncate(text, maxLength) {
6
+ return text.length > maxLength ? text.substring(0, maxLength - 1) : text;
7
+ }
8
+ export {
9
+ safeTruncate,
10
+ truncateToWidth
11
+ };
12
+ //# sourceMappingURL=string-utils.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/string-utils.ts"],
4
+ "sourcesContent": ["/**\n * String manipulation utilities for consistent formatting across CLI output\n */\n\n/**\n * Truncates a string to a specified width, leaving room for padding\n * @param text - The text to truncate\n * @param width - The maximum width (reserves 1 character for padding)\n * @returns Truncated string padded to width\n */\nexport function truncateToWidth(text: string, width: number): string {\n const maxLength = width - 1;\n if (text.length >= width) {\n return text.substring(0, maxLength).padEnd(width);\n }\n return text.padEnd(width);\n}\n\n/**\n * Safely truncates text and returns the raw truncated value\n * @param text - The text to truncate\n * @param maxLength - Maximum number of characters to keep\n * @returns Truncated string\n */\nexport function safeTruncate(text: string, maxLength: number): string {\n if (text.length > maxLength) {\n return text.substring(0, maxLength - 1);\n }\n return text;\n}\n"],
5
+ "mappings": "AAUM,SAAU,gBAAgB,MAAc,OAAa;AACzD,QAAM,YAAY,QAAQ;AAC1B,SAAI,KAAK,UAAU,QACV,KAAK,UAAU,GAAG,SAAS,EAAE,OAAO,KAAK,IAE3C,KAAK,OAAO,KAAK;AAC1B;AAQM,SAAU,aAAa,MAAc,WAAiB;AAC1D,SAAI,KAAK,SAAS,YACT,KAAK,UAAU,GAAG,YAAY,CAAC,IAEjC;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,19 @@
1
+ const TABLE_COLUMN_WIDTHS = {
2
+ // Single element display (list command)
3
+ LIST_ID_WIDTH: 50,
4
+ LIST_TYPE_WIDTH: 25,
5
+ LIST_NAME_WIDTH: 35,
6
+ // Search results display
7
+ SEARCH_LAYER_WIDTH: 12,
8
+ SEARCH_ID_WIDTH: 50,
9
+ SEARCH_TYPE_WIDTH: 12,
10
+ SEARCH_NAME_WIDTH: 28,
11
+ // Info/summary display
12
+ INFO_ID_WIDTH: 20,
13
+ INFO_COUNT_WIDTH: 10
14
+ }, TABLE_SEPARATOR = "\u2500".repeat(80);
15
+ export {
16
+ TABLE_COLUMN_WIDTHS,
17
+ TABLE_SEPARATOR
18
+ };
19
+ //# sourceMappingURL=table-formatting.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/table-formatting.ts"],
4
+ "sourcesContent": ["/**\n * Table formatting constants for consistent column widths\n * Used across list, search, and info commands for uniform output\n */\n\nexport const TABLE_COLUMN_WIDTHS = {\n // Single element display (list command)\n LIST_ID_WIDTH: 50,\n LIST_TYPE_WIDTH: 25,\n LIST_NAME_WIDTH: 35,\n\n // Search results display\n SEARCH_LAYER_WIDTH: 12,\n SEARCH_ID_WIDTH: 50,\n SEARCH_TYPE_WIDTH: 12,\n SEARCH_NAME_WIDTH: 28,\n\n // Info/summary display\n INFO_ID_WIDTH: 20,\n INFO_COUNT_WIDTH: 10,\n} as const;\n\nexport const TABLE_SEPARATOR = \"\u2500\".repeat(80);\n"],
5
+ "mappings": "AAKO,MAAM,sBAAsB;;EAEjC,eAAe;EACf,iBAAiB;EACjB,iBAAiB;;EAGjB,oBAAoB;EACpB,iBAAiB;EACjB,mBAAmB;EACnB,mBAAmB;;EAGnB,eAAe;EACf,kBAAkB;GAGP,kBAAkB,SAAI,OAAO,EAAE;",
6
+ "names": []
7
+ }
@@ -3,12 +3,16 @@ import { SchemaValidator } from "./schema-validator.js";
3
3
  import { NamingValidator } from "./naming-validator.js";
4
4
  import { ReferenceValidator } from "./reference-validator.js";
5
5
  import { SemanticValidator } from "./semantic-validator.js";
6
+ import { RelationshipValidator } from "./relationship-schema-validator.js";
6
7
  import { Validator } from "./validator.js";
8
+ import { ValidationFormatter } from "./validation-formatter.js";
7
9
  export {
8
10
  NamingValidator,
9
11
  ReferenceValidator,
12
+ RelationshipValidator,
10
13
  SchemaValidator,
11
14
  SemanticValidator,
15
+ ValidationFormatter,
12
16
  ValidationResult,
13
17
  Validator
14
18
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/validators/index.ts"],
4
- "sourcesContent": ["/**\n * Validators module - 4-stage validation pipeline\n */\n\nexport { ValidationResult, type ValidationIssue } from './types.js';\nexport { SchemaValidator } from './schema-validator.js';\nexport { NamingValidator } from './naming-validator.js';\nexport { ReferenceValidator } from './reference-validator.js';\nexport { SemanticValidator } from './semantic-validator.js';\nexport { Validator } from './validator.js';\n"],
5
- "mappings": "AAIA,SAAS,wBAA8C;AACvD,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,iBAAiB;",
4
+ "sourcesContent": ["/**\n * Validators module - 5-stage validation pipeline\n */\n\nexport { ValidationResult, type ValidationIssue } from \"./types.js\";\nexport { SchemaValidator } from \"./schema-validator.js\";\nexport { NamingValidator } from \"./naming-validator.js\";\nexport { ReferenceValidator } from \"./reference-validator.js\";\nexport { SemanticValidator } from \"./semantic-validator.js\";\nexport { RelationshipValidator } from \"./relationship-schema-validator.js\";\nexport { Validator } from \"./validator.js\";\nexport { ValidationFormatter } from \"./validation-formatter.js\";\n"],
5
+ "mappings": "AAIA,SAAS,wBAA8C;AACvD,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,6BAA6B;AACtC,SAAS,iBAAiB;AAC1B,SAAS,2BAA2B;",
6
6
  "names": []
7
7
  }
@@ -1,39 +1,36 @@
1
1
  import { ValidationResult } from "./types.js";
2
+ import { getAllLayerIds } from "../generated/layer-registry.js";
3
+ const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2
4
  class NamingValidator {
3
- // Element ID format: {layer}.{type}.{name} (dot-separated, matching Python CLI)
5
+ // Path format: {layer}.{type}.{name} (dot-separated, matching Python CLI)
4
6
  // Also accepts: {layer}-{type}-{kebab-case-name} (legacy kebab-case format)
5
- DOT_SEPARATED_PATTERN = /^[a-z_][a-z0-9_]*(\.[a-z_][a-z0-9_-]*)+$/;
7
+ // Layer names can contain hyphens (e.g., data-model, data-store) or underscores
8
+ DOT_SEPARATED_PATTERN = /^[a-z_][a-z0-9_-]*(\.[a-z_][a-z0-9_-]*)+$/;
6
9
  KEBAB_CASE_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*(-[a-z0-9]+)+$/;
7
- // Known layer names (including hyphenated and underscored ones)
8
- KNOWN_LAYERS = [
9
- "motivation",
10
- "business",
11
- "security",
12
- "application",
13
- "technology",
14
- "api",
15
- "data_model",
16
- "data-model",
17
- "datastore",
18
- "data-store",
19
- "ux",
20
- "navigation",
21
- "apm",
22
- "testing"
23
- ];
10
+ // Known layer names from generated registry (including hyphenated and underscored ones)
11
+ KNOWN_LAYERS = getAllLayerIds();
24
12
  /**
25
13
  * Validate all elements in a layer
26
14
  */
27
15
  validateLayer(layer) {
28
16
  const result = new ValidationResult();
29
- for (const element of layer.listElements())
30
- this.validateElementId(element.id, layer.name, result);
17
+ for (const element of layer.listElements()) {
18
+ const pathToValidate = element.path || element.id;
19
+ this.validateElementPath(pathToValidate, layer.name, result), element.id && element.path && element.id !== element.path && !UUID_PATTERN.test(element.id) && result.addError({
20
+ layer: layer.name,
21
+ elementId: element.id,
22
+ message: `Element id '${element.id}' is not a valid UUIDv4`,
23
+ fixSuggestion: "The id field must be a UUIDv4 (e.g., 550e8400-e29b-41d4-a716-446655440000)"
24
+ });
25
+ }
31
26
  return result;
32
27
  }
33
28
  /**
34
- * Validate an individual element ID
29
+ * Validate an individual element path (slug)
35
30
  */
36
- validateElementId(elementId, layerName, result) {
31
+ validateElementPath(elementId, layerName, result) {
32
+ if (UUID_PATTERN.test(elementId))
33
+ return;
37
34
  const isDotSeparated = this.DOT_SEPARATED_PATTERN.test(elementId), isKebabCase = this.KEBAB_CASE_PATTERN.test(elementId);
38
35
  if (!isDotSeparated && !isKebabCase) {
39
36
  result.addError({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/validators/naming-validator.ts"],
4
- "sourcesContent": ["/**\n * Naming validation for element IDs\n */\n\nimport { ValidationResult } from './types.js';\nimport type { Layer } from '../core/layer.js';\n\n/**\n * Validator for element ID naming conventions\n */\nexport class NamingValidator {\n // Element ID format: {layer}.{type}.{name} (dot-separated, matching Python CLI)\n // Also accepts: {layer}-{type}-{kebab-case-name} (legacy kebab-case format)\n private readonly DOT_SEPARATED_PATTERN = /^[a-z_][a-z0-9_]*(\\.[a-z_][a-z0-9_-]*)+$/;\n private readonly KEBAB_CASE_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*(-[a-z0-9]+)+$/;\n\n // Known layer names (including hyphenated and underscored ones)\n private readonly KNOWN_LAYERS = [\n 'motivation',\n 'business',\n 'security',\n 'application',\n 'technology',\n 'api',\n 'data_model',\n 'data-model',\n 'datastore',\n 'data-store',\n 'ux',\n 'navigation',\n 'apm',\n 'testing',\n ];\n\n /**\n * Validate all elements in a layer\n */\n validateLayer(layer: Layer): ValidationResult {\n const result = new ValidationResult();\n\n for (const element of layer.listElements()) {\n this.validateElementId(element.id, layer.name, result);\n }\n\n return result;\n }\n\n /**\n * Validate an individual element ID\n */\n private validateElementId(\n elementId: string,\n layerName: string,\n result: ValidationResult\n ): void {\n // Check if ID matches dot-separated format (primary) or kebab-case format (legacy)\n const isDotSeparated = this.DOT_SEPARATED_PATTERN.test(elementId);\n const isKebabCase = this.KEBAB_CASE_PATTERN.test(elementId);\n\n if (!isDotSeparated && !isKebabCase) {\n result.addError({\n layer: layerName,\n elementId,\n message: `Invalid element ID format: ${elementId}`,\n fixSuggestion: 'Use format: {layer}.{type}.{name} (e.g., motivation.goal.increase-revenue) or {layer}-{type}-{kebab-case-name}',\n });\n return;\n }\n\n const idLayer = this.extractLayerFromId(elementId, isDotSeparated);\n\n // Verify layer prefix matches the actual layer\n const normalizedLayerName = layerName.replace(/-/g, '_');\n const normalizedIdLayer = idLayer.replace(/-/g, '_');\n\n if (normalizedIdLayer !== normalizedLayerName) {\n result.addError({\n layer: layerName,\n elementId,\n message: `Element ID layer prefix '${idLayer}' does not match layer '${layerName}'`,\n fixSuggestion: `Change prefix to '${layerName}' (e.g., ${layerName}.type.name)`,\n });\n return;\n }\n\n // Extract remaining parts after layer\n const separator = isDotSeparated ? '.' : '-';\n const remainingParts = elementId.slice(idLayer.length + 1).split(separator);\n\n // Verify type is present and non-empty\n if (remainingParts.length < 2) {\n result.addError({\n layer: layerName,\n elementId,\n message: 'Element ID must have type and name components after layer',\n fixSuggestion: 'Use format: {layer}.{type}.{name}',\n });\n return;\n }\n }\n\n /**\n * Extract layer name from element ID, handling hyphenated/underscored layer names\n */\n private extractLayerFromId(elementId: string, isDotSeparated: boolean): string {\n // Try to match known layers in order of specificity (longest first)\n const sortedLayers = [...this.KNOWN_LAYERS].sort((a, b) => b.length - a.length);\n\n const separator = isDotSeparated ? '.' : '-';\n\n for (const layer of sortedLayers) {\n if (elementId.startsWith(layer + separator)) {\n return layer;\n }\n }\n\n // Fallback: take first component before separator\n return elementId.split(separator)[0];\n }\n}\n"],
5
- "mappings": "AAIA,SAAS,wBAAwB;AAM3B,MAAO,gBAAe;;;EAGT,wBAAwB;EACxB,qBAAqB;;EAGrB,eAAe;IAC9B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;;;EAMF,cAAc,OAAY;AACxB,UAAM,SAAS,IAAI,iBAAgB;AAEnC,eAAW,WAAW,MAAM,aAAY;AACtC,WAAK,kBAAkB,QAAQ,IAAI,MAAM,MAAM,MAAM;AAGvD,WAAO;EACT;;;;EAKQ,kBACN,WACA,WACA,QAAwB;AAGxB,UAAM,iBAAiB,KAAK,sBAAsB,KAAK,SAAS,GAC1D,cAAc,KAAK,mBAAmB,KAAK,SAAS;AAE1D,QAAI,CAAC,kBAAkB,CAAC,aAAa;AACnC,aAAO,SAAS;QACd,OAAO;QACP;QACA,SAAS,8BAA8B,SAAS;QAChD,eAAe;OAChB;AACD;IACF;AAEA,UAAM,UAAU,KAAK,mBAAmB,WAAW,cAAc,GAG3D,sBAAsB,UAAU,QAAQ,MAAM,GAAG;AAGvD,QAF0B,QAAQ,QAAQ,MAAM,GAAG,MAEzB,qBAAqB;AAC7C,aAAO,SAAS;QACd,OAAO;QACP;QACA,SAAS,4BAA4B,OAAO,2BAA2B,SAAS;QAChF,eAAe,qBAAqB,SAAS,YAAY,SAAS;OACnE;AACD;IACF;AAGA,UAAM,YAAY,iBAAiB,MAAM;AAIzC,QAHuB,UAAU,MAAM,QAAQ,SAAS,CAAC,EAAE,MAAM,SAAS,EAGvD,SAAS,GAAG;AAC7B,aAAO,SAAS;QACd,OAAO;QACP;QACA,SAAS;QACT,eAAe;OAChB;AACD;IACF;EACF;;;;EAKQ,mBAAmB,WAAmB,gBAAuB;AAEnE,UAAM,eAAe,CAAC,GAAG,KAAK,YAAY,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,GAExE,YAAY,iBAAiB,MAAM;AAEzC,eAAW,SAAS;AAClB,UAAI,UAAU,WAAW,QAAQ,SAAS;AACxC,eAAO;AAKX,WAAO,UAAU,MAAM,SAAS,EAAE,CAAC;EACrC;;",
4
+ "sourcesContent": ["/**\n * Naming validation for element IDs\n */\n\nimport { ValidationResult } from \"./types.js\";\nimport type { Layer } from \"../core/layer.js\";\nimport { getAllLayerIds } from \"../generated/layer-registry.js\";\n\n/**\n * UUID pattern for validating id field\n */\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Validator for element ID naming conventions\n */\nexport class NamingValidator {\n // Path format: {layer}.{type}.{name} (dot-separated, matching Python CLI)\n // Also accepts: {layer}-{type}-{kebab-case-name} (legacy kebab-case format)\n // Layer names can contain hyphens (e.g., data-model, data-store) or underscores\n private readonly DOT_SEPARATED_PATTERN = /^[a-z_][a-z0-9_-]*(\\.[a-z_][a-z0-9_-]*)+$/;\n private readonly KEBAB_CASE_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*(-[a-z0-9]+)+$/;\n\n // Known layer names from generated registry (including hyphenated and underscored ones)\n private readonly KNOWN_LAYERS = getAllLayerIds();\n\n /**\n * Validate all elements in a layer\n */\n validateLayer(layer: Layer): ValidationResult {\n const result = new ValidationResult();\n\n for (const element of layer.listElements()) {\n // Validate the path (slug identifier); fall back to id when path is absent\n const pathToValidate = element.path || element.id;\n this.validateElementPath(pathToValidate, layer.name, result);\n\n // Only validate id as UUID when id and path are distinct values\n // If id === path (legacy slug serving both roles), skip UUID check\n // If id !== path (proper separation), id must be a UUID\n if (element.id && element.path && element.id !== element.path && !UUID_PATTERN.test(element.id)) {\n result.addError({\n layer: layer.name,\n elementId: element.id,\n message: `Element id '${element.id}' is not a valid UUIDv4`,\n fixSuggestion: \"The id field must be a UUIDv4 (e.g., 550e8400-e29b-41d4-a716-446655440000)\",\n });\n }\n }\n\n return result;\n }\n\n /**\n * Validate an individual element path (slug)\n */\n private validateElementPath(elementId: string, layerName: string, result: ValidationResult): void {\n // Skip UUID values \u2014 they are not paths\n if (UUID_PATTERN.test(elementId)) {\n return;\n }\n\n // Check if path matches dot-separated format (primary) or kebab-case format (legacy)\n const isDotSeparated = this.DOT_SEPARATED_PATTERN.test(elementId);\n const isKebabCase = this.KEBAB_CASE_PATTERN.test(elementId);\n\n if (!isDotSeparated && !isKebabCase) {\n result.addError({\n layer: layerName,\n elementId,\n message: `Invalid element ID format: ${elementId}`,\n fixSuggestion:\n \"Use format: {layer}.{type}.{name} (e.g., motivation.goal.increase-revenue) or {layer}-{type}-{kebab-case-name}\",\n });\n return;\n }\n\n const idLayer = this.extractLayerFromId(elementId, isDotSeparated);\n\n // Verify layer prefix matches the actual layer\n const normalizedLayerName = layerName.replace(/-/g, \"_\");\n const normalizedIdLayer = idLayer.replace(/-/g, \"_\");\n\n if (normalizedIdLayer !== normalizedLayerName) {\n result.addError({\n layer: layerName,\n elementId,\n message: `Element ID layer prefix '${idLayer}' does not match layer '${layerName}'`,\n fixSuggestion: `Change prefix to '${layerName}' (e.g., ${layerName}.type.name)`,\n });\n return;\n }\n\n // Extract remaining parts after layer\n const separator = isDotSeparated ? \".\" : \"-\";\n const remainingParts = elementId.slice(idLayer.length + 1).split(separator);\n\n // Verify type is present and non-empty\n if (remainingParts.length < 2) {\n result.addError({\n layer: layerName,\n elementId,\n message: \"Element ID must have type and name components after layer\",\n fixSuggestion: \"Use format: {layer}.{type}.{name}\",\n });\n return;\n }\n }\n\n /**\n * Extract layer name from element ID, handling hyphenated/underscored layer names\n */\n private extractLayerFromId(elementId: string, isDotSeparated: boolean): string {\n // Try to match known layers in order of specificity (longest first)\n const sortedLayers = [...this.KNOWN_LAYERS].sort((a, b) => b.length - a.length);\n\n const separator = isDotSeparated ? \".\" : \"-\";\n\n for (const layer of sortedLayers) {\n if (elementId.startsWith(layer + separator)) {\n return layer;\n }\n }\n\n // Fallback: take first component before separator\n return elementId.split(separator)[0];\n }\n}\n"],
5
+ "mappings": "AAIA,SAAS,wBAAwB;AAEjC,SAAS,sBAAsB;AAK/B,MAAM,eAAe;AAKf,MAAO,gBAAe;;;;EAIT,wBAAwB;EACxB,qBAAqB;;EAGrB,eAAe,eAAc;;;;EAK9C,cAAc,OAAY;AACxB,UAAM,SAAS,IAAI,iBAAgB;AAEnC,eAAW,WAAW,MAAM,aAAY,GAAI;AAE1C,YAAM,iBAAiB,QAAQ,QAAQ,QAAQ;AAC/C,WAAK,oBAAoB,gBAAgB,MAAM,MAAM,MAAM,GAKvD,QAAQ,MAAM,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,CAAC,aAAa,KAAK,QAAQ,EAAE,KAC5F,OAAO,SAAS;QACd,OAAO,MAAM;QACb,WAAW,QAAQ;QACnB,SAAS,eAAe,QAAQ,EAAE;QAClC,eAAe;OAChB;IAEL;AAEA,WAAO;EACT;;;;EAKQ,oBAAoB,WAAmB,WAAmB,QAAwB;AAExF,QAAI,aAAa,KAAK,SAAS;AAC7B;AAIF,UAAM,iBAAiB,KAAK,sBAAsB,KAAK,SAAS,GAC1D,cAAc,KAAK,mBAAmB,KAAK,SAAS;AAE1D,QAAI,CAAC,kBAAkB,CAAC,aAAa;AACnC,aAAO,SAAS;QACd,OAAO;QACP;QACA,SAAS,8BAA8B,SAAS;QAChD,eACE;OACH;AACD;IACF;AAEA,UAAM,UAAU,KAAK,mBAAmB,WAAW,cAAc,GAG3D,sBAAsB,UAAU,QAAQ,MAAM,GAAG;AAGvD,QAF0B,QAAQ,QAAQ,MAAM,GAAG,MAEzB,qBAAqB;AAC7C,aAAO,SAAS;QACd,OAAO;QACP;QACA,SAAS,4BAA4B,OAAO,2BAA2B,SAAS;QAChF,eAAe,qBAAqB,SAAS,YAAY,SAAS;OACnE;AACD;IACF;AAGA,UAAM,YAAY,iBAAiB,MAAM;AAIzC,QAHuB,UAAU,MAAM,QAAQ,SAAS,CAAC,EAAE,MAAM,SAAS,EAGvD,SAAS,GAAG;AAC7B,aAAO,SAAS;QACd,OAAO;QACP;QACA,SAAS;QACT,eAAe;OAChB;AACD;IACF;EACF;;;;EAKQ,mBAAmB,WAAmB,gBAAuB;AAEnE,UAAM,eAAe,CAAC,GAAG,KAAK,YAAY,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,GAExE,YAAY,iBAAiB,MAAM;AAEzC,eAAW,SAAS;AAClB,UAAI,UAAU,WAAW,QAAQ,SAAS;AACxC,eAAO;AAKX,WAAO,UAAU,MAAM,SAAS,EAAE,CAAC;EACrC;;",
6
6
  "names": []
7
7
  }
@@ -1,35 +1,18 @@
1
1
  import { ValidationResult } from "./types.js";
2
+ import { getLayerByNumber, LAYER_HIERARCHY, getAllLayerIds } from "../generated/layer-registry.js";
2
3
  class ReferenceValidator {
3
- // Layer hierarchy (lower numbers are "higher" in the architecture)
4
- LAYER_HIERARCHY = {
5
- motivation: 1,
6
- business: 2,
7
- security: 3,
8
- application: 4,
9
- technology: 5,
10
- api: 6,
11
- "data-model": 7,
12
- "data-store": 8,
13
- ux: 9,
14
- navigation: 10,
15
- apm: 11,
16
- testing: 12
17
- };
18
- // Known layer names (including hyphenated ones)
19
- KNOWN_LAYERS = [
20
- "motivation",
21
- "business",
22
- "security",
23
- "application",
24
- "technology",
25
- "api",
26
- "data-model",
27
- "data-store",
28
- "ux",
29
- "navigation",
30
- "apm",
31
- "testing"
32
- ];
4
+ // Known layer names from generated registry (including hyphenated ones)
5
+ KNOWN_LAYERS = getAllLayerIds();
6
+ // Build layer hierarchy map at instantiation from generated registry
7
+ LAYER_HIERARCHY = this.buildLayerHierarchy();
8
+ buildLayerHierarchy() {
9
+ const hierarchy = {};
10
+ for (const layerNumber of LAYER_HIERARCHY) {
11
+ const layer = getLayerByNumber(layerNumber);
12
+ layer && (hierarchy[layer.id] = layer.number);
13
+ }
14
+ return hierarchy;
15
+ }
33
16
  /**
34
17
  * Validate all references in a model
35
18
  */
@@ -37,7 +20,7 @@ class ReferenceValidator {
37
20
  const result = new ValidationResult(), allElementIds = this.collectAllElementIds(model);
38
21
  for (const [layerName, layer] of model.layers)
39
22
  for (const element of layer.listElements())
40
- this.validateReferences(element.id, element.references || [], layerName, allElementIds, result);
23
+ this.validateReferences(element.path || element.id, element.references || [], layerName, allElementIds, result);
41
24
  return result;
42
25
  }
43
26
  /**
@@ -47,7 +30,7 @@ class ReferenceValidator {
47
30
  const ids = /* @__PURE__ */ new Set();
48
31
  for (const layer of model.layers.values())
49
32
  for (const element of layer.listElements())
50
- ids.add(element.id);
33
+ ids.add(element.path || element.id), ids.add(element.id);
51
34
  return ids;
52
35
  }
53
36
  /**
@@ -69,7 +52,8 @@ class ReferenceValidator {
69
52
  result.addError({
70
53
  layer: sourceLayerName,
71
54
  elementId,
72
- message: `Unknown source layer: ${sourceLayerName}`
55
+ message: `Unknown source layer: ${sourceLayerName}`,
56
+ fixSuggestion: `Use one of the valid layers: ${this.KNOWN_LAYERS.join(", ")}`
73
57
  });
74
58
  continue;
75
59
  }
@@ -77,7 +61,8 @@ class ReferenceValidator {
77
61
  result.addError({
78
62
  layer: sourceLayerName,
79
63
  elementId,
80
- message: `Target element '${ref.target}' has unknown layer: ${targetLayerName}`
64
+ message: `Target element '${ref.target}' has unknown layer: ${targetLayerName}`,
65
+ fixSuggestion: `Check that element ID '${ref.target}' uses a valid layer prefix (e.g., motivation-, business-, api-)`
81
66
  });
82
67
  continue;
83
68
  }
@@ -90,14 +75,14 @@ class ReferenceValidator {
90
75
  }
91
76
  }
92
77
  /**
93
- * Extract layer name from element ID, handling hyphenated layer names
78
+ * Extract layer name from element ID, handling both dot-separated and hyphenated layer names
94
79
  */
95
80
  extractLayerFromId(elementId) {
96
- const sortedLayers = [...this.KNOWN_LAYERS].sort((a, b) => b.length - a.length);
81
+ const separator = elementId.includes(".") ? "." : "-", sortedLayers = [...this.KNOWN_LAYERS].sort((a, b) => b.length - a.length);
97
82
  for (const layer of sortedLayers)
98
- if (elementId.startsWith(layer + "-"))
83
+ if (elementId.startsWith(layer + separator))
99
84
  return layer;
100
- return elementId.split("-")[0] || "";
85
+ return elementId.split(separator)[0] || "";
101
86
  }
102
87
  }
103
88
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/validators/reference-validator.ts"],
4
- "sourcesContent": ["/**\n * Reference validation for cross-layer integrity\n */\n\nimport { ValidationResult } from './types.js';\nimport type { Model } from '../core/model.js';\n\n/**\n * Validator for cross-layer references\n */\nexport class ReferenceValidator {\n // Layer hierarchy (lower numbers are \"higher\" in the architecture)\n private readonly LAYER_HIERARCHY: Record<string, number> = {\n motivation: 1,\n business: 2,\n security: 3,\n application: 4,\n technology: 5,\n api: 6,\n 'data-model': 7,\n 'data-store': 8,\n ux: 9,\n navigation: 10,\n apm: 11,\n testing: 12,\n };\n\n // Known layer names (including hyphenated ones)\n private readonly KNOWN_LAYERS = [\n 'motivation',\n 'business',\n 'security',\n 'application',\n 'technology',\n 'api',\n 'data-model',\n 'data-store',\n 'ux',\n 'navigation',\n 'apm',\n 'testing',\n ];\n\n /**\n * Validate all references in a model\n */\n validateModel(model: Model): ValidationResult {\n const result = new ValidationResult();\n const allElementIds = this.collectAllElementIds(model);\n\n for (const [layerName, layer] of model.layers) {\n for (const element of layer.listElements()) {\n this.validateReferences(\n element.id,\n element.references || [],\n layerName,\n allElementIds,\n result\n );\n }\n }\n\n return result;\n }\n\n /**\n * Collect all element IDs across the model\n */\n private collectAllElementIds(model: Model): Set<string> {\n const ids = new Set<string>();\n\n for (const layer of model.layers.values()) {\n for (const element of layer.listElements()) {\n ids.add(element.id);\n }\n }\n\n return ids;\n }\n\n /**\n * Validate references for an element\n */\n private validateReferences(\n elementId: string,\n references: Array<{ target: string; type?: string }>,\n sourceLayerName: string,\n validIds: Set<string>,\n result: ValidationResult\n ): void {\n for (const ref of references) {\n // Check target exists\n if (!validIds.has(ref.target)) {\n result.addError({\n layer: sourceLayerName,\n elementId,\n message: `Broken reference: target '${ref.target}' does not exist`,\n fixSuggestion: `Remove reference or create element '${ref.target}'`,\n });\n continue;\n }\n\n // Check directional constraint (higher \u2192 lower only)\n const targetLayerName = this.extractLayerFromId(ref.target);\n const sourceLevel = this.LAYER_HIERARCHY[sourceLayerName];\n const targetLevel = this.LAYER_HIERARCHY[targetLayerName];\n\n if (sourceLevel === undefined) {\n result.addError({\n layer: sourceLayerName,\n elementId,\n message: `Unknown source layer: ${sourceLayerName}`,\n });\n continue;\n }\n\n if (targetLevel === undefined) {\n result.addError({\n layer: sourceLayerName,\n elementId,\n message: `Target element '${ref.target}' has unknown layer: ${targetLayerName}`,\n });\n continue;\n }\n\n // References must go from higher layers (lower numbers) to lower layers (higher numbers)\n // or within the same layer\n if (sourceLevel > targetLevel) {\n result.addError({\n layer: sourceLayerName,\n elementId,\n message: `Invalid reference direction: ${sourceLayerName} (level ${sourceLevel}) cannot reference ${targetLayerName} (level ${targetLevel})`,\n fixSuggestion:\n 'References must go from higher layers to lower layers (motivation \u2192 testing)',\n });\n }\n }\n }\n\n /**\n * Extract layer name from element ID, handling hyphenated layer names\n */\n private extractLayerFromId(elementId: string): string {\n // Try to match known layers in order of specificity (longest first)\n const sortedLayers = [...this.KNOWN_LAYERS].sort((a, b) => b.length - a.length);\n\n for (const layer of sortedLayers) {\n if (elementId.startsWith(layer + '-')) {\n return layer;\n }\n }\n\n // Fallback: return first segment (shouldn't reach here with valid element IDs)\n return elementId.split('-')[0] || '';\n }\n}\n"],
5
- "mappings": "AAIA,SAAS,wBAAwB;AAM3B,MAAO,mBAAkB;;EAEZ,kBAA0C;IACzD,YAAY;IACZ,UAAU;IACV,UAAU;IACV,aAAa;IACb,YAAY;IACZ,KAAK;IACL,cAAc;IACd,cAAc;IACd,IAAI;IACJ,YAAY;IACZ,KAAK;IACL,SAAS;;;EAIM,eAAe;IAC9B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;;;;;EAMF,cAAc,OAAY;AACxB,UAAM,SAAS,IAAI,iBAAgB,GAC7B,gBAAgB,KAAK,qBAAqB,KAAK;AAErD,eAAW,CAAC,WAAW,KAAK,KAAK,MAAM;AACrC,iBAAW,WAAW,MAAM,aAAY;AACtC,aAAK,mBACH,QAAQ,IACR,QAAQ,cAAc,CAAA,GACtB,WACA,eACA,MAAM;AAKZ,WAAO;EACT;;;;EAKQ,qBAAqB,OAAY;AACvC,UAAM,MAAM,oBAAI,IAAG;AAEnB,eAAW,SAAS,MAAM,OAAO,OAAM;AACrC,iBAAW,WAAW,MAAM,aAAY;AACtC,YAAI,IAAI,QAAQ,EAAE;AAItB,WAAO;EACT;;;;EAKQ,mBACN,WACA,YACA,iBACA,UACA,QAAwB;AAExB,eAAW,OAAO,YAAY;AAE5B,UAAI,CAAC,SAAS,IAAI,IAAI,MAAM,GAAG;AAC7B,eAAO,SAAS;UACd,OAAO;UACP;UACA,SAAS,6BAA6B,IAAI,MAAM;UAChD,eAAe,uCAAuC,IAAI,MAAM;SACjE;AACD;MACF;AAGA,YAAM,kBAAkB,KAAK,mBAAmB,IAAI,MAAM,GACpD,cAAc,KAAK,gBAAgB,eAAe,GAClD,cAAc,KAAK,gBAAgB,eAAe;AAExD,UAAI,gBAAgB,QAAW;AAC7B,eAAO,SAAS;UACd,OAAO;UACP;UACA,SAAS,yBAAyB,eAAe;SAClD;AACD;MACF;AAEA,UAAI,gBAAgB,QAAW;AAC7B,eAAO,SAAS;UACd,OAAO;UACP;UACA,SAAS,mBAAmB,IAAI,MAAM,wBAAwB,eAAe;SAC9E;AACD;MACF;AAIA,MAAI,cAAc,eAChB,OAAO,SAAS;QACd,OAAO;QACP;QACA,SAAS,gCAAgC,eAAe,WAAW,WAAW,sBAAsB,eAAe,WAAW,WAAW;QACzI,eACE;OACH;IAEL;EACF;;;;EAKQ,mBAAmB,WAAiB;AAE1C,UAAM,eAAe,CAAC,GAAG,KAAK,YAAY,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAE9E,eAAW,SAAS;AAClB,UAAI,UAAU,WAAW,QAAQ,GAAG;AAClC,eAAO;AAKX,WAAO,UAAU,MAAM,GAAG,EAAE,CAAC,KAAK;EACpC;;",
4
+ "sourcesContent": ["/**\n * Reference validation for cross-layer integrity\n */\n\nimport { ValidationResult } from \"./types.js\";\nimport type { Model } from \"../core/model.js\";\nimport { getLayerByNumber, LAYER_HIERARCHY, getAllLayerIds } from \"../generated/layer-registry.js\";\n\n/**\n * Validator for cross-layer references\n */\nexport class ReferenceValidator {\n // Known layer names from generated registry (including hyphenated ones)\n private readonly KNOWN_LAYERS = getAllLayerIds();\n\n // Build layer hierarchy map at instantiation from generated registry\n private readonly LAYER_HIERARCHY: Record<string, number> = this.buildLayerHierarchy();\n\n private buildLayerHierarchy(): Record<string, number> {\n const hierarchy: Record<string, number> = {};\n for (const layerNumber of LAYER_HIERARCHY) {\n const layer = getLayerByNumber(layerNumber);\n if (layer) {\n hierarchy[layer.id] = layer.number;\n }\n }\n return hierarchy;\n }\n\n /**\n * Validate all references in a model\n */\n validateModel(model: Model): ValidationResult {\n const result = new ValidationResult();\n const allElementIds = this.collectAllElementIds(model);\n\n for (const [layerName, layer] of model.layers) {\n for (const element of layer.listElements()) {\n this.validateReferences(\n element.path || element.id,\n element.references || [],\n layerName,\n allElementIds,\n result\n );\n }\n }\n\n return result;\n }\n\n /**\n * Collect all element IDs across the model\n */\n private collectAllElementIds(model: Model): Set<string> {\n const ids = new Set<string>();\n\n for (const layer of model.layers.values()) {\n for (const element of layer.listElements()) {\n ids.add(element.path || element.id);\n // Also add raw UUID so references stored by UUID still resolve\n ids.add(element.id);\n }\n }\n\n return ids;\n }\n\n /**\n * Validate references for an element\n */\n private validateReferences(\n elementId: string,\n references: Array<{ target: string; type?: string }>,\n sourceLayerName: string,\n validIds: Set<string>,\n result: ValidationResult\n ): void {\n for (const ref of references) {\n // Check target exists\n if (!validIds.has(ref.target)) {\n result.addError({\n layer: sourceLayerName,\n elementId,\n message: `Broken reference: target '${ref.target}' does not exist`,\n fixSuggestion: `Remove reference or create element '${ref.target}'`,\n });\n continue;\n }\n\n // Check directional constraint (higher \u2192 lower only)\n const targetLayerName = this.extractLayerFromId(ref.target);\n const sourceLevel = this.LAYER_HIERARCHY[sourceLayerName];\n const targetLevel = this.LAYER_HIERARCHY[targetLayerName];\n\n if (sourceLevel === undefined) {\n result.addError({\n layer: sourceLayerName,\n elementId,\n message: `Unknown source layer: ${sourceLayerName}`,\n fixSuggestion:\n `Use one of the valid layers: ${this.KNOWN_LAYERS.join(\", \")}`,\n });\n continue;\n }\n\n if (targetLevel === undefined) {\n result.addError({\n layer: sourceLayerName,\n elementId,\n message: `Target element '${ref.target}' has unknown layer: ${targetLayerName}`,\n fixSuggestion: `Check that element ID '${ref.target}' uses a valid layer prefix (e.g., motivation-, business-, api-)`,\n });\n continue;\n }\n\n // References must go from higher layers (lower numbers) to lower layers (higher numbers)\n // or within the same layer\n if (sourceLevel > targetLevel) {\n result.addError({\n layer: sourceLayerName,\n elementId,\n message: `Invalid reference direction: ${sourceLayerName} (level ${sourceLevel}) cannot reference ${targetLayerName} (level ${targetLevel})`,\n fixSuggestion:\n \"References must go from higher layers to lower layers (motivation \u2192 testing)\",\n });\n }\n }\n }\n\n /**\n * Extract layer name from element ID, handling both dot-separated and hyphenated layer names\n */\n private extractLayerFromId(elementId: string): string {\n // Determine if using dot-separated format (e.g., motivation.goal.name) or hyphenated (e.g., motivation-goal-name)\n const isDotSeparated = elementId.includes(\".\");\n const separator = isDotSeparated ? \".\" : \"-\";\n\n // Try to match known layers in order of specificity (longest first)\n const sortedLayers = [...this.KNOWN_LAYERS].sort((a, b) => b.length - a.length);\n\n for (const layer of sortedLayers) {\n if (elementId.startsWith(layer + separator)) {\n return layer;\n }\n }\n\n // Fallback: return first segment (shouldn't reach here with valid element IDs)\n return elementId.split(separator)[0] || \"\";\n }\n}\n"],
5
+ "mappings": "AAIA,SAAS,wBAAwB;AAEjC,SAAS,kBAAkB,iBAAiB,sBAAsB;AAK5D,MAAO,mBAAkB;;EAEZ,eAAe,eAAc;;EAG7B,kBAA0C,KAAK,oBAAmB;EAE3E,sBAAmB;AACzB,UAAM,YAAoC,CAAA;AAC1C,eAAW,eAAe,iBAAiB;AACzC,YAAM,QAAQ,iBAAiB,WAAW;AAC1C,MAAI,UACF,UAAU,MAAM,EAAE,IAAI,MAAM;IAEhC;AACA,WAAO;EACT;;;;EAKA,cAAc,OAAY;AACxB,UAAM,SAAS,IAAI,iBAAgB,GAC7B,gBAAgB,KAAK,qBAAqB,KAAK;AAErD,eAAW,CAAC,WAAW,KAAK,KAAK,MAAM;AACrC,iBAAW,WAAW,MAAM,aAAY;AACtC,aAAK,mBACH,QAAQ,QAAQ,QAAQ,IACxB,QAAQ,cAAc,CAAA,GACtB,WACA,eACA,MAAM;AAKZ,WAAO;EACT;;;;EAKQ,qBAAqB,OAAY;AACvC,UAAM,MAAM,oBAAI,IAAG;AAEnB,eAAW,SAAS,MAAM,OAAO,OAAM;AACrC,iBAAW,WAAW,MAAM,aAAY;AACtC,YAAI,IAAI,QAAQ,QAAQ,QAAQ,EAAE,GAElC,IAAI,IAAI,QAAQ,EAAE;AAItB,WAAO;EACT;;;;EAKQ,mBACN,WACA,YACA,iBACA,UACA,QAAwB;AAExB,eAAW,OAAO,YAAY;AAE5B,UAAI,CAAC,SAAS,IAAI,IAAI,MAAM,GAAG;AAC7B,eAAO,SAAS;UACd,OAAO;UACP;UACA,SAAS,6BAA6B,IAAI,MAAM;UAChD,eAAe,uCAAuC,IAAI,MAAM;SACjE;AACD;MACF;AAGA,YAAM,kBAAkB,KAAK,mBAAmB,IAAI,MAAM,GACpD,cAAc,KAAK,gBAAgB,eAAe,GAClD,cAAc,KAAK,gBAAgB,eAAe;AAExD,UAAI,gBAAgB,QAAW;AAC7B,eAAO,SAAS;UACd,OAAO;UACP;UACA,SAAS,yBAAyB,eAAe;UACjD,eACE,gCAAgC,KAAK,aAAa,KAAK,IAAI,CAAC;SAC/D;AACD;MACF;AAEA,UAAI,gBAAgB,QAAW;AAC7B,eAAO,SAAS;UACd,OAAO;UACP;UACA,SAAS,mBAAmB,IAAI,MAAM,wBAAwB,eAAe;UAC7E,eAAe,0BAA0B,IAAI,MAAM;SACpD;AACD;MACF;AAIA,MAAI,cAAc,eAChB,OAAO,SAAS;QACd,OAAO;QACP;QACA,SAAS,gCAAgC,eAAe,WAAW,WAAW,sBAAsB,eAAe,WAAW,WAAW;QACzI,eACE;OACH;IAEL;EACF;;;;EAKQ,mBAAmB,WAAiB;AAG1C,UAAM,YADiB,UAAU,SAAS,GAAG,IACV,MAAM,KAGnC,eAAe,CAAC,GAAG,KAAK,YAAY,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAE9E,eAAW,SAAS;AAClB,UAAI,UAAU,WAAW,QAAQ,SAAS;AACxC,eAAO;AAKX,WAAO,UAAU,MAAM,SAAS,EAAE,CAAC,KAAK;EAC1C;;",
6
6
  "names": []
7
7
  }