@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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/server/telemetry-middleware.ts"],
4
- "sourcesContent": ["/**\n * OpenTelemetry middleware for Hono server\n * Instruments HTTP requests with spans and semantic attributes\n */\n\nimport type { Context, Next } from 'hono';\n\n// Conditional imports based on telemetry flag\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== 'undefined' ? TELEMETRY_ENABLED : false;\n\n/**\n * Hono middleware that creates a span for each HTTP request\n * Captures HTTP semantic attributes according to OpenTelemetry conventions:\n * - http.method: HTTP request method\n * - http.route: HTTP route pattern\n * - http.status_code: HTTP response status code\n * - http.url: Full request URL\n * - http.user_agent: User agent string\n *\n * Also emits logs at request start and completion per SigNoz integration guide\n * for request lifecycle tracking.\n */\nexport async function telemetryMiddleware(c: Context, next: Next): Promise<void> {\n if (!isTelemetryEnabled) {\n return next();\n }\n\n // Dynamic import for tree-shaking\n const { startSpan, endSpan, emitLog } = await import('../telemetry/index.js');\n const { SeverityNumber } = await import('@opentelemetry/api-logs');\n\n const method = c.req.method;\n const path = c.req.path;\n const route = c.req.routePath || path; // Use route pattern if available\n const requestStartTime = Date.now();\n\n // Create span for the HTTP request\n const span = startSpan('http.server.request', {\n 'http.method': method,\n 'http.route': route,\n 'http.url': c.req.url,\n 'http.target': path,\n 'http.user_agent': c.req.header('user-agent') || '',\n 'http.scheme': new URL(c.req.url).protocol.replace(':', ''),\n });\n\n // Log request received (per SigNoz integration guide: request lifecycle logging)\n await emitLog(SeverityNumber.INFO, 'Request received', {\n 'http.method': method,\n 'http.route': route,\n 'http.target': path,\n });\n\n try {\n // Process the request\n await next();\n\n // Add response attributes after request is processed\n if (span && 'setAttribute' in span) {\n const statusCode = c.res.status;\n const durationMs = Date.now() - requestStartTime;\n\n (span as any).setAttribute('http.status_code', statusCode);\n (span as any).setAttribute('http.duration_ms', durationMs);\n\n // Set span status based on HTTP status code\n if (statusCode >= 500) {\n (span as any).setStatus({ code: 2, message: 'Server Error' }); // ERROR\n } else if (statusCode >= 400) {\n (span as any).setStatus({ code: 2, message: 'Client Error' }); // ERROR\n } else {\n (span as any).setStatus({ code: 1 }); // OK\n }\n\n // Log request completed (per SigNoz integration guide: request lifecycle logging)\n await emitLog(\n statusCode >= 400 ? SeverityNumber.ERROR : SeverityNumber.INFO,\n 'Request completed',\n {\n 'http.method': method,\n 'http.route': route,\n 'http.target': path,\n 'http.status_code': statusCode,\n 'duration_ms': durationMs,\n }\n );\n }\n } catch (error) {\n // Record exception in span\n if (span && 'recordException' in span) {\n (span as any).recordException(error as Error);\n (span as any).setStatus({ code: 2, message: (error as Error).message }); // ERROR\n }\n throw error;\n } finally {\n // End the span\n endSpan(span);\n }\n}\n"],
5
- "mappings": "AASA,MAAM,qBAAgE;AActE,eAAsB,oBAAoB,GAAY,MAAU;AAE5D,SAAO,KAAI;AA6Bb,MAAI;AAKF,QAHA,MAAM,KAAI,GAGN,QAAQ,kBAAkB,MAAM;AAClC,YAAM,aAAa,EAAE,IAAI,QACnB,aAAa,KAAK,IAAG,IAAK;AAE/B,WAAa,aAAa,oBAAoB,UAAU,GACxD,KAAa,aAAa,oBAAoB,UAAU,GAGrD,cAAc,MACf,KAAa,UAAU,EAAE,MAAM,GAAG,SAAS,eAAc,CAAE,IACnD,cAAc,MACtB,KAAa,UAAU,EAAE,MAAM,GAAG,SAAS,eAAc,CAAE,IAE3D,KAAa,UAAU,EAAE,MAAM,EAAC,CAAE,GAIrC,MAAM,QACJ,cAAc,MAAM,eAAe,QAAQ,eAAe,MAC1D,qBACA;QACE,eAAe;QACf,cAAc;QACd,eAAe;QACf,oBAAoB;QACpB,aAAe;OAChB;IAEL;EACF,SAAS,OAAO;AAEd,UAAI,QAAQ,qBAAqB,SAC9B,KAAa,gBAAgB,KAAc,GAC3C,KAAa,UAAU,EAAE,MAAM,GAAG,SAAU,MAAgB,QAAO,CAAE,IAElE;EACR;AAEE,YAAQ,IAAI;EACd;AACF;",
4
+ "sourcesContent": ["/**\n * OpenTelemetry middleware for Hono server\n * Instruments HTTP requests with spans and semantic attributes\n */\n\nimport type { Context, Next } from \"hono\";\n\n// Conditional imports based on telemetry flag\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== \"undefined\" ? TELEMETRY_ENABLED : false;\n\n/**\n * Hono middleware that creates a span for each HTTP request\n * Captures HTTP semantic attributes according to OpenTelemetry conventions:\n * - http.method: HTTP request method\n * - http.route: HTTP route pattern\n * - http.status_code: HTTP response status code\n * - http.url: Full request URL\n * - http.user_agent: User agent string\n *\n * Also emits logs at request start and completion per SigNoz integration guide\n * for request lifecycle tracking.\n */\nexport async function telemetryMiddleware(c: Context, next: Next): Promise<void> {\n const method = c.req.method;\n const path = c.req.path;\n const url = c.req.url;\n const isDebug = process.env.DEBUG || process.env.VERBOSE;\n\n // Log ALL incoming requests for debugging\n if (isDebug) {\n console.log(`[HTTP] ${method} ${path} (full URL: ${url})`);\n }\n\n if (!isTelemetryEnabled) {\n if (isDebug) {\n console.log(`[Telemetry] Skipping span creation - TELEMETRY_ENABLED is false`);\n }\n return next();\n }\n\n // Dynamic import for tree-shaking\n const { startActiveSpan } = await import(\"../telemetry/index.js\");\n\n const route = c.req.routePath || path; // Use route pattern if available\n\n if (isDebug) {\n console.log(`[Telemetry] Creating active span for http.server.request`);\n }\n\n // Use startActiveSpan for proper context propagation and automatic span management\n return await startActiveSpan(\n \"http.server.request\",\n async (span) => {\n const requestStartTime = Date.now();\n\n // Set initial attributes\n span.setAttributes({\n \"http.method\": method,\n \"http.route\": route,\n \"http.url\": url,\n \"http.target\": path,\n \"http.user_agent\": c.req.header(\"user-agent\") || \"\",\n \"http.scheme\": new URL(url).protocol.replace(\":\", \"\"),\n });\n\n if (isDebug) {\n console.log(`[Telemetry] Active span created successfully`);\n }\n\n try {\n // Process the request\n await next();\n\n // Add response attributes after request is processed\n const statusCode = c.res.status;\n const durationMs = Date.now() - requestStartTime;\n\n span.setAttribute(\"http.status_code\", statusCode);\n span.setAttribute(\"http.duration_ms\", durationMs);\n\n // Set span status based on HTTP status code\n if (statusCode >= 500) {\n span.setStatus({ code: 2, message: \"Server Error\" }); // ERROR\n } else if (statusCode >= 400) {\n span.setStatus({ code: 2, message: \"Client Error\" }); // ERROR\n } else {\n span.setStatus({ code: 1 }); // OK\n }\n } catch (error) {\n // Record exception in span\n span.recordException(error as Error);\n span.setStatus({ code: 2, message: (error as Error).message }); // ERROR\n throw error;\n }\n // Span is automatically ended when this async function completes\n },\n {\n \"http.method\": method,\n \"http.route\": route,\n }\n );\n}\n"],
5
+ "mappings": "AASA,MAAM,qBAAgE;AActE,eAAsB,oBAAoB,GAAY,MAAU;AAC9D,QAAM,SAAS,EAAE,IAAI,QACf,OAAO,EAAE,IAAI,MACb,MAAM,EAAE,IAAI,KACZ,UAAU,QAAQ,IAAI,SAAS,QAAQ,IAAI;AAGjD,SAAI,WACF,QAAQ,IAAI,UAAU,MAAM,IAAI,IAAI,eAAe,GAAG,GAAG,GAIrD,WACF,QAAQ,IAAI,iEAAiE,GAExE,KAAI;AAIb,QAAM,EAAE,gBAAe,IAAK,MAAM,OAAO,uBAAuB,GAE1D,QAAQ,EAAE,IAAI,aAAa;AAEjC,SAAI,WACF,QAAQ,IAAI,0DAA0D,GAIjE,MAAM,gBACX,uBACA,OAAO,SAAQ;AACb,UAAM,mBAAmB,KAAK,IAAG;AAGjC,SAAK,cAAc;MACjB,eAAe;MACf,cAAc;MACd,YAAY;MACZ,eAAe;MACf,mBAAmB,EAAE,IAAI,OAAO,YAAY,KAAK;MACjD,eAAe,IAAI,IAAI,GAAG,EAAE,SAAS,QAAQ,KAAK,EAAE;KACrD,GAEG,WACF,QAAQ,IAAI,8CAA8C;AAG5D,QAAI;AAEF,YAAM,KAAI;AAGV,YAAM,aAAa,EAAE,IAAI,QACnB,aAAa,KAAK,IAAG,IAAK;AAEhC,WAAK,aAAa,oBAAoB,UAAU,GAChD,KAAK,aAAa,oBAAoB,UAAU,GAG5C,cAAc,MAChB,KAAK,UAAU,EAAE,MAAM,GAAG,SAAS,eAAc,CAAE,IAC1C,cAAc,MACvB,KAAK,UAAU,EAAE,MAAM,GAAG,SAAS,eAAc,CAAE,IAEnD,KAAK,UAAU,EAAE,MAAM,EAAC,CAAE;IAE9B,SAAS,OAAO;AAEd,iBAAK,gBAAgB,KAAc,GACnC,KAAK,UAAU,EAAE,MAAM,GAAG,SAAU,MAAgB,QAAO,CAAE,GACvD;IACR;EAEF,GACA;IACE,eAAe;IACf,cAAc;GACf;AAEL;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,65 @@
1
+ import { Model } from "./core/model.js";
2
+ import { VisualizationServer } from "./server/server.js";
3
+ import { getErrorMessage } from "./utils/errors.js";
4
+ const port = parseInt(process.env.DR_VISUALIZE_PORT || "8080", 10), projectPath = process.env.DR_PROJECT_PATH || process.cwd(), authEnabled = process.env.DR_AUTH_ENABLED !== "false", authToken = process.env.DR_AUTH_TOKEN && process.env.DR_AUTH_TOKEN.length > 0 ? process.env.DR_AUTH_TOKEN : void 0, withDanger = process.env.DR_WITH_DANGER === "true", viewerPath = process.env.DR_VIEWER_PATH, isTelemetryEnabled = !1;
5
+ let serverInstance = null, isShuttingDown = !1;
6
+ async function main() {
7
+ try {
8
+ if (isTelemetryEnabled)
9
+ try {
10
+ const { initTelemetry } = await import("./telemetry/index.js");
11
+ await initTelemetry();
12
+ const { loadOTLPConfig } = await import("./telemetry/config.js"), otlpConfig = await loadOTLPConfig();
13
+ if (process.env.DEBUG || process.env.VERBOSE) {
14
+ console.log("[Telemetry] SDK initialized in server subprocess"), console.log(`[Telemetry] OTLP traces endpoint: ${otlpConfig.endpoint}`), console.log(`[Telemetry] OTLP logs endpoint: ${otlpConfig.logsEndpoint}`), console.log(`[Telemetry] Service name: ${otlpConfig.serviceName}`);
15
+ const isBun = typeof globalThis.Bun < "u";
16
+ console.log(isBun ? "[Telemetry] Runtime: Bun (using fetch-based OTLP exporter)" : "[Telemetry] Runtime: Node.js (using http-based OTLP exporter)");
17
+ }
18
+ } catch (error) {
19
+ console.error("[Telemetry] Failed to initialize telemetry:", error), console.error("[Telemetry] Server will continue without telemetry");
20
+ }
21
+ else (process.env.DEBUG || process.env.VERBOSE) && console.log("[Telemetry] TELEMETRY_ENABLED is false - telemetry disabled");
22
+ const model = await Model.load(projectPath, { lazyLoad: !1 }), server = new VisualizationServer(model, {
23
+ authEnabled,
24
+ authToken,
25
+ withDanger,
26
+ viewerPath
27
+ });
28
+ serverInstance = server, await server.start(port), authEnabled && console.log(`TOKEN:${server.getAuthToken()}`), setupShutdownHandlers();
29
+ } catch (error) {
30
+ const message = getErrorMessage(error);
31
+ console.error(`Error: ${message}`), error instanceof Error && console.error(`Stack: ${error.stack}`), await gracefulShutdown(1);
32
+ }
33
+ }
34
+ async function gracefulShutdown(exitCode = 0) {
35
+ if (!isShuttingDown) {
36
+ isShuttingDown = !0;
37
+ try {
38
+ if (serverInstance && (serverInstance.stop(), serverInstance = null), isTelemetryEnabled) {
39
+ console.log("[Telemetry] Shutting down telemetry and flushing spans...");
40
+ const { shutdownTelemetry } = await import("./telemetry/index.js");
41
+ await shutdownTelemetry(), console.log("[Telemetry] Telemetry shutdown complete");
42
+ } else
43
+ process.env.DEBUG && console.log("[Telemetry] Telemetry is disabled (TELEMETRY_ENABLED=false at build time)");
44
+ } catch (error) {
45
+ process.env.DEBUG && console.error("Error during shutdown:", error);
46
+ } finally {
47
+ process.exit(exitCode);
48
+ }
49
+ }
50
+ }
51
+ function setupShutdownHandlers() {
52
+ process.on("SIGINT", async () => {
53
+ console.log(`
54
+ [SIGINT] Shutting down visualization server...`), await gracefulShutdown(0);
55
+ }), process.on("SIGTERM", async () => {
56
+ console.log(`
57
+ [SIGTERM] Shutting down visualization server...`), await gracefulShutdown(0);
58
+ }), process.on("uncaughtException", async (error) => {
59
+ console.error("Uncaught exception:", error), await gracefulShutdown(1);
60
+ }), process.on("unhandledRejection", async (reason) => {
61
+ console.error("Unhandled rejection:", reason), await gracefulShutdown(1);
62
+ });
63
+ }
64
+ main();
65
+ //# sourceMappingURL=server-entry.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/server-entry.ts"],
4
+ "sourcesContent": ["/**\n * Visualization Server Entry Point\n * This is a Bun-specific entry point for running the visualization server\n * It receives configuration via environment variables and starts the server\n */\n\nimport { Model } from \"./core/model.js\";\nimport { VisualizationServer } from \"./server/server.js\";\nimport { getErrorMessage } from \"./utils/errors.js\";\n\n// Get configuration from environment variables\nconst port = parseInt(process.env.DR_VISUALIZE_PORT || \"8080\", 10);\nconst projectPath = process.env.DR_PROJECT_PATH || process.cwd();\nconst authEnabled = process.env.DR_AUTH_ENABLED !== \"false\";\n// Only pass authToken if it's a non-empty string, otherwise let server generate one\nconst authToken =\n process.env.DR_AUTH_TOKEN && process.env.DR_AUTH_TOKEN.length > 0\n ? process.env.DR_AUTH_TOKEN\n : undefined;\nconst withDanger = process.env.DR_WITH_DANGER === \"true\";\nconst viewerPath = process.env.DR_VIEWER_PATH;\n\n// Conditional telemetry import based on compile-time flag\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== \"undefined\" ? TELEMETRY_ENABLED : false;\n\nlet serverInstance: VisualizationServer | null = null;\nlet isShuttingDown = false;\n\nasync function main() {\n try {\n // CRITICAL: Initialize telemetry SDK in subprocess\n // Without this, no spans will be created or exported even though TELEMETRY_ENABLED=true\n if (isTelemetryEnabled) {\n try {\n const { initTelemetry } = await import(\"./telemetry/index.js\");\n await initTelemetry();\n\n // Load and display actual OTLP configuration\n const { loadOTLPConfig } = await import(\"./telemetry/config.js\");\n const otlpConfig = await loadOTLPConfig();\n\n if (process.env.DEBUG || process.env.VERBOSE) {\n console.log(`[Telemetry] SDK initialized in server subprocess`);\n console.log(`[Telemetry] OTLP traces endpoint: ${otlpConfig.endpoint}`);\n console.log(`[Telemetry] OTLP logs endpoint: ${otlpConfig.logsEndpoint}`);\n console.log(`[Telemetry] Service name: ${otlpConfig.serviceName}`);\n\n // Runtime detection and compatibility info\n const isBun = typeof (globalThis as any).Bun !== \"undefined\";\n if (isBun) {\n console.log(`[Telemetry] Runtime: Bun (using fetch-based OTLP exporter)`);\n } else {\n console.log(`[Telemetry] Runtime: Node.js (using http-based OTLP exporter)`);\n }\n }\n } catch (error) {\n // Log telemetry initialization errors but don't fail the server\n console.error(\"[Telemetry] Failed to initialize telemetry:\", error);\n console.error(\"[Telemetry] Server will continue without telemetry\");\n }\n } else if (process.env.DEBUG || process.env.VERBOSE) {\n console.log(`[Telemetry] TELEMETRY_ENABLED is false - telemetry disabled`);\n }\n\n // Load model with full content\n const model = await Model.load(projectPath, { lazyLoad: false });\n\n // Create and start server\n const server = new VisualizationServer(model, {\n authEnabled,\n authToken,\n withDanger,\n viewerPath,\n });\n serverInstance = server; // Store for signal handlers\n await server.start(port);\n\n // Output token for parent process to read\n if (authEnabled) {\n console.log(`TOKEN:${server.getAuthToken()}`);\n }\n\n // Setup graceful shutdown handlers\n setupShutdownHandlers();\n } catch (error) {\n const message = getErrorMessage(error);\n console.error(`Error: ${message}`);\n if (error instanceof Error) {\n console.error(`Stack: ${error.stack}`);\n }\n await gracefulShutdown(1);\n }\n}\n\n/**\n * Gracefully shutdown the server and flush telemetry\n */\nasync function gracefulShutdown(exitCode: number = 0): Promise<void> {\n if (isShuttingDown) {\n return; // Prevent multiple shutdown attempts\n }\n isShuttingDown = true;\n\n try {\n // Stop the visualization server\n if (serverInstance) {\n serverInstance.stop();\n serverInstance = null;\n }\n\n // Flush telemetry spans before exit\n if (isTelemetryEnabled) {\n console.log(\"[Telemetry] Shutting down telemetry and flushing spans...\");\n const { shutdownTelemetry } = await import(\"./telemetry/index.js\");\n await shutdownTelemetry();\n console.log(\"[Telemetry] Telemetry shutdown complete\");\n } else {\n if (process.env.DEBUG) {\n console.log(\"[Telemetry] Telemetry is disabled (TELEMETRY_ENABLED=false at build time)\");\n }\n }\n } catch (error) {\n // Don't block shutdown on errors\n if (process.env.DEBUG) {\n console.error(\"Error during shutdown:\", error);\n }\n } finally {\n process.exit(exitCode);\n }\n}\n\n/**\n * Setup handlers for graceful shutdown on signals\n */\nfunction setupShutdownHandlers(): void {\n // Handle Ctrl-C (SIGINT)\n process.on(\"SIGINT\", async () => {\n console.log(\"\\n[SIGINT] Shutting down visualization server...\");\n await gracefulShutdown(0);\n });\n\n // Handle termination signal (SIGTERM)\n process.on(\"SIGTERM\", async () => {\n console.log(\"\\n[SIGTERM] Shutting down visualization server...\");\n await gracefulShutdown(0);\n });\n\n // Handle uncaught exceptions\n process.on(\"uncaughtException\", async (error) => {\n console.error(\"Uncaught exception:\", error);\n await gracefulShutdown(1);\n });\n\n // Handle unhandled promise rejections\n process.on(\"unhandledRejection\", async (reason) => {\n console.error(\"Unhandled rejection:\", reason);\n await gracefulShutdown(1);\n });\n}\n\nmain();\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,89 @@
1
+ import { homedir } from "node:os";
2
+ import { existsSync } from "node:fs";
3
+ import { readFile } from "node:fs/promises";
4
+ import { parse } from "yaml";
5
+ import { join } from "node:path";
6
+ const CONFIG_FILENAME = ".dr-config.yaml";
7
+ async function loadOTLPConfig() {
8
+ const defaults = {
9
+ endpoint: "http://localhost:4318/v1/traces",
10
+ logsEndpoint: "http://localhost:4318/v1/logs",
11
+ serviceName: "dr-cli",
12
+ isExplicitlyConfigured: !1
13
+ };
14
+ let fileConfig = {};
15
+ const configPath = process.env.DR_CONFIG_PATH ?? join(homedir(), CONFIG_FILENAME);
16
+ if (existsSync(configPath))
17
+ try {
18
+ const content = await readFile(configPath, "utf-8");
19
+ fileConfig = parse(content);
20
+ } catch (error) {
21
+ if (error instanceof Error) {
22
+ const errorMsg = error.message;
23
+ errorMsg.includes("EACCES") || errorMsg.includes("permission denied") ? (process.stderr.write(`Error: Cannot read config file ${configPath} - permission denied
24
+ `), process.stderr.write(`Suggestions:
25
+ `), process.stderr.write(` \u2022 Check file permissions with: ls -l ${configPath}
26
+ `), process.stderr.write(` \u2022 Ensure you have read access to the file
27
+ `), process.stderr.write(` \u2022 Try: chmod 644 ${configPath}
28
+ `)) : errorMsg.includes("YAMLException") || error.name === "YAMLException" || errorMsg.includes("bad indentation") || errorMsg.includes("unexpected") ? (process.stderr.write(`Error: Invalid YAML syntax in ${configPath}
29
+ `), process.stderr.write(`Details: ${errorMsg}
30
+ `), process.stderr.write(`Suggestions:
31
+ `), process.stderr.write(` \u2022 Validate your YAML syntax at https://www.yamllint.com/
32
+ `), process.stderr.write(` \u2022 Check for proper indentation (use spaces, not tabs)
33
+ `), process.stderr.write(` \u2022 Verify colons have spaces after them
34
+ `)) : (process.stderr.write(`Error: Failed to load config file ${configPath}
35
+ `), process.stderr.write(`Details: ${errorMsg}
36
+ `), process.stderr.write(`Suggestions:
37
+ `), process.stderr.write(` \u2022 Verify the file is valid UTF-8 encoded text
38
+ `), process.stderr.write(` \u2022 Check if the file system is accessible
39
+ `), process.stderr.write(` \u2022 Try recreating the file if it may be corrupted
40
+ `)), process.stderr.write(`Using default OTLP configuration due to config file error
41
+ `);
42
+ } else
43
+ process.stderr.write(`Warning: Failed to parse ${configPath}, using defaults
44
+ `);
45
+ }
46
+ const otlp = fileConfig?.telemetry?.otlp, getEnvVar = (value) => value !== void 0 && value.trim().length > 0 ? value : void 0, getValidUrl = (url, fieldName = "URL") => {
47
+ if (!url)
48
+ return;
49
+ const trimmed = url.trim();
50
+ if (trimmed.length !== 0)
51
+ try {
52
+ const parsedUrl = new URL(trimmed);
53
+ if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
54
+ const protocolMsg = parsedUrl.protocol === "" || parsedUrl.protocol === ":" ? "URL must include http:// or https:// scheme" : `Invalid protocol "${parsedUrl.protocol}" (expected http or https)`;
55
+ process.stderr.write(`Error: ${protocolMsg} in ${fieldName}
56
+ `), process.stderr.write(` Provided: ${trimmed}
57
+ `), process.stderr.write(` Expected: URL must start with http:// or https://
58
+ `), process.stderr.write(` Using fallback configuration for this field
59
+ `);
60
+ return;
61
+ }
62
+ return trimmed;
63
+ } catch (error) {
64
+ process.stderr.write(`Error: Invalid URL in ${fieldName}: "${trimmed}"
65
+ `), error instanceof Error && process.stderr.write(` Reason: ${error.message}
66
+ `), process.stderr.write(`Suggestions:
67
+ `), process.stderr.write(` \u2022 Ensure URL starts with http:// or https://
68
+ `), process.stderr.write(` \u2022 Check for typos in hostname
69
+ `), process.stderr.write(` \u2022 Verify port number if specified (e.g., :4318)
70
+ `), process.stderr.write(` \u2022 Example: http://localhost:4318/v1/traces
71
+ `), process.stderr.write(` Using fallback configuration for this field
72
+ `);
73
+ return;
74
+ }
75
+ }, explicitEndpoint = getValidUrl(getEnvVar(process.env.DR_OTLP_ENDPOINT), "DR_OTLP_ENDPOINT") ?? getValidUrl(otlp?.endpoint, "telemetry.otlp.endpoint") ?? getValidUrl(getEnvVar(process.env.OTEL_EXPORTER_OTLP_ENDPOINT), "OTEL_EXPORTER_OTLP_ENDPOINT"), explicitLogsEndpoint = getValidUrl(getEnvVar(process.env.DR_OTLP_LOGS_ENDPOINT), "DR_OTLP_LOGS_ENDPOINT") ?? getValidUrl(otlp?.logs_endpoint, "telemetry.otlp.logs_endpoint") ?? getValidUrl(getEnvVar(process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT), "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT");
76
+ return {
77
+ endpoint: explicitEndpoint ?? defaults.endpoint,
78
+ logsEndpoint: explicitLogsEndpoint ?? defaults.logsEndpoint,
79
+ serviceName: getEnvVar(process.env.DR_OTLP_SERVICE_NAME) ?? otlp?.service_name ?? getEnvVar(process.env.OTEL_SERVICE_NAME) ?? defaults.serviceName,
80
+ // True only when at least one endpoint was explicitly provided. Without this,
81
+ // TELEMETRY_ENABLED=true (build-time) would try to connect to localhost:4318
82
+ // even when no collector is running, causing a hang at shutdown.
83
+ isExplicitlyConfigured: !!(explicitEndpoint || explicitLogsEndpoint)
84
+ };
85
+ }
86
+ export {
87
+ loadOTLPConfig
88
+ };
89
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/telemetry/config.ts"],
4
+ "sourcesContent": ["/**\n * OTLP Configuration Loader\n *\n * Loads and merges OTLP configuration from multiple sources with the following precedence:\n * 1. DR-specific env vars: DR_OTLP_ENDPOINT, DR_OTLP_LOGS_ENDPOINT, DR_OTLP_SERVICE_NAME (highest)\n * 2. ~/.dr-config.yaml file configuration\n * 3. Standard OTEL env vars: OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,\n * OTEL_SERVICE_NAME \u2014 treated as a low-priority fallback so that ambient OTEL env vars set\n * by a parent process (e.g. Claude Code) do not silently override the DR config file.\n * 4. Hard-coded defaults (lowest priority)\n *\n * Why DR-specific env vars are highest: the standard OTEL_* vars are commonly set in developer\n * environments by other OTEL-instrumented tools (IDEs, shell profiles, CI). When dr runs as a\n * subprocess it inherits those vars and would silently misdirect spans. DR_OTLP_* vars are\n * unambiguously for dr and always win.\n *\n * Configuration file format (~/.dr-config.yaml):\n * ```yaml\n * telemetry:\n * otlp:\n * endpoint: 'http://localhost:4318/v1/traces'\n * logs_endpoint: 'http://localhost:4318/v1/logs'\n * service_name: 'dr-cli'\n * ```\n */\n\nimport { homedir } from \"node:os\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { parse } from \"yaml\";\nimport { join } from \"node:path\";\n\n/**\n * Configuration structure parsed from ~/.dr-config.yaml\n */\ninterface DRConfig {\n telemetry?: {\n otlp?: {\n endpoint?: string;\n logs_endpoint?: string;\n service_name?: string;\n };\n };\n}\n\n/**\n * Resolved OTLP configuration with all required fields\n */\nexport interface OTLPConfig {\n endpoint: string;\n logsEndpoint: string;\n serviceName: string;\n /** True only when an endpoint was explicitly set via env var or config file. */\n isExplicitlyConfigured: boolean;\n}\n\nconst CONFIG_FILENAME = \".dr-config.yaml\";\n\n/**\n * Load OTLP configuration from multiple sources.\n *\n * Configuration precedence (each field resolved independently):\n * 1. Environment variables (OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT, OTEL_SERVICE_NAME)\n * 2. File configuration (~/.dr-config.yaml)\n * 3. Hard-coded defaults\n *\n * All endpoint URLs are validated. Invalid URLs are treated as not set and fall back to next priority.\n *\n * @returns Resolved OTLP configuration with all required fields\n *\n * @example\n * ```typescript\n * const config = await loadOTLPConfig();\n * console.log(config.endpoint); // 'http://localhost:4318/v1/traces' (or from env/file)\n * ```\n */\nexport async function loadOTLPConfig(): Promise<OTLPConfig> {\n // Hard-coded defaults (Priority 3)\n const defaults: OTLPConfig = {\n endpoint: \"http://localhost:4318/v1/traces\",\n logsEndpoint: \"http://localhost:4318/v1/logs\",\n serviceName: \"dr-cli\",\n isExplicitlyConfigured: false,\n };\n\n // Load file configuration (Priority 2)\n let fileConfig: DRConfig = {};\n // Support DR_CONFIG_PATH override for testing; default to ~/.dr-config.yaml\n const configPath = process.env.DR_CONFIG_PATH ?? join(homedir(), CONFIG_FILENAME);\n\n if (existsSync(configPath)) {\n try {\n const content = await readFile(configPath, \"utf-8\");\n fileConfig = parse(content) as DRConfig;\n } catch (error) {\n // Provide specific error messages based on error type\n if (error instanceof Error) {\n const errorMsg = error.message;\n\n // File permission errors\n if (errorMsg.includes(\"EACCES\") || errorMsg.includes(\"permission denied\")) {\n process.stderr.write(\n `Error: Cannot read config file ${configPath} - permission denied\\n`\n );\n process.stderr.write(\"Suggestions:\\n\");\n process.stderr.write(` \u2022 Check file permissions with: ls -l ${configPath}\\n`);\n process.stderr.write(\" \u2022 Ensure you have read access to the file\\n\");\n process.stderr.write(` \u2022 Try: chmod 644 ${configPath}\\n`);\n }\n // YAML parse errors\n else if (\n errorMsg.includes(\"YAMLException\") ||\n error.name === \"YAMLException\" ||\n errorMsg.includes(\"bad indentation\") ||\n errorMsg.includes(\"unexpected\")\n ) {\n process.stderr.write(`Error: Invalid YAML syntax in ${configPath}\\n`);\n process.stderr.write(`Details: ${errorMsg}\\n`);\n process.stderr.write(\"Suggestions:\\n\");\n process.stderr.write(\" \u2022 Validate your YAML syntax at https://www.yamllint.com/\\n\");\n process.stderr.write(\" \u2022 Check for proper indentation (use spaces, not tabs)\\n\");\n process.stderr.write(\" \u2022 Verify colons have spaces after them\\n\");\n }\n // File encoding or other I/O errors\n else {\n process.stderr.write(`Error: Failed to load config file ${configPath}\\n`);\n process.stderr.write(`Details: ${errorMsg}\\n`);\n process.stderr.write(\"Suggestions:\\n\");\n process.stderr.write(\" \u2022 Verify the file is valid UTF-8 encoded text\\n\");\n process.stderr.write(\" \u2022 Check if the file system is accessible\\n\");\n process.stderr.write(\" \u2022 Try recreating the file if it may be corrupted\\n\");\n }\n process.stderr.write(`Using default OTLP configuration due to config file error\\n`);\n } else {\n process.stderr.write(`Warning: Failed to parse ${configPath}, using defaults\\n`);\n }\n }\n }\n\n const otlp = fileConfig?.telemetry?.otlp;\n\n // Helper to check if env var is effectively set (not empty after trim)\n const getEnvVar = (value: string | undefined) => {\n return value !== undefined && value.trim().length > 0 ? value : undefined;\n };\n\n // Helper to validate URL and return if valid, undefined if invalid\n const getValidUrl = (url: string | undefined, fieldName: string = \"URL\") => {\n if (!url) return undefined;\n const trimmed = url.trim();\n if (trimmed.length === 0) return undefined;\n\n try {\n const parsedUrl = new URL(trimmed);\n\n // Only accept http and https protocols\n if (parsedUrl.protocol !== \"http:\" && parsedUrl.protocol !== \"https:\") {\n const protocolMsg =\n parsedUrl.protocol === \"\" || parsedUrl.protocol === \":\"\n ? \"URL must include http:// or https:// scheme\"\n : `Invalid protocol \"${parsedUrl.protocol}\" (expected http or https)`;\n process.stderr.write(`Error: ${protocolMsg} in ${fieldName}\\n`);\n process.stderr.write(` Provided: ${trimmed}\\n`);\n process.stderr.write(` Expected: URL must start with http:// or https://\\n`);\n process.stderr.write(` Using fallback configuration for this field\\n`);\n return undefined;\n }\n\n return trimmed;\n } catch (error) {\n process.stderr.write(`Error: Invalid URL in ${fieldName}: \"${trimmed}\"\\n`);\n if (error instanceof Error) {\n process.stderr.write(` Reason: ${error.message}\\n`);\n }\n process.stderr.write(\"Suggestions:\\n\");\n process.stderr.write(\" \u2022 Ensure URL starts with http:// or https://\\n\");\n process.stderr.write(\" \u2022 Check for typos in hostname\\n\");\n process.stderr.write(\" \u2022 Verify port number if specified (e.g., :4318)\\n\");\n process.stderr.write(\" \u2022 Example: http://localhost:4318/v1/traces\\n\");\n process.stderr.write(` Using fallback configuration for this field\\n`);\n return undefined;\n }\n };\n\n // Resolve each field using the 4-level precedence chain:\n // 1. DR-specific env vars (unambiguously for dr, never set by other tools)\n // 2. ~/.dr-config.yaml (explicit user config for dr)\n // 3. Standard OTEL env vars (low-priority fallback; may be set by parent processes)\n // 4. Hard-coded defaults\n //\n // Standard OTEL env vars are intentionally below the config file. When dr runs as a\n // subprocess of another OTEL-instrumented tool (e.g. Claude Code), it inherits those\n // env vars and would otherwise silently redirect spans to the wrong collector.\n const explicitEndpoint =\n getValidUrl(getEnvVar(process.env.DR_OTLP_ENDPOINT), \"DR_OTLP_ENDPOINT\") ??\n getValidUrl(otlp?.endpoint, \"telemetry.otlp.endpoint\") ??\n getValidUrl(getEnvVar(process.env.OTEL_EXPORTER_OTLP_ENDPOINT), \"OTEL_EXPORTER_OTLP_ENDPOINT\");\n\n const explicitLogsEndpoint =\n getValidUrl(getEnvVar(process.env.DR_OTLP_LOGS_ENDPOINT), \"DR_OTLP_LOGS_ENDPOINT\") ??\n getValidUrl(otlp?.logs_endpoint, \"telemetry.otlp.logs_endpoint\") ??\n getValidUrl(getEnvVar(process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT), \"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT\");\n\n return {\n endpoint: explicitEndpoint ?? defaults.endpoint,\n logsEndpoint: explicitLogsEndpoint ?? defaults.logsEndpoint,\n serviceName:\n getEnvVar(process.env.DR_OTLP_SERVICE_NAME) ??\n otlp?.service_name ??\n getEnvVar(process.env.OTEL_SERVICE_NAME) ??\n defaults.serviceName,\n // True only when at least one endpoint was explicitly provided. Without this,\n // TELEMETRY_ENABLED=true (build-time) would try to connect to localhost:4318\n // even when no collector is running, causing a hang at shutdown.\n isExplicitlyConfigured: !!(explicitEndpoint || explicitLogsEndpoint),\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/telemetry/console-interceptor.ts"],
4
- "sourcesContent": ["/**\n * Console method interceptor for OpenTelemetry log emission.\n *\n * Wraps console.log, console.error, console.warn, and console.debug to emit\n * OpenTelemetry log records while preserving original console behavior.\n *\n * Log records inherit trace context from active spans and include stack traces\n * for errors. This module is only active when TELEMETRY_ENABLED is true.\n *\n * Pattern: All telemetry function calls must be directly guarded by\n * `if (TELEMETRY_ENABLED)` checks in calling code to enable tree-shaking\n * and zero-cost abstractions in production builds.\n */\n\n// Fallback for runtime environments where TELEMETRY_ENABLED is not defined by esbuild\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== 'undefined' ? TELEMETRY_ENABLED : false;\n\n// Store original console methods before any wrapping\nconst originalConsole = {\n log: console.log,\n error: console.error,\n warn: console.warn,\n debug: console.debug,\n};\n\n/**\n * Format console arguments into a single string.\n * Converts objects to JSON representation for readability in logs.\n */\nfunction formatArgs(args: any[]): string {\n return args\n .map((arg) => {\n if (typeof arg === 'object' && arg !== null) {\n try {\n return JSON.stringify(arg);\n } catch {\n return String(arg);\n }\n }\n return String(arg);\n })\n .join(' ');\n}\n\n/**\n * Extract error stack trace and message from console arguments.\n * Returns attributes suitable for log record enrichment.\n */\nfunction extractStackTrace(args: any[]): Record<string, string> {\n const errorArg = args.find((arg) => arg instanceof Error);\n if (errorArg) {\n return {\n 'error.message': errorArg.message,\n 'error.stack': errorArg.stack || '',\n };\n }\n return {};\n}\n\n/**\n * Install console interceptor to emit OpenTelemetry log records.\n *\n * Maps console methods to OpenTelemetry severity levels:\n * - console.debug() \u2192 DEBUG\n * - console.log() \u2192 INFO\n * - console.warn() \u2192 WARN\n * - console.error() \u2192 ERROR\n *\n * Each log record includes the active trace and span identifiers\n * from the current OpenTelemetry context (if available).\n *\n * Original console behavior is preserved - all console output still appears.\n *\n * No-op when TELEMETRY_ENABLED is false.\n */\nexport async function installConsoleInterceptor(): Promise<void> {\n if (!isTelemetryEnabled) return;\n\n const [{ SeverityNumber }, { emitLog }] = await Promise.all([\n import('@opentelemetry/api-logs'),\n import('./index.js')\n ]);\n\n console.log = (...args: any[]): void => {\n emitLog(SeverityNumber.INFO, formatArgs(args));\n originalConsole.log.apply(console, args);\n };\n\n console.error = (...args: any[]): void => {\n const attrs = extractStackTrace(args);\n emitLog(SeverityNumber.ERROR, formatArgs(args), attrs);\n originalConsole.error.apply(console, args);\n };\n\n console.warn = (...args: any[]): void => {\n emitLog(SeverityNumber.WARN, formatArgs(args));\n originalConsole.warn.apply(console, args);\n };\n\n console.debug = (...args: any[]): void => {\n emitLog(SeverityNumber.DEBUG, formatArgs(args));\n originalConsole.debug.apply(console, args);\n };\n}\n\n/**\n * Uninstall console interceptor and restore original console methods.\n *\n * Useful for testing to prevent state pollution between tests.\n * Safe to call when telemetry is disabled (no-op).\n */\nexport function uninstallConsoleInterceptor(): void {\n console.log = originalConsole.log;\n console.error = originalConsole.error;\n console.warn = originalConsole.warn;\n console.debug = originalConsole.debug;\n}\n"],
4
+ "sourcesContent": ["/**\n * Console method interceptor for OpenTelemetry log emission.\n *\n * Wraps console.log, console.error, console.warn, and console.debug to emit\n * OpenTelemetry log records while preserving original console behavior.\n *\n * Log records inherit trace context from active spans and include stack traces\n * for errors. This module is only active when TELEMETRY_ENABLED is true.\n *\n * Pattern: All telemetry function calls must be directly guarded by\n * `if (TELEMETRY_ENABLED)` checks in calling code to enable tree-shaking\n * and zero-cost abstractions in production builds.\n */\n\n// Fallback for runtime environments where TELEMETRY_ENABLED is not defined by esbuild\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== \"undefined\" ? TELEMETRY_ENABLED : false;\n\n// Store original console methods before any wrapping\nconst originalConsole = {\n log: console.log,\n error: console.error,\n warn: console.warn,\n debug: console.debug,\n};\n\n/**\n * Format console arguments into a single string.\n * Converts objects to JSON representation for readability in logs.\n */\nfunction formatArgs(args: any[]): string {\n return args\n .map((arg) => {\n if (typeof arg === \"object\" && arg !== null) {\n try {\n return JSON.stringify(arg);\n } catch {\n return String(arg);\n }\n }\n return String(arg);\n })\n .join(\" \");\n}\n\n/**\n * Extract error stack trace and message from console arguments.\n * Returns attributes suitable for log record enrichment.\n */\nfunction extractStackTrace(args: any[]): Record<string, string> {\n const errorArg = args.find((arg) => arg instanceof Error);\n if (errorArg) {\n return {\n \"error.message\": errorArg.message,\n \"error.stack\": errorArg.stack || \"\",\n };\n }\n return {};\n}\n\n/**\n * Install console interceptor to emit OpenTelemetry log records.\n *\n * Maps console methods to OpenTelemetry severity levels:\n * - console.debug() \u2192 DEBUG\n * - console.log() \u2192 INFO\n * - console.warn() \u2192 WARN\n * - console.error() \u2192 ERROR\n *\n * Each log record includes the active trace and span identifiers\n * from the current OpenTelemetry context (if available).\n *\n * Original console behavior is preserved - all console output still appears.\n *\n * No-op when TELEMETRY_ENABLED is false.\n */\nexport async function installConsoleInterceptor(): Promise<void> {\n if (!isTelemetryEnabled) return;\n\n const [{ SeverityNumber }, { emitLog }] = await Promise.all([\n import(\"@opentelemetry/api-logs\"),\n import(\"./index.js\"),\n ]);\n\n console.log = (...args: any[]): void => {\n emitLog(SeverityNumber.INFO, formatArgs(args));\n originalConsole.log.apply(console, args);\n };\n\n console.error = (...args: any[]): void => {\n const attrs = extractStackTrace(args);\n emitLog(SeverityNumber.ERROR, formatArgs(args), attrs);\n originalConsole.error.apply(console, args);\n };\n\n console.warn = (...args: any[]): void => {\n emitLog(SeverityNumber.WARN, formatArgs(args));\n originalConsole.warn.apply(console, args);\n };\n\n console.debug = (...args: any[]): void => {\n emitLog(SeverityNumber.DEBUG, formatArgs(args));\n originalConsole.debug.apply(console, args);\n };\n}\n\n/**\n * Uninstall console interceptor and restore original console methods.\n *\n * Useful for testing to prevent state pollution between tests.\n * Safe to call when telemetry is disabled (no-op).\n */\nexport function uninstallConsoleInterceptor(): void {\n console.log = originalConsole.log;\n console.error = originalConsole.error;\n console.warn = originalConsole.warn;\n console.debug = originalConsole.debug;\n}\n"],
5
5
  "mappings": "AAgBA,MAAM,qBAAgE,IAGhE,kBAAkB;EACtB,KAAK,QAAQ;EACb,OAAO,QAAQ;EACf,MAAM,QAAQ;EACd,OAAO,QAAQ;;AAOjB,SAAS,WAAW,MAAW;AAC7B,SAAO,KACJ,IAAI,CAAC,QAAO;AACX,QAAI,OAAO,OAAQ,YAAY,QAAQ;AACrC,UAAI;AACF,eAAO,KAAK,UAAU,GAAG;MAC3B,QAAQ;AACN,eAAO,OAAO,GAAG;MACnB;AAEF,WAAO,OAAO,GAAG;EACnB,CAAC,EACA,KAAK,GAAG;AACb;AAMA,SAAS,kBAAkB,MAAW;AACpC,QAAM,WAAW,KAAK,KAAK,CAAC,QAAQ,eAAe,KAAK;AACxD,SAAI,WACK;IACL,iBAAiB,SAAS;IAC1B,eAAe,SAAS,SAAS;MAG9B,CAAA;AACT;AAkBA,eAAsB,4BAAyB;AA4B/C;AAQM,SAAU,8BAA2B;AACzC,UAAQ,MAAM,gBAAgB,KAC9B,QAAQ,QAAQ,gBAAgB,OAChC,QAAQ,OAAO,gBAAgB,MAC/B,QAAQ,QAAQ,gBAAgB;AAClC;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,24 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readFile } from "node:fs/promises";
3
+ import { parse } from "yaml";
4
+ import { join } from "node:path";
5
+ import { homedir } from "node:os";
6
+ function isTelemetryBuiltIn() {
7
+ return !1;
8
+ }
9
+ async function isTelemetryConfigured() {
10
+ const configPath = process.env.DR_CONFIG_PATH ?? join(homedir(), ".dr-config.yaml");
11
+ if (!existsSync(configPath))
12
+ return !1;
13
+ try {
14
+ const content = await readFile(configPath, "utf-8");
15
+ return !!parse(content)?.telemetry?.otlp?.endpoint;
16
+ } catch {
17
+ return !1;
18
+ }
19
+ }
20
+ export {
21
+ isTelemetryBuiltIn,
22
+ isTelemetryConfigured
23
+ };
24
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/telemetry/detect.ts"],
4
+ "sourcesContent": ["/**\n * Telemetry Detection\n *\n * Determines if the CLI was built with telemetry (OTLP sender) enabled\n * and if telemetry is configured via ~/.dr-config.yaml.\n * This is a build-time constant that gets dead-code eliminated in production builds.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { parse } from \"yaml\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\n// Declare TELEMETRY_ENABLED as a build-time constant (substituted by esbuild)\ndeclare const TELEMETRY_ENABLED: boolean;\n\n/**\n * Check if the CLI was built with telemetry enabled\n * @returns true if telemetry is enabled, false otherwise\n */\nexport function isTelemetryBuiltIn(): boolean {\n return typeof TELEMETRY_ENABLED !== \"undefined\" ? TELEMETRY_ENABLED : false;\n}\n\n/**\n * Check if telemetry is configured via ~/.dr-config.yaml\n * @returns true if config file exists with telemetry.otlp section, false otherwise\n */\nexport async function isTelemetryConfigured(): Promise<boolean> {\n const configPath = process.env.DR_CONFIG_PATH ?? join(homedir(), \".dr-config.yaml\");\n\n if (!existsSync(configPath)) {\n return false;\n }\n\n try {\n const content = await readFile(configPath, \"utf-8\");\n const config = parse(content) as any;\n\n // Check if config has telemetry.otlp.endpoint (minimum required)\n return !!(config?.telemetry?.otlp?.endpoint);\n } catch {\n return false;\n }\n}\n"],
5
+ "mappings": "AAQA,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,aAAa;AACtB,SAAS,YAAY;AACrB,SAAS,eAAe;AASlB,SAAU,qBAAkB;AAChC,SAAkD;AACpD;AAMA,eAAsB,wBAAqB;AACzC,QAAM,aAAa,QAAQ,IAAI,kBAAkB,KAAK,QAAO,GAAI,iBAAiB;AAElF,MAAI,CAAC,WAAW,UAAU;AACxB,WAAO;AAGT,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,YAAY,OAAO;AAIlD,WAAO,CAAC,CAHO,MAAM,OAAO,GAGV,WAAW,MAAM;EACrC,QAAQ;AACN,WAAO;EACT;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,112 @@
1
+ import { ExportResultCode } from "@opentelemetry/core";
2
+ import { getErrorMessage } from "../utils/errors.js";
3
+ class FetchOTLPExporter {
4
+ url;
5
+ debug;
6
+ timeoutMs;
7
+ constructor(config) {
8
+ this.url = config?.url || "http://localhost:4318/v1/traces", this.timeoutMs = config?.timeoutMillis ?? 1e4, this.debug = process.env.DR_TELEMETRY_DEBUG === "1" || process.env.DEBUG === "1" || process.env.VERBOSE === "1", this.debug && process.stderr.write(`[TELEMETRY] Fetch-based trace exporter initialized: ${this.url}
9
+ `);
10
+ }
11
+ export(spans, resultCallback) {
12
+ this.debug && process.stderr.write(`[TELEMETRY] Exporting ${spans.length} span(s) to ${this.url}
13
+ `);
14
+ const payload = this.convertSpansToOTLP(spans), controller = new AbortController(), timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
15
+ fetch(this.url, {
16
+ method: "POST",
17
+ headers: {
18
+ "Content-Type": "application/json"
19
+ },
20
+ body: JSON.stringify(payload),
21
+ signal: controller.signal
22
+ }).then(async (response) => {
23
+ if (clearTimeout(timeoutId), response.ok)
24
+ this.debug && process.stderr.write(`[TELEMETRY] Export SUCCESS - ${spans.length} span(s) sent
25
+ `), resultCallback({ code: ExportResultCode.SUCCESS });
26
+ else {
27
+ const errorText = await response.text();
28
+ this.debug && process.stderr.write(`[TELEMETRY] Export FAILED - HTTP ${response.status}: ${errorText}
29
+ `), resultCallback({
30
+ code: ExportResultCode.FAILED,
31
+ error: new Error(`HTTP ${response.status}: ${errorText}`)
32
+ });
33
+ }
34
+ }).catch((error) => {
35
+ if (clearTimeout(timeoutId), this.debug) {
36
+ const errorMsg = getErrorMessage(error);
37
+ process.stderr.write(`[TELEMETRY] Export FAILED - ${errorMsg}
38
+ `);
39
+ }
40
+ resultCallback({
41
+ code: ExportResultCode.FAILED,
42
+ error: error instanceof Error ? error : new Error(String(error))
43
+ });
44
+ });
45
+ }
46
+ async forceFlush() {
47
+ }
48
+ async shutdown() {
49
+ }
50
+ /**
51
+ * Convert OpenTelemetry spans to OTLP JSON format.
52
+ * Simplified version that covers the essential fields.
53
+ */
54
+ convertSpansToOTLP(spans) {
55
+ return {
56
+ resourceSpans: [
57
+ {
58
+ resource: {
59
+ attributes: this.convertAttributes(spans[0]?.resource?.attributes || {})
60
+ },
61
+ scopeSpans: [
62
+ {
63
+ scope: {
64
+ name: spans[0]?.instrumentationLibrary?.name || "unknown",
65
+ version: spans[0]?.instrumentationLibrary?.version || ""
66
+ },
67
+ spans: spans.map((span) => ({
68
+ traceId: span.spanContext().traceId,
69
+ spanId: span.spanContext().spanId,
70
+ parentSpanId: span.parentSpanId || void 0,
71
+ name: span.name,
72
+ kind: span.kind,
73
+ startTimeUnixNano: String(span.startTime[0] * 1e9 + span.startTime[1]),
74
+ endTimeUnixNano: String(span.endTime[0] * 1e9 + span.endTime[1]),
75
+ attributes: this.convertAttributes(span.attributes),
76
+ status: span.status,
77
+ events: span.events.map((event) => ({
78
+ timeUnixNano: String(event.time[0] * 1e9 + event.time[1]),
79
+ name: event.name,
80
+ attributes: this.convertAttributes(event.attributes || {})
81
+ }))
82
+ }))
83
+ }
84
+ ]
85
+ }
86
+ ]
87
+ };
88
+ }
89
+ /**
90
+ * Convert attributes to OTLP format.
91
+ */
92
+ convertAttributes(attrs) {
93
+ return attrs ? Object.entries(attrs).map(([key, value]) => ({
94
+ key,
95
+ value: this.convertValue(value)
96
+ })) : [];
97
+ }
98
+ /**
99
+ * Convert attribute value to OTLP format.
100
+ */
101
+ convertValue(value) {
102
+ return typeof value == "string" ? { stringValue: value } : typeof value == "number" ? Number.isInteger(value) ? { intValue: String(value) } : { doubleValue: value } : typeof value == "boolean" ? { boolValue: value } : Array.isArray(value) ? {
103
+ arrayValue: {
104
+ values: value.map((v) => this.convertValue(v))
105
+ }
106
+ } : { stringValue: String(value) };
107
+ }
108
+ }
109
+ export {
110
+ FetchOTLPExporter
111
+ };
112
+ //# sourceMappingURL=fetch-otlp-exporter.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/telemetry/fetch-otlp-exporter.ts"],
4
+ "sourcesContent": ["/**\n * Fetch-based OTLP exporter for Bun compatibility.\n * Uses native fetch API instead of Node.js http module.\n */\n\nimport type { SpanExporter, ReadableSpan } from \"@opentelemetry/sdk-trace-base\";\nimport type { ExportResult } from \"@opentelemetry/core\";\nimport { ExportResultCode } from \"@opentelemetry/core\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\n/**\n * OTLP exporter using fetch API for Bun compatibility.\n * Bun's http module has compatibility issues with the standard OTLP exporter,\n * so we use fetch which is natively supported by Bun.\n */\nexport class FetchOTLPExporter implements SpanExporter {\n private readonly url: string;\n private readonly debug: boolean;\n private readonly timeoutMs: number;\n\n constructor(config?: { url?: string; timeoutMillis?: number }) {\n this.url = config?.url || \"http://localhost:4318/v1/traces\";\n this.timeoutMs = config?.timeoutMillis ?? 10000;\n this.debug =\n process.env.DR_TELEMETRY_DEBUG === \"1\" ||\n process.env.DEBUG === \"1\" ||\n process.env.VERBOSE === \"1\";\n\n if (this.debug) {\n process.stderr.write(`[TELEMETRY] Fetch-based trace exporter initialized: ${this.url}\\n`);\n }\n }\n\n export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n if (this.debug) {\n process.stderr.write(`[TELEMETRY] Exporting ${spans.length} span(s) to ${this.url}\\n`);\n }\n\n // Convert spans to OTLP JSON format\n const payload = this.convertSpansToOTLP(spans);\n\n // Use AbortController for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);\n\n fetch(this.url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(payload),\n signal: controller.signal,\n })\n .then(async (response) => {\n clearTimeout(timeoutId);\n\n if (response.ok) {\n if (this.debug) {\n process.stderr.write(`[TELEMETRY] Export SUCCESS - ${spans.length} span(s) sent\\n`);\n }\n resultCallback({ code: ExportResultCode.SUCCESS });\n } else {\n const errorText = await response.text();\n if (this.debug) {\n process.stderr.write(\n `[TELEMETRY] Export FAILED - HTTP ${response.status}: ${errorText}\\n`\n );\n }\n resultCallback({\n code: ExportResultCode.FAILED,\n error: new Error(`HTTP ${response.status}: ${errorText}`),\n });\n }\n })\n .catch((error) => {\n clearTimeout(timeoutId);\n if (this.debug) {\n const errorMsg = getErrorMessage(error);\n process.stderr.write(`[TELEMETRY] Export FAILED - ${errorMsg}\\n`);\n }\n resultCallback({\n code: ExportResultCode.FAILED,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n });\n }\n\n async forceFlush(): Promise<void> {\n // No-op for fetch-based exporter (no buffering)\n }\n\n async shutdown(): Promise<void> {\n // No-op for fetch-based exporter (no persistent connections)\n }\n\n /**\n * Convert OpenTelemetry spans to OTLP JSON format.\n * Simplified version that covers the essential fields.\n */\n private convertSpansToOTLP(spans: ReadableSpan[]): any {\n return {\n resourceSpans: [\n {\n resource: {\n attributes: this.convertAttributes(spans[0]?.resource?.attributes || {}),\n },\n scopeSpans: [\n {\n scope: {\n name: spans[0]?.instrumentationLibrary?.name || \"unknown\",\n version: spans[0]?.instrumentationLibrary?.version || \"\",\n },\n spans: spans.map((span) => ({\n traceId: span.spanContext().traceId,\n spanId: span.spanContext().spanId,\n parentSpanId: span.parentSpanId || undefined,\n name: span.name,\n kind: span.kind,\n startTimeUnixNano: String(span.startTime[0] * 1e9 + span.startTime[1]),\n endTimeUnixNano: String(span.endTime[0] * 1e9 + span.endTime[1]),\n attributes: this.convertAttributes(span.attributes),\n status: span.status,\n events: span.events.map((event) => ({\n timeUnixNano: String(event.time[0] * 1e9 + event.time[1]),\n name: event.name,\n attributes: this.convertAttributes(event.attributes || {}),\n })),\n })),\n },\n ],\n },\n ],\n };\n }\n\n /**\n * Convert attributes to OTLP format.\n */\n private convertAttributes(attrs: any): any[] {\n if (!attrs) return [];\n return Object.entries(attrs).map(([key, value]) => ({\n key,\n value: this.convertValue(value),\n }));\n }\n\n /**\n * Convert attribute value to OTLP format.\n */\n private convertValue(value: any): any {\n if (typeof value === \"string\") {\n return { stringValue: value };\n } else if (typeof value === \"number\") {\n if (Number.isInteger(value)) {\n return { intValue: String(value) };\n } else {\n return { doubleValue: value };\n }\n } else if (typeof value === \"boolean\") {\n return { boolValue: value };\n } else if (Array.isArray(value)) {\n return {\n arrayValue: {\n values: value.map((v) => this.convertValue(v)),\n },\n };\n } else {\n return { stringValue: String(value) };\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,12 +1,88 @@
1
+ import { SeverityNumber } from "@opentelemetry/api-logs";
1
2
  const isTelemetryEnabled = !1;
2
- let sdk = null, tracer = null, loggerProvider = null, logger = null, cachedContext = null, cachedTrace = null;
3
+ let sdk = null, tracer = null, loggerProvider = null, logger = null, spanProcessor = null, cachedContext = null, cachedTrace = null;
3
4
  async function initTelemetry() {
5
+ if (isTelemetryEnabled) {
6
+ const { loadOTLPConfig } = await import("./config.js"), otlpConfig = await loadOTLPConfig();
7
+ if (!otlpConfig.isExplicitlyConfigured)
8
+ return;
9
+ const [{ NodeSDK }, { BatchSpanProcessor }, { SimpleLogRecordProcessor }, otelApi, { Resource }, { LoggerProvider }, { ResilientOTLPExporter }, { ResilientLogExporter }] = await Promise.all([
10
+ import("@opentelemetry/sdk-node"),
11
+ import("@opentelemetry/sdk-trace-base"),
12
+ import("@opentelemetry/sdk-logs"),
13
+ import("@opentelemetry/api"),
14
+ import("@opentelemetry/resources"),
15
+ import("@opentelemetry/sdk-logs"),
16
+ import("./resilient-exporter.js"),
17
+ import("./resilient-log-exporter.js")
18
+ ]), { trace, context } = otelApi;
19
+ cachedTrace = trace, cachedContext = context, process.env.DR_TELEMETRY_DEBUG && (process.stderr.write(`[TELEMETRY] Configuration loaded:
20
+ `), process.stderr.write(` - Traces endpoint: ${otlpConfig.endpoint}
21
+ `), process.stderr.write(` - Logs endpoint: ${otlpConfig.logsEndpoint}
22
+ `), process.stderr.write(` - Service name: ${otlpConfig.serviceName}
23
+ `));
24
+ const cliVersion = "0.1.5";
25
+ let projectName = "unknown";
26
+ try {
27
+ const [{ readFileSync, existsSync }, { parse }] = await Promise.all([
28
+ import("fs"),
29
+ import("yaml")
30
+ ]), possiblePaths = [
31
+ `${process.cwd()}/documentation-robotics/model/manifest.yaml`,
32
+ `${process.cwd()}/model/manifest.yaml`
33
+ ];
34
+ for (const manifestPath of possiblePaths)
35
+ try {
36
+ if (existsSync(manifestPath)) {
37
+ const content = readFileSync(manifestPath, "utf-8");
38
+ projectName = parse(content).project?.name || "unknown";
39
+ break;
40
+ }
41
+ } catch {
42
+ }
43
+ } catch {
44
+ }
45
+ const resource = new Resource({
46
+ "service.name": otlpConfig.serviceName,
47
+ "service.version": cliVersion,
48
+ "dr.project.name": projectName
49
+ }), traceExporter = new ResilientOTLPExporter({
50
+ url: otlpConfig.endpoint,
51
+ timeoutMillis: 1e4
52
+ // 10s timeout for network requests (serialization + network latency)
53
+ });
54
+ spanProcessor = new BatchSpanProcessor(traceExporter, {
55
+ maxExportBatchSize: 32,
56
+ maxQueueSize: 64,
57
+ scheduledDelayMillis: 100,
58
+ // Short delay for CLI
59
+ exportTimeoutMillis: 5e3
60
+ });
61
+ const nodeSdk = new NodeSDK({
62
+ resource,
63
+ spanProcessor
64
+ });
65
+ nodeSdk.start(), sdk = nodeSdk, tracer = trace.getTracer("dr-cli", cliVersion), (process.env.DR_TELEMETRY_DEBUG || process.env.DEBUG || process.env.VERBOSE) && (process.stderr.write(`[TELEMETRY] SDK initialized successfully
66
+ `), process.stderr.write(`[TELEMETRY] Tracer initialized: ${tracer !== null}
67
+ `));
68
+ const logExporter = new ResilientLogExporter({
69
+ url: otlpConfig.logsEndpoint,
70
+ timeoutMillis: 1e4
71
+ // 10s timeout for network requests (serialization + network latency)
72
+ });
73
+ loggerProvider = new LoggerProvider({
74
+ resource
75
+ }), loggerProvider.addLogRecordProcessor(new SimpleLogRecordProcessor(logExporter)), logger = loggerProvider.getLogger("dr-cli", cliVersion);
76
+ }
4
77
  }
5
78
  function startSpan(name, attributes) {
6
- return null;
79
+ return isTelemetryEnabled && tracer && cachedContext ? tracer.startSpan(name, { attributes }, cachedContext.active()) : ((process.env.DR_TELEMETRY_DEBUG || process.env.DEBUG || process.env.VERBOSE) && (isTelemetryEnabled ? tracer ? cachedContext || process.stderr.write(`[TELEMETRY] startSpan('${name}'): skipped - cachedContext is null
80
+ `) : process.stderr.write(`[TELEMETRY] startSpan('${name}'): skipped - tracer is null (initTelemetry not called?)
81
+ `) : process.stderr.write(`[TELEMETRY] startSpan('${name}'): skipped - isTelemetryEnabled=false
82
+ `)), null);
7
83
  }
8
84
  async function startActiveSpan(name, fn, attributes) {
9
- {
85
+ if (!isTelemetryEnabled || !tracer) {
10
86
  const noopSpan = {
11
87
  end: () => {
12
88
  },
@@ -38,15 +114,89 @@ async function startActiveSpan(name, fn, attributes) {
38
114
  });
39
115
  }
40
116
  function endSpan(span) {
117
+ isTelemetryEnabled && span && span.end();
118
+ }
119
+ function getActiveSpan() {
120
+ return isTelemetryEnabled && cachedTrace ? cachedTrace.getActiveSpan?.() ?? null : null;
41
121
  }
42
122
  function emitLog(severity, message, attributes) {
123
+ if (!isTelemetryEnabled || !logger || !cachedTrace)
124
+ return;
125
+ const context = cachedTrace.getActiveSpan()?.spanContext(), severityText = {
126
+ 0: "UNSPECIFIED",
127
+ 1: "TRACE",
128
+ 2: "TRACE2",
129
+ 3: "TRACE3",
130
+ 4: "TRACE4",
131
+ 5: "DEBUG",
132
+ 6: "DEBUG2",
133
+ 7: "DEBUG3",
134
+ 8: "DEBUG4",
135
+ 9: "INFO",
136
+ 10: "INFO2",
137
+ 11: "INFO3",
138
+ 12: "INFO4",
139
+ 13: "WARN",
140
+ 14: "WARN2",
141
+ 15: "WARN3",
142
+ 16: "WARN4",
143
+ 17: "ERROR",
144
+ 18: "ERROR2",
145
+ 19: "ERROR3",
146
+ 20: "ERROR4",
147
+ 21: "FATAL",
148
+ 22: "FATAL2",
149
+ 23: "FATAL3",
150
+ 24: "FATAL4"
151
+ }[severity] || "UNSPECIFIED";
152
+ logger.emit({
153
+ severityNumber: severity,
154
+ severityText,
155
+ body: message,
156
+ attributes: {
157
+ ...attributes,
158
+ ...context && {
159
+ "trace.id": context.traceId,
160
+ "span.id": context.spanId
161
+ }
162
+ }
163
+ });
164
+ }
165
+ async function flushTelemetry() {
166
+ if (isTelemetryEnabled && spanProcessor)
167
+ try {
168
+ await spanProcessor.forceFlush();
169
+ } catch {
170
+ }
171
+ }
172
+ function setSpanAttribute(span, key, value) {
173
+ if (span && typeof span.setAttribute == "function")
174
+ try {
175
+ span.setAttribute(key, value);
176
+ } catch {
177
+ }
43
178
  }
44
179
  async function shutdownTelemetry() {
180
+ if (isTelemetryEnabled) {
181
+ try {
182
+ spanProcessor && await spanProcessor.forceFlush(), await sdk?.shutdown();
183
+ } catch {
184
+ }
185
+ try {
186
+ await loggerProvider?.shutdown();
187
+ } catch {
188
+ }
189
+ }
45
190
  }
46
191
  export {
192
+ SeverityNumber,
47
193
  emitLog,
48
194
  endSpan,
195
+ flushTelemetry,
196
+ getActiveSpan,
49
197
  initTelemetry,
198
+ isTelemetryEnabled,
199
+ setSpanAttribute,
50
200
  shutdownTelemetry,
51
201
  startActiveSpan,
52
202
  startSpan