@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
@@ -0,0 +1,157 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import * as yaml from "yaml";
4
+ import { CoverageAnalyzer } from "../analysis/coverage-analyzer.js";
5
+ import { DuplicateDetector } from "../analysis/duplicate-detector.js";
6
+ import { GapAnalyzer } from "../analysis/gap-analyzer.js";
7
+ import { BalanceAssessor } from "../analysis/balance-assessor.js";
8
+ import { ConnectivityAnalyzer } from "../graph/connectivity.js";
9
+ import { RelationshipCatalog } from "../../../core/relationship-catalog.js";
10
+ import { RelationshipGraph } from "../graph/relationship-graph.js";
11
+ import { getLayerById, getAllLayers } from "../../../generated/layer-registry.js";
12
+ import { getErrorMessage } from "../../../utils/errors.js";
13
+ class AuditOrchestrator {
14
+ catalog;
15
+ graph;
16
+ coverageAnalyzer;
17
+ duplicateDetector;
18
+ gapAnalyzer;
19
+ balanceAssessor;
20
+ connectivityAnalyzer;
21
+ initialized = !1;
22
+ constructor() {
23
+ this.catalog = new RelationshipCatalog(), this.graph = new RelationshipGraph(), this.coverageAnalyzer = new CoverageAnalyzer(this.catalog), this.duplicateDetector = new DuplicateDetector(this.catalog), this.gapAnalyzer = new GapAnalyzer(), this.balanceAssessor = new BalanceAssessor(), this.connectivityAnalyzer = new ConnectivityAnalyzer(this.graph, this.catalog);
24
+ }
25
+ /**
26
+ * Initialize the orchestrator (must be called before running audit)
27
+ */
28
+ async initialize() {
29
+ this.initialized || (await this.catalog.load(), this.initialized = !0);
30
+ }
31
+ /**
32
+ * Get predicates applicable to a specific layer
33
+ * Useful for AI evaluation to provide available relationship types
34
+ */
35
+ getPredicatesForLayer(layer) {
36
+ return this.catalog.getTypesForLayer(layer).map((t) => t.predicate);
37
+ }
38
+ /**
39
+ * Run coverage analysis
40
+ */
41
+ async runCoverageAnalysis(options) {
42
+ if (this.log(options, "Running coverage analysis..."), options.layer) {
43
+ const layer = getLayerById(options.layer);
44
+ if (!layer) {
45
+ const validLayerNames = getAllLayers().map((l) => l.id).join(", ");
46
+ throw new Error(`Layer not found: '${options.layer}'. Valid layers: ${validLayerNames}`);
47
+ }
48
+ return [await this.coverageAnalyzer.analyzeLayer(layer)];
49
+ }
50
+ return (await this.coverageAnalyzer.analyzeAll()).results;
51
+ }
52
+ /**
53
+ * Run duplicate detection
54
+ */
55
+ async runDuplicateDetection(options) {
56
+ if (this.log(options, "Running duplicate detection..."), options.layer) {
57
+ const layer = getLayerById(options.layer);
58
+ if (!layer)
59
+ throw new Error(`Layer not found: ${options.layer}`);
60
+ return this.duplicateDetector.detectDuplicatesByLayer(layer.id);
61
+ }
62
+ return this.duplicateDetector.detectDuplicates();
63
+ }
64
+ /**
65
+ * Run gap analysis
66
+ */
67
+ async runGapAnalysis(options) {
68
+ if (this.log(options, "Running gap analysis..."), options.layer) {
69
+ const layer = getLayerById(options.layer);
70
+ if (!layer)
71
+ throw new Error(`Layer not found: ${options.layer}`);
72
+ return this.gapAnalyzer.analyzeLayer(layer);
73
+ }
74
+ return this.gapAnalyzer.analyzeAll();
75
+ }
76
+ /**
77
+ * Run balance assessment
78
+ */
79
+ async runBalanceAssessment(options) {
80
+ if (this.log(options, "Running balance assessment..."), options.layer) {
81
+ const layer = getLayerById(options.layer);
82
+ if (!layer)
83
+ throw new Error(`Layer not found: ${options.layer}`);
84
+ return this.balanceAssessor.assessLayer(layer);
85
+ }
86
+ return this.balanceAssessor.assessAll();
87
+ }
88
+ /**
89
+ * Run connectivity analysis
90
+ */
91
+ async runConnectivityAnalysis(options) {
92
+ this.log(options, "Running connectivity analysis...");
93
+ const layerId = options.layer ? getLayerById(options.layer)?.id : void 0;
94
+ await this.graph.build(layerId);
95
+ const components = this.connectivityAnalyzer.findConnectedComponents(), degrees = this.connectivityAnalyzer.calculateDegreeDistribution(), transitiveChains = await this.connectivityAnalyzer.findTransitiveChains(), rawStats = this.connectivityAnalyzer.getConnectivityStats(), stats = {
96
+ totalNodes: rawStats.nodeCount,
97
+ totalEdges: rawStats.edgeCount,
98
+ connectedComponents: rawStats.componentCount,
99
+ largestComponentSize: rawStats.largestComponentSize,
100
+ isolatedNodes: rawStats.isolatedNodeCount,
101
+ averageDegree: rawStats.averageDegree,
102
+ transitiveChainCount: transitiveChains.length
103
+ };
104
+ return { components, degrees, transitiveChains, stats };
105
+ }
106
+ /**
107
+ * Load model metadata from manifest
108
+ */
109
+ async loadModelMetadata(options) {
110
+ this.log(options, "Loading model metadata...");
111
+ const projectRoot = options.projectRoot || process.cwd(), defaultMetadata = {
112
+ name: "Documentation Robotics Model",
113
+ version: "1.0.0"
114
+ };
115
+ try {
116
+ const manifestPath = join(projectRoot, "documentation-robotics", "model", "manifest.yaml"), manifestContent = await readFile(manifestPath, "utf-8");
117
+ let manifest;
118
+ try {
119
+ manifest = yaml.parse(manifestContent);
120
+ } catch (parseError) {
121
+ const parseErrorMsg = getErrorMessage(parseError);
122
+ return console.warn(`\u26A0\uFE0F Warning: Manifest file is corrupted or has invalid YAML syntax (${parseErrorMsg}). Using default model metadata.`), defaultMetadata;
123
+ }
124
+ const name = manifest.name || manifest.project?.name, version = manifest.project?.version || manifest.version;
125
+ return !name || typeof name != "string" ? (console.warn("\u26A0\uFE0F Warning: Manifest missing required field 'name'. Using default model metadata."), defaultMetadata) : !version || typeof version != "string" ? (console.warn("\u26A0\uFE0F Warning: Manifest missing required field 'version'. Using default model metadata."), defaultMetadata) : { name, version };
126
+ } catch (error) {
127
+ const errorMsg = getErrorMessage(error);
128
+ return errorMsg.includes("ENOENT") || errorMsg.includes("no such file") ? this.log(options, "Using default model metadata (manifest not found)") : console.warn(`\u26A0\uFE0F Warning: Cannot read manifest file (${errorMsg}). Using default model metadata.`), defaultMetadata;
129
+ }
130
+ }
131
+ /**
132
+ * Run complete audit and build report
133
+ */
134
+ async runAudit(options = {}) {
135
+ await this.initialize();
136
+ const coverage = await this.runCoverageAnalysis(options), duplicates = await this.runDuplicateDetection(options), gaps = await this.runGapAnalysis(options), balance = await this.runBalanceAssessment(options), connectivity = await this.runConnectivityAnalysis(options), modelMetadata = await this.loadModelMetadata(options);
137
+ return this.log(options, "Generating audit report..."), {
138
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
139
+ model: modelMetadata,
140
+ coverage,
141
+ duplicates,
142
+ gaps,
143
+ balance,
144
+ connectivity
145
+ };
146
+ }
147
+ /**
148
+ * Log helper that respects verbose/debug flags
149
+ */
150
+ log(options, message) {
151
+ (options.verbose || options.debug) && console.error(message);
152
+ }
153
+ }
154
+ export {
155
+ AuditOrchestrator
156
+ };
157
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/audit/relationships/spec/orchestrator.ts"],
4
+ "sourcesContent": ["/**\n * Audit Orchestrator - Centralized audit execution logic\n *\n * This class eliminates code duplication between cli/src/commands/audit.ts\n * and cli/scripts/relationship-audit.ts by extracting shared audit orchestration.\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport * as yaml from \"yaml\";\nimport { CoverageAnalyzer } from \"../analysis/coverage-analyzer.js\";\nimport { DuplicateDetector } from \"../analysis/duplicate-detector.js\";\nimport { GapAnalyzer } from \"../analysis/gap-analyzer.js\";\nimport { BalanceAssessor } from \"../analysis/balance-assessor.js\";\nimport { ConnectivityAnalyzer } from \"../graph/connectivity.js\";\nimport { RelationshipCatalog } from \"../../../core/relationship-catalog.js\";\nimport { RelationshipGraph } from \"../graph/relationship-graph.js\";\nimport { getLayerById, getAllLayers } from \"../../../generated/layer-registry.js\";\nimport type {\n AuditReport,\n ConnectivityStats,\n CoverageMetrics,\n DuplicateCandidate,\n GapCandidate,\n BalanceAssessment,\n} from \"../../types.js\";\nimport { getErrorMessage } from \"../../../utils/errors.js\";\n\nexport interface AuditOptions {\n layer?: string;\n verbose?: boolean;\n debug?: boolean;\n projectRoot?: string;\n}\n\nexport interface AuditComponents {\n coverage: CoverageMetrics[];\n duplicates: DuplicateCandidate[];\n gaps: GapCandidate[];\n balance: BalanceAssessment[];\n connectivity: {\n components: ReturnType<ConnectivityAnalyzer[\"findConnectedComponents\"]>;\n degrees: ReturnType<ConnectivityAnalyzer[\"calculateDegreeDistribution\"]>;\n transitiveChains: Awaited<\n ReturnType<ConnectivityAnalyzer[\"findTransitiveChains\"]>\n >;\n stats: ConnectivityStats;\n };\n}\n\n/**\n * Orchestrates the full audit pipeline\n */\nexport class AuditOrchestrator {\n private catalog: RelationshipCatalog;\n private graph: RelationshipGraph;\n private coverageAnalyzer: CoverageAnalyzer;\n private duplicateDetector: DuplicateDetector;\n private gapAnalyzer: GapAnalyzer;\n private balanceAssessor: BalanceAssessor;\n private connectivityAnalyzer: ConnectivityAnalyzer;\n private initialized = false;\n\n constructor() {\n this.catalog = new RelationshipCatalog();\n this.graph = new RelationshipGraph();\n\n this.coverageAnalyzer = new CoverageAnalyzer(this.catalog);\n this.duplicateDetector = new DuplicateDetector(this.catalog);\n this.gapAnalyzer = new GapAnalyzer();\n this.balanceAssessor = new BalanceAssessor();\n this.connectivityAnalyzer = new ConnectivityAnalyzer(this.graph, this.catalog);\n }\n\n /**\n * Initialize the orchestrator (must be called before running audit)\n */\n async initialize(): Promise<void> {\n if (!this.initialized) {\n await this.catalog.load();\n this.initialized = true;\n }\n }\n\n /**\n * Get predicates applicable to a specific layer\n * Useful for AI evaluation to provide available relationship types\n */\n getPredicatesForLayer(layer: string): string[] {\n const relationshipTypes = this.catalog.getTypesForLayer(layer);\n return relationshipTypes.map((t) => t.predicate);\n }\n\n /**\n * Run coverage analysis\n */\n async runCoverageAnalysis(options: AuditOptions): Promise<CoverageMetrics[]> {\n this.log(options, \"Running coverage analysis...\");\n\n if (options.layer) {\n const layer = getLayerById(options.layer);\n if (!layer) {\n const allLayers = getAllLayers();\n const validLayerNames = allLayers.map((l) => l.id).join(\", \");\n throw new Error(\n `Layer not found: '${options.layer}'. Valid layers: ${validLayerNames}`\n );\n }\n const metrics = await this.coverageAnalyzer.analyzeLayer(layer);\n return [metrics];\n }\n const result = await this.coverageAnalyzer.analyzeAll();\n return result.results;\n }\n\n /**\n * Run duplicate detection\n */\n async runDuplicateDetection(\n options: AuditOptions\n ): Promise<DuplicateCandidate[]> {\n this.log(options, \"Running duplicate detection...\");\n\n if (options.layer) {\n const layer = getLayerById(options.layer);\n if (!layer) {\n throw new Error(`Layer not found: ${options.layer}`);\n }\n return this.duplicateDetector.detectDuplicatesByLayer(layer.id);\n }\n return this.duplicateDetector.detectDuplicates();\n }\n\n /**\n * Run gap analysis\n */\n async runGapAnalysis(options: AuditOptions): Promise<GapCandidate[]> {\n this.log(options, \"Running gap analysis...\");\n\n if (options.layer) {\n const layer = getLayerById(options.layer);\n if (!layer) {\n throw new Error(`Layer not found: ${options.layer}`);\n }\n return this.gapAnalyzer.analyzeLayer(layer);\n }\n return this.gapAnalyzer.analyzeAll();\n }\n\n /**\n * Run balance assessment\n */\n async runBalanceAssessment(options: AuditOptions): Promise<BalanceAssessment[]> {\n this.log(options, \"Running balance assessment...\");\n\n if (options.layer) {\n const layer = getLayerById(options.layer);\n if (!layer) {\n throw new Error(`Layer not found: ${options.layer}`);\n }\n return this.balanceAssessor.assessLayer(layer);\n }\n return this.balanceAssessor.assessAll();\n }\n\n /**\n * Run connectivity analysis\n */\n async runConnectivityAnalysis(options: AuditOptions): Promise<{\n components: ReturnType<ConnectivityAnalyzer[\"findConnectedComponents\"]>;\n degrees: ReturnType<ConnectivityAnalyzer[\"calculateDegreeDistribution\"]>;\n transitiveChains: Awaited<\n ReturnType<ConnectivityAnalyzer[\"findTransitiveChains\"]>\n >;\n stats: ConnectivityStats;\n }> {\n this.log(options, \"Running connectivity analysis...\");\n\n // Build the graph first if analyzing a specific layer or all relationships\n const layerId = options.layer ? getLayerById(options.layer)?.id : undefined;\n await this.graph.build(layerId);\n\n const components = this.connectivityAnalyzer.findConnectedComponents();\n const degrees = this.connectivityAnalyzer.calculateDegreeDistribution();\n const transitiveChains =\n await this.connectivityAnalyzer.findTransitiveChains();\n const rawStats = this.connectivityAnalyzer.getConnectivityStats();\n\n // Convert connectivity stats to match AuditReport format\n const stats: ConnectivityStats = {\n totalNodes: rawStats.nodeCount,\n totalEdges: rawStats.edgeCount,\n connectedComponents: rawStats.componentCount,\n largestComponentSize: rawStats.largestComponentSize,\n isolatedNodes: rawStats.isolatedNodeCount,\n averageDegree: rawStats.averageDegree,\n transitiveChainCount: transitiveChains.length,\n };\n\n return { components, degrees, transitiveChains, stats };\n }\n\n /**\n * Load model metadata from manifest\n */\n async loadModelMetadata(options: AuditOptions): Promise<{\n name: string;\n version: string;\n }> {\n this.log(options, \"Loading model metadata...\");\n\n const projectRoot = options.projectRoot || process.cwd();\n const defaultMetadata = {\n name: \"Documentation Robotics Model\",\n version: \"1.0.0\",\n };\n\n try {\n const manifestPath = join(\n projectRoot,\n \"documentation-robotics\",\n \"model\",\n \"manifest.yaml\"\n );\n const manifestContent = await readFile(manifestPath, \"utf-8\");\n let manifest: { name?: string; version?: string; project?: { name?: string; version?: string } };\n\n try {\n manifest = yaml.parse(manifestContent) as typeof manifest;\n } catch (parseError: unknown) {\n // YAML parsing failed - file is corrupt\n const parseErrorMsg = getErrorMessage(parseError);\n console.warn(\n `\u26A0\uFE0F Warning: Manifest file is corrupted or has invalid YAML syntax (${parseErrorMsg}). Using default model metadata.`\n );\n return defaultMetadata;\n }\n\n // Name may be at top level or nested under project.name (CLI-generated manifests)\n const name = manifest.name || manifest.project?.name;\n // Version may be at top level or nested under project.version; top-level version is\n // the manifest schema version, so prefer project.version when available\n const version = manifest.project?.version || manifest.version;\n\n if (!name || typeof name !== \"string\") {\n console.warn(\n `\u26A0\uFE0F Warning: Manifest missing required field 'name'. Using default model metadata.`\n );\n return defaultMetadata;\n }\n if (!version || typeof version !== \"string\") {\n console.warn(\n `\u26A0\uFE0F Warning: Manifest missing required field 'version'. Using default model metadata.`\n );\n return defaultMetadata;\n }\n\n return { name, version };\n } catch (error: unknown) {\n // Distinguish between file not found vs read error\n const errorMsg = getErrorMessage(error);\n if (errorMsg.includes(\"ENOENT\") || errorMsg.includes(\"no such file\")) {\n // File not found - expected in tests, use defaults silently\n this.log(\n options,\n \"Using default model metadata (manifest not found)\"\n );\n } else {\n // File exists but cannot be read (permissions, disk error, etc)\n console.warn(\n `\u26A0\uFE0F Warning: Cannot read manifest file (${errorMsg}). Using default model metadata.`\n );\n }\n return defaultMetadata;\n }\n }\n\n /**\n * Run complete audit and build report\n */\n async runAudit(options: AuditOptions = {}): Promise<AuditReport> {\n // Ensure catalog is loaded before running analysis\n await this.initialize();\n\n const coverage = await this.runCoverageAnalysis(options);\n const duplicates = await this.runDuplicateDetection(options);\n const gaps = await this.runGapAnalysis(options);\n const balance = await this.runBalanceAssessment(options);\n const connectivity = await this.runConnectivityAnalysis(options);\n const modelMetadata = await this.loadModelMetadata(options);\n\n this.log(options, \"Generating audit report...\");\n\n return {\n timestamp: new Date().toISOString(),\n model: modelMetadata,\n coverage,\n duplicates,\n gaps,\n balance,\n connectivity,\n };\n }\n\n /**\n * Log helper that respects verbose/debug flags\n */\n private log(options: AuditOptions, message: string): void {\n if (options.verbose || options.debug) {\n console.error(message);\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,5 @@
1
+ import { ReportGenerator } from "./report-generator.js";
2
+ export {
3
+ ReportGenerator
4
+ };
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/audit/reports/index.ts"],
4
+ "sourcesContent": ["export { ReportGenerator, type ReportOptions, type ReportMetadata } from \"./report-generator.js\";\n"],
5
+ "mappings": "AAAA,SAAS,uBAAgE;",
6
+ "names": []
7
+ }
@@ -0,0 +1,118 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ class ReportGenerator {
4
+ /**
5
+ * Generate a complete audit report
6
+ */
7
+ async generateReport(result, options) {
8
+ try {
9
+ await fs.mkdir(options.outputDir, { recursive: !0 });
10
+ } catch (error) {
11
+ const errorMsg = error instanceof Error ? error.message : String(error);
12
+ throw new Error(`Failed to create output directory for ${options.format} report at ${options.outputDir}: ${errorMsg}`);
13
+ }
14
+ const totalNodeTypes = result.coverage.reduce((sum, c) => sum + c.nodeTypeCount, 0), totalRelationships = result.coverage.reduce((sum, c) => sum + c.relationshipCount, 0), metadata = {
15
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
16
+ phase: options.phase,
17
+ layer: options.layer,
18
+ totalNodeTypes,
19
+ totalRelationships
20
+ };
21
+ let reportContent, filename;
22
+ switch (options.format) {
23
+ case "json":
24
+ reportContent = this.generateJsonReport(result, metadata), filename = `audit-${options.phase}.json`;
25
+ break;
26
+ case "markdown":
27
+ reportContent = this.generateMarkdownReport(result, metadata, options.verbose), filename = `audit-${options.phase}.md`;
28
+ break;
29
+ case "text":
30
+ default:
31
+ reportContent = this.generateTextReport(result, metadata, options.verbose), filename = `audit-${options.phase}.txt`;
32
+ break;
33
+ }
34
+ const outputPath = path.join(options.outputDir, filename);
35
+ try {
36
+ await fs.writeFile(outputPath, reportContent, "utf-8");
37
+ } catch (error) {
38
+ const errorMsg = error instanceof Error ? error.message : String(error);
39
+ throw new Error(`Failed to write ${options.format} report to ${outputPath}: ${errorMsg}`);
40
+ }
41
+ return outputPath;
42
+ }
43
+ /**
44
+ * Generate JSON format report
45
+ */
46
+ generateJsonReport(result, metadata) {
47
+ return JSON.stringify({
48
+ metadata,
49
+ ...result
50
+ }, null, 2);
51
+ }
52
+ /**
53
+ * Generate Markdown format report
54
+ */
55
+ generateMarkdownReport(result, metadata, verbose = !1) {
56
+ const lines = [];
57
+ if (lines.push(`# Relationship Audit Report - ${metadata.phase.toUpperCase()}`), lines.push(""), lines.push(`**Timestamp**: ${metadata.timestamp}`), metadata.layer && lines.push(`**Layer**: ${metadata.layer}`), lines.push(`**Total Node Types**: ${metadata.totalNodeTypes}`), lines.push(`**Total Relationships**: ${metadata.totalRelationships}`), lines.push(""), result.coverage && result.coverage.length > 0 && (lines.push("## Coverage Metrics"), lines.push(""), result.coverage.forEach((coverage) => {
58
+ lines.push(`### Layer: ${coverage.layer}`), lines.push(`- **Isolation Rate**: ${coverage.isolationPercentage.toFixed(1)}%`), lines.push(`- **Density**: ${coverage.relationshipsPerNodeType.toFixed(2)} relationships/node type`), lines.push(`- **Predicate Utilization**: ${coverage.utilizationPercentage.toFixed(1)}%`), lines.push(""), verbose && coverage.isolatedNodeTypes.length > 0 && (lines.push("#### Isolated Node Types"), coverage.isolatedNodeTypes.forEach((nodeType) => {
59
+ lines.push(`- ${nodeType}`);
60
+ }), lines.push(""));
61
+ })), result.gaps && result.gaps.length > 0) {
62
+ lines.push("## Gap Analysis"), lines.push(""), lines.push(`Total Gaps Found: ${result.gaps.length}`), lines.push("");
63
+ const highPriorityGaps = result.gaps.filter((g) => g.priority === "high");
64
+ if (highPriorityGaps.length > 0 && (lines.push("### High Priority Gaps"), highPriorityGaps.forEach((gap) => {
65
+ lines.push(`- **${gap.sourceNodeType}** \u2192 **${gap.destinationNodeType}**: ${gap.suggestedPredicate} - ${gap.reason}`);
66
+ }), lines.push("")), verbose) {
67
+ const mediumPriorityGaps = result.gaps.filter((g) => g.priority === "medium");
68
+ mediumPriorityGaps.length > 0 && (lines.push("### Medium Priority Gaps"), mediumPriorityGaps.forEach((gap) => {
69
+ lines.push(`- **${gap.sourceNodeType}** \u2192 **${gap.destinationNodeType}**: ${gap.suggestedPredicate} - ${gap.reason}`);
70
+ }), lines.push(""));
71
+ }
72
+ }
73
+ if (result.duplicates && result.duplicates.length > 0 && (lines.push("## Duplicate Candidates"), lines.push(""), lines.push(`Total Duplicates Found: ${result.duplicates.length}`), lines.push(""), result.duplicates.slice(0, verbose ? void 0 : 10).forEach((dup) => {
74
+ lines.push(`- ${dup.relationships[0]} \u2194 ${dup.relationships[1]}`), lines.push(` - Predicates: ${dup.predicates[0]} / ${dup.predicates[1]}`), lines.push(` - Reason: ${dup.reason}`), lines.push(` - Confidence: ${dup.confidence}`);
75
+ }), lines.push("")), result.balance && result.balance.length > 0) {
76
+ lines.push("## Balance Analysis"), lines.push("");
77
+ const summary = this.summarizeBalance(result.balance);
78
+ lines.push(`- **Structural Node Types**: ${summary.structural}`), lines.push(`- **Behavioral Node Types**: ${summary.behavioral}`), lines.push(`- **Under-connected**: ${summary.under}`), lines.push(`- **Well-balanced**: ${summary.balanced}`), lines.push(`- **Over-connected**: ${summary.over}`), lines.push("");
79
+ }
80
+ return result.connectivity && (lines.push("## Connectivity"), lines.push(""), lines.push(`- **Connected Components**: ${result.connectivity.stats.connectedComponents}`), lines.push(`- **Largest Component**: ${result.connectivity.stats.largestComponentSize} nodes`), lines.push(`- **Isolated Nodes**: ${result.connectivity.stats.isolatedNodes}`), lines.push(`- **Average Degree**: ${result.connectivity.stats.averageDegree.toFixed(2)}`), lines.push("")), lines.join(`
81
+ `);
82
+ }
83
+ /**
84
+ * Summarize balance assessments
85
+ */
86
+ summarizeBalance(balance) {
87
+ return {
88
+ structural: balance.filter((b) => b.category === "structural").length,
89
+ behavioral: balance.filter((b) => b.category === "behavioral").length,
90
+ under: balance.filter((b) => b.status === "under").length,
91
+ balanced: balance.filter((b) => b.status === "balanced").length,
92
+ over: balance.filter((b) => b.status === "over").length
93
+ };
94
+ }
95
+ /**
96
+ * Generate Text format report
97
+ */
98
+ generateTextReport(result, metadata, verbose = !1) {
99
+ const lines = [];
100
+ if (lines.push("=".repeat(80)), lines.push(`RELATIONSHIP AUDIT REPORT - ${metadata.phase.toUpperCase()}`), lines.push("=".repeat(80)), lines.push(""), lines.push(`Timestamp: ${metadata.timestamp}`), metadata.layer && lines.push(`Layer: ${metadata.layer}`), lines.push(`Total Node Types: ${metadata.totalNodeTypes}`), lines.push(`Total Relationships: ${metadata.totalRelationships}`), lines.push(""), result.coverage && result.coverage.length > 0 && (lines.push("-".repeat(80)), lines.push("COVERAGE METRICS"), lines.push("-".repeat(80)), result.coverage.forEach((coverage) => {
101
+ lines.push(`Layer: ${coverage.layer}`), lines.push(` Isolation Rate: ${coverage.isolationPercentage.toFixed(1)}%`), lines.push(` Density: ${coverage.relationshipsPerNodeType.toFixed(2)} relationships/node type`), lines.push(` Predicate Utilization: ${coverage.utilizationPercentage.toFixed(1)}%`), lines.push("");
102
+ })), result.gaps && result.gaps.length > 0) {
103
+ lines.push("-".repeat(80)), lines.push("GAP ANALYSIS"), lines.push("-".repeat(80)), lines.push(`Total Gaps: ${result.gaps.length}`), lines.push("");
104
+ const highPriorityGaps = result.gaps.filter((g) => g.priority === "high");
105
+ highPriorityGaps.length > 0 && (lines.push("High Priority Gaps:"), highPriorityGaps.forEach((gap, i) => {
106
+ lines.push(` ${i + 1}. ${gap.sourceNodeType} \u2192 ${gap.destinationNodeType}`), lines.push(` ${gap.suggestedPredicate}: ${gap.reason}`);
107
+ }), lines.push(""));
108
+ }
109
+ return result.duplicates && result.duplicates.length > 0 && (lines.push("-".repeat(80)), lines.push("DUPLICATE CANDIDATES"), lines.push("-".repeat(80)), lines.push(`Total Duplicates: ${result.duplicates.length}`), lines.push(""), result.duplicates.slice(0, verbose ? void 0 : 10).forEach((dup, i) => {
110
+ lines.push(` ${i + 1}. ${dup.relationships[0]} \u2194 ${dup.relationships[1]}`), lines.push(` Predicates: ${dup.predicates[0]} / ${dup.predicates[1]}`), lines.push(` ${dup.reason} (${dup.confidence})`);
111
+ }), lines.push("")), result.connectivity && (lines.push("-".repeat(80)), lines.push("CONNECTIVITY"), lines.push("-".repeat(80)), lines.push(`Connected Components: ${result.connectivity.stats.connectedComponents}`), lines.push(`Largest Component: ${result.connectivity.stats.largestComponentSize} nodes`), lines.push(`Isolated Nodes: ${result.connectivity.stats.isolatedNodes}`), lines.push(`Average Degree: ${result.connectivity.stats.averageDegree.toFixed(2)}`), lines.push("")), lines.push("=".repeat(80)), lines.join(`
112
+ `);
113
+ }
114
+ }
115
+ export {
116
+ ReportGenerator
117
+ };
118
+ //# sourceMappingURL=report-generator.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/audit/reports/report-generator.ts"],
4
+ "sourcesContent": ["import fs from \"fs/promises\";\nimport path from \"path\";\nimport type { AuditReport, GapCandidate, DuplicateCandidate, BalanceAssessment } from \"../types.js\";\n\nexport interface ReportOptions {\n /**\n * Phase of the audit pipeline - before or after AI evaluation\n */\n phase: \"before\" | \"after\";\n\n /**\n * Output directory for the report\n */\n outputDir: string;\n\n /**\n * Report format\n */\n format: \"text\" | \"json\" | \"markdown\";\n\n /**\n * Layer name (if audit is layer-specific)\n */\n layer?: string;\n\n /**\n * Whether to include verbose details\n */\n verbose?: boolean;\n}\n\nexport interface ReportMetadata {\n timestamp: string;\n phase: \"before\" | \"after\";\n layer?: string;\n totalNodeTypes: number;\n totalRelationships: number;\n}\n\n/**\n * Generates audit reports with support for before/after phases\n */\nexport class ReportGenerator {\n /**\n * Generate a complete audit report\n */\n async generateReport(\n result: AuditReport,\n options: ReportOptions\n ): Promise<string> {\n // Ensure output directory exists\n try {\n await fs.mkdir(options.outputDir, { recursive: true });\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to create output directory for ${options.format} report at ${options.outputDir}: ${errorMsg}`\n );\n }\n\n // Calculate totals from all layers\n const totalNodeTypes = result.coverage.reduce((sum, c) => sum + c.nodeTypeCount, 0);\n const totalRelationships = result.coverage.reduce((sum, c) => sum + c.relationshipCount, 0);\n\n const metadata: ReportMetadata = {\n timestamp: new Date().toISOString(),\n phase: options.phase,\n layer: options.layer,\n totalNodeTypes,\n totalRelationships,\n };\n\n // Generate report based on format\n let reportContent: string;\n let filename: string;\n\n switch (options.format) {\n case \"json\":\n reportContent = this.generateJsonReport(result, metadata);\n filename = `audit-${options.phase}.json`;\n break;\n case \"markdown\":\n reportContent = this.generateMarkdownReport(result, metadata, options.verbose);\n filename = `audit-${options.phase}.md`;\n break;\n case \"text\":\n default:\n reportContent = this.generateTextReport(result, metadata, options.verbose);\n filename = `audit-${options.phase}.txt`;\n break;\n }\n\n const outputPath = path.join(options.outputDir, filename);\n try {\n await fs.writeFile(outputPath, reportContent, \"utf-8\");\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to write ${options.format} report to ${outputPath}: ${errorMsg}`\n );\n }\n\n return outputPath;\n }\n\n /**\n * Generate JSON format report\n */\n private generateJsonReport(\n result: AuditReport,\n metadata: ReportMetadata\n ): string {\n return JSON.stringify(\n {\n metadata,\n ...result,\n },\n null,\n 2\n );\n }\n\n /**\n * Generate Markdown format report\n */\n private generateMarkdownReport(\n result: AuditReport,\n metadata: ReportMetadata,\n verbose = false\n ): string {\n const lines: string[] = [];\n\n // Header\n lines.push(`# Relationship Audit Report - ${metadata.phase.toUpperCase()}`);\n lines.push(\"\");\n lines.push(`**Timestamp**: ${metadata.timestamp}`);\n if (metadata.layer) {\n lines.push(`**Layer**: ${metadata.layer}`);\n }\n lines.push(`**Total Node Types**: ${metadata.totalNodeTypes}`);\n lines.push(`**Total Relationships**: ${metadata.totalRelationships}`);\n lines.push(\"\");\n\n // Coverage Section\n if (result.coverage && result.coverage.length > 0) {\n lines.push(\"## Coverage Metrics\");\n lines.push(\"\");\n\n result.coverage.forEach((coverage) => {\n lines.push(`### Layer: ${coverage.layer}`);\n lines.push(`- **Isolation Rate**: ${coverage.isolationPercentage.toFixed(1)}%`);\n lines.push(`- **Density**: ${coverage.relationshipsPerNodeType.toFixed(2)} relationships/node type`);\n lines.push(`- **Predicate Utilization**: ${coverage.utilizationPercentage.toFixed(1)}%`);\n lines.push(\"\");\n\n if (verbose && coverage.isolatedNodeTypes.length > 0) {\n lines.push(\"#### Isolated Node Types\");\n coverage.isolatedNodeTypes.forEach((nodeType: string) => {\n lines.push(`- ${nodeType}`);\n });\n lines.push(\"\");\n }\n });\n }\n\n // Gap Analysis Section\n if (result.gaps && result.gaps.length > 0) {\n lines.push(\"## Gap Analysis\");\n lines.push(\"\");\n lines.push(`Total Gaps Found: ${result.gaps.length}`);\n lines.push(\"\");\n\n const highPriorityGaps = result.gaps.filter((g: GapCandidate) => g.priority === \"high\");\n if (highPriorityGaps.length > 0) {\n lines.push(\"### High Priority Gaps\");\n highPriorityGaps.forEach((gap: GapCandidate) => {\n lines.push(`- **${gap.sourceNodeType}** \u2192 **${gap.destinationNodeType}**: ${gap.suggestedPredicate} - ${gap.reason}`);\n });\n lines.push(\"\");\n }\n\n if (verbose) {\n const mediumPriorityGaps = result.gaps.filter((g: GapCandidate) => g.priority === \"medium\");\n if (mediumPriorityGaps.length > 0) {\n lines.push(\"### Medium Priority Gaps\");\n mediumPriorityGaps.forEach((gap: GapCandidate) => {\n lines.push(`- **${gap.sourceNodeType}** \u2192 **${gap.destinationNodeType}**: ${gap.suggestedPredicate} - ${gap.reason}`);\n });\n lines.push(\"\");\n }\n }\n }\n\n // Duplicates Section\n if (result.duplicates && result.duplicates.length > 0) {\n lines.push(\"## Duplicate Candidates\");\n lines.push(\"\");\n lines.push(`Total Duplicates Found: ${result.duplicates.length}`);\n lines.push(\"\");\n\n result.duplicates.slice(0, verbose ? undefined : 10).forEach((dup: DuplicateCandidate) => {\n lines.push(`- ${dup.relationships[0]} \u2194 ${dup.relationships[1]}`);\n lines.push(` - Predicates: ${dup.predicates[0]} / ${dup.predicates[1]}`);\n lines.push(` - Reason: ${dup.reason}`);\n lines.push(` - Confidence: ${dup.confidence}`);\n });\n lines.push(\"\");\n }\n\n // Balance Section\n if (result.balance && result.balance.length > 0) {\n lines.push(\"## Balance Analysis\");\n lines.push(\"\");\n\n const summary = this.summarizeBalance(result.balance as BalanceAssessment[]);\n lines.push(`- **Structural Node Types**: ${summary.structural}`);\n lines.push(`- **Behavioral Node Types**: ${summary.behavioral}`);\n lines.push(`- **Under-connected**: ${summary.under}`);\n lines.push(`- **Well-balanced**: ${summary.balanced}`);\n lines.push(`- **Over-connected**: ${summary.over}`);\n lines.push(\"\");\n }\n\n // Connectivity Section\n if (result.connectivity) {\n lines.push(\"## Connectivity\");\n lines.push(\"\");\n lines.push(`- **Connected Components**: ${result.connectivity.stats.connectedComponents}`);\n lines.push(`- **Largest Component**: ${result.connectivity.stats.largestComponentSize} nodes`);\n lines.push(`- **Isolated Nodes**: ${result.connectivity.stats.isolatedNodes}`);\n lines.push(`- **Average Degree**: ${result.connectivity.stats.averageDegree.toFixed(2)}`);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n }\n\n /**\n * Summarize balance assessments\n */\n private summarizeBalance(balance: BalanceAssessment[]): {\n structural: number;\n behavioral: number;\n under: number;\n balanced: number;\n over: number;\n } {\n return {\n structural: balance.filter((b) => b.category === \"structural\").length,\n behavioral: balance.filter((b) => b.category === \"behavioral\").length,\n under: balance.filter((b) => b.status === \"under\").length,\n balanced: balance.filter((b) => b.status === \"balanced\").length,\n over: balance.filter((b) => b.status === \"over\").length,\n };\n }\n\n /**\n * Generate Text format report\n */\n private generateTextReport(\n result: AuditReport,\n metadata: ReportMetadata,\n verbose = false\n ): string {\n const lines: string[] = [];\n\n // Header\n lines.push(\"=\".repeat(80));\n lines.push(`RELATIONSHIP AUDIT REPORT - ${metadata.phase.toUpperCase()}`);\n lines.push(\"=\".repeat(80));\n lines.push(\"\");\n lines.push(`Timestamp: ${metadata.timestamp}`);\n if (metadata.layer) {\n lines.push(`Layer: ${metadata.layer}`);\n }\n lines.push(`Total Node Types: ${metadata.totalNodeTypes}`);\n lines.push(`Total Relationships: ${metadata.totalRelationships}`);\n lines.push(\"\");\n\n // Coverage Section\n if (result.coverage && result.coverage.length > 0) {\n lines.push(\"-\".repeat(80));\n lines.push(\"COVERAGE METRICS\");\n lines.push(\"-\".repeat(80));\n\n result.coverage.forEach((coverage) => {\n lines.push(`Layer: ${coverage.layer}`);\n lines.push(` Isolation Rate: ${coverage.isolationPercentage.toFixed(1)}%`);\n lines.push(` Density: ${coverage.relationshipsPerNodeType.toFixed(2)} relationships/node type`);\n lines.push(` Predicate Utilization: ${coverage.utilizationPercentage.toFixed(1)}%`);\n lines.push(\"\");\n });\n }\n\n // Gap Analysis Section\n if (result.gaps && result.gaps.length > 0) {\n lines.push(\"-\".repeat(80));\n lines.push(\"GAP ANALYSIS\");\n lines.push(\"-\".repeat(80));\n lines.push(`Total Gaps: ${result.gaps.length}`);\n lines.push(\"\");\n\n const highPriorityGaps = result.gaps.filter((g: GapCandidate) => g.priority === \"high\");\n if (highPriorityGaps.length > 0) {\n lines.push(\"High Priority Gaps:\");\n highPriorityGaps.forEach((gap: GapCandidate, i: number) => {\n lines.push(` ${i + 1}. ${gap.sourceNodeType} \u2192 ${gap.destinationNodeType}`);\n lines.push(` ${gap.suggestedPredicate}: ${gap.reason}`);\n });\n lines.push(\"\");\n }\n }\n\n // Duplicates Section\n if (result.duplicates && result.duplicates.length > 0) {\n lines.push(\"-\".repeat(80));\n lines.push(\"DUPLICATE CANDIDATES\");\n lines.push(\"-\".repeat(80));\n lines.push(`Total Duplicates: ${result.duplicates.length}`);\n lines.push(\"\");\n\n result.duplicates.slice(0, verbose ? undefined : 10).forEach((dup: DuplicateCandidate, i: number) => {\n lines.push(` ${i + 1}. ${dup.relationships[0]} \u2194 ${dup.relationships[1]}`);\n lines.push(` Predicates: ${dup.predicates[0]} / ${dup.predicates[1]}`);\n lines.push(` ${dup.reason} (${dup.confidence})`);\n });\n lines.push(\"\");\n }\n\n // Connectivity Section\n if (result.connectivity) {\n lines.push(\"-\".repeat(80));\n lines.push(\"CONNECTIVITY\");\n lines.push(\"-\".repeat(80));\n lines.push(`Connected Components: ${result.connectivity.stats.connectedComponents}`);\n lines.push(`Largest Component: ${result.connectivity.stats.largestComponentSize} nodes`);\n lines.push(`Isolated Nodes: ${result.connectivity.stats.isolatedNodes}`);\n lines.push(`Average Degree: ${result.connectivity.stats.averageDegree.toFixed(2)}`);\n lines.push(\"\");\n }\n\n lines.push(\"=\".repeat(80));\n\n return lines.join(\"\\n\");\n }\n}\n"],
5
+ "mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AAyCX,MAAO,gBAAe;;;;EAI1B,MAAM,eACJ,QACA,SAAsB;AAGtB,QAAI;AACF,YAAM,GAAG,MAAM,QAAQ,WAAW,EAAE,WAAW,GAAI,CAAE;IACvD,SAAS,OAAO;AACd,YAAM,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACtE,YAAM,IAAI,MACR,yCAAyC,QAAQ,MAAM,cAAc,QAAQ,SAAS,KAAK,QAAQ,EAAE;IAEzG;AAGA,UAAM,iBAAiB,OAAO,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,eAAe,CAAC,GAC5E,qBAAqB,OAAO,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,mBAAmB,CAAC,GAEpF,WAA2B;MAC/B,YAAW,oBAAI,KAAI,GAAG,YAAW;MACjC,OAAO,QAAQ;MACf,OAAO,QAAQ;MACf;MACA;;AAIF,QAAI,eACA;AAEJ,YAAQ,QAAQ,QAAQ;MACtB,KAAK;AACH,wBAAgB,KAAK,mBAAmB,QAAQ,QAAQ,GACxD,WAAW,SAAS,QAAQ,KAAK;AACjC;MACF,KAAK;AACH,wBAAgB,KAAK,uBAAuB,QAAQ,UAAU,QAAQ,OAAO,GAC7E,WAAW,SAAS,QAAQ,KAAK;AACjC;MACF,KAAK;MACL;AACE,wBAAgB,KAAK,mBAAmB,QAAQ,UAAU,QAAQ,OAAO,GACzE,WAAW,SAAS,QAAQ,KAAK;AACjC;IACJ;AAEA,UAAM,aAAa,KAAK,KAAK,QAAQ,WAAW,QAAQ;AACxD,QAAI;AACF,YAAM,GAAG,UAAU,YAAY,eAAe,OAAO;IACvD,SAAS,OAAO;AACd,YAAM,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACtE,YAAM,IAAI,MACR,mBAAmB,QAAQ,MAAM,cAAc,UAAU,KAAK,QAAQ,EAAE;IAE5E;AAEA,WAAO;EACT;;;;EAKQ,mBACN,QACA,UAAwB;AAExB,WAAO,KAAK,UACV;MACE;MACA,GAAG;OAEL,MACA,CAAC;EAEL;;;;EAKQ,uBACN,QACA,UACA,UAAU,IAAK;AAEf,UAAM,QAAkB,CAAA;AAoCxB,QAjCA,MAAM,KAAK,iCAAiC,SAAS,MAAM,YAAW,CAAE,EAAE,GAC1E,MAAM,KAAK,EAAE,GACb,MAAM,KAAK,kBAAkB,SAAS,SAAS,EAAE,GAC7C,SAAS,SACX,MAAM,KAAK,cAAc,SAAS,KAAK,EAAE,GAE3C,MAAM,KAAK,yBAAyB,SAAS,cAAc,EAAE,GAC7D,MAAM,KAAK,4BAA4B,SAAS,kBAAkB,EAAE,GACpE,MAAM,KAAK,EAAE,GAGT,OAAO,YAAY,OAAO,SAAS,SAAS,MAC9C,MAAM,KAAK,qBAAqB,GAChC,MAAM,KAAK,EAAE,GAEb,OAAO,SAAS,QAAQ,CAAC,aAAY;AACnC,YAAM,KAAK,cAAc,SAAS,KAAK,EAAE,GACzC,MAAM,KAAK,yBAAyB,SAAS,oBAAoB,QAAQ,CAAC,CAAC,GAAG,GAC9E,MAAM,KAAK,kBAAkB,SAAS,yBAAyB,QAAQ,CAAC,CAAC,0BAA0B,GACnG,MAAM,KAAK,gCAAgC,SAAS,sBAAsB,QAAQ,CAAC,CAAC,GAAG,GACvF,MAAM,KAAK,EAAE,GAET,WAAW,SAAS,kBAAkB,SAAS,MACjD,MAAM,KAAK,0BAA0B,GACrC,SAAS,kBAAkB,QAAQ,CAAC,aAAoB;AACtD,cAAM,KAAK,KAAK,QAAQ,EAAE;MAC5B,CAAC,GACD,MAAM,KAAK,EAAE;IAEjB,CAAC,IAIC,OAAO,QAAQ,OAAO,KAAK,SAAS,GAAG;AACzC,YAAM,KAAK,iBAAiB,GAC5B,MAAM,KAAK,EAAE,GACb,MAAM,KAAK,qBAAqB,OAAO,KAAK,MAAM,EAAE,GACpD,MAAM,KAAK,EAAE;AAEb,YAAM,mBAAmB,OAAO,KAAK,OAAO,CAAC,MAAoB,EAAE,aAAa,MAAM;AAStF,UARI,iBAAiB,SAAS,MAC5B,MAAM,KAAK,wBAAwB,GACnC,iBAAiB,QAAQ,CAAC,QAAqB;AAC7C,cAAM,KAAK,OAAO,IAAI,cAAc,eAAU,IAAI,mBAAmB,OAAO,IAAI,kBAAkB,MAAM,IAAI,MAAM,EAAE;MACtH,CAAC,GACD,MAAM,KAAK,EAAE,IAGX,SAAS;AACX,cAAM,qBAAqB,OAAO,KAAK,OAAO,CAAC,MAAoB,EAAE,aAAa,QAAQ;AAC1F,QAAI,mBAAmB,SAAS,MAC9B,MAAM,KAAK,0BAA0B,GACrC,mBAAmB,QAAQ,CAAC,QAAqB;AAC/C,gBAAM,KAAK,OAAO,IAAI,cAAc,eAAU,IAAI,mBAAmB,OAAO,IAAI,kBAAkB,MAAM,IAAI,MAAM,EAAE;QACtH,CAAC,GACD,MAAM,KAAK,EAAE;MAEjB;IACF;AAmBA,QAhBI,OAAO,cAAc,OAAO,WAAW,SAAS,MAClD,MAAM,KAAK,yBAAyB,GACpC,MAAM,KAAK,EAAE,GACb,MAAM,KAAK,2BAA2B,OAAO,WAAW,MAAM,EAAE,GAChE,MAAM,KAAK,EAAE,GAEb,OAAO,WAAW,MAAM,GAAG,UAAU,SAAY,EAAE,EAAE,QAAQ,CAAC,QAA2B;AACvF,YAAM,KAAK,KAAK,IAAI,cAAc,CAAC,CAAC,WAAM,IAAI,cAAc,CAAC,CAAC,EAAE,GAChE,MAAM,KAAK,mBAAmB,IAAI,WAAW,CAAC,CAAC,MAAM,IAAI,WAAW,CAAC,CAAC,EAAE,GACxE,MAAM,KAAK,eAAe,IAAI,MAAM,EAAE,GACtC,MAAM,KAAK,mBAAmB,IAAI,UAAU,EAAE;IAChD,CAAC,GACD,MAAM,KAAK,EAAE,IAIX,OAAO,WAAW,OAAO,QAAQ,SAAS,GAAG;AAC/C,YAAM,KAAK,qBAAqB,GAChC,MAAM,KAAK,EAAE;AAEb,YAAM,UAAU,KAAK,iBAAiB,OAAO,OAA8B;AAC3E,YAAM,KAAK,gCAAgC,QAAQ,UAAU,EAAE,GAC/D,MAAM,KAAK,gCAAgC,QAAQ,UAAU,EAAE,GAC/D,MAAM,KAAK,0BAA0B,QAAQ,KAAK,EAAE,GACpD,MAAM,KAAK,wBAAwB,QAAQ,QAAQ,EAAE,GACrD,MAAM,KAAK,yBAAyB,QAAQ,IAAI,EAAE,GAClD,MAAM,KAAK,EAAE;IACf;AAGA,WAAI,OAAO,iBACT,MAAM,KAAK,iBAAiB,GAC5B,MAAM,KAAK,EAAE,GACb,MAAM,KAAK,+BAA+B,OAAO,aAAa,MAAM,mBAAmB,EAAE,GACzF,MAAM,KAAK,4BAA4B,OAAO,aAAa,MAAM,oBAAoB,QAAQ,GAC7F,MAAM,KAAK,yBAAyB,OAAO,aAAa,MAAM,aAAa,EAAE,GAC7E,MAAM,KAAK,yBAAyB,OAAO,aAAa,MAAM,cAAc,QAAQ,CAAC,CAAC,EAAE,GACxF,MAAM,KAAK,EAAE,IAGR,MAAM,KAAK;CAAI;EACxB;;;;EAKQ,iBAAiB,SAA4B;AAOnD,WAAO;MACL,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,aAAa,YAAY,EAAE;MAC/D,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,aAAa,YAAY,EAAE;MAC/D,OAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,EAAE;MACnD,UAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EAAE;MACzD,MAAM,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;;EAErD;;;;EAKQ,mBACN,QACA,UACA,UAAU,IAAK;AAEf,UAAM,QAAkB,CAAA;AA+BxB,QA5BA,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,+BAA+B,SAAS,MAAM,YAAW,CAAE,EAAE,GACxE,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,EAAE,GACb,MAAM,KAAK,cAAc,SAAS,SAAS,EAAE,GACzC,SAAS,SACX,MAAM,KAAK,UAAU,SAAS,KAAK,EAAE,GAEvC,MAAM,KAAK,qBAAqB,SAAS,cAAc,EAAE,GACzD,MAAM,KAAK,wBAAwB,SAAS,kBAAkB,EAAE,GAChE,MAAM,KAAK,EAAE,GAGT,OAAO,YAAY,OAAO,SAAS,SAAS,MAC9C,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,kBAAkB,GAC7B,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GAEzB,OAAO,SAAS,QAAQ,CAAC,aAAY;AACnC,YAAM,KAAK,UAAU,SAAS,KAAK,EAAE,GACrC,MAAM,KAAK,qBAAqB,SAAS,oBAAoB,QAAQ,CAAC,CAAC,GAAG,GAC1E,MAAM,KAAK,cAAc,SAAS,yBAAyB,QAAQ,CAAC,CAAC,0BAA0B,GAC/F,MAAM,KAAK,4BAA4B,SAAS,sBAAsB,QAAQ,CAAC,CAAC,GAAG,GACnF,MAAM,KAAK,EAAE;IACf,CAAC,IAIC,OAAO,QAAQ,OAAO,KAAK,SAAS,GAAG;AACzC,YAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,cAAc,GACzB,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,eAAe,OAAO,KAAK,MAAM,EAAE,GAC9C,MAAM,KAAK,EAAE;AAEb,YAAM,mBAAmB,OAAO,KAAK,OAAO,CAAC,MAAoB,EAAE,aAAa,MAAM;AACtF,MAAI,iBAAiB,SAAS,MAC5B,MAAM,KAAK,qBAAqB,GAChC,iBAAiB,QAAQ,CAAC,KAAmB,MAAa;AACxD,cAAM,KAAK,KAAK,IAAI,CAAC,KAAK,IAAI,cAAc,WAAM,IAAI,mBAAmB,EAAE,GAC3E,MAAM,KAAK,QAAQ,IAAI,kBAAkB,KAAK,IAAI,MAAM,EAAE;MAC5D,CAAC,GACD,MAAM,KAAK,EAAE;IAEjB;AAGA,WAAI,OAAO,cAAc,OAAO,WAAW,SAAS,MAClD,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,sBAAsB,GACjC,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,qBAAqB,OAAO,WAAW,MAAM,EAAE,GAC1D,MAAM,KAAK,EAAE,GAEb,OAAO,WAAW,MAAM,GAAG,UAAU,SAAY,EAAE,EAAE,QAAQ,CAAC,KAAyB,MAAa;AAClG,YAAM,KAAK,KAAK,IAAI,CAAC,KAAK,IAAI,cAAc,CAAC,CAAC,WAAM,IAAI,cAAc,CAAC,CAAC,EAAE,GAC1E,MAAM,KAAK,oBAAoB,IAAI,WAAW,CAAC,CAAC,MAAM,IAAI,WAAW,CAAC,CAAC,EAAE,GACzE,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,UAAU,GAAG;IACrD,CAAC,GACD,MAAM,KAAK,EAAE,IAIX,OAAO,iBACT,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,cAAc,GACzB,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,yBAAyB,OAAO,aAAa,MAAM,mBAAmB,EAAE,GACnF,MAAM,KAAK,sBAAsB,OAAO,aAAa,MAAM,oBAAoB,QAAQ,GACvF,MAAM,KAAK,mBAAmB,OAAO,aAAa,MAAM,aAAa,EAAE,GACvE,MAAM,KAAK,mBAAmB,OAAO,aAAa,MAAM,cAAc,QAAQ,CAAC,CAAC,EAAE,GAClF,MAAM,KAAK,EAAE,IAGf,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GAElB,MAAM,KAAK;CAAI;EACxB;;",
6
+ "names": []
7
+ }
@@ -0,0 +1,163 @@
1
+ import { promises as fs } from "fs";
2
+ import * as path from "path";
3
+ class SnapshotStorage {
4
+ storageDir;
5
+ maxSnapshots;
6
+ constructor(config = {}) {
7
+ this.storageDir = config.storageDir || path.join(process.cwd(), ".dr", "audit-snapshots"), this.maxSnapshots = config.maxSnapshots || 0;
8
+ }
9
+ /**
10
+ * Initialize storage directory
11
+ */
12
+ async ensureStorageDir() {
13
+ await fs.mkdir(this.storageDir, { recursive: !0 });
14
+ }
15
+ /**
16
+ * Generate snapshot ID from timestamp
17
+ */
18
+ generateSnapshotId(timestamp) {
19
+ return new Date(timestamp).toISOString().replace(/[-:]/g, "").replace(/\..+/, "").replace("T", "-");
20
+ }
21
+ /**
22
+ * Get snapshot file path
23
+ */
24
+ getSnapshotPath(id) {
25
+ return path.join(this.storageDir, `${id}.json`);
26
+ }
27
+ /**
28
+ * Get metadata file path
29
+ */
30
+ getMetadataPath(id) {
31
+ return path.join(this.storageDir, `${id}.meta.json`);
32
+ }
33
+ /**
34
+ * Save an audit report as a snapshot
35
+ */
36
+ async save(report) {
37
+ await this.ensureStorageDir();
38
+ const id = this.generateSnapshotId(report.timestamp), snapshotPath = this.getSnapshotPath(id), metadataPath = this.getMetadataPath(id), layers = report.coverage.map((c) => c.layer), metadata = {
39
+ id,
40
+ timestamp: report.timestamp,
41
+ modelName: report.model.name,
42
+ modelVersion: report.model.version,
43
+ layers,
44
+ snapshotPath
45
+ };
46
+ try {
47
+ await fs.writeFile(snapshotPath, JSON.stringify(report, null, 2), "utf-8");
48
+ } catch (error) {
49
+ throw new Error(`Failed to write snapshot file ${snapshotPath}: ${error instanceof Error ? error.message : String(error)}`);
50
+ }
51
+ try {
52
+ await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2), "utf-8");
53
+ } catch (error) {
54
+ try {
55
+ await fs.unlink(snapshotPath);
56
+ } catch {
57
+ }
58
+ throw new Error(`Failed to write snapshot metadata ${metadataPath}: ${error instanceof Error ? error.message : String(error)}`);
59
+ }
60
+ return this.maxSnapshots > 0 && await this.cleanupOldSnapshots(), metadata;
61
+ }
62
+ /**
63
+ * Load a snapshot by ID or timestamp
64
+ */
65
+ async load(idOrTimestamp) {
66
+ await this.ensureStorageDir();
67
+ let id;
68
+ /^\d{8}-\d{6}$/.test(idOrTimestamp) ? id = idOrTimestamp : id = this.generateSnapshotId(idOrTimestamp);
69
+ const snapshotPath = this.getSnapshotPath(id);
70
+ try {
71
+ const content = await fs.readFile(snapshotPath, "utf-8");
72
+ return JSON.parse(content);
73
+ } catch (error) {
74
+ throw error.code === "ENOENT" ? new Error(`Snapshot not found: ${id}. Use 'dr audit snapshots' to list available snapshots.`) : new Error(`Failed to parse snapshot ${id}: ${error instanceof Error ? error.message : String(error)}`);
75
+ }
76
+ }
77
+ /**
78
+ * List all available snapshots
79
+ */
80
+ async list() {
81
+ await this.ensureStorageDir();
82
+ try {
83
+ const metadataFiles = (await fs.readdir(this.storageDir)).filter((f) => f.endsWith(".meta.json")), snapshots = [];
84
+ for (const file of metadataFiles) {
85
+ const content = await fs.readFile(path.join(this.storageDir, file), "utf-8");
86
+ snapshots.push(JSON.parse(content));
87
+ }
88
+ return snapshots.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
89
+ } catch (error) {
90
+ if (error.code === "ENOENT")
91
+ return [];
92
+ throw error;
93
+ }
94
+ }
95
+ /**
96
+ * Delete a snapshot
97
+ *
98
+ * Deletes both snapshot and metadata files sequentially with rollback on failure
99
+ * to prevent partial deletion state.
100
+ */
101
+ async delete(idOrTimestamp) {
102
+ await this.ensureStorageDir();
103
+ let id;
104
+ /^\d{8}-\d{6}$/.test(idOrTimestamp) ? id = idOrTimestamp : id = this.generateSnapshotId(idOrTimestamp);
105
+ const snapshotPath = this.getSnapshotPath(id), metadataPath = this.getMetadataPath(id);
106
+ try {
107
+ await fs.unlink(snapshotPath);
108
+ } catch (error) {
109
+ if (error.code !== "ENOENT")
110
+ throw new Error(`Failed to delete snapshot ${id}: ${error.message}`);
111
+ }
112
+ try {
113
+ await fs.unlink(metadataPath);
114
+ } catch (error) {
115
+ if (error.code !== "ENOENT")
116
+ throw new Error(`Failed to delete snapshot metadata ${id}: ${error.message}`);
117
+ }
118
+ }
119
+ /**
120
+ * Get the most recent snapshot
121
+ */
122
+ async getLatest() {
123
+ const snapshots = await this.list();
124
+ return snapshots.length === 0 ? null : this.load(snapshots[0].id);
125
+ }
126
+ /**
127
+ * Get the two most recent snapshots for comparison.
128
+ * Returns a tuple of [before, after] where 'before' is the older snapshot
129
+ * and 'after' is the more recent snapshot (for differential analysis).
130
+ * @returns [before, after] tuple where both are sorted chronologically, or [null, null] if fewer than 2 snapshots exist
131
+ */
132
+ async getLatestPair() {
133
+ const snapshots = await this.list();
134
+ if (snapshots.length < 2)
135
+ return [null, null];
136
+ const [after, before] = await Promise.all([
137
+ this.load(snapshots[0].id),
138
+ this.load(snapshots[1].id)
139
+ ]);
140
+ return [before, after];
141
+ }
142
+ /**
143
+ * Clean up old snapshots beyond the retention limit
144
+ */
145
+ async cleanupOldSnapshots() {
146
+ const snapshots = await this.list();
147
+ if (snapshots.length <= this.maxSnapshots)
148
+ return;
149
+ const toDelete = snapshots.slice(this.maxSnapshots);
150
+ await Promise.all(toDelete.map((s) => this.delete(s.id)));
151
+ }
152
+ /**
153
+ * Clear all snapshots
154
+ */
155
+ async clear() {
156
+ const snapshots = await this.list();
157
+ await Promise.all(snapshots.map((s) => this.delete(s.id)));
158
+ }
159
+ }
160
+ export {
161
+ SnapshotStorage
162
+ };
163
+ //# sourceMappingURL=snapshot-storage.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/audit/snapshot-storage.ts"],
4
+ "sourcesContent": ["/**\n * Audit snapshot storage and management\n *\n * Provides persistence for audit reports to enable temporal analysis\n * and before/after differential comparison.\n */\n\nimport { promises as fs } from \"fs\";\nimport * as path from \"path\";\nimport type { AuditReport } from \"./types.js\";\n\n/**\n * Metadata for a stored audit snapshot\n */\nexport interface SnapshotMetadata {\n id: string; // Unique identifier (timestamp-based)\n timestamp: string; // ISO 8601 timestamp\n modelName: string;\n modelVersion: string;\n layers: string[]; // Layers included in this snapshot\n snapshotPath: string; // Path to snapshot file\n}\n\n/**\n * Snapshot storage configuration\n */\nexport interface SnapshotStorageConfig {\n storageDir?: string; // Override default storage directory\n maxSnapshots?: number; // Maximum snapshots to retain (0 = unlimited)\n}\n\n/**\n * Manager for audit snapshot persistence\n */\nexport class SnapshotStorage {\n private readonly storageDir: string;\n private readonly maxSnapshots: number;\n\n constructor(config: SnapshotStorageConfig = {}) {\n this.storageDir =\n config.storageDir || path.join(process.cwd(), \".dr\", \"audit-snapshots\");\n this.maxSnapshots = config.maxSnapshots || 0; // Unlimited by default\n }\n\n /**\n * Initialize storage directory\n */\n private async ensureStorageDir(): Promise<void> {\n await fs.mkdir(this.storageDir, { recursive: true });\n }\n\n /**\n * Generate snapshot ID from timestamp\n */\n private generateSnapshotId(timestamp: string): string {\n // Format: YYYYMMDD-HHmmss\n const date = new Date(timestamp);\n const formatted = date\n .toISOString()\n .replace(/[-:]/g, \"\")\n .replace(/\\..+/, \"\")\n .replace(\"T\", \"-\");\n return formatted;\n }\n\n /**\n * Get snapshot file path\n */\n private getSnapshotPath(id: string): string {\n return path.join(this.storageDir, `${id}.json`);\n }\n\n /**\n * Get metadata file path\n */\n private getMetadataPath(id: string): string {\n return path.join(this.storageDir, `${id}.meta.json`);\n }\n\n /**\n * Save an audit report as a snapshot\n */\n async save(report: AuditReport): Promise<SnapshotMetadata> {\n await this.ensureStorageDir();\n\n const id = this.generateSnapshotId(report.timestamp);\n const snapshotPath = this.getSnapshotPath(id);\n const metadataPath = this.getMetadataPath(id);\n\n // Extract layers from coverage data\n const layers = report.coverage.map((c) => c.layer);\n\n const metadata: SnapshotMetadata = {\n id,\n timestamp: report.timestamp,\n modelName: report.model.name,\n modelVersion: report.model.version,\n layers,\n snapshotPath,\n };\n\n // Write snapshot data\n try {\n await fs.writeFile(snapshotPath, JSON.stringify(report, null, 2), \"utf-8\");\n } catch (error) {\n throw new Error(\n `Failed to write snapshot file ${snapshotPath}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n // Write metadata\n try {\n await fs.writeFile(\n metadataPath,\n JSON.stringify(metadata, null, 2),\n \"utf-8\",\n );\n } catch (error) {\n // If metadata write fails, clean up orphaned snapshot file\n try {\n await fs.unlink(snapshotPath);\n } catch (unlinkError) {\n // Ignore cleanup errors\n }\n throw new Error(\n `Failed to write snapshot metadata ${metadataPath}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n // Cleanup old snapshots if limit exceeded\n if (this.maxSnapshots > 0) {\n await this.cleanupOldSnapshots();\n }\n\n return metadata;\n }\n\n /**\n * Load a snapshot by ID or timestamp\n */\n async load(idOrTimestamp: string): Promise<AuditReport> {\n await this.ensureStorageDir();\n\n let id: string;\n\n // Check if input is already a snapshot ID\n if (/^\\d{8}-\\d{6}$/.test(idOrTimestamp)) {\n id = idOrTimestamp;\n } else {\n // Assume it's a timestamp, convert to ID\n id = this.generateSnapshotId(idOrTimestamp);\n }\n\n const snapshotPath = this.getSnapshotPath(id);\n\n try {\n const content = await fs.readFile(snapshotPath, \"utf-8\");\n return JSON.parse(content) as AuditReport;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new Error(\n `Snapshot not found: ${id}. Use 'dr audit snapshots' to list available snapshots.`,\n );\n }\n // Include snapshot ID in parse error context\n throw new Error(\n `Failed to parse snapshot ${id}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * List all available snapshots\n */\n async list(): Promise<SnapshotMetadata[]> {\n await this.ensureStorageDir();\n\n try {\n const files = await fs.readdir(this.storageDir);\n const metadataFiles = files.filter((f) => f.endsWith(\".meta.json\"));\n\n const snapshots: SnapshotMetadata[] = [];\n for (const file of metadataFiles) {\n const content = await fs.readFile(\n path.join(this.storageDir, file),\n \"utf-8\",\n );\n snapshots.push(JSON.parse(content) as SnapshotMetadata);\n }\n\n // Sort by timestamp (newest first)\n return snapshots.sort(\n (a, b) =>\n new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(),\n );\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return []; // Directory doesn't exist yet\n }\n throw error;\n }\n }\n\n /**\n * Delete a snapshot\n *\n * Deletes both snapshot and metadata files sequentially with rollback on failure\n * to prevent partial deletion state.\n */\n async delete(idOrTimestamp: string): Promise<void> {\n await this.ensureStorageDir();\n\n let id: string;\n if (/^\\d{8}-\\d{6}$/.test(idOrTimestamp)) {\n id = idOrTimestamp;\n } else {\n id = this.generateSnapshotId(idOrTimestamp);\n }\n\n const snapshotPath = this.getSnapshotPath(id);\n const metadataPath = this.getMetadataPath(id);\n\n // Delete snapshot file first\n try {\n await fs.unlink(snapshotPath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw new Error(`Failed to delete snapshot ${id}: ${(error as NodeJS.ErrnoException).message}`);\n }\n // File doesn't exist, continue to metadata\n }\n\n // Delete metadata file\n try {\n await fs.unlink(metadataPath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw new Error(\n `Failed to delete snapshot metadata ${id}: ${(error as NodeJS.ErrnoException).message}`\n );\n }\n // File doesn't exist, both are gone\n }\n }\n\n /**\n * Get the most recent snapshot\n */\n async getLatest(): Promise<AuditReport | null> {\n const snapshots = await this.list();\n if (snapshots.length === 0) {\n return null;\n }\n return this.load(snapshots[0].id);\n }\n\n /**\n * Get the two most recent snapshots for comparison.\n * Returns a tuple of [before, after] where 'before' is the older snapshot\n * and 'after' is the more recent snapshot (for differential analysis).\n * @returns [before, after] tuple where both are sorted chronologically, or [null, null] if fewer than 2 snapshots exist\n */\n async getLatestPair(): Promise<\n [AuditReport, AuditReport] | [null, null]\n > {\n const snapshots = await this.list();\n if (snapshots.length < 2) {\n return [null, null];\n }\n\n const [after, before] = await Promise.all([\n this.load(snapshots[0].id),\n this.load(snapshots[1].id),\n ]);\n\n return [before, after];\n }\n\n /**\n * Clean up old snapshots beyond the retention limit\n */\n private async cleanupOldSnapshots(): Promise<void> {\n const snapshots = await this.list();\n\n if (snapshots.length <= this.maxSnapshots) {\n return;\n }\n\n const toDelete = snapshots.slice(this.maxSnapshots);\n await Promise.all(toDelete.map((s) => this.delete(s.id)));\n }\n\n /**\n * Clear all snapshots\n */\n async clear(): Promise<void> {\n const snapshots = await this.list();\n await Promise.all(snapshots.map((s) => this.delete(s.id)));\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,21 @@
1
+ function createPercentage(value) {
2
+ if (value < 0 || value > 100 || !Number.isFinite(value))
3
+ throw new Error(`Invalid percentage: ${value}. Must be a number between 0 and 100.`);
4
+ return value;
5
+ }
6
+ function gapImpactScore(priority) {
7
+ return { high: 85, medium: 55, low: 25 }[priority];
8
+ }
9
+ function duplicateImpactScore(confidence) {
10
+ return { high: 75, medium: 45, low: 20 }[confidence];
11
+ }
12
+ function recommendationImpactScore(priority) {
13
+ return gapImpactScore(priority);
14
+ }
15
+ export {
16
+ createPercentage,
17
+ duplicateImpactScore,
18
+ gapImpactScore,
19
+ recommendationImpactScore
20
+ };
21
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/audit/types.ts"],
4
+ "sourcesContent": ["/**\n * Type definitions for relationship audit system\n */\n\n/**\n * Percentage value constrained to 0-100 range\n * Use createPercentage() to construct safely\n */\nexport type Percentage = number & { readonly __brand: \"Percentage\" };\n\n/**\n * Create a validated percentage value (0-100)\n * @throws Error if value is not in valid range\n */\nexport function createPercentage(value: number): Percentage {\n if (value < 0 || value > 100 || !Number.isFinite(value)) {\n throw new Error(`Invalid percentage: ${value}. Must be a number between 0 and 100.`);\n }\n return value as Percentage;\n}\n\n/**\n * Coverage metrics for a layer\n */\nexport interface CoverageMetrics {\n readonly layer: string;\n readonly nodeTypeCount: number;\n /** Intra-layer relationship instances (both endpoints in this layer) */\n readonly relationshipCount: number;\n /** Outgoing cross-layer relationship instances (source in this layer, target in another) */\n readonly interLayerRelationshipCount: number;\n\n // Node isolation\n readonly isolatedNodeTypes: readonly string[]; // Zero relationships\n /** Percentage of node types with zero relationships (0-100) */\n readonly isolationPercentage: Percentage;\n\n // Predicate utilization\n readonly availablePredicates: readonly string[]; // Predicates applicable to this layer\n readonly usedPredicates: readonly string[]; // Actually used\n /** Percentage of available predicates actually used (0-100) */\n readonly utilizationPercentage: Percentage;\n\n // Density\n readonly relationshipsPerNodeType: number;\n\n // Standard alignment (for ArchiMate layers)\n readonly standardAlignment?: {\n readonly standard: string;\n readonly expectedRelationships: number;\n readonly missingFromStandard: readonly string[];\n };\n}\n\n/**\n * Semantic duplicate candidate\n */\nexport interface DuplicateCandidate {\n readonly relationships: readonly [string, string]; // IDs of duplicate pair\n readonly predicates: readonly [string, string]; // Predicate names\n readonly sourceNodeType: string;\n readonly destinationNodeType: string;\n readonly reason: string; // Explanation of semantic overlap\n readonly confidence: \"high\" | \"medium\" | \"low\";\n /** How necessary it is to clean up this duplicate (0\u2013100, higher = more urgent) */\n readonly impactScore: number;\n /** 100 - impactScore; aligns with NodeAIEvaluation.alignmentScore semantics (lower = more action needed) */\n readonly alignmentScore: number;\n}\n\n/**\n * Missing relationship gap candidate\n */\nexport interface GapCandidate {\n readonly sourceNodeType: string;\n readonly destinationNodeType: string;\n readonly suggestedPredicate: string;\n readonly reason: string;\n readonly priority: \"high\" | \"medium\" | \"low\";\n readonly standardReference?: string; // e.g., \"ArchiMate 3.2 \u00A75.2\"\n /** How necessary this gap is to fill (0\u2013100, higher = more urgent) */\n readonly impactScore: number;\n /** 100 - impactScore; aligns with NodeAIEvaluation.alignmentScore semantics (lower = more action needed) */\n readonly alignmentScore: number;\n}\n\n/**\n * Balance assessment for node type relationship density\n */\nexport interface BalanceAssessment {\n readonly nodeType: string;\n readonly layer: string;\n readonly category: \"structural\" | \"behavioral\" | \"enumeration\" | \"reference\";\n readonly currentCount: number;\n readonly targetRange: readonly [number, number];\n readonly status: \"under\" | \"balanced\" | \"over\";\n readonly recommendation?: string;\n}\n\n/**\n * Connected component in relationship graph\n */\nexport interface ConnectedComponent {\n readonly nodes: readonly string[];\n}\n\n/**\n * Node degree information\n */\nexport interface NodeDegree {\n readonly nodeType: string;\n readonly inDegree: number;\n readonly outDegree: number;\n readonly totalDegree: number;\n}\n\n/**\n * Transitive relationship chain\n */\nexport interface TransitiveChain {\n readonly predicate: string;\n readonly chain: readonly string[]; // Node types in chain\n}\n\n/**\n * Connectivity statistics summary\n */\nexport interface ConnectivityStats {\n readonly totalNodes: number;\n readonly totalEdges: number;\n readonly connectedComponents: number;\n readonly largestComponentSize: number;\n readonly isolatedNodes: number;\n readonly averageDegree: number;\n readonly transitiveChainCount: number;\n}\n\n/**\n * Comprehensive audit report combining all analysis results\n */\nexport interface AuditReport {\n readonly timestamp: string;\n readonly model: {\n readonly name: string;\n readonly version: string;\n };\n readonly coverage: readonly CoverageMetrics[];\n readonly duplicates: readonly DuplicateCandidate[];\n readonly gaps: readonly GapCandidate[];\n readonly balance: readonly BalanceAssessment[];\n readonly connectivity: {\n readonly components: readonly ConnectedComponent[];\n readonly degrees: readonly NodeDegree[];\n readonly transitiveChains: readonly TransitiveChain[];\n readonly stats: ConnectivityStats;\n };\n}\n\n/**\n * Summary report comparing before/after audit states\n */\nexport interface SummaryReport {\n readonly timestamp: string;\n readonly coverageChanges: readonly {\n readonly layer: string;\n readonly before: { readonly isolation: number; readonly density: number };\n readonly after: { readonly isolation: number; readonly density: number };\n readonly delta: { readonly isolation: number; readonly density: number };\n }[];\n readonly relationshipsAdded: number;\n readonly gapsResolved: number;\n readonly remainingGaps: number;\n readonly duplicatesResolved: number;\n readonly balanceImprovements: readonly string[];\n}\n\n/**\n * Layer-specific aggregated data\n */\nexport interface LayerData {\n readonly layer: string;\n readonly coverage: CoverageMetrics;\n readonly duplicates: readonly DuplicateCandidate[];\n readonly gaps: readonly GapCandidate[];\n readonly balance: readonly BalanceAssessment[];\n}\n\n// ---------------------------------------------------------------------------\n// Score helpers \u2014 shared by all gap/duplicate analyzers\n// ---------------------------------------------------------------------------\n\n/**\n * Impact score for a gap (missing relationship).\n * Higher = more urgently needed. Maps directly to priority.\n */\nexport function gapImpactScore(priority: \"high\" | \"medium\" | \"low\"): number {\n const scores: Record<\"high\" | \"medium\" | \"low\", number> = { high: 85, medium: 55, low: 25 };\n return scores[priority];\n}\n\n/**\n * Impact score for a duplicate candidate.\n * Higher = more confident it should be removed. Maps directly to confidence.\n */\nexport function duplicateImpactScore(confidence: \"high\" | \"medium\" | \"low\"): number {\n const scores: Record<\"high\" | \"medium\" | \"low\", number> = { high: 75, medium: 45, low: 20 };\n return scores[confidence];\n}\n\n/**\n * Impact score for an AI relationship recommendation.\n * Same scale as gap scores \u2014 recommendations describe missing relationships.\n */\nexport function recommendationImpactScore(priority: \"high\" | \"medium\" | \"low\"): number {\n return gapImpactScore(priority);\n}\n"],
5
+ "mappings": "AAcM,SAAU,iBAAiB,OAAa;AAC5C,MAAI,QAAQ,KAAK,QAAQ,OAAO,CAAC,OAAO,SAAS,KAAK;AACpD,UAAM,IAAI,MAAM,uBAAuB,KAAK,uCAAuC;AAErF,SAAO;AACT;AAgLM,SAAU,eAAe,UAAmC;AAEhE,SAD0D,EAAE,MAAM,IAAI,QAAQ,IAAI,KAAK,GAAE,EAC3E,QAAQ;AACxB;AAMM,SAAU,qBAAqB,YAAqC;AAExE,SAD0D,EAAE,MAAM,IAAI,QAAQ,IAAI,KAAK,GAAE,EAC3E,UAAU;AAC1B;AAMM,SAAU,0BAA0B,UAAmC;AAC3E,SAAO,eAAe,QAAQ;AAChC;",
6
+ "names": []
7
+ }