@documentation-robotics/cli 0.1.0 → 0.1.5

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 +206 -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 +155 -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 +37 -13
  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,124 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ import { CLIError, ErrorCategory } from "../utils/errors.js";
5
+ import { CbmAnalyzer } from "./cbm-analyzer.js";
6
+ import { MappingLoader } from "./mapping-loader.js";
7
+ const ANALYZER_CLASSES = {
8
+ cbm: CbmAnalyzer
9
+ };
10
+ class AnalyzerRegistry {
11
+ static instance = null;
12
+ manifest = null;
13
+ mappers = /* @__PURE__ */ new Map();
14
+ analyzers = /* @__PURE__ */ new Map();
15
+ /**
16
+ * Get the singleton registry instance
17
+ */
18
+ static getInstance() {
19
+ return AnalyzerRegistry.instance || (AnalyzerRegistry.instance = new AnalyzerRegistry()), AnalyzerRegistry.instance;
20
+ }
21
+ /**
22
+ * Reset the registry singleton for testing
23
+ *
24
+ * This method clears the singleton instance and all cached state.
25
+ * Use this in test teardown to ensure a clean registry for each test.
26
+ *
27
+ * @internal For testing only
28
+ */
29
+ static resetForTesting() {
30
+ AnalyzerRegistry.instance = null;
31
+ }
32
+ constructor() {
33
+ }
34
+ /**
35
+ * Initialize the registry by loading the manifest
36
+ *
37
+ * @throws CLIError if manifest is missing or malformed
38
+ */
39
+ async initialize() {
40
+ this.manifest || await this.loadManifest();
41
+ }
42
+ /**
43
+ * Load the analyzer manifest from bundled schemas
44
+ *
45
+ * @private
46
+ * @throws CLIError if manifest is missing or malformed
47
+ */
48
+ async loadManifest() {
49
+ const currentDir = path.dirname(fileURLToPath(import.meta.url)), manifestPath = path.join(currentDir, "../schemas/bundled/analyzers/manifest.json");
50
+ let content;
51
+ try {
52
+ const fileContent = await fs.readFile(manifestPath, "utf-8");
53
+ content = JSON.parse(fileContent);
54
+ } catch (error) {
55
+ const message = error instanceof Error && "code" in error && error.code === "ENOENT" ? `Analyzer manifest not found: ${manifestPath}` : `Failed to read analyzer manifest: ${error instanceof Error ? error.message : String(error)}`;
56
+ throw new CLIError(message, ErrorCategory.NOT_FOUND, [
57
+ "Run `npm run build:spec` to compile the analyzer artifacts",
58
+ "Check that spec/analyzers/ sources exist"
59
+ ]);
60
+ }
61
+ if (!content || typeof content != "object")
62
+ throw new CLIError("Invalid analyzer manifest structure: expected object", ErrorCategory.VALIDATION, ["Run `npm run build:spec` to recompile the analyzer artifacts"]);
63
+ const obj = content;
64
+ if (!Array.isArray(obj.analyzers))
65
+ throw new CLIError("Invalid analyzer manifest: analyzers must be an array", ErrorCategory.VALIDATION, ["Run `npm run build:spec` to recompile the analyzer artifacts"]);
66
+ if (typeof obj.specVersion != "string")
67
+ throw new CLIError("Invalid analyzer manifest: specVersion must be a string", ErrorCategory.VALIDATION, ["Run `npm run build:spec` to recompile the analyzer artifacts"]);
68
+ this.manifest = {
69
+ specVersion: obj.specVersion,
70
+ analyzers: obj.analyzers
71
+ };
72
+ }
73
+ /**
74
+ * Get an analyzer by name
75
+ *
76
+ * @param name Analyzer name (e.g., "cbm")
77
+ * @returns AnalyzerBackend instance, or undefined if not found
78
+ * @throws CLIError if manifest is not initialized or mapping cannot be loaded
79
+ */
80
+ async getAnalyzer(name) {
81
+ if (await this.initialize(), this.analyzers.has(name))
82
+ return this.analyzers.get(name);
83
+ if (!this.manifest.analyzers.find((a) => a.name === name))
84
+ return;
85
+ let mapper = this.mappers.get(name);
86
+ mapper || (mapper = await MappingLoader.load(name), this.mappers.set(name, mapper));
87
+ const AnalyzerClass = ANALYZER_CLASSES[name];
88
+ if (!AnalyzerClass)
89
+ throw new CLIError(`Unknown analyzer: ${name}`, ErrorCategory.NOT_FOUND, [
90
+ "Check the analyzer name is spelled correctly",
91
+ "Ensure the analyzer class is registered in ANALYZER_CLASSES in registry.ts",
92
+ "Use getAnalyzerNames() to list available analyzers"
93
+ ]);
94
+ const analyzer = new AnalyzerClass(mapper);
95
+ return this.analyzers.set(name, analyzer), analyzer;
96
+ }
97
+ /**
98
+ * Get all available analyzers
99
+ *
100
+ * @returns Array of all analyzer instances
101
+ * @throws CLIError if manifest is not initialized or mapping cannot be loaded
102
+ */
103
+ async getAllAnalyzers() {
104
+ const names = await this.getAnalyzerNames(), analyzers = [];
105
+ for (const name of names) {
106
+ const analyzer = await this.getAnalyzer(name);
107
+ analyzer && analyzers.push(analyzer);
108
+ }
109
+ return analyzers;
110
+ }
111
+ /**
112
+ * Get all available analyzer names
113
+ *
114
+ * @returns Array of analyzer names
115
+ * @throws CLIError if manifest cannot be loaded
116
+ */
117
+ async getAnalyzerNames() {
118
+ return await this.initialize(), this.manifest.analyzers.map((a) => a.name);
119
+ }
120
+ }
121
+ export {
122
+ AnalyzerRegistry
123
+ };
124
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/analyzers/registry.ts"],
4
+ "sourcesContent": ["/**\n * Analyzer Registry\n *\n * Reads the analyzer manifest from bundled schemas and constructs analyzer instances.\n * The registry maps analyzer names to their backend implementations and metadata.\n *\n * To add a new analyzer:\n * 1. Create a new class implementing AnalyzerBackend (e.g., NewAnalyzer)\n * 2. Create analyzer definition in spec/analyzers/{name}/analyzer.json\n * 3. Add mapping for the new analyzer class in the ANALYZER_CLASSES map below\n * 4. Run `npm run build:spec` to compile the analyzer artifacts\n * 5. Run `npm run build` in the cli/ directory to sync bundled schemas\n */\n\nimport fs from \"fs/promises\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { CLIError, ErrorCategory } from \"../utils/errors.js\";\nimport type { AnalyzerBackend } from \"./base-analyzer.js\";\nimport { CbmAnalyzer } from \"./cbm-analyzer.js\";\nimport { MappingLoader } from \"./mapping-loader.js\";\n\n/**\n * Type for analyzer class constructor\n */\ntype AnalyzerConstructor = new (mapper: MappingLoader) => AnalyzerBackend;\n\n/**\n * Mapping of analyzer names to their class implementations\n *\n * Add entries here when implementing a new analyzer.\n * The manifest (spec/dist/analyzers/manifest.json) defines which analyzers are available,\n * and this map provides the runtime bindings to construct instances.\n */\nconst ANALYZER_CLASSES: Record<string, AnalyzerConstructor> = {\n cbm: CbmAnalyzer,\n};\n\n/**\n * Analyzer metadata from manifest\n */\ninterface AnalyzerMetadata {\n name: string;\n version: string;\n}\n\n/**\n * Analyzer registry manifest structure\n */\ninterface RegistryManifest {\n specVersion: string;\n analyzers: AnalyzerMetadata[];\n}\n\n/**\n * Analyzer Registry - constructs and manages analyzer instances\n */\nexport class AnalyzerRegistry {\n private static instance: AnalyzerRegistry | null = null;\n private manifest: RegistryManifest | null = null;\n private mappers: Map<string, MappingLoader> = new Map();\n private analyzers: Map<string, AnalyzerBackend> = new Map();\n\n /**\n * Get the singleton registry instance\n */\n static getInstance(): AnalyzerRegistry {\n if (!AnalyzerRegistry.instance) {\n AnalyzerRegistry.instance = new AnalyzerRegistry();\n }\n return AnalyzerRegistry.instance;\n }\n\n /**\n * Reset the registry singleton for testing\n *\n * This method clears the singleton instance and all cached state.\n * Use this in test teardown to ensure a clean registry for each test.\n *\n * @internal For testing only\n */\n static resetForTesting(): void {\n AnalyzerRegistry.instance = null;\n }\n\n private constructor() {}\n\n /**\n * Initialize the registry by loading the manifest\n *\n * @throws CLIError if manifest is missing or malformed\n */\n async initialize(): Promise<void> {\n if (this.manifest) {\n return; // Already initialized\n }\n\n await this.loadManifest();\n }\n\n /**\n * Load the analyzer manifest from bundled schemas\n *\n * @private\n * @throws CLIError if manifest is missing or malformed\n */\n private async loadManifest(): Promise<void> {\n const currentDir = path.dirname(fileURLToPath(import.meta.url));\n const manifestPath = path.join(\n currentDir,\n \"../schemas/bundled/analyzers/manifest.json\"\n );\n\n let content: unknown;\n try {\n const fileContent = await fs.readFile(manifestPath, \"utf-8\");\n content = JSON.parse(fileContent);\n } catch (error) {\n const message =\n error instanceof Error && \"code\" in error && (error as { code: string }).code === \"ENOENT\"\n ? `Analyzer manifest not found: ${manifestPath}`\n : `Failed to read analyzer manifest: ${error instanceof Error ? error.message : String(error)}`;\n\n throw new CLIError(message, ErrorCategory.NOT_FOUND, [\n \"Run `npm run build:spec` to compile the analyzer artifacts\",\n \"Check that spec/analyzers/ sources exist\",\n ]);\n }\n\n if (!content || typeof content !== \"object\") {\n throw new CLIError(\n \"Invalid analyzer manifest structure: expected object\",\n ErrorCategory.VALIDATION,\n [\"Run `npm run build:spec` to recompile the analyzer artifacts\"]\n );\n }\n\n const obj = content as Record<string, unknown>;\n if (!Array.isArray(obj.analyzers)) {\n throw new CLIError(\n \"Invalid analyzer manifest: analyzers must be an array\",\n ErrorCategory.VALIDATION,\n [\"Run `npm run build:spec` to recompile the analyzer artifacts\"]\n );\n }\n\n if (typeof obj.specVersion !== \"string\") {\n throw new CLIError(\n \"Invalid analyzer manifest: specVersion must be a string\",\n ErrorCategory.VALIDATION,\n [\"Run `npm run build:spec` to recompile the analyzer artifacts\"]\n );\n }\n\n this.manifest = {\n specVersion: obj.specVersion,\n analyzers: obj.analyzers as AnalyzerMetadata[],\n };\n }\n\n /**\n * Get an analyzer by name\n *\n * @param name Analyzer name (e.g., \"cbm\")\n * @returns AnalyzerBackend instance, or undefined if not found\n * @throws CLIError if manifest is not initialized or mapping cannot be loaded\n */\n async getAnalyzer(name: string): Promise<AnalyzerBackend | undefined> {\n await this.initialize();\n\n // Check cache first\n if (this.analyzers.has(name)) {\n return this.analyzers.get(name);\n }\n\n // Check if analyzer exists in manifest\n const metadata = this.manifest!.analyzers.find((a) => a.name === name);\n if (!metadata) {\n return undefined;\n }\n\n // Load the mapping\n let mapper = this.mappers.get(name);\n if (!mapper) {\n mapper = await MappingLoader.load(name);\n this.mappers.set(name, mapper);\n }\n\n // Construct the appropriate analyzer instance using the class map\n const AnalyzerClass = ANALYZER_CLASSES[name];\n if (!AnalyzerClass) {\n throw new CLIError(\n `Unknown analyzer: ${name}`,\n ErrorCategory.NOT_FOUND,\n [\n \"Check the analyzer name is spelled correctly\",\n \"Ensure the analyzer class is registered in ANALYZER_CLASSES in registry.ts\",\n \"Use getAnalyzerNames() to list available analyzers\",\n ]\n );\n }\n\n const analyzer = new AnalyzerClass(mapper);\n this.analyzers.set(name, analyzer);\n return analyzer;\n }\n\n /**\n * Get all available analyzers\n *\n * @returns Array of all analyzer instances\n * @throws CLIError if manifest is not initialized or mapping cannot be loaded\n */\n async getAllAnalyzers(): Promise<AnalyzerBackend[]> {\n const names = await this.getAnalyzerNames();\n const analyzers: AnalyzerBackend[] = [];\n\n for (const name of names) {\n const analyzer = await this.getAnalyzer(name);\n if (analyzer) {\n analyzers.push(analyzer);\n }\n }\n\n return analyzers;\n }\n\n /**\n * Get all available analyzer names\n *\n * @returns Array of analyzer names\n * @throws CLIError if manifest cannot be loaded\n */\n async getAnalyzerNames(): Promise<string[]> {\n await this.initialize();\n\n return this.manifest!.analyzers.map((a) => a.name);\n }\n}\n"],
5
+ "mappings": "AAcA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAC9B,SAAS,UAAU,qBAAqB;AAExC,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAc9B,MAAM,mBAAwD;EAC5D,KAAK;;AAsBD,MAAO,iBAAgB;EACnB,OAAO,WAAoC;EAC3C,WAAoC;EACpC,UAAsC,oBAAI,IAAG;EAC7C,YAA0C,oBAAI,IAAG;;;;EAKzD,OAAO,cAAW;AAChB,WAAK,iBAAiB,aACpB,iBAAiB,WAAW,IAAI,iBAAgB,IAE3C,iBAAiB;EAC1B;;;;;;;;;EAUA,OAAO,kBAAe;AACpB,qBAAiB,WAAW;EAC9B;EAEA,cAAA;EAAuB;;;;;;EAOvB,MAAM,aAAU;AACd,IAAI,KAAK,YAIT,MAAM,KAAK,aAAY;EACzB;;;;;;;EAQQ,MAAM,eAAY;AACxB,UAAM,aAAa,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC,GACxD,eAAe,KAAK,KACxB,YACA,4CAA4C;AAG9C,QAAI;AACJ,QAAI;AACF,YAAM,cAAc,MAAM,GAAG,SAAS,cAAc,OAAO;AAC3D,gBAAU,KAAK,MAAM,WAAW;IAClC,SAAS,OAAO;AACd,YAAM,UACJ,iBAAiB,SAAS,UAAU,SAAU,MAA2B,SAAS,WAC9E,gCAAgC,YAAY,KAC5C,qCAAqC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAEjG,YAAM,IAAI,SAAS,SAAS,cAAc,WAAW;QACnD;QACA;OACD;IACH;AAEA,QAAI,CAAC,WAAW,OAAO,WAAY;AACjC,YAAM,IAAI,SACR,wDACA,cAAc,YACd,CAAC,8DAA8D,CAAC;AAIpE,UAAM,MAAM;AACZ,QAAI,CAAC,MAAM,QAAQ,IAAI,SAAS;AAC9B,YAAM,IAAI,SACR,yDACA,cAAc,YACd,CAAC,8DAA8D,CAAC;AAIpE,QAAI,OAAO,IAAI,eAAgB;AAC7B,YAAM,IAAI,SACR,2DACA,cAAc,YACd,CAAC,8DAA8D,CAAC;AAIpE,SAAK,WAAW;MACd,aAAa,IAAI;MACjB,WAAW,IAAI;;EAEnB;;;;;;;;EASA,MAAM,YAAY,MAAY;AAI5B,QAHA,MAAM,KAAK,WAAU,GAGjB,KAAK,UAAU,IAAI,IAAI;AACzB,aAAO,KAAK,UAAU,IAAI,IAAI;AAKhC,QAAI,CADa,KAAK,SAAU,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAEnE;AAIF,QAAI,SAAS,KAAK,QAAQ,IAAI,IAAI;AAClC,IAAK,WACH,SAAS,MAAM,cAAc,KAAK,IAAI,GACtC,KAAK,QAAQ,IAAI,MAAM,MAAM;AAI/B,UAAM,gBAAgB,iBAAiB,IAAI;AAC3C,QAAI,CAAC;AACH,YAAM,IAAI,SACR,qBAAqB,IAAI,IACzB,cAAc,WACd;QACE;QACA;QACA;OACD;AAIL,UAAM,WAAW,IAAI,cAAc,MAAM;AACzC,gBAAK,UAAU,IAAI,MAAM,QAAQ,GAC1B;EACT;;;;;;;EAQA,MAAM,kBAAe;AACnB,UAAM,QAAQ,MAAM,KAAK,iBAAgB,GACnC,YAA+B,CAAA;AAErC,eAAW,QAAQ,OAAO;AACxB,YAAM,WAAW,MAAM,KAAK,YAAY,IAAI;AAC5C,MAAI,YACF,UAAU,KAAK,QAAQ;IAE3B;AAEA,WAAO;EACT;;;;;;;EAQA,MAAM,mBAAgB;AACpB,iBAAM,KAAK,WAAU,GAEd,KAAK,SAAU,UAAU,IAAI,CAAC,MAAM,EAAE,IAAI;EACnD;;",
6
+ "names": []
7
+ }
@@ -0,0 +1,176 @@
1
+ import { promises as fs } from "fs";
2
+ import * as path from "path";
3
+ function validateAnalyzerName(analyzerName) {
4
+ if (!analyzerName)
5
+ throw new Error("Analyzer name cannot be empty");
6
+ if (analyzerName.includes("/") || analyzerName.includes("\\"))
7
+ throw new Error("Analyzer name cannot contain path separators (/ or \\)");
8
+ if (analyzerName.includes(".."))
9
+ throw new Error("Analyzer name cannot contain parent directory references (..)");
10
+ }
11
+ function validateSessionState(data) {
12
+ if (!data || typeof data != "object")
13
+ throw new Error("SessionState must be an object");
14
+ const obj = data;
15
+ if (typeof obj.active_analyzer != "string")
16
+ throw new Error("SessionState.active_analyzer must be a string");
17
+ if (typeof obj.selected_at != "string")
18
+ throw new Error("SessionState.selected_at must be a string");
19
+ return {
20
+ active_analyzer: obj.active_analyzer,
21
+ selected_at: obj.selected_at
22
+ };
23
+ }
24
+ function validateIndexMeta(data) {
25
+ if (!data || typeof data != "object")
26
+ throw new Error("IndexMeta must be an object");
27
+ const obj = data;
28
+ if (typeof obj.git_head != "string")
29
+ throw new Error("IndexMeta.git_head must be a string");
30
+ if (typeof obj.timestamp != "string")
31
+ throw new Error("IndexMeta.timestamp must be a string");
32
+ if (typeof obj.node_count != "number")
33
+ throw new Error("IndexMeta.node_count must be a number");
34
+ if (typeof obj.edge_count != "number")
35
+ throw new Error("IndexMeta.edge_count must be a number");
36
+ return {
37
+ git_head: obj.git_head,
38
+ timestamp: obj.timestamp,
39
+ node_count: obj.node_count,
40
+ edge_count: obj.edge_count
41
+ };
42
+ }
43
+ function validateAnalyzerStatus(data) {
44
+ if (!data || typeof data != "object")
45
+ throw new Error("AnalyzerStatus must be an object");
46
+ const obj = data;
47
+ if (!obj.detected || typeof obj.detected != "object")
48
+ throw new Error("AnalyzerStatus.detected must be an object");
49
+ const detected = obj.detected;
50
+ if (typeof detected.installed != "boolean")
51
+ throw new Error("AnalyzerStatus.detected.installed must be a boolean");
52
+ const installed = detected.installed;
53
+ if (installed) {
54
+ if (typeof detected.binary_path != "string")
55
+ throw new Error("AnalyzerStatus.detected.binary_path must be a string when installed: true");
56
+ if (detected.version !== void 0 && typeof detected.version != "string")
57
+ throw new Error("AnalyzerStatus.detected.version must be a string");
58
+ if (detected.mcp_registered !== void 0 && typeof detected.mcp_registered != "boolean")
59
+ throw new Error("AnalyzerStatus.detected.mcp_registered must be a boolean");
60
+ if (detected.contract_ok !== void 0 && typeof detected.contract_ok != "boolean")
61
+ throw new Error("AnalyzerStatus.detected.contract_ok must be a boolean");
62
+ } else if (detected.binary_path !== void 0)
63
+ throw new Error("AnalyzerStatus.detected.binary_path must not be present when installed: false");
64
+ if (typeof obj.indexed != "boolean")
65
+ throw new Error("AnalyzerStatus.indexed must be a boolean");
66
+ if (typeof obj.fresh != "boolean")
67
+ throw new Error("AnalyzerStatus.fresh must be a boolean");
68
+ if (obj.indexed) {
69
+ if (obj.index_meta === void 0)
70
+ throw new Error("AnalyzerStatus.index_meta must be present when indexed: true");
71
+ const validatedIndexMeta = validateIndexMeta(obj.index_meta);
72
+ if (obj.last_indexed !== void 0 && typeof obj.last_indexed != "string")
73
+ throw new Error("AnalyzerStatus.last_indexed must be a string");
74
+ return {
75
+ detected: installed ? {
76
+ installed: !0,
77
+ binary_path: detected.binary_path,
78
+ version: detected.version,
79
+ mcp_registered: detected.mcp_registered,
80
+ contract_ok: detected.contract_ok
81
+ } : {
82
+ installed: !1
83
+ },
84
+ indexed: !0,
85
+ index_meta: validatedIndexMeta,
86
+ fresh: obj.fresh,
87
+ last_indexed: obj.last_indexed
88
+ };
89
+ } else {
90
+ if (obj.index_meta !== void 0)
91
+ throw new Error("AnalyzerStatus.index_meta must not be present when indexed: false");
92
+ if (obj.last_indexed !== void 0 && typeof obj.last_indexed != "string")
93
+ throw new Error("AnalyzerStatus.last_indexed must be a string");
94
+ return {
95
+ detected: installed ? {
96
+ installed: !0,
97
+ binary_path: detected.binary_path,
98
+ version: detected.version,
99
+ mcp_registered: detected.mcp_registered,
100
+ contract_ok: detected.contract_ok
101
+ } : {
102
+ installed: !1
103
+ },
104
+ indexed: !1,
105
+ fresh: obj.fresh,
106
+ last_indexed: obj.last_indexed
107
+ };
108
+ }
109
+ }
110
+ function getStateDir(baseDir, analyzerName) {
111
+ const base = baseDir ?? process.cwd(), analyzersDir = path.join(base, ".dr", "analyzers");
112
+ return analyzerName !== void 0 ? (validateAnalyzerName(analyzerName), path.join(analyzersDir, analyzerName)) : analyzersDir;
113
+ }
114
+ async function ensureStateDir(baseDir, analyzerName) {
115
+ await fs.mkdir(getStateDir(baseDir, analyzerName), { recursive: !0 });
116
+ }
117
+ function getStatePath(filename, baseDir, analyzerName) {
118
+ return path.join(getStateDir(baseDir, analyzerName), filename);
119
+ }
120
+ async function readSession(baseDir) {
121
+ const filePath = getStatePath("session.json", baseDir);
122
+ try {
123
+ const content = await fs.readFile(filePath, "utf-8"), parsed = JSON.parse(content);
124
+ return validateSessionState(parsed);
125
+ } catch (error) {
126
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
127
+ return null;
128
+ throw error;
129
+ }
130
+ }
131
+ async function writeSession(state, baseDir) {
132
+ await ensureStateDir(baseDir);
133
+ const filePath = getStatePath("session.json", baseDir), content = JSON.stringify(state, null, 2);
134
+ await fs.writeFile(filePath, content, "utf-8");
135
+ }
136
+ async function readIndexMeta(baseDir, analyzerName) {
137
+ const filePath = getStatePath("index-meta.json", baseDir, analyzerName);
138
+ try {
139
+ const content = await fs.readFile(filePath, "utf-8"), parsed = JSON.parse(content);
140
+ return validateIndexMeta(parsed);
141
+ } catch (error) {
142
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
143
+ return null;
144
+ throw error;
145
+ }
146
+ }
147
+ async function writeIndexMeta(meta, baseDir, analyzerName) {
148
+ await ensureStateDir(baseDir, analyzerName);
149
+ const filePath = getStatePath("index-meta.json", baseDir, analyzerName), content = JSON.stringify(meta, null, 2);
150
+ await fs.writeFile(filePath, content, "utf-8");
151
+ }
152
+ async function readStatus(baseDir, analyzerName) {
153
+ const filePath = getStatePath("status.json", baseDir, analyzerName);
154
+ try {
155
+ const content = await fs.readFile(filePath, "utf-8"), parsed = JSON.parse(content);
156
+ return validateAnalyzerStatus(parsed);
157
+ } catch (error) {
158
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
159
+ return null;
160
+ throw error;
161
+ }
162
+ }
163
+ async function writeStatus(status, baseDir, analyzerName) {
164
+ await ensureStateDir(baseDir, analyzerName);
165
+ const filePath = getStatePath("status.json", baseDir, analyzerName), content = JSON.stringify(status, null, 2);
166
+ await fs.writeFile(filePath, content, "utf-8");
167
+ }
168
+ export {
169
+ readIndexMeta,
170
+ readSession,
171
+ readStatus,
172
+ writeIndexMeta,
173
+ writeSession,
174
+ writeStatus
175
+ };
176
+ //# sourceMappingURL=session-state.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/analyzers/session-state.ts"],
4
+ "sourcesContent": ["/**\n * Session state and metadata persistence\n *\n * Provides file-based storage for analyzer session state, index metadata,\n * and analyzer status information in `.dr/analyzers/` directory.\n *\n * Per-analyzer files (index-meta.json, status.json) are stored in subdirectories:\n * - `.dr/analyzers/{analyzerName}/index-meta.json`\n * - `.dr/analyzers/{analyzerName}/status.json`\n *\n * Global files (session.json) are stored at the base level:\n * - `.dr/analyzers/session.json`\n *\n * All operations are async and use JSON for serialization.\n * Missing files gracefully return null rather than throwing errors.\n * Read operations validate JSON structure and throw errors for corrupted files.\n */\n\nimport { promises as fs } from \"fs\";\nimport * as path from \"path\";\nimport type { SessionState, IndexMeta, AnalyzerStatus } from \"./types.js\";\n\n/**\n * Validate analyzer name to prevent path traversal attacks\n * Rejects names containing `/`, `\\`, or `..`\n *\n * @param analyzerName Analyzer name to validate\n * @throws Error if name contains path traversal characters\n */\nfunction validateAnalyzerName(analyzerName: string): void {\n if (!analyzerName) {\n throw new Error(\"Analyzer name cannot be empty\");\n }\n\n if (analyzerName.includes(\"/\") || analyzerName.includes(\"\\\\\")) {\n throw new Error(\"Analyzer name cannot contain path separators (/ or \\\\)\");\n }\n\n if (analyzerName.includes(\"..\")) {\n throw new Error(\"Analyzer name cannot contain parent directory references (..)\");\n }\n}\n\n/**\n * Validate SessionState structure\n * @throws Error if data is missing required fields\n */\nfunction validateSessionState(data: unknown): SessionState {\n if (!data || typeof data !== \"object\") {\n throw new Error(\"SessionState must be an object\");\n }\n\n const obj = data as Record<string, unknown>;\n\n if (typeof obj.active_analyzer !== \"string\") {\n throw new Error(\"SessionState.active_analyzer must be a string\");\n }\n\n if (typeof obj.selected_at !== \"string\") {\n throw new Error(\"SessionState.selected_at must be a string\");\n }\n\n return {\n active_analyzer: obj.active_analyzer,\n selected_at: obj.selected_at,\n };\n}\n\n/**\n * Validate IndexMeta structure\n * @throws Error if data is missing required fields\n */\nfunction validateIndexMeta(data: unknown): IndexMeta {\n if (!data || typeof data !== \"object\") {\n throw new Error(\"IndexMeta must be an object\");\n }\n\n const obj = data as Record<string, unknown>;\n\n if (typeof obj.git_head !== \"string\") {\n throw new Error(\"IndexMeta.git_head must be a string\");\n }\n\n if (typeof obj.timestamp !== \"string\") {\n throw new Error(\"IndexMeta.timestamp must be a string\");\n }\n\n if (typeof obj.node_count !== \"number\") {\n throw new Error(\"IndexMeta.node_count must be a number\");\n }\n\n if (typeof obj.edge_count !== \"number\") {\n throw new Error(\"IndexMeta.edge_count must be a number\");\n }\n\n return {\n git_head: obj.git_head,\n timestamp: obj.timestamp,\n node_count: obj.node_count as number,\n edge_count: obj.edge_count as number,\n };\n}\n\n/**\n * Validate AnalyzerStatus structure\n * Enforces discriminated union constraints:\n * - When installed: true, binary_path must be present\n * - When installed: false, binary_path must not be present\n * - When indexed: true, index_meta must be present\n * - When indexed: false, index_meta must not be present\n *\n * @throws Error if data is missing required fields or violates discriminated union constraints\n */\nfunction validateAnalyzerStatus(data: unknown): AnalyzerStatus {\n if (!data || typeof data !== \"object\") {\n throw new Error(\"AnalyzerStatus must be an object\");\n }\n\n const obj = data as Record<string, unknown>;\n\n if (!obj.detected || typeof obj.detected !== \"object\") {\n throw new Error(\"AnalyzerStatus.detected must be an object\");\n }\n\n const detected = obj.detected as Record<string, unknown>;\n if (typeof detected.installed !== \"boolean\") {\n throw new Error(\"AnalyzerStatus.detected.installed must be a boolean\");\n }\n\n // Validate DetectionResult discriminated union\n const installed = detected.installed as boolean;\n\n if (installed) {\n // When installed: true, binary_path is required\n if (typeof detected.binary_path !== \"string\") {\n throw new Error(\"AnalyzerStatus.detected.binary_path must be a string when installed: true\");\n }\n\n // Validate optional fields\n if (detected.version !== undefined && typeof detected.version !== \"string\") {\n throw new Error(\"AnalyzerStatus.detected.version must be a string\");\n }\n\n if (detected.mcp_registered !== undefined && typeof detected.mcp_registered !== \"boolean\") {\n throw new Error(\"AnalyzerStatus.detected.mcp_registered must be a boolean\");\n }\n\n if (detected.contract_ok !== undefined && typeof detected.contract_ok !== \"boolean\") {\n throw new Error(\"AnalyzerStatus.detected.contract_ok must be a boolean\");\n }\n } else {\n // When installed: false, binary_path must not be present\n if (detected.binary_path !== undefined) {\n throw new Error(\"AnalyzerStatus.detected.binary_path must not be present when installed: false\");\n }\n }\n\n if (typeof obj.indexed !== \"boolean\") {\n throw new Error(\"AnalyzerStatus.indexed must be a boolean\");\n }\n\n if (typeof obj.fresh !== \"boolean\") {\n throw new Error(\"AnalyzerStatus.fresh must be a boolean\");\n }\n\n // Validate AnalyzerStatus discriminated union\n const indexed = obj.indexed as boolean;\n if (indexed) {\n // When indexed: true, index_meta is required\n if (obj.index_meta === undefined) {\n throw new Error(\"AnalyzerStatus.index_meta must be present when indexed: true\");\n }\n const validatedIndexMeta = validateIndexMeta(obj.index_meta);\n\n // Validate optional last_indexed if present\n if (obj.last_indexed !== undefined && typeof obj.last_indexed !== \"string\") {\n throw new Error(\"AnalyzerStatus.last_indexed must be a string\");\n }\n\n // Build detected from validated detection data based on installed flag\n const detectedResult = installed\n ? {\n installed: true,\n binary_path: detected.binary_path as string,\n version: detected.version as string | undefined,\n mcp_registered: detected.mcp_registered as boolean | undefined,\n contract_ok: detected.contract_ok as boolean | undefined,\n }\n : {\n installed: false,\n };\n\n return {\n detected: detectedResult,\n indexed: true,\n index_meta: validatedIndexMeta,\n fresh: obj.fresh as boolean,\n last_indexed: obj.last_indexed as string | undefined,\n } as AnalyzerStatus;\n } else {\n // When indexed: false, index_meta must not be present\n if (obj.index_meta !== undefined) {\n throw new Error(\"AnalyzerStatus.index_meta must not be present when indexed: false\");\n }\n\n // Validate optional last_indexed if present\n if (obj.last_indexed !== undefined && typeof obj.last_indexed !== \"string\") {\n throw new Error(\"AnalyzerStatus.last_indexed must be a string\");\n }\n\n // Build detected from validated detection data based on installed flag\n const detectedResult = installed\n ? {\n installed: true,\n binary_path: detected.binary_path as string,\n version: detected.version as string | undefined,\n mcp_registered: detected.mcp_registered as boolean | undefined,\n contract_ok: detected.contract_ok as boolean | undefined,\n }\n : {\n installed: false,\n };\n\n return {\n detected: detectedResult,\n indexed: false,\n fresh: obj.fresh as boolean,\n last_indexed: obj.last_indexed as string | undefined,\n } as AnalyzerStatus;\n }\n}\n\n/**\n * Get the base directory for analyzer state files\n * Resolves to `.dr/analyzers/` (and optionally `{analyzerName}/` subdirectory)\n *\n * @param baseDir Optional base directory. Defaults to process.cwd()\n * @param analyzerName Optional analyzer name for per-analyzer subdirectory\n * @throws Error if analyzerName is provided but empty or contains path traversal characters\n */\nfunction getStateDir(baseDir?: string, analyzerName?: string): string {\n const base = baseDir ?? process.cwd();\n const analyzersDir = path.join(base, \".dr\", \"analyzers\");\n\n if (analyzerName !== undefined) {\n validateAnalyzerName(analyzerName);\n return path.join(analyzersDir, analyzerName);\n }\n\n return analyzersDir;\n}\n\n/**\n * Ensure the state directory exists\n * Creates intermediate directories with recursive flag\n *\n * @param baseDir Optional base directory. Defaults to process.cwd()\n * @param analyzerName Optional analyzer name for per-analyzer subdirectory\n */\nasync function ensureStateDir(baseDir?: string, analyzerName?: string): Promise<void> {\n await fs.mkdir(getStateDir(baseDir, analyzerName), { recursive: true });\n}\n\n/**\n * Get the full path to a state file\n *\n * @param filename Name of the state file\n * @param baseDir Optional base directory. Defaults to process.cwd()\n * @param analyzerName Optional analyzer name for per-analyzer subdirectory\n * @returns Full path to the file\n */\nfunction getStatePath(filename: string, baseDir?: string, analyzerName?: string): string {\n return path.join(getStateDir(baseDir, analyzerName), filename);\n}\n\n/**\n * Read session state from `.dr/analyzers/session.json`\n *\n * @param baseDir Optional base directory. Defaults to process.cwd()\n * @returns Parsed and validated session state, or null if file does not exist\n * @throws Error if file exists but is malformed JSON or invalid structure\n */\nexport async function readSession(baseDir?: string): Promise<SessionState | null> {\n const filePath = getStatePath(\"session.json\", baseDir);\n try {\n const content = await fs.readFile(filePath, \"utf-8\");\n const parsed = JSON.parse(content);\n return validateSessionState(parsed);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && (error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n throw error;\n }\n}\n\n/**\n * Write session state to `.dr/analyzers/session.json`\n *\n * Creates the state directory if it does not exist.\n * Writes with pretty-printed JSON (2-space indentation).\n *\n * @param state Session state to persist\n * @param baseDir Optional base directory. Defaults to process.cwd()\n */\nexport async function writeSession(state: SessionState, baseDir?: string): Promise<void> {\n await ensureStateDir(baseDir);\n const filePath = getStatePath(\"session.json\", baseDir);\n const content = JSON.stringify(state, null, 2);\n await fs.writeFile(filePath, content, \"utf-8\");\n}\n\n/**\n * Read index metadata from `.dr/analyzers/{analyzerName}/index-meta.json`\n *\n * @param baseDir Optional base directory. Defaults to process.cwd()\n * @param analyzerName Analyzer name for per-analyzer subdirectory (required)\n * @returns Parsed and validated index metadata, or null if file does not exist\n * @throws Error if file exists but is malformed JSON or invalid structure\n */\nexport async function readIndexMeta(\n baseDir: string | undefined,\n analyzerName: string\n): Promise<IndexMeta | null> {\n const filePath = getStatePath(\"index-meta.json\", baseDir, analyzerName);\n try {\n const content = await fs.readFile(filePath, \"utf-8\");\n const parsed = JSON.parse(content);\n return validateIndexMeta(parsed);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && (error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n throw error;\n }\n}\n\n/**\n * Write index metadata to `.dr/analyzers/{analyzerName}/index-meta.json`\n *\n * Creates the state directory (including analyzer subdirectory) if it does not exist.\n * Writes with pretty-printed JSON (2-space indentation).\n *\n * @param meta Index metadata to persist\n * @param baseDir Optional base directory. Defaults to process.cwd()\n * @param analyzerName Analyzer name for per-analyzer subdirectory (required)\n */\nexport async function writeIndexMeta(\n meta: IndexMeta,\n baseDir: string | undefined,\n analyzerName: string\n): Promise<void> {\n await ensureStateDir(baseDir, analyzerName);\n const filePath = getStatePath(\"index-meta.json\", baseDir, analyzerName);\n const content = JSON.stringify(meta, null, 2);\n await fs.writeFile(filePath, content, \"utf-8\");\n}\n\n/**\n * Read analyzer status from `.dr/analyzers/{analyzerName}/status.json`\n *\n * @param baseDir Optional base directory. Defaults to process.cwd()\n * @param analyzerName Analyzer name for per-analyzer subdirectory (required)\n * @returns Parsed and validated analyzer status, or null if file does not exist\n * @throws Error if file exists but is malformed JSON or invalid structure\n */\nexport async function readStatus(\n baseDir: string | undefined,\n analyzerName: string\n): Promise<AnalyzerStatus | null> {\n const filePath = getStatePath(\"status.json\", baseDir, analyzerName);\n try {\n const content = await fs.readFile(filePath, \"utf-8\");\n const parsed = JSON.parse(content);\n return validateAnalyzerStatus(parsed);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && (error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n throw error;\n }\n}\n\n/**\n * Write analyzer status to `.dr/analyzers/{analyzerName}/status.json`\n *\n * Creates the state directory (including analyzer subdirectory) if it does not exist.\n * Writes with pretty-printed JSON (2-space indentation).\n *\n * @param status Analyzer status to persist\n * @param baseDir Optional base directory. Defaults to process.cwd()\n * @param analyzerName Analyzer name for per-analyzer subdirectory (required)\n */\nexport async function writeStatus(\n status: AnalyzerStatus,\n baseDir: string | undefined,\n analyzerName: string\n): Promise<void> {\n await ensureStateDir(baseDir, analyzerName);\n const filePath = getStatePath(\"status.json\", baseDir, analyzerName);\n const content = JSON.stringify(status, null, 2);\n await fs.writeFile(filePath, content, \"utf-8\");\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,206 @@
1
+ import { spawn } from "child_process";
2
+ class StdioClient {
3
+ proc = null;
4
+ requestId = 0;
5
+ pendingRequests = /* @__PURE__ */ new Map();
6
+ /**
7
+ * Spawn an analyzer process
8
+ *
9
+ * @param binaryPath Path to the analyzer binary
10
+ * @param args Optional command-line arguments (or env object for backwards compatibility)
11
+ * @param env Optional environment variables (merged with process.env)
12
+ * @throws Error if spawn fails
13
+ */
14
+ spawn(binaryPath, args, env) {
15
+ if (this.proc)
16
+ throw new Error("Process already spawned");
17
+ let actualArgs = [], actualEnv = process.env;
18
+ if (Array.isArray(args) ? (actualArgs = args, actualEnv = { ...actualEnv, ...env }) : args && typeof args == "object" && (actualEnv = { ...actualEnv, ...args }), this.proc = spawn(binaryPath, actualArgs, {
19
+ stdio: ["pipe", "pipe", "pipe"],
20
+ env: actualEnv
21
+ }), this.proc.stdout) {
22
+ this.proc.stdout.setEncoding("utf-8");
23
+ let buffer = "";
24
+ this.proc.stdout.on("data", (chunk) => {
25
+ buffer += chunk;
26
+ const lines = buffer.split(`
27
+ `);
28
+ buffer = lines.pop() || "";
29
+ for (const line of lines)
30
+ if (line.trim())
31
+ try {
32
+ const message = JSON.parse(line);
33
+ this.handleMessage(message);
34
+ } catch {
35
+ const firstKey = this.pendingRequests.keys().next().value;
36
+ if (firstKey !== void 0) {
37
+ const pending = this.pendingRequests.get(firstKey);
38
+ pending && (clearTimeout(pending.timeout), this.pendingRequests.delete(firstKey), pending.reject(new Error(`Failed to parse JSON-RPC response from analyzer: ${line}`)));
39
+ } else
40
+ console.error(`Failed to parse JSON-RPC message from analyzer: ${line}`);
41
+ }
42
+ });
43
+ }
44
+ this.proc.stderr && (this.proc.stderr.setEncoding("utf-8"), this.proc.stderr.on("data", (chunk) => {
45
+ console.error(`[Analyzer stderr] ${chunk}`);
46
+ })), this.proc.on("exit", (code, signal) => {
47
+ this.proc = null;
48
+ for (const [, { reject, timeout }] of this.pendingRequests)
49
+ clearTimeout(timeout), reject(new Error(`Process exited with code ${code} (signal: ${signal})`));
50
+ this.pendingRequests.clear();
51
+ }), this.proc.on("error", (error) => {
52
+ for (const [, { reject, timeout }] of this.pendingRequests)
53
+ clearTimeout(timeout), reject(error);
54
+ this.pendingRequests.clear();
55
+ });
56
+ }
57
+ /**
58
+ * Initialize the analyzer with client information
59
+ *
60
+ * Sends an initialize request and waits for the response.
61
+ * Times out after 2 seconds if no response is received.
62
+ *
63
+ * @param clientInfo Client information object
64
+ * @throws Error if initialize times out or fails
65
+ */
66
+ async initialize(clientInfo) {
67
+ return this.callTool("initialize", clientInfo, { timeout: 2e3 });
68
+ }
69
+ /**
70
+ * Call a tool on the analyzer
71
+ *
72
+ * Sends a JSON-RPC request and waits for the response.
73
+ * Defaults to 30-second timeout for graph queries.
74
+ *
75
+ * @param name Tool name (method)
76
+ * @param params Tool parameters
77
+ * @param options Optional configuration (timeout in milliseconds)
78
+ * @returns Tool result
79
+ * @throws Error if tool call fails or times out
80
+ */
81
+ async callTool(name, params, options) {
82
+ if (!this.proc)
83
+ throw new Error("Process not spawned");
84
+ const timeout = options?.timeout ?? 3e4, id = ++this.requestId, request = {
85
+ jsonrpc: "2.0",
86
+ method: name,
87
+ params,
88
+ id
89
+ };
90
+ return new Promise((resolve, reject) => {
91
+ const timeoutHandle = setTimeout(() => {
92
+ this.pendingRequests.delete(id), reject(new Error(`Tool call '${name}' timed out after ${timeout}ms`));
93
+ }, timeout);
94
+ this.pendingRequests.set(id, { resolve, reject, timeout: timeoutHandle });
95
+ try {
96
+ const line = JSON.stringify(request) + `
97
+ `;
98
+ if (!this.proc || !this.proc.stdin) {
99
+ clearTimeout(timeoutHandle), this.pendingRequests.delete(id), reject(new Error("Process or stdin closed before write could complete"));
100
+ return;
101
+ }
102
+ this.proc.stdin.write(line) || this.proc.stdin.once("drain", () => {
103
+ });
104
+ } catch (error) {
105
+ clearTimeout(timeoutHandle), this.pendingRequests.delete(id), reject(error);
106
+ }
107
+ });
108
+ }
109
+ /**
110
+ * Close the connection and clean up
111
+ *
112
+ * Sends a shutdown notification and terminates the process.
113
+ * Sends SIGTERM first, then escalates to SIGKILL after 1 second if needed.
114
+ * Cleans up all pending requests and event listeners.
115
+ */
116
+ /**
117
+ * Invoke a tool on the analyzer via the MCP tools/call protocol
118
+ *
119
+ * Sends a tools/call request with {name, arguments} and unwraps the
120
+ * MCP content envelope from the response (content[0].text parsed as JSON).
121
+ *
122
+ * Use this for all tool invocations. Use callTool() only for MCP protocol
123
+ * methods (initialize, tools/list).
124
+ *
125
+ * @param name Tool name (e.g., "search_graph", "index_repository")
126
+ * @param args Tool arguments to pass as the arguments field
127
+ * @param options Optional configuration (timeout in milliseconds)
128
+ * @returns Parsed tool result unwrapped from MCP content envelope
129
+ */
130
+ async invokeTool(name, args, options) {
131
+ const response = await this.callTool("tools/call", { name, arguments: args ?? {} }, options);
132
+ if (response?.content && Array.isArray(response.content) && response.content.length > 0) {
133
+ const first = response.content[0];
134
+ if (first.type === "text" && typeof first.text == "string")
135
+ try {
136
+ return JSON.parse(first.text);
137
+ } catch {
138
+ return first.text;
139
+ }
140
+ }
141
+ return response;
142
+ }
143
+ close() {
144
+ if (!this.proc)
145
+ return;
146
+ const procToClose = this.proc;
147
+ this.proc = null;
148
+ try {
149
+ const line = JSON.stringify({
150
+ jsonrpc: "2.0",
151
+ method: "shutdown"
152
+ }) + `
153
+ `;
154
+ procToClose.stdin?.write(line);
155
+ } catch {
156
+ }
157
+ for (const [, { reject, timeout }] of this.pendingRequests)
158
+ clearTimeout(timeout), reject(new Error("Client closed"));
159
+ this.pendingRequests.clear(), procToClose.stdout && procToClose.stdout.removeAllListeners(), procToClose.stderr && procToClose.stderr.removeAllListeners(), procToClose.removeAllListeners();
160
+ try {
161
+ procToClose.stdin?.end(), procToClose.killed || (procToClose.kill("SIGTERM"), setTimeout(() => {
162
+ if (procToClose.exitCode === null)
163
+ try {
164
+ procToClose.kill("SIGKILL");
165
+ } catch {
166
+ }
167
+ }, 1e3).unref());
168
+ } catch {
169
+ }
170
+ }
171
+ /**
172
+ * Handle a JSON-RPC message from the analyzer
173
+ *
174
+ * Matches responses to pending requests by ID and resolves/rejects accordingly.
175
+ * Extracts error information from JSON-RPC error objects.
176
+ *
177
+ * @param message Parsed JSON-RPC message
178
+ */
179
+ handleMessage(message) {
180
+ if (!message || typeof message != "object")
181
+ return;
182
+ const msg = message;
183
+ if (!("id" in msg) || typeof msg.id != "number")
184
+ return;
185
+ const msgId = msg.id, pending = this.pendingRequests.get(msgId);
186
+ if (!pending) {
187
+ console.warn(`Received response with unmatched ID ${msgId} (type: ${typeof msgId}). Pending request IDs: [${Array.from(this.pendingRequests.keys()).join(", ")}]. This may indicate a type mismatch or stale response.`);
188
+ return;
189
+ }
190
+ const { resolve, reject, timeout } = pending;
191
+ if (clearTimeout(timeout), this.pendingRequests.delete(msgId), "error" in msg && msg.error !== null && typeof msg.error == "object") {
192
+ const error = msg.error, errMessage = error.message || "Unknown error", code = error.code ?? -1, data = error.data, errorMessage = data ? `${errMessage}: ${JSON.stringify(data)}` : errMessage;
193
+ reject(new Error(`[Error ${code}] ${errorMessage}`));
194
+ return;
195
+ }
196
+ if ("result" in msg) {
197
+ resolve(msg.result);
198
+ return;
199
+ }
200
+ reject(new Error("Invalid JSON-RPC response: no result or error field"));
201
+ }
202
+ }
203
+ export {
204
+ StdioClient
205
+ };
206
+ //# sourceMappingURL=stdio-client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/analyzers/stdio-client.ts"],
4
+ "sourcesContent": ["/**\n * MCP JSON-RPC 2.0 stdio client\n *\n * Minimal implementation for communicating with analyzers via JSON-RPC over stdio.\n * Handles process spawning, request/response correlation, timeouts, and clean shutdown.\n *\n * Protocol: JSON-RPC 2.0 with line-delimited JSON framing.\n * - Each request/response is a complete JSON object on a single line\n * - Request IDs are integers for correlation\n * - Errors are extracted from JSON-RPC error response objects\n */\n\nimport { spawn, ChildProcess } from \"child_process\";\n\n/**\n * JSON-RPC 2.0 request structure\n */\ninterface JsonRpcRequest {\n jsonrpc: \"2.0\";\n method: string;\n params?: unknown;\n id: number;\n}\n\n/**\n * JSON-RPC notification (no id field)\n */\ninterface JsonRpcNotification {\n jsonrpc: \"2.0\";\n method: string;\n params?: unknown;\n}\n\n/**\n * MCP client for communicating with analyzer backends via JSON-RPC 2.0 stdio\n */\nexport class StdioClient {\n private proc: ChildProcess | null = null;\n private requestId: number = 0;\n private pendingRequests: Map<number, { resolve: (value: unknown) => void; reject: (reason: Error) => void; timeout: NodeJS.Timeout }> = new Map();\n\n /**\n * Spawn an analyzer process\n *\n * @param binaryPath Path to the analyzer binary\n * @param args Optional command-line arguments (or env object for backwards compatibility)\n * @param env Optional environment variables (merged with process.env)\n * @throws Error if spawn fails\n */\n spawn(binaryPath: string, args?: string[] | Record<string, string>, env?: Record<string, string>): void {\n if (this.proc) {\n throw new Error(\"Process already spawned\");\n }\n\n // Handle backwards compatibility: if args is an object, treat it as env\n let actualArgs: string[] = [];\n let actualEnv = process.env as Record<string, string>;\n\n if (Array.isArray(args)) {\n actualArgs = args;\n actualEnv = { ...actualEnv, ...env };\n } else if (args && typeof args === \"object\") {\n actualEnv = { ...actualEnv, ...args };\n }\n\n this.proc = spawn(binaryPath, actualArgs, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n env: actualEnv,\n });\n\n // Set up stdout listener for responses\n if (this.proc.stdout) {\n this.proc.stdout.setEncoding(\"utf-8\");\n let buffer = \"\";\n\n this.proc.stdout.on(\"data\", (chunk: string) => {\n buffer += chunk;\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\";\n\n for (const line of lines) {\n if (!line.trim()) continue;\n\n try {\n const message = JSON.parse(line);\n this.handleMessage(message);\n } catch (error) {\n // If we have pending requests, reject the oldest one since it likely\n // sent the request that produced this invalid response\n const firstKey = this.pendingRequests.keys().next().value;\n if (firstKey !== undefined) {\n const pending = this.pendingRequests.get(firstKey);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pendingRequests.delete(firstKey);\n pending.reject(new Error(`Failed to parse JSON-RPC response from analyzer: ${line}`));\n }\n } else {\n // No pending requests, just log the error\n console.error(`Failed to parse JSON-RPC message from analyzer: ${line}`);\n }\n }\n }\n });\n }\n\n // Set up stderr listener\n if (this.proc.stderr) {\n this.proc.stderr.setEncoding(\"utf-8\");\n this.proc.stderr.on(\"data\", (chunk: string) => {\n console.error(`[Analyzer stderr] ${chunk}`);\n });\n }\n\n // Handle process exit\n this.proc.on(\"exit\", (code: number | null, signal: string | null) => {\n this.proc = null;\n // Reject all pending requests\n for (const [, { reject, timeout }] of this.pendingRequests) {\n clearTimeout(timeout);\n reject(new Error(`Process exited with code ${code} (signal: ${signal})`));\n }\n this.pendingRequests.clear();\n });\n\n this.proc.on(\"error\", (error: Error) => {\n // Reject all pending requests\n for (const [, { reject, timeout }] of this.pendingRequests) {\n clearTimeout(timeout);\n reject(error);\n }\n this.pendingRequests.clear();\n });\n }\n\n /**\n * Initialize the analyzer with client information\n *\n * Sends an initialize request and waits for the response.\n * Times out after 2 seconds if no response is received.\n *\n * @param clientInfo Client information object\n * @throws Error if initialize times out or fails\n */\n async initialize(clientInfo: Record<string, unknown>): Promise<unknown> {\n return this.callTool(\"initialize\", clientInfo, { timeout: 2000 });\n }\n\n /**\n * Call a tool on the analyzer\n *\n * Sends a JSON-RPC request and waits for the response.\n * Defaults to 30-second timeout for graph queries.\n *\n * @param name Tool name (method)\n * @param params Tool parameters\n * @param options Optional configuration (timeout in milliseconds)\n * @returns Tool result\n * @throws Error if tool call fails or times out\n */\n async callTool(\n name: string,\n params?: unknown,\n options?: { timeout?: number }\n ): Promise<unknown> {\n if (!this.proc) {\n throw new Error(\"Process not spawned\");\n }\n\n const timeout = options?.timeout ?? 30000;\n const id = ++this.requestId;\n\n const request: JsonRpcRequest = {\n jsonrpc: \"2.0\",\n method: name,\n params,\n id,\n };\n\n return new Promise((resolve, reject) => {\n const timeoutHandle = setTimeout(() => {\n this.pendingRequests.delete(id);\n reject(new Error(`Tool call '${name}' timed out after ${timeout}ms`));\n }, timeout);\n\n this.pendingRequests.set(id, { resolve, reject, timeout: timeoutHandle });\n\n try {\n const line = JSON.stringify(request) + \"\\n\";\n // Explicit null checks to prevent race condition with exit handler\n if (!this.proc || !this.proc.stdin) {\n clearTimeout(timeoutHandle);\n this.pendingRequests.delete(id);\n reject(new Error(\"Process or stdin closed before write could complete\"));\n return;\n }\n\n if (!this.proc.stdin.write(line)) {\n // Write returned false (backpressure), but data is already in the buffer.\n // No action needed \u2014 the data will be flushed automatically.\n this.proc.stdin.once(\"drain\", () => {\n // Drain event listener registered but no action needed\n });\n }\n } catch (error) {\n clearTimeout(timeoutHandle);\n this.pendingRequests.delete(id);\n reject(error);\n }\n });\n }\n\n /**\n * Close the connection and clean up\n *\n * Sends a shutdown notification and terminates the process.\n * Sends SIGTERM first, then escalates to SIGKILL after 1 second if needed.\n * Cleans up all pending requests and event listeners.\n */\n\n /**\n * Invoke a tool on the analyzer via the MCP tools/call protocol\n *\n * Sends a tools/call request with {name, arguments} and unwraps the\n * MCP content envelope from the response (content[0].text parsed as JSON).\n *\n * Use this for all tool invocations. Use callTool() only for MCP protocol\n * methods (initialize, tools/list).\n *\n * @param name Tool name (e.g., \"search_graph\", \"index_repository\")\n * @param args Tool arguments to pass as the arguments field\n * @param options Optional configuration (timeout in milliseconds)\n * @returns Parsed tool result unwrapped from MCP content envelope\n */\n async invokeTool(\n name: string,\n args?: unknown,\n options?: { timeout?: number }\n ): Promise<unknown> {\n const response = await this.callTool(\n \"tools/call\",\n { name, arguments: args ?? {} },\n options\n ) as { content?: Array<{ type: string; text?: string }>; isError?: boolean };\n\n // Unwrap MCP tools/call envelope: result is JSON-encoded in content[0].text\n if (response?.content && Array.isArray(response.content) && response.content.length > 0) {\n const first = response.content[0];\n if (first.type === \"text\" && typeof first.text === \"string\") {\n try {\n return JSON.parse(first.text);\n } catch {\n return first.text;\n }\n }\n }\n return response;\n }\n\n close(): void {\n if (!this.proc) {\n return;\n }\n\n const procToClose = this.proc;\n this.proc = null;\n\n // Send shutdown notification\n try {\n const notification: JsonRpcNotification = {\n jsonrpc: \"2.0\",\n method: \"shutdown\",\n };\n const line = JSON.stringify(notification) + \"\\n\";\n procToClose.stdin?.write(line);\n } catch (error) {\n // Ignore write errors during shutdown\n }\n\n // Clean up pending requests\n for (const [, { reject, timeout }] of this.pendingRequests) {\n clearTimeout(timeout);\n reject(new Error(\"Client closed\"));\n }\n this.pendingRequests.clear();\n\n // Remove listeners\n if (procToClose.stdout) {\n procToClose.stdout.removeAllListeners();\n }\n if (procToClose.stderr) {\n procToClose.stderr.removeAllListeners();\n }\n procToClose.removeAllListeners();\n\n // Terminate process with SIGKILL fallback\n try {\n procToClose.stdin?.end();\n if (!procToClose.killed) {\n procToClose.kill(\"SIGTERM\");\n\n // Schedule SIGKILL fallback after 1 second if process doesn't exit\n const killTimer = setTimeout(() => {\n // Check if process has actually exited (exitCode is non-null once exit event fires)\n if (procToClose.exitCode === null) {\n try {\n procToClose.kill(\"SIGKILL\");\n } catch {\n // Process may have already exited\n }\n }\n }, 1000);\n\n // Unreference the timer so it doesn't keep the event loop alive\n killTimer.unref();\n }\n } catch (error) {\n // Ignore errors during shutdown\n }\n }\n\n /**\n * Handle a JSON-RPC message from the analyzer\n *\n * Matches responses to pending requests by ID and resolves/rejects accordingly.\n * Extracts error information from JSON-RPC error objects.\n *\n * @param message Parsed JSON-RPC message\n */\n private handleMessage(message: unknown): void {\n if (!message || typeof message !== \"object\") {\n return;\n }\n\n const msg = message as Record<string, unknown>;\n\n // Ignore notifications (no id field)\n if (!(\"id\" in msg) || typeof msg.id !== \"number\") {\n return;\n }\n\n const msgId = msg.id as number;\n const pending = this.pendingRequests.get(msgId);\n\n if (!pending) {\n // Log diagnostic information for unmatched response IDs\n console.warn(\n `Received response with unmatched ID ${msgId} (type: ${typeof msgId}). ` +\n `Pending request IDs: [${Array.from(this.pendingRequests.keys()).join(\", \")}]. ` +\n `This may indicate a type mismatch or stale response.`\n );\n return;\n }\n\n const { resolve, reject, timeout } = pending;\n clearTimeout(timeout);\n this.pendingRequests.delete(msgId);\n\n // Check for error response\n if (\"error\" in msg && msg.error !== null && typeof msg.error === \"object\") {\n const error = msg.error as Record<string, unknown>;\n const errMessage = (error.message as string) || \"Unknown error\";\n const code = (error.code as number) ?? -1;\n const data = error.data;\n\n const errorMessage = data ? `${errMessage}: ${JSON.stringify(data)}` : errMessage;\n reject(new Error(`[Error ${code}] ${errorMessage}`));\n return;\n }\n\n // Success response\n if (\"result\" in msg) {\n resolve(msg.result);\n return;\n }\n\n // Invalid response\n reject(new Error(\"Invalid JSON-RPC response: no result or error field\"));\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,15 @@
1
+ const VALID_HTTP_METHODS = [
2
+ "GET",
3
+ "POST",
4
+ "PUT",
5
+ "DELETE",
6
+ "PATCH",
7
+ "HEAD",
8
+ "OPTIONS",
9
+ "TRACE",
10
+ "CONNECT"
11
+ ];
12
+ export {
13
+ VALID_HTTP_METHODS
14
+ };
15
+ //# sourceMappingURL=types.js.map