@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,292 @@
1
+ import { mkdir, writeFile, appendFile, readdir, readFile } from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { randomUUID } from "node:crypto";
6
+ async function appendWithRetry(filePath, content, onRetry) {
7
+ try {
8
+ await appendFile(filePath, content, "utf-8");
9
+ } catch (appendError) {
10
+ if (appendError.code === "ENOENT") {
11
+ onRetry && await onRetry();
12
+ try {
13
+ await appendFile(filePath, content, "utf-8");
14
+ } catch (retryError) {
15
+ console.warn("[ChatLogger] WARNING: Could not append entry to chat log (non-fatal)"), console.warn("[ChatLogger] Log path:", filePath), console.warn("[ChatLogger] Error:", retryError), console.warn("[ChatLogger] The chat session will continue, but this entry was not logged.");
16
+ }
17
+ } else
18
+ throw appendError;
19
+ }
20
+ }
21
+ class ChatLogger {
22
+ sessionId;
23
+ sessionStartTime;
24
+ sessionLogPath;
25
+ logDir;
26
+ projectRoot;
27
+ headerWritten = !1;
28
+ headerWritePromise = null;
29
+ /**
30
+ * Creates a new ChatLogger instance
31
+ * @param projectRoot Optional project root for relative path resolution
32
+ */
33
+ constructor(projectRoot) {
34
+ this.sessionId = randomUUID(), this.sessionStartTime = this.getTimestamp(), this.projectRoot = projectRoot, this.logDir = this.getLogDirectory();
35
+ const filenameSafeTimestamp = this.sessionStartTime.replace(/:/g, "_");
36
+ this.sessionLogPath = join(this.logDir, `${filenameSafeTimestamp}_${this.sessionId}.log`);
37
+ }
38
+ /**
39
+ * Get the log directory path
40
+ * Prefers .dr/chat/sessions/ in project root, falls back to ~/.dr/chat/sessions/
41
+ */
42
+ getLogDirectory() {
43
+ return this.projectRoot && existsSync(this.projectRoot) ? join(this.projectRoot, ".dr", "chat", "sessions") : join(homedir(), ".dr", "chat", "sessions");
44
+ }
45
+ /**
46
+ * Get current ISO timestamp with milliseconds
47
+ */
48
+ getTimestamp() {
49
+ return (/* @__PURE__ */ new Date()).toISOString();
50
+ }
51
+ /**
52
+ * Get session ID
53
+ */
54
+ getSessionId() {
55
+ return this.sessionId;
56
+ }
57
+ /**
58
+ * Get session log file path
59
+ */
60
+ getSessionLogPath() {
61
+ return this.sessionLogPath;
62
+ }
63
+ /**
64
+ * Ensure log directory exists
65
+ */
66
+ async ensureLogDirectory() {
67
+ try {
68
+ await mkdir(this.logDir, { recursive: !0 });
69
+ } catch (error) {
70
+ if (error instanceof Error && !error.message.includes("EEXIST"))
71
+ throw error;
72
+ }
73
+ }
74
+ /**
75
+ * Format a log entry as JSON
76
+ */
77
+ formatEntry(entry) {
78
+ return JSON.stringify(entry) + `
79
+ `;
80
+ }
81
+ /**
82
+ * Log a user message
83
+ * @param message The user message content
84
+ * @param metadata Optional metadata
85
+ */
86
+ async logUserMessage(message, metadata) {
87
+ const entry = {
88
+ timestamp: this.getTimestamp(),
89
+ type: "message",
90
+ role: "user",
91
+ content: message,
92
+ metadata
93
+ };
94
+ await this.writeEntry(entry);
95
+ }
96
+ /**
97
+ * Log an assistant/AI response
98
+ * @param content The response content
99
+ * @param metadata Optional metadata
100
+ */
101
+ async logAssistantMessage(content, metadata) {
102
+ const entry = {
103
+ timestamp: this.getTimestamp(),
104
+ type: "message",
105
+ role: "assistant",
106
+ content,
107
+ metadata
108
+ };
109
+ await this.writeEntry(entry);
110
+ }
111
+ /**
112
+ * Log a command being sent to the CLI
113
+ * @param command Command name (e.g., "gh copilot explain")
114
+ * @param args Command arguments
115
+ * @param metadata Optional metadata
116
+ */
117
+ async logCommand(command, args = [], metadata) {
118
+ const content = [command, ...args].join(" "), entry = {
119
+ timestamp: this.getTimestamp(),
120
+ type: "command",
121
+ role: "cli",
122
+ content,
123
+ metadata: {
124
+ ...metadata,
125
+ command,
126
+ args
127
+ }
128
+ };
129
+ await this.writeEntry(entry);
130
+ }
131
+ /**
132
+ * Log an error
133
+ * @param errorMessage The error message
134
+ * @param metadata Optional metadata including error details
135
+ */
136
+ async logError(errorMessage, metadata) {
137
+ const entry = {
138
+ timestamp: this.getTimestamp(),
139
+ type: "error",
140
+ role: "system",
141
+ content: errorMessage,
142
+ metadata
143
+ };
144
+ await this.writeEntry(entry);
145
+ }
146
+ /**
147
+ * Log an event (initialization, session start, etc.)
148
+ * @param eventName Event name
149
+ * @param metadata Optional metadata
150
+ */
151
+ async logEvent(eventName, metadata) {
152
+ const entry = {
153
+ timestamp: this.getTimestamp(),
154
+ type: "event",
155
+ role: "system",
156
+ content: eventName,
157
+ metadata
158
+ };
159
+ await this.writeEntry(entry);
160
+ }
161
+ /**
162
+ * Ensure header is written exactly once, even with concurrent calls
163
+ */
164
+ async ensureHeaderWritten() {
165
+ if (!this.headerWritten) {
166
+ if (this.headerWritePromise) {
167
+ await this.headerWritePromise;
168
+ return;
169
+ }
170
+ this.headerWritePromise = this.writeHeader(), await this.headerWritePromise, this.headerWritePromise = null;
171
+ }
172
+ }
173
+ /**
174
+ * Write the session header to the log file
175
+ */
176
+ async writeHeader() {
177
+ const header = {
178
+ timestamp: this.sessionStartTime,
179
+ type: "event",
180
+ role: "system",
181
+ content: "Session started",
182
+ metadata: {
183
+ sessionId: this.sessionId,
184
+ logVersion: "1.0"
185
+ }
186
+ };
187
+ try {
188
+ await writeFile(this.sessionLogPath, this.formatEntry(header), "utf-8"), this.headerWritten = !0;
189
+ } catch (error) {
190
+ if (error.code === "ENOENT") {
191
+ await this.ensureLogDirectory();
192
+ try {
193
+ await writeFile(this.sessionLogPath, this.formatEntry(header), "utf-8"), this.headerWritten = !0;
194
+ } catch (retryError) {
195
+ throw retryError;
196
+ }
197
+ } else
198
+ throw error;
199
+ }
200
+ }
201
+ /**
202
+ * Write an entry to the log file
203
+ */
204
+ async writeEntry(entry) {
205
+ try {
206
+ await this.ensureLogDirectory(), await this.ensureHeaderWritten(), await appendWithRetry(this.sessionLogPath, this.formatEntry(entry), async () => {
207
+ await this.ensureLogDirectory(), this.headerWritten = !1, await this.ensureHeaderWritten();
208
+ });
209
+ } catch (error) {
210
+ const errno = error.code;
211
+ errno === "EACCES" ? (console.error("[ChatLogger] ERROR: Permission denied writing to log file:", this.sessionLogPath), console.error("[ChatLogger] Session logging disabled for this session.")) : errno === "ENOSPC" ? console.error("[ChatLogger] ERROR: Disk full, cannot write to log file:", this.sessionLogPath) : (console.error("[ChatLogger] CRITICAL: Unexpected error writing to log file:", error), console.error("[ChatLogger] Session ID:", this.sessionId), console.error("[ChatLogger] Log path:", this.sessionLogPath), console.error("[ChatLogger] This is a bug - please report with error details above."));
212
+ }
213
+ }
214
+ /**
215
+ * Read all entries from the session log.
216
+ * Parses lines individually to preserve valid entries when one line is corrupt.
217
+ */
218
+ async readEntries() {
219
+ try {
220
+ const content = await readFile(this.sessionLogPath, "utf-8"), entries = [];
221
+ for (const line of content.split(`
222
+ `)) {
223
+ const trimmed = line.trim();
224
+ if (trimmed)
225
+ try {
226
+ entries.push(JSON.parse(trimmed));
227
+ } catch (parseError) {
228
+ console.warn("[ChatLogger] Skipping corrupt JSON line in session log:", parseError instanceof Error ? parseError.message : String(parseError));
229
+ }
230
+ }
231
+ return entries;
232
+ } catch (fileError) {
233
+ return fileError.code !== "ENOENT" && console.warn("[ChatLogger] Warning: Could not read log file:", fileError), [];
234
+ }
235
+ }
236
+ /**
237
+ * Get summary of the session
238
+ */
239
+ async getSummary() {
240
+ const entries = await this.readEntries(), messageCount = entries.filter((e) => e.type === "message" && e.role === "user").length, commandCount = entries.filter((e) => e.type === "command").length, errorCount = entries.filter((e) => e.type === "error").length;
241
+ let duration = "N/A";
242
+ if (entries.length > 1) {
243
+ const first = new Date(entries[0].timestamp), ms = new Date(entries[entries.length - 1].timestamp).getTime() - first.getTime(), seconds = Math.floor(ms / 1e3), minutes = Math.floor(seconds / 60), secs = seconds % 60;
244
+ minutes > 0 ? duration = `${minutes}m ${secs}s` : duration = `${secs}s`;
245
+ }
246
+ return {
247
+ sessionId: this.sessionId,
248
+ messageCount,
249
+ commandCount,
250
+ errorCount,
251
+ duration
252
+ };
253
+ }
254
+ }
255
+ let globalChatLogger;
256
+ function initializeChatLogger(projectRoot) {
257
+ return globalChatLogger = new ChatLogger(projectRoot), globalChatLogger;
258
+ }
259
+ function getChatLogger() {
260
+ return globalChatLogger;
261
+ }
262
+ function resetGlobalChatLogger() {
263
+ globalChatLogger = void 0;
264
+ }
265
+ async function listChatSessions(projectRoot) {
266
+ const logDir = new ChatLogger(projectRoot).getLogDirectory();
267
+ try {
268
+ return (await readdir(logDir)).filter((f) => f.endsWith(".log")).sort().reverse();
269
+ } catch (error) {
270
+ if (error.code === "ENOENT")
271
+ return [];
272
+ throw error;
273
+ }
274
+ }
275
+ async function readChatSession(logFile, projectRoot) {
276
+ const logDir = new ChatLogger(projectRoot).getLogDirectory(), logPath = join(logDir, logFile);
277
+ try {
278
+ return (await readFile(logPath, "utf-8")).split(`
279
+ `).filter((line) => line.trim()).map((line) => JSON.parse(line));
280
+ } catch (error) {
281
+ throw console.error("Error reading chat session:", error), error;
282
+ }
283
+ }
284
+ export {
285
+ ChatLogger,
286
+ getChatLogger,
287
+ initializeChatLogger,
288
+ listChatSessions,
289
+ readChatSession,
290
+ resetGlobalChatLogger
291
+ };
292
+ //# sourceMappingURL=chat-logger.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/chat-logger.ts"],
4
+ "sourcesContent": ["/**\n * Chat Logger Utility\n *\n * Provides universal logging for all chat messages and commands.\n * Stores logs in .dr/chat/sessions/ with one file per session.\n * Filenames include both timestamp and session ID for chronological ordering.\n *\n * Log format:\n * - Session file: .dr/chat/sessions/{timestamp}_{sessionId}.log\n * - Timestamp comes first for natural sorting (most recent first)\n * - Timestamp format: ISO 8601 with colons replaced by underscores for filesystem compatibility\n * - Each entry contains: timestamp, type (message/command/error), role, content\n */\n\nimport { mkdir, writeFile, appendFile, readdir, readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\n\n/**\n * Helper to append content to file with automatic retry on ENOENT\n *\n * When appending to a file, a race condition can occur where the file\n * or directory is deleted between the initial write and the append.\n * This helper handles ENOENT by recreating the directory and file with header.\n *\n * @param filePath Path to file to append to\n * @param content Content to append\n * @param onRetry Callback to prepare file (e.g., write header) before retry\n * @throws Error if append fails for non-ENOENT reasons\n */\nasync function appendWithRetry(\n filePath: string,\n content: string,\n onRetry?: () => Promise<void>\n): Promise<void> {\n try {\n await appendFile(filePath, content, \"utf-8\");\n } catch (appendError) {\n const errno = (appendError as NodeJS.ErrnoException).code;\n if (errno === \"ENOENT\") {\n // File doesn't exist - race condition where directory/file was deleted\n // Call retry callback (e.g., to recreate directory and file with header)\n if (onRetry) {\n await onRetry();\n }\n // Retry the append\n try {\n await appendFile(filePath, content, \"utf-8\");\n } catch (retryError) {\n // Retry failed - this is a real problem\n console.warn(\"[ChatLogger] WARNING: Could not append entry to chat log (non-fatal)\");\n console.warn(\"[ChatLogger] Log path:\", filePath);\n console.warn(\"[ChatLogger] Error:\", retryError);\n console.warn(\n \"[ChatLogger] The chat session will continue, but this entry was not logged.\"\n );\n // Intentional: Continue without logging rather than crash the entire session.\n // The chat log is best-effort; we don't want logging failures to break the user's work.\n }\n } else {\n // Rethrow non-ENOENT errors to outer handler\n throw appendError;\n }\n }\n}\n\n/**\n * Chat log entry types\n */\nexport type ChatLogEntryType = \"message\" | \"command\" | \"error\" | \"event\";\n\n/**\n * A single chat log entry\n */\nexport interface ChatLogEntry {\n timestamp: string;\n type: ChatLogEntryType;\n role?: \"user\" | \"assistant\" | \"system\" | \"cli\";\n content: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Chat Logger class\n *\n * Manages logging of chat sessions and messages\n */\nexport class ChatLogger {\n private sessionId: string;\n private sessionStartTime: string;\n private sessionLogPath: string;\n private logDir: string;\n private projectRoot?: string;\n private headerWritten = false;\n private headerWritePromise: Promise<void> | null = null;\n\n /**\n * Creates a new ChatLogger instance\n * @param projectRoot Optional project root for relative path resolution\n */\n constructor(projectRoot?: string) {\n this.sessionId = randomUUID();\n this.sessionStartTime = this.getTimestamp();\n this.projectRoot = projectRoot;\n this.logDir = this.getLogDirectory();\n // Timestamp first for natural sorting, replace colons with underscores for filesystem compatibility\n const filenameSafeTimestamp = this.sessionStartTime.replace(/:/g, \"_\");\n this.sessionLogPath = join(this.logDir, `${filenameSafeTimestamp}_${this.sessionId}.log`);\n }\n\n /**\n * Get the log directory path\n * Prefers .dr/chat/sessions/ in project root, falls back to ~/.dr/chat/sessions/\n */\n getLogDirectory(): string {\n if (this.projectRoot && existsSync(this.projectRoot)) {\n const projectLogDir = join(this.projectRoot, \".dr\", \"chat\", \"sessions\");\n return projectLogDir;\n }\n\n // Fall back to home directory\n return join(homedir(), \".dr\", \"chat\", \"sessions\");\n }\n\n /**\n * Get current ISO timestamp with milliseconds\n */\n private getTimestamp(): string {\n return new Date().toISOString();\n }\n\n /**\n * Get session ID\n */\n getSessionId(): string {\n return this.sessionId;\n }\n\n /**\n * Get session log file path\n */\n getSessionLogPath(): string {\n return this.sessionLogPath;\n }\n\n /**\n * Ensure log directory exists\n */\n async ensureLogDirectory(): Promise<void> {\n try {\n await mkdir(this.logDir, { recursive: true });\n } catch (error) {\n if (error instanceof Error && !error.message.includes(\"EEXIST\")) {\n throw error;\n }\n }\n }\n\n /**\n * Format a log entry as JSON\n */\n private formatEntry(entry: ChatLogEntry): string {\n return JSON.stringify(entry) + \"\\n\";\n }\n\n /**\n * Log a user message\n * @param message The user message content\n * @param metadata Optional metadata\n */\n async logUserMessage(message: string, metadata?: Record<string, unknown>): Promise<void> {\n const entry: ChatLogEntry = {\n timestamp: this.getTimestamp(),\n type: \"message\",\n role: \"user\",\n content: message,\n metadata,\n };\n\n await this.writeEntry(entry);\n }\n\n /**\n * Log an assistant/AI response\n * @param content The response content\n * @param metadata Optional metadata\n */\n async logAssistantMessage(content: string, metadata?: Record<string, unknown>): Promise<void> {\n const entry: ChatLogEntry = {\n timestamp: this.getTimestamp(),\n type: \"message\",\n role: \"assistant\",\n content,\n metadata,\n };\n\n await this.writeEntry(entry);\n }\n\n /**\n * Log a command being sent to the CLI\n * @param command Command name (e.g., \"gh copilot explain\")\n * @param args Command arguments\n * @param metadata Optional metadata\n */\n async logCommand(\n command: string,\n args: string[] = [],\n metadata?: Record<string, unknown>\n ): Promise<void> {\n const content = [command, ...args].join(\" \");\n\n const entry: ChatLogEntry = {\n timestamp: this.getTimestamp(),\n type: \"command\",\n role: \"cli\",\n content,\n metadata: {\n ...metadata,\n command,\n args,\n },\n };\n\n await this.writeEntry(entry);\n }\n\n /**\n * Log an error\n * @param errorMessage The error message\n * @param metadata Optional metadata including error details\n */\n async logError(errorMessage: string, metadata?: Record<string, unknown>): Promise<void> {\n const entry: ChatLogEntry = {\n timestamp: this.getTimestamp(),\n type: \"error\",\n role: \"system\",\n content: errorMessage,\n metadata,\n };\n\n await this.writeEntry(entry);\n }\n\n /**\n * Log an event (initialization, session start, etc.)\n * @param eventName Event name\n * @param metadata Optional metadata\n */\n async logEvent(eventName: string, metadata?: Record<string, unknown>): Promise<void> {\n const entry: ChatLogEntry = {\n timestamp: this.getTimestamp(),\n type: \"event\",\n role: \"system\",\n content: eventName,\n metadata,\n };\n\n await this.writeEntry(entry);\n }\n\n /**\n * Ensure header is written exactly once, even with concurrent calls\n */\n private async ensureHeaderWritten(): Promise<void> {\n // If header is already written, return immediately\n if (this.headerWritten) {\n return;\n }\n\n // If a write is in progress, wait for it\n if (this.headerWritePromise) {\n await this.headerWritePromise;\n return;\n }\n\n // Start the write and store the promise\n this.headerWritePromise = this.writeHeader();\n await this.headerWritePromise;\n this.headerWritePromise = null;\n }\n\n /**\n * Write the session header to the log file\n */\n private async writeHeader(): Promise<void> {\n const header: ChatLogEntry = {\n timestamp: this.sessionStartTime,\n type: \"event\",\n role: \"system\",\n content: \"Session started\",\n metadata: {\n sessionId: this.sessionId,\n logVersion: \"1.0\",\n },\n };\n\n try {\n await writeFile(this.sessionLogPath, this.formatEntry(header), \"utf-8\");\n this.headerWritten = true;\n } catch (error) {\n const errno = (error as NodeJS.ErrnoException).code;\n if (errno === \"ENOENT\") {\n // Directory doesn't exist - create it and retry\n await this.ensureLogDirectory();\n try {\n await writeFile(this.sessionLogPath, this.formatEntry(header), \"utf-8\");\n this.headerWritten = true;\n } catch (retryError) {\n throw retryError;\n }\n } else {\n // Permissions, disk full, or other error\n throw error;\n }\n }\n }\n\n /**\n * Write an entry to the log file\n */\n private async writeEntry(entry: ChatLogEntry): Promise<void> {\n try {\n await this.ensureLogDirectory();\n await this.ensureHeaderWritten();\n\n // Append the entry with automatic retry on ENOENT race condition\n await appendWithRetry(this.sessionLogPath, this.formatEntry(entry), async () => {\n // On ENOENT, recreate directory and header before retrying append\n await this.ensureLogDirectory();\n this.headerWritten = false;\n await this.ensureHeaderWritten();\n });\n } catch (error) {\n const errno = (error as NodeJS.ErrnoException).code;\n\n // Distinguish between expected issues (permissions, disk full) and unexpected bugs\n if (errno === \"EACCES\") {\n // Permissions issue - warn but continue (can't fix at runtime)\n console.error(\n \"[ChatLogger] ERROR: Permission denied writing to log file:\",\n this.sessionLogPath\n );\n console.error(\"[ChatLogger] Session logging disabled for this session.\");\n } else if (errno === \"ENOSPC\") {\n // Disk full - warn but continue\n console.error(\n \"[ChatLogger] ERROR: Disk full, cannot write to log file:\",\n this.sessionLogPath\n );\n } else {\n // Unexpected error - this is a bug that should be reported\n console.error(\"[ChatLogger] CRITICAL: Unexpected error writing to log file:\", error);\n console.error(\"[ChatLogger] Session ID:\", this.sessionId);\n console.error(\"[ChatLogger] Log path:\", this.sessionLogPath);\n console.error(\"[ChatLogger] This is a bug - please report with error details above.\");\n }\n }\n }\n\n /**\n * Read all entries from the session log.\n * Parses lines individually to preserve valid entries when one line is corrupt.\n */\n async readEntries(): Promise<ChatLogEntry[]> {\n try {\n const content = await readFile(this.sessionLogPath, \"utf-8\");\n const entries: ChatLogEntry[] = [];\n\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n try {\n entries.push(JSON.parse(trimmed) as ChatLogEntry);\n } catch (parseError) {\n // Skip corrupt lines but continue parsing remaining entries\n console.warn(\n \"[ChatLogger] Skipping corrupt JSON line in session log:\",\n parseError instanceof Error ? parseError.message : String(parseError)\n );\n // Continue to next line instead of failing entire read\n }\n }\n\n return entries;\n } catch (fileError) {\n // ENOENT is expected when session log hasn't been created yet - don't warn\n if ((fileError as NodeJS.ErrnoException).code !== \"ENOENT\") {\n console.warn(\"[ChatLogger] Warning: Could not read log file:\", fileError);\n }\n // Return empty array on file read errors but preserve any entries that were successfully parsed\n return [];\n }\n }\n\n /**\n * Get summary of the session\n */\n async getSummary(): Promise<{\n sessionId: string;\n messageCount: number;\n commandCount: number;\n errorCount: number;\n duration: string;\n }> {\n const entries = await this.readEntries();\n\n const messageCount = entries.filter((e) => e.type === \"message\" && e.role === \"user\").length;\n const commandCount = entries.filter((e) => e.type === \"command\").length;\n const errorCount = entries.filter((e) => e.type === \"error\").length;\n\n // Calculate duration from first to last entry\n let duration = \"N/A\";\n if (entries.length > 1) {\n const first = new Date(entries[0].timestamp);\n const last = new Date(entries[entries.length - 1].timestamp);\n const ms = last.getTime() - first.getTime();\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const secs = seconds % 60;\n\n if (minutes > 0) {\n duration = `${minutes}m ${secs}s`;\n } else {\n duration = `${secs}s`;\n }\n }\n\n return {\n sessionId: this.sessionId,\n messageCount,\n commandCount,\n errorCount,\n duration,\n };\n }\n}\n\n/**\n * Global chat logger instance or undefined\n */\nlet globalChatLogger: ChatLogger | undefined;\n\n/**\n * Initialize global chat logger\n * @param projectRoot Optional project root\n * @returns The initialized ChatLogger instance\n */\nexport function initializeChatLogger(projectRoot?: string): ChatLogger {\n globalChatLogger = new ChatLogger(projectRoot);\n return globalChatLogger;\n}\n\n/**\n * Get the global chat logger instance\n * @returns The global ChatLogger instance or undefined if not initialized\n */\nexport function getChatLogger(): ChatLogger | undefined {\n return globalChatLogger;\n}\n\n/**\n * Reset the global chat logger (for testing purposes)\n */\nexport function resetGlobalChatLogger(): void {\n globalChatLogger = undefined;\n}\n\n/**\n * List all chat session logs\n * @param projectRoot Optional project root for relative path resolution\n */\nexport async function listChatSessions(projectRoot?: string): Promise<string[]> {\n const logger = new ChatLogger(projectRoot);\n const logDir = logger.getLogDirectory();\n\n try {\n const files = await readdir(logDir);\n return files\n .filter((f) => f.endsWith(\".log\"))\n .sort()\n .reverse();\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Read a specific chat session\n * @param logFile The log filename\n * @param projectRoot Optional project root\n */\nexport async function readChatSession(\n logFile: string,\n projectRoot?: string\n): Promise<ChatLogEntry[]> {\n const logger = new ChatLogger(projectRoot);\n const logDir = logger.getLogDirectory();\n const logPath = join(logDir, logFile);\n\n try {\n const content = await readFile(logPath, \"utf-8\");\n return content\n .split(\"\\n\")\n .filter((line) => line.trim())\n .map((line) => JSON.parse(line) as ChatLogEntry);\n } catch (error) {\n console.error(\"Error reading chat session:\", error);\n throw error;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,8 @@
1
+ import { ClaudeCodeClient } from "../coding-agents/claude-code-client.js";
2
+ async function invokeClaudeStreaming(prompt) {
3
+ return await new ClaudeCodeClient().sendMessage(prompt, { withDanger: !1 });
4
+ }
5
+ export {
6
+ invokeClaudeStreaming
7
+ };
8
+ //# sourceMappingURL=claude-stream.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/claude-stream.ts"],
4
+ "sourcesContent": ["import { ClaudeCodeClient } from \"../coding-agents/claude-code-client.js\"\n\n/**\n * Invoke Claude Code CLI in non-interactive print mode, relaying text and\n * tool-use events to stdout in real-time, and returning the complete response\n * text for parsing.\n *\n * Delegates entirely to ClaudeCodeClient.sendMessage(), which handles:\n * - Prompt delivery via stdin (handles long prompts)\n * - stream-json event parsing\n * - Real-time tool-use and text output to process.stdout\n * - Complete response capture for the caller to parse\n *\n * @param prompt - The prompt to send to Claude via stdin\n * @returns The complete response text, ready for parsing\n */\nexport async function invokeClaudeStreaming(\n prompt: string,\n): Promise<string> {\n const client = new ClaudeCodeClient()\n\n return await client.sendMessage(prompt, { withDanger: false })\n}\n"],
5
+ "mappings": "AAAA,SAAS,wBAAwB;AAgBjC,eAAsB,sBACpB,QAAc;AAId,SAAO,MAFQ,IAAI,iBAAgB,EAEf,YAAY,QAAQ,EAAE,YAAY,GAAK,CAAE;AAC/D;",
6
+ "names": []
7
+ }
@@ -0,0 +1,7 @@
1
+ function formatDate(timestamp) {
2
+ return new Date(timestamp).toISOString().replace("T", " ").slice(0, 19);
3
+ }
4
+ export {
5
+ formatDate
6
+ };
7
+ //# sourceMappingURL=date-utils.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/date-utils.ts"],
4
+ "sourcesContent": ["/**\n * Date utility functions\n */\n\n/**\n * Formats a timestamp as a human-readable date string\n * @param timestamp ISO 8601 timestamp string\n * @returns Formatted date string in format \"YYYY-MM-DD HH:MM:SS\"\n */\nexport function formatDate(timestamp: string): string {\n return new Date(timestamp).toISOString().replace(\"T\", \" \").slice(0, 19);\n}\n"],
5
+ "mappings": "AASM,SAAU,WAAW,WAAiB;AACxC,SAAO,IAAI,KAAK,SAAS,EAAE,YAAW,EAAG,QAAQ,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE;AAC1E;",
6
+ "names": []
7
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/element-utils.ts"],
4
- "sourcesContent": ["/**\n * Element utility functions shared across commands\n */\n\nimport { Model } from '../core/model.js';\n\n/**\n * Find which layer contains an element by ID\n */\nexport async function findElementLayer(\n model: Model,\n elementId: string\n): Promise<string | undefined> {\n for (const layerName of model.getLayerNames()) {\n const layer = await model.getLayer(layerName);\n if (layer && layer.getElement(elementId)) {\n return layerName;\n }\n }\n return undefined;\n}\n"],
4
+ "sourcesContent": ["/**\n * Element utility functions shared across commands\n */\n\nimport { Model } from \"../core/model.js\";\n\n/**\n * Find which layer contains an element by ID\n */\nexport async function findElementLayer(\n model: Model,\n elementId: string\n): Promise<string | undefined> {\n for (const layerName of model.getLayerNames()) {\n const layer = await model.getLayer(layerName);\n if (layer && layer.getElement(elementId)) {\n return layerName;\n }\n }\n return undefined;\n}\n"],
5
5
  "mappings": "AASA,eAAsB,iBACpB,OACA,WAAiB;AAEjB,aAAW,aAAa,MAAM,cAAa,GAAI;AAC7C,UAAM,QAAQ,MAAM,MAAM,SAAS,SAAS;AAC5C,QAAI,SAAS,MAAM,WAAW,SAAS;AACrC,aAAO;EAEX;AAEF;",
6
6
  "names": []
7
7
  }
@@ -1,13 +1,29 @@
1
1
  import ansis from "ansis";
2
+ const MAX_SUGGESTIONS = 5;
3
+ var ErrorCategory;
4
+ (function(ErrorCategory2) {
5
+ ErrorCategory2[ErrorCategory2.USER = 1] = "USER", ErrorCategory2[ErrorCategory2.NOT_FOUND = 2] = "NOT_FOUND", ErrorCategory2[ErrorCategory2.SYSTEM = 3] = "SYSTEM", ErrorCategory2[ErrorCategory2.VALIDATION = 4] = "VALIDATION", ErrorCategory2[ErrorCategory2.BREAKING_CHANGE = 5] = "BREAKING_CHANGE";
6
+ })(ErrorCategory || (ErrorCategory = {}));
2
7
  class CLIError extends Error {
3
8
  exitCode;
4
9
  suggestions;
5
- constructor(message, exitCode = 1, suggestions) {
6
- super(message), this.exitCode = exitCode, this.suggestions = suggestions, this.name = "CLIError";
10
+ context;
11
+ constructor(message, exitCode = ErrorCategory.USER, suggestions, context) {
12
+ super(message), this.exitCode = exitCode, this.suggestions = suggestions, this.context = context, this.name = "CLIError";
7
13
  }
8
14
  format() {
9
15
  const lines = [];
10
- if (lines.push(ansis.red(`Error: ${this.message}`)), this.suggestions && this.suggestions.length > 0) {
16
+ if (lines.push(ansis.red(`Error: ${this.message}`)), this.context?.operation && lines.push(ansis.dim(`During: ${this.context.operation}`)), this.context?.partialProgress) {
17
+ const { completed, total } = this.context.partialProgress;
18
+ lines.push(ansis.yellow(`\u26A0 Partial progress: ${completed}/${total} completed (operation rolled back)`));
19
+ }
20
+ if (this.context?.relatedElements && this.context.relatedElements.length > 0) {
21
+ lines.push(ansis.dim("Related elements:"));
22
+ for (const elem of this.context.relatedElements.slice(0, MAX_SUGGESTIONS))
23
+ lines.push(ansis.dim(` \u2022 ${elem}`));
24
+ this.context.relatedElements.length > MAX_SUGGESTIONS && lines.push(ansis.dim(` ... and ${this.context.relatedElements.length - MAX_SUGGESTIONS} more`));
25
+ }
26
+ if (this.suggestions && this.suggestions.length > 0) {
11
27
  lines.push(""), lines.push(ansis.dim("Suggestions:"));
12
28
  for (const suggestion of this.suggestions)
13
29
  lines.push(ansis.dim(` \u2022 ${suggestion}`));
@@ -18,16 +34,28 @@ class CLIError extends Error {
18
34
  }
19
35
  class ValidationError extends CLIError {
20
36
  errors;
21
- constructor(message, errors = [], suggestions) {
22
- super(message, 1, suggestions), this.errors = errors, this.name = "ValidationError";
37
+ constructor(message, errors = [], suggestions, context) {
38
+ super(message, ErrorCategory.VALIDATION, suggestions, context), this.errors = errors, this.name = "ValidationError";
23
39
  }
24
40
  format() {
25
41
  const lines = [];
26
42
  if (lines.push(ansis.red(`Error: ${this.message}`)), this.errors.length > 0) {
27
- lines.push(""), lines.push(ansis.dim("Details:"));
43
+ const errorsByLayer = {};
28
44
  for (const error of this.errors) {
29
- let detail = "";
30
- error.layer && error.elementId ? detail = ` [${error.layer}:${error.elementId}] ${error.message}` : error.layer ? detail = ` [${error.layer}] ${error.message}` : detail = ` ${error.message}`, lines.push(ansis.dim(detail));
45
+ const layer = error.layer || "general";
46
+ errorsByLayer[layer] || (errorsByLayer[layer] = []), errorsByLayer[layer].push({ elementId: error.elementId, message: error.message });
47
+ }
48
+ lines.push(""), lines.push(ansis.dim(`Validation errors: ${this.errors.length} found`)), lines.push("");
49
+ const layerNames = Object.keys(errorsByLayer).sort();
50
+ for (const layer of layerNames) {
51
+ const layerErrors = errorsByLayer[layer];
52
+ lines.push(ansis.dim(` [${layer}] ${layerErrors.length} error(s):`));
53
+ for (let i = 0; i < Math.min(layerErrors.length, MAX_SUGGESTIONS); i++) {
54
+ const error = layerErrors[i];
55
+ let detail = "";
56
+ error.elementId ? detail = ` ${error.elementId}: ${error.message}` : detail = ` ${error.message}`, lines.push(ansis.dim(detail));
57
+ }
58
+ layerErrors.length > MAX_SUGGESTIONS && lines.push(ansis.dim(` ... and ${layerErrors.length - MAX_SUGGESTIONS} more in this layer`));
31
59
  }
32
60
  }
33
61
  if (this.suggestions && this.suggestions.length > 0) {
@@ -42,7 +70,7 @@ class ValidationError extends CLIError {
42
70
  class FileNotFoundError extends CLIError {
43
71
  constructor(path, context) {
44
72
  const message = context ? `${context}: ${path}` : `File not found: ${path}`;
45
- super(message, 2, [
73
+ super(message, ErrorCategory.NOT_FOUND, [
46
74
  `Check that the path is correct: ${path}`,
47
75
  'Use "dr init" to create a new model',
48
76
  'Use "dr list <layer>" to see available elements'
@@ -51,30 +79,33 @@ class FileNotFoundError extends CLIError {
51
79
  }
52
80
  class ElementNotFoundError extends CLIError {
53
81
  constructor(elementId) {
54
- super(`Element not found: ${elementId}`, 2, [
82
+ super(`Element not found: ${elementId}`, ErrorCategory.NOT_FOUND, [
55
83
  `Use "dr search ${elementId}" to find similar elements`,
56
84
  'Use "dr list <layer>" to list all elements in a layer',
57
- "Check the element ID format: {layer}-{type}-{kebab-case-name}"
85
+ "Check the element ID format: {layer}.{type}.{kebab-case-name}"
58
86
  ]), this.name = "ElementNotFoundError";
59
87
  }
60
88
  }
61
89
  class ModelNotFoundError extends CLIError {
62
90
  constructor(rootPath = ".") {
63
- super(`No model found at ${rootPath}`, 2, ['Run "dr init" to initialize a new model', "Check that you are in the correct directory"]), this.name = "ModelNotFoundError";
91
+ super(`No model found at ${rootPath}`, ErrorCategory.NOT_FOUND, [
92
+ 'Run "dr init" to initialize a new model',
93
+ "Check that you are in the correct directory"
94
+ ]), this.name = "ModelNotFoundError";
64
95
  }
65
96
  }
66
97
  class InvalidJSONError extends CLIError {
67
98
  constructor(input, context) {
68
99
  const message = context ? `Invalid JSON in ${context}` : "Invalid JSON format";
69
- super(message, 1, [
100
+ super(message, ErrorCategory.USER, [
70
101
  `Check your JSON syntax: ${input}`,
71
- `Use single quotes to wrap JSON: --properties '{"key":"value"}'`,
102
+ `Use single quotes to wrap JSON: --attributes '{"key":"value"}'`,
72
103
  "Escape special characters properly"
73
104
  ]), this.name = "InvalidJSONError";
74
105
  }
75
106
  }
76
107
  function handleError(error) {
77
- error instanceof CLIError ? (console.error(error.format()), process.exit(error.exitCode)) : error instanceof Error ? (console.error(ansis.red(`Error: ${error.message}`)), process.env.DEBUG && console.error(ansis.dim(error.stack)), process.exit(1)) : (console.error(ansis.red("An unexpected error occurred")), process.env.DEBUG && console.error(ansis.dim(String(error))), process.exit(1));
108
+ throw error instanceof CLIError ? (console.error(error.format()), error) : error instanceof Error ? (console.error(ansis.red(`Error: ${error.message}`)), process.env.DEBUG && console.error(ansis.dim(error.stack)), error) : (console.error(ansis.red("An unexpected error occurred")), process.env.DEBUG && console.error(ansis.dim(String(error))), new Error(String(error)));
78
109
  }
79
110
  function handleWarning(message, suggestions) {
80
111
  const lines = [];
@@ -91,13 +122,55 @@ function handleSuccess(message, details) {
91
122
  for (const [key, value] of Object.entries(details))
92
123
  console.log(ansis.dim(` ${key}: ${value}`));
93
124
  }
125
+ function formatValidOptions(options, heading = "Valid options") {
126
+ return options.length === 0 ? "" : options.length === 1 ? `${heading}: ${options[0]}` : `${heading}: ${options.slice(0, -1).join(", ")} or ${options[options.length - 1]}`;
127
+ }
128
+ function categorizeError(error) {
129
+ if (error instanceof CLIError)
130
+ return error.exitCode;
131
+ if (error instanceof Error && "code" in error) {
132
+ const code = error.code;
133
+ if (typeof code == "string") {
134
+ if (code === "ENOENT")
135
+ return ErrorCategory.NOT_FOUND;
136
+ if ((/* @__PURE__ */ new Set(["EACCES", "ENOSPC", "EIO", "EROFS", "EPERM"])).has(code))
137
+ return ErrorCategory.SYSTEM;
138
+ }
139
+ }
140
+ return ErrorCategory.USER;
141
+ }
142
+ function getErrorMessage(error) {
143
+ return error instanceof Error ? error.message : String(error);
144
+ }
145
+ function findSimilar(input, options, maxDistance = 2) {
146
+ return options.map((option) => ({
147
+ option,
148
+ distance: levenshteinDistance(input.toLowerCase(), option.toLowerCase())
149
+ })).filter(({ distance }) => distance <= maxDistance).sort((a, b) => a.distance - b.distance).slice(0, 3).map(({ option }) => option);
150
+ }
151
+ function levenshteinDistance(a, b) {
152
+ const matrix = [];
153
+ for (let i = 0; i <= b.length; i++)
154
+ matrix[i] = [i];
155
+ for (let j = 0; j <= a.length; j++)
156
+ matrix[0][j] = j;
157
+ for (let i = 1; i <= b.length; i++)
158
+ for (let j = 1; j <= a.length; j++)
159
+ b.charAt(i - 1) === a.charAt(j - 1) ? matrix[i][j] = matrix[i - 1][j - 1] : matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1);
160
+ return matrix[b.length][a.length];
161
+ }
94
162
  export {
95
163
  CLIError,
96
164
  ElementNotFoundError,
165
+ ErrorCategory,
97
166
  FileNotFoundError,
98
167
  InvalidJSONError,
99
168
  ModelNotFoundError,
100
169
  ValidationError,
170
+ categorizeError,
171
+ findSimilar,
172
+ formatValidOptions,
173
+ getErrorMessage,
101
174
  handleError,
102
175
  handleSuccess,
103
176
  handleWarning
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/errors.ts"],
4
- "sourcesContent": ["/**\n * Error handling utilities with formatted output\n * Matches Python CLI error message formatting\n *\n * NOTE: The add.ts command demonstrates usage of CLIError.\n * Future commands should adopt this pattern to ensure consistent error handling.\n */\n\nimport ansis from 'ansis';\n\nexport class CLIError extends Error {\n constructor(\n message: string,\n public exitCode: number = 1,\n public suggestions?: string[]\n ) {\n super(message);\n this.name = 'CLIError';\n }\n\n format(): string {\n const lines: string[] = [];\n\n lines.push(ansis.red(`Error: ${this.message}`));\n\n if (this.suggestions && this.suggestions.length > 0) {\n lines.push('');\n lines.push(ansis.dim('Suggestions:'));\n for (const suggestion of this.suggestions) {\n lines.push(ansis.dim(` \u2022 ${suggestion}`));\n }\n }\n\n return lines.join('\\n');\n }\n}\n\nexport class ValidationError extends CLIError {\n constructor(\n message: string,\n public errors: Array<{ layer?: string; elementId?: string; message: string }> = [],\n suggestions?: string[]\n ) {\n super(message, 1, suggestions);\n this.name = 'ValidationError';\n }\n\n format(): string {\n const lines: string[] = [];\n\n lines.push(ansis.red(`Error: ${this.message}`));\n\n if (this.errors.length > 0) {\n lines.push('');\n lines.push(ansis.dim('Details:'));\n for (const error of this.errors) {\n let detail = '';\n if (error.layer && error.elementId) {\n detail = ` [${error.layer}:${error.elementId}] ${error.message}`;\n } else if (error.layer) {\n detail = ` [${error.layer}] ${error.message}`;\n } else {\n detail = ` ${error.message}`;\n }\n lines.push(ansis.dim(detail));\n }\n }\n\n if (this.suggestions && this.suggestions.length > 0) {\n lines.push('');\n lines.push(ansis.dim('Suggestions:'));\n for (const suggestion of this.suggestions) {\n lines.push(ansis.dim(` \u2022 ${suggestion}`));\n }\n }\n\n return lines.join('\\n');\n }\n}\n\nexport class FileNotFoundError extends CLIError {\n constructor(path: string, context?: string) {\n const message = context ? `${context}: ${path}` : `File not found: ${path}`;\n super(message, 2, [\n `Check that the path is correct: ${path}`,\n 'Use \"dr init\" to create a new model',\n 'Use \"dr list <layer>\" to see available elements',\n ]);\n this.name = 'FileNotFoundError';\n }\n}\n\nexport class ElementNotFoundError extends CLIError {\n constructor(elementId: string) {\n super(\n `Element not found: ${elementId}`,\n 2,\n [\n `Use \"dr search ${elementId}\" to find similar elements`,\n 'Use \"dr list <layer>\" to list all elements in a layer',\n 'Check the element ID format: {layer}-{type}-{kebab-case-name}',\n ]\n );\n this.name = 'ElementNotFoundError';\n }\n}\n\nexport class ModelNotFoundError extends CLIError {\n constructor(rootPath: string = '.') {\n super(\n `No model found at ${rootPath}`,\n 2,\n [`Run \"dr init\" to initialize a new model`, 'Check that you are in the correct directory']\n );\n this.name = 'ModelNotFoundError';\n }\n}\n\nexport class InvalidJSONError extends CLIError {\n constructor(input: string, context?: string) {\n const message = context ? `Invalid JSON in ${context}` : 'Invalid JSON format';\n super(message, 1, [\n `Check your JSON syntax: ${input}`,\n 'Use single quotes to wrap JSON: --properties \\'{\"key\":\"value\"}\\'',\n 'Escape special characters properly',\n ]);\n this.name = 'InvalidJSONError';\n }\n}\n\nexport function handleError(error: unknown): never {\n if (error instanceof CLIError) {\n console.error(error.format());\n process.exit(error.exitCode);\n } else if (error instanceof Error) {\n console.error(ansis.red(`Error: ${error.message}`));\n if (process.env.DEBUG) {\n console.error(ansis.dim(error.stack));\n }\n process.exit(1);\n } else {\n console.error(ansis.red('An unexpected error occurred'));\n if (process.env.DEBUG) {\n console.error(ansis.dim(String(error)));\n }\n process.exit(1);\n }\n}\n\nexport function handleWarning(message: string, suggestions?: string[]): void {\n const lines: string[] = [];\n lines.push(ansis.yellow(`Warning: ${message}`));\n if (suggestions && suggestions.length > 0) {\n lines.push('');\n lines.push(ansis.dim('Suggestions:'));\n for (const suggestion of suggestions) {\n lines.push(ansis.dim(` \u2022 ${suggestion}`));\n }\n }\n console.warn(lines.join('\\n'));\n}\n\nexport function handleSuccess(message: string, details?: Record<string, string>): void {\n console.log(ansis.green(`\u2713 ${message}`));\n if (details) {\n for (const [key, value] of Object.entries(details)) {\n console.log(ansis.dim(` ${key}: ${value}`));\n }\n }\n}\n"],
5
- "mappings": "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",
6
- "names": []
4
+ "sourcesContent": ["/**\n * Error handling utilities with formatted output\n * Matches Python CLI error message formatting\n *\n * Error Categories:\n * - User Error (exit code 1): Invalid input, wrong format, element exists\n * - Not Found (exit code 2): File/element/model not found\n * - System Error (exit code 3): Permission denied, I/O failure\n * - Validation Error (exit code 4): Schema/reference/semantic validation failed\n * - Breaking Change (exit code 5): Version migration required\n */\n\nimport ansis from \"ansis\";\n\nconst MAX_SUGGESTIONS = 5;\n\nexport enum ErrorCategory {\n USER = 1,\n NOT_FOUND = 2,\n SYSTEM = 3,\n VALIDATION = 4,\n BREAKING_CHANGE = 5,\n}\n\nexport interface ErrorContext {\n operation?: string;\n context?: string;\n relatedElements?: string[];\n partialProgress?: { completed: number; total: number };\n}\n\nexport class CLIError extends Error {\n constructor(\n message: string,\n public exitCode: number = ErrorCategory.USER,\n public suggestions?: string[],\n public context?: ErrorContext\n ) {\n super(message);\n this.name = \"CLIError\";\n }\n\n format(): string {\n const lines: string[] = [];\n\n lines.push(ansis.red(`Error: ${this.message}`));\n\n if (this.context?.operation) {\n lines.push(ansis.dim(`During: ${this.context.operation}`));\n }\n\n if (this.context?.partialProgress) {\n const { completed, total } = this.context.partialProgress;\n lines.push(\n ansis.yellow(`\u26A0 Partial progress: ${completed}/${total} completed (operation rolled back)`)\n );\n }\n\n if (this.context?.relatedElements && this.context.relatedElements.length > 0) {\n lines.push(ansis.dim(\"Related elements:\"));\n for (const elem of this.context.relatedElements.slice(0, MAX_SUGGESTIONS)) {\n lines.push(ansis.dim(` \u2022 ${elem}`));\n }\n if (this.context.relatedElements.length > MAX_SUGGESTIONS) {\n lines.push(\n ansis.dim(` ... and ${this.context.relatedElements.length - MAX_SUGGESTIONS} more`)\n );\n }\n }\n\n if (this.suggestions && this.suggestions.length > 0) {\n lines.push(\"\");\n lines.push(ansis.dim(\"Suggestions:\"));\n for (const suggestion of this.suggestions) {\n lines.push(ansis.dim(` \u2022 ${suggestion}`));\n }\n }\n\n return lines.join(\"\\n\");\n }\n}\n\nexport class ValidationError extends CLIError {\n constructor(\n message: string,\n public errors: Array<{ layer?: string; elementId?: string; message: string }> = [],\n suggestions?: string[],\n context?: ErrorContext\n ) {\n super(message, ErrorCategory.VALIDATION, suggestions, context);\n this.name = \"ValidationError\";\n }\n\n format(): string {\n const lines: string[] = [];\n\n lines.push(ansis.red(`Error: ${this.message}`));\n\n if (this.errors.length > 0) {\n // Show error count and grouping\n const errorsByLayer: Record<string, Array<{ elementId?: string; message: string }>> = {};\n for (const error of this.errors) {\n const layer = error.layer || \"general\";\n if (!errorsByLayer[layer]) {\n errorsByLayer[layer] = [];\n }\n errorsByLayer[layer].push({ elementId: error.elementId, message: error.message });\n }\n\n lines.push(\"\");\n lines.push(ansis.dim(`Validation errors: ${this.errors.length} found`));\n lines.push(\"\");\n\n const layerNames = Object.keys(errorsByLayer).sort();\n\n for (const layer of layerNames) {\n const layerErrors = errorsByLayer[layer];\n lines.push(ansis.dim(` [${layer}] ${layerErrors.length} error(s):`));\n\n for (let i = 0; i < Math.min(layerErrors.length, MAX_SUGGESTIONS); i++) {\n const error = layerErrors[i];\n let detail = \"\";\n if (error.elementId) {\n detail = ` ${error.elementId}: ${error.message}`;\n } else {\n detail = ` ${error.message}`;\n }\n lines.push(ansis.dim(detail));\n }\n\n if (layerErrors.length > MAX_SUGGESTIONS) {\n lines.push(\n ansis.dim(` ... and ${layerErrors.length - MAX_SUGGESTIONS} more in this layer`)\n );\n }\n }\n }\n\n if (this.suggestions && this.suggestions.length > 0) {\n lines.push(\"\");\n lines.push(ansis.dim(\"Suggestions:\"));\n for (const suggestion of this.suggestions) {\n lines.push(ansis.dim(` \u2022 ${suggestion}`));\n }\n }\n\n return lines.join(\"\\n\");\n }\n}\n\nexport class FileNotFoundError extends CLIError {\n constructor(path: string, context?: string) {\n const message = context ? `${context}: ${path}` : `File not found: ${path}`;\n super(message, ErrorCategory.NOT_FOUND, [\n `Check that the path is correct: ${path}`,\n 'Use \"dr init\" to create a new model',\n 'Use \"dr list <layer>\" to see available elements',\n ]);\n this.name = \"FileNotFoundError\";\n }\n}\n\nexport class ElementNotFoundError extends CLIError {\n constructor(elementId: string) {\n super(`Element not found: ${elementId}`, ErrorCategory.NOT_FOUND, [\n `Use \"dr search ${elementId}\" to find similar elements`,\n 'Use \"dr list <layer>\" to list all elements in a layer',\n \"Check the element ID format: {layer}.{type}.{kebab-case-name}\",\n ]);\n this.name = \"ElementNotFoundError\";\n }\n}\n\nexport class ModelNotFoundError extends CLIError {\n constructor(rootPath: string = \".\") {\n super(`No model found at ${rootPath}`, ErrorCategory.NOT_FOUND, [\n `Run \"dr init\" to initialize a new model`,\n \"Check that you are in the correct directory\",\n ]);\n this.name = \"ModelNotFoundError\";\n }\n}\n\nexport class InvalidJSONError extends CLIError {\n constructor(input: string, context?: string) {\n const message = context ? `Invalid JSON in ${context}` : \"Invalid JSON format\";\n super(message, ErrorCategory.USER, [\n `Check your JSON syntax: ${input}`,\n 'Use single quotes to wrap JSON: --attributes \\'{\"key\":\"value\"}\\'',\n \"Escape special characters properly\",\n ]);\n this.name = \"InvalidJSONError\";\n }\n}\n\nexport function handleError(error: unknown): never {\n if (error instanceof CLIError) {\n console.error(error.format());\n // Don't call process.exit() - rethrow so CLI wrapper can handle telemetry shutdown\n throw error;\n } else if (error instanceof Error) {\n console.error(ansis.red(`Error: ${error.message}`));\n if (process.env.DEBUG) {\n console.error(ansis.dim(error.stack));\n }\n // Rethrow to allow CLI wrapper to handle shutdown\n throw error;\n } else {\n console.error(ansis.red(\"An unexpected error occurred\"));\n if (process.env.DEBUG) {\n console.error(ansis.dim(String(error)));\n }\n // Create proper error to throw\n throw new Error(String(error));\n }\n}\n\nexport function handleWarning(message: string, suggestions?: string[]): void {\n const lines: string[] = [];\n lines.push(ansis.yellow(`Warning: ${message}`));\n if (suggestions && suggestions.length > 0) {\n lines.push(\"\");\n lines.push(ansis.dim(\"Suggestions:\"));\n for (const suggestion of suggestions) {\n lines.push(ansis.dim(` \u2022 ${suggestion}`));\n }\n }\n console.warn(lines.join(\"\\n\"));\n}\n\nexport function handleSuccess(message: string, details?: Record<string, string>): void {\n console.log(ansis.green(`\u2713 ${message}`));\n if (details) {\n for (const [key, value] of Object.entries(details)) {\n console.log(ansis.dim(` ${key}: ${value}`));\n }\n }\n}\n\n/**\n * Utility to extract common valid options for better error suggestions\n */\nexport function formatValidOptions(options: string[], heading: string = \"Valid options\"): string {\n if (options.length === 0) return \"\";\n if (options.length === 1) return `${heading}: ${options[0]}`;\n return `${heading}: ${options.slice(0, -1).join(\", \")} or ${options[options.length - 1]}`;\n}\n\n/**\n * Categorize errors based on type, using stable error.code for system errors\n * Returns the appropriate ErrorCategory for a given error\n */\nexport function categorizeError(error: unknown): ErrorCategory {\n if (error instanceof CLIError) {\n return error.exitCode;\n }\n\n // Check for system errors using stable error.code\n if (error instanceof Error && \"code\" in error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (typeof code === \"string\") {\n // File not found errors should map to NOT_FOUND category\n if (code === \"ENOENT\") {\n return ErrorCategory.NOT_FOUND;\n }\n // Other system-level errors\n const SYSTEM_ERROR_CODES = new Set([\"EACCES\", \"ENOSPC\", \"EIO\", \"EROFS\", \"EPERM\"]);\n if (SYSTEM_ERROR_CODES.has(code)) {\n return ErrorCategory.SYSTEM;\n }\n }\n }\n\n // Default to USER for other errors\n return ErrorCategory.USER;\n}\n\n/**\n * Extract error message from any error type\n * Handles Error instances, strings, and unknown types consistently\n */\nexport function getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n return String(error);\n}\n\n/**\n * Simple fuzzy match to find similar strings (for typo suggestions)\n */\nexport function findSimilar(input: string, options: string[], maxDistance: number = 2): string[] {\n return options\n .map((option) => ({\n option,\n distance: levenshteinDistance(input.toLowerCase(), option.toLowerCase()),\n }))\n .filter(({ distance }) => distance <= maxDistance)\n .sort((a, b) => a.distance - b.distance)\n .slice(0, 3)\n .map(({ option }) => option);\n}\n\n/**\n * Calculate Levenshtein distance for typo detection\n */\nfunction levenshteinDistance(a: string, b: string): number {\n const matrix: number[][] = [];\n\n for (let i = 0; i <= b.length; i++) {\n matrix[i] = [i];\n }\n\n for (let j = 0; j <= a.length; j++) {\n matrix[0][j] = j;\n }\n\n for (let i = 1; i <= b.length; i++) {\n for (let j = 1; j <= a.length; j++) {\n if (b.charAt(i - 1) === a.charAt(j - 1)) {\n matrix[i][j] = matrix[i - 1][j - 1];\n } else {\n matrix[i][j] = Math.min(\n matrix[i - 1][j - 1] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j] + 1\n );\n }\n }\n }\n\n return matrix[b.length][a.length];\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["ErrorCategory"]
7
7
  }