@documentation-robotics/cli 0.1.13 → 0.3.0

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 (351) hide show
  1. package/README.md +74 -2
  2. package/dist/analysis/relationship-classifier.js +2 -9
  3. package/dist/analysis/relationship-classifier.js.map +2 -2
  4. package/dist/analyzers/call-graph-utils.js +2 -2
  5. package/dist/analyzers/call-graph-utils.js.map +2 -2
  6. package/dist/analyzers/cards/build.js +171 -0
  7. package/dist/analyzers/cards/build.js.map +7 -0
  8. package/dist/analyzers/cards/classify.js +42 -0
  9. package/dist/analyzers/cards/classify.js.map +7 -0
  10. package/dist/analyzers/cards/edge-index.js +44 -0
  11. package/dist/analyzers/cards/edge-index.js.map +7 -0
  12. package/dist/analyzers/cards/facts.js +46 -0
  13. package/dist/analyzers/cards/facts.js.map +7 -0
  14. package/dist/analyzers/cards/graph.js +42 -0
  15. package/dist/analyzers/cards/graph.js.map +7 -0
  16. package/dist/analyzers/cards/index.js +8 -0
  17. package/dist/analyzers/cards/index.js.map +7 -0
  18. package/dist/analyzers/cards/tier0.js +18 -0
  19. package/dist/analyzers/cards/tier0.js.map +7 -0
  20. package/dist/analyzers/cards/types.js +1 -0
  21. package/dist/analyzers/cards/types.js.map +7 -0
  22. package/dist/analyzers/cbm-analyzer.js +195 -171
  23. package/dist/analyzers/cbm-analyzer.js.map +2 -2
  24. package/dist/analyzers/cbm-responses.js +336 -0
  25. package/dist/analyzers/cbm-responses.js.map +7 -0
  26. package/dist/analyzers/edge-relationships.js +45 -0
  27. package/dist/analyzers/edge-relationships.js.map +7 -0
  28. package/dist/analyzers/mapping-loader.js +9 -0
  29. package/dist/analyzers/mapping-loader.js.map +2 -2
  30. package/dist/analyzers/tier0-rules.js +153 -0
  31. package/dist/analyzers/tier0-rules.js.map +7 -0
  32. package/dist/analyzers/types.js.map +1 -1
  33. package/dist/analyzers/verify-engine.js +22 -19
  34. package/dist/analyzers/verify-engine.js.map +2 -2
  35. package/dist/audit/relationships/ai/prompts.js +10 -10
  36. package/dist/audit/relationships/ai/prompts.js.map +2 -2
  37. package/dist/audit/relationships/analysis/layer-templates.js +52 -52
  38. package/dist/audit/relationships/analysis/layer-templates.js.map +1 -1
  39. package/dist/cli.js +112 -28
  40. package/dist/cli.js.map +3 -3
  41. package/dist/coding-agents/agents/claude-code.js +3 -1
  42. package/dist/coding-agents/agents/claude-code.js.map +2 -2
  43. package/dist/coding-agents/claude-code-client.js +2 -1
  44. package/dist/coding-agents/claude-code-client.js.map +2 -2
  45. package/dist/coding-agents/copilot-client.js +17 -12
  46. package/dist/coding-agents/copilot-client.js.map +2 -2
  47. package/dist/coding-agents/default-permissions.js +152 -0
  48. package/dist/coding-agents/default-permissions.js.map +7 -0
  49. package/dist/coding-agents/drbot-mcp.js +167 -0
  50. package/dist/coding-agents/drbot-mcp.js.map +7 -0
  51. package/dist/commands/add.js +12 -7
  52. package/dist/commands/add.js.map +2 -2
  53. package/dist/commands/analyzer.js +134 -23
  54. package/dist/commands/analyzer.js.map +2 -2
  55. package/dist/commands/audit.js +6 -6
  56. package/dist/commands/audit.js.map +2 -2
  57. package/dist/commands/changeset-verify.js +55 -0
  58. package/dist/commands/changeset-verify.js.map +7 -0
  59. package/dist/commands/changeset.js +261 -147
  60. package/dist/commands/changeset.js.map +2 -2
  61. package/dist/commands/delete.js +52 -19
  62. package/dist/commands/delete.js.map +3 -3
  63. package/dist/commands/element.js +3 -2
  64. package/dist/commands/element.js.map +2 -2
  65. package/dist/commands/farm.js +773 -0
  66. package/dist/commands/farm.js.map +7 -0
  67. package/dist/commands/init.js +11 -1
  68. package/dist/commands/init.js.map +2 -2
  69. package/dist/commands/mcp.js +122 -0
  70. package/dist/commands/mcp.js.map +7 -0
  71. package/dist/commands/relationship.js +251 -47
  72. package/dist/commands/relationship.js.map +2 -2
  73. package/dist/commands/reports.js +1 -1
  74. package/dist/commands/reports.js.map +2 -2
  75. package/dist/commands/update.js +56 -24
  76. package/dist/commands/update.js.map +2 -2
  77. package/dist/commands/upgrade.js +99 -11
  78. package/dist/commands/upgrade.js.map +3 -3
  79. package/dist/commands/validate.js +41 -3
  80. package/dist/commands/validate.js.map +2 -2
  81. package/dist/commands/version.js +2 -2
  82. package/dist/commands/version.js.map +2 -2
  83. package/dist/commands/visualize.js +4 -3
  84. package/dist/commands/visualize.js.map +2 -2
  85. package/dist/config.js +83 -0
  86. package/dist/config.js.map +7 -0
  87. package/dist/core/annotation-store.js +138 -0
  88. package/dist/core/annotation-store.js.map +7 -0
  89. package/dist/core/catalog-migration.js +33 -0
  90. package/dist/core/catalog-migration.js.map +7 -0
  91. package/dist/core/changeset-analysis.js +421 -0
  92. package/dist/core/changeset-analysis.js.map +7 -0
  93. package/dist/core/changeset-base-index.js +153 -0
  94. package/dist/core/changeset-base-index.js.map +7 -0
  95. package/dist/core/changeset-brief-delta.js +102 -0
  96. package/dist/core/changeset-brief-delta.js.map +7 -0
  97. package/dist/core/changeset-graph.js +281 -0
  98. package/dist/core/changeset-graph.js.map +7 -0
  99. package/dist/core/changeset-only-guard.js +32 -0
  100. package/dist/core/changeset-only-guard.js.map +7 -0
  101. package/dist/core/changeset-summary.js +68 -0
  102. package/dist/core/changeset-summary.js.map +7 -0
  103. package/dist/core/changeset-validator.js +66 -20
  104. package/dist/core/changeset-validator.js.map +2 -2
  105. package/dist/core/changeset-verify.js +518 -0
  106. package/dist/core/changeset-verify.js.map +7 -0
  107. package/dist/core/changeset.js +56 -9
  108. package/dist/core/changeset.js.map +2 -2
  109. package/dist/core/element-type-migration.js +145 -0
  110. package/dist/core/element-type-migration.js.map +7 -0
  111. package/dist/core/farm-manifest.js +140 -0
  112. package/dist/core/farm-manifest.js.map +7 -0
  113. package/dist/core/farm-sync-engine.js +346 -0
  114. package/dist/core/farm-sync-engine.js.map +7 -0
  115. package/dist/core/farm-sync-state.js +167 -0
  116. package/dist/core/farm-sync-state.js.map +7 -0
  117. package/dist/core/manifest.js +6 -3
  118. package/dist/core/manifest.js.map +2 -2
  119. package/dist/core/migration-registry.js +84 -1
  120. package/dist/core/migration-registry.js.map +2 -2
  121. package/dist/core/model-upgrade.js +102 -0
  122. package/dist/core/model-upgrade.js.map +7 -0
  123. package/dist/core/model.js +257 -44
  124. package/dist/core/model.js.map +3 -3
  125. package/dist/core/mutation-handler.js +71 -6
  126. package/dist/core/mutation-handler.js.map +2 -2
  127. package/dist/core/relationship-migration-table.js +6639 -0
  128. package/dist/core/relationship-migration-table.js.map +7 -0
  129. package/dist/core/relationship-migration.js +272 -0
  130. package/dist/core/relationship-migration.js.map +7 -0
  131. package/dist/core/relationship-prune.js +49 -0
  132. package/dist/core/relationship-prune.js.map +7 -0
  133. package/dist/core/relationship-staging.js +68 -0
  134. package/dist/core/relationship-staging.js.map +7 -0
  135. package/dist/core/relationships.js +26 -4
  136. package/dist/core/relationships.js.map +2 -2
  137. package/dist/core/report-data-model.js +7 -13
  138. package/dist/core/report-data-model.js.map +2 -2
  139. package/dist/core/staged-changeset-storage.js +64 -17
  140. package/dist/core/staged-changeset-storage.js.map +2 -2
  141. package/dist/core/staged-source-reference.js +28 -0
  142. package/dist/core/staged-source-reference.js.map +7 -0
  143. package/dist/core/staging-area.js +83 -18
  144. package/dist/core/staging-area.js.map +2 -2
  145. package/dist/core/virtual-projection.js +14 -5
  146. package/dist/core/virtual-projection.js.map +2 -2
  147. package/dist/export/archimate-exporter.js +1 -0
  148. package/dist/export/archimate-exporter.js.map +2 -2
  149. package/dist/generated/compiled-validators.js +2 -2
  150. package/dist/generated/compiled-validators.js.map +2 -2
  151. package/dist/generated/layer-registry.js +16 -16
  152. package/dist/generated/layer-registry.js.map +2 -2
  153. package/dist/generated/node-types.js +186 -168
  154. package/dist/generated/node-types.js.map +2 -2
  155. package/dist/generated/relationship-index.js +2209 -7727
  156. package/dist/generated/relationship-index.js.map +2 -2
  157. package/dist/integrations/claude_code/agents/dr-architect.md +16 -3
  158. package/dist/integrations/claude_code/agents/dr-extractor.md +1 -1
  159. package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
  160. package/dist/integrations/claude_code/commands/dr-map.md +13 -0
  161. package/dist/integrations/claude_code/commands/dr-plan.md +40 -0
  162. package/dist/integrations/claude_code/commands/dr-relate.md +106 -96
  163. package/dist/integrations/claude_code/commands/dr-verify.md +45 -2
  164. package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +14 -0
  165. package/dist/integrations/claude_code/docs/MCP_SERVER.md +79 -0
  166. package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
  167. package/dist/integrations/claude_code/docs/README.md +52 -1
  168. package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +93 -72
  169. package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +163 -126
  170. package/dist/integrations/claude_code/skills/dr_03_product_layer/SKILL.md +161 -126
  171. package/dist/integrations/claude_code/skills/dr_04_security_layer/SKILL.md +153 -133
  172. package/dist/integrations/claude_code/skills/dr_05_application_layer/SKILL.md +129 -100
  173. package/dist/integrations/claude_code/skills/dr_06_technology_layer/SKILL.md +111 -94
  174. package/dist/integrations/claude_code/skills/dr_07_api_layer/SKILL.md +143 -157
  175. package/dist/integrations/claude_code/skills/dr_08_data_model_layer/SKILL.md +117 -33
  176. package/dist/integrations/claude_code/skills/dr_09_dataset_layer/SKILL.md +74 -25
  177. package/dist/integrations/claude_code/skills/dr_10_ux_layer/SKILL.md +88 -12
  178. package/dist/integrations/claude_code/skills/dr_11_navigation_layer/SKILL.md +83 -24
  179. package/dist/integrations/claude_code/skills/dr_12_apm_layer/SKILL.md +57 -12
  180. package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +92 -15
  181. package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +119 -0
  182. package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +3 -0
  183. package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +1 -1
  184. package/dist/integrations/github_copilot/agents/dr-architect.md +1 -1
  185. package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +182 -102
  186. package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +266 -148
  187. package/dist/integrations/github_copilot/skills/dr_03_product_layer/SKILL.md +547 -86
  188. package/dist/integrations/github_copilot/skills/dr_04_security_layer/SKILL.md +164 -169
  189. package/dist/integrations/github_copilot/skills/dr_05_application_layer/SKILL.md +420 -150
  190. package/dist/integrations/github_copilot/skills/dr_06_technology_layer/SKILL.md +331 -138
  191. package/dist/integrations/github_copilot/skills/dr_07_api_layer/SKILL.md +265 -201
  192. package/dist/integrations/github_copilot/skills/dr_08_data_model_layer/SKILL.md +181 -58
  193. package/dist/integrations/github_copilot/skills/dr_09_dataset_layer/SKILL.md +209 -57
  194. package/dist/integrations/github_copilot/skills/dr_10_ux_layer/SKILL.md +277 -112
  195. package/dist/integrations/github_copilot/skills/dr_11_navigation_layer/SKILL.md +219 -70
  196. package/dist/integrations/github_copilot/skills/dr_12_apm_layer/SKILL.md +189 -105
  197. package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +222 -102
  198. package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +119 -0
  199. package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +3 -0
  200. package/dist/integrations/hash-utils.js.map +2 -2
  201. package/dist/mcp/api-key-manager.js +111 -0
  202. package/dist/mcp/api-key-manager.js.map +7 -0
  203. package/dist/mcp/changeset-only.js +34 -0
  204. package/dist/mcp/changeset-only.js.map +7 -0
  205. package/dist/mcp/http-transport.js +176 -0
  206. package/dist/mcp/http-transport.js.map +7 -0
  207. package/dist/mcp/resource-registry.js +97 -0
  208. package/dist/mcp/resource-registry.js.map +7 -0
  209. package/dist/mcp/tool-registry.js +60 -0
  210. package/dist/mcp/tool-registry.js.map +7 -0
  211. package/dist/mcp/tools/annotation-create.js +39 -0
  212. package/dist/mcp/tools/annotation-create.js.map +7 -0
  213. package/dist/mcp/tools/annotation-delete.js +29 -0
  214. package/dist/mcp/tools/annotation-delete.js.map +7 -0
  215. package/dist/mcp/tools/annotation-get.js +29 -0
  216. package/dist/mcp/tools/annotation-get.js.map +7 -0
  217. package/dist/mcp/tools/annotation-list.js +24 -0
  218. package/dist/mcp/tools/annotation-list.js.map +7 -0
  219. package/dist/mcp/tools/annotation-reply.js +34 -0
  220. package/dist/mcp/tools/annotation-reply.js.map +7 -0
  221. package/dist/mcp/tools/annotation-shared.js +10 -0
  222. package/dist/mcp/tools/annotation-shared.js.map +7 -0
  223. package/dist/mcp/tools/annotation-update.js +39 -0
  224. package/dist/mcp/tools/annotation-update.js.map +7 -0
  225. package/dist/mcp/tools/changeset-analysis-tools.js +78 -0
  226. package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
  227. package/dist/mcp/tools/changeset-editing.js +184 -0
  228. package/dist/mcp/tools/changeset-editing.js.map +7 -0
  229. package/dist/mcp/tools/changeset-lifecycle.js +83 -0
  230. package/dist/mcp/tools/changeset-lifecycle.js.map +7 -0
  231. package/dist/mcp/tools/changeset-list.js +33 -0
  232. package/dist/mcp/tools/changeset-list.js.map +7 -0
  233. package/dist/mcp/tools/changeset-shared.js +31 -0
  234. package/dist/mcp/tools/changeset-shared.js.map +7 -0
  235. package/dist/mcp/tools/changeset-show.js +55 -0
  236. package/dist/mcp/tools/changeset-show.js.map +7 -0
  237. package/dist/mcp/tools/changeset-verify.js +43 -0
  238. package/dist/mcp/tools/changeset-verify.js.map +7 -0
  239. package/dist/mcp/tools/chat-launch.js +50 -0
  240. package/dist/mcp/tools/chat-launch.js.map +7 -0
  241. package/dist/mcp/tools/chat-status.js +26 -0
  242. package/dist/mcp/tools/chat-status.js.map +7 -0
  243. package/dist/mcp/tools/index.js +65 -0
  244. package/dist/mcp/tools/index.js.map +7 -0
  245. package/dist/mcp/tools/model-add.js +107 -0
  246. package/dist/mcp/tools/model-add.js.map +7 -0
  247. package/dist/mcp/tools/model-delete.js +99 -0
  248. package/dist/mcp/tools/model-delete.js.map +7 -0
  249. package/dist/mcp/tools/model-export.js +72 -0
  250. package/dist/mcp/tools/model-export.js.map +7 -0
  251. package/dist/mcp/tools/model-info.js +51 -0
  252. package/dist/mcp/tools/model-info.js.map +7 -0
  253. package/dist/mcp/tools/model-list.js +53 -0
  254. package/dist/mcp/tools/model-list.js.map +7 -0
  255. package/dist/mcp/tools/model-reload.js +34 -0
  256. package/dist/mcp/tools/model-reload.js.map +7 -0
  257. package/dist/mcp/tools/model-search.js +102 -0
  258. package/dist/mcp/tools/model-search.js.map +7 -0
  259. package/dist/mcp/tools/model-show.js +68 -0
  260. package/dist/mcp/tools/model-show.js.map +7 -0
  261. package/dist/mcp/tools/model-stats.js +22 -0
  262. package/dist/mcp/tools/model-stats.js.map +7 -0
  263. package/dist/mcp/tools/model-trace.js +118 -0
  264. package/dist/mcp/tools/model-trace.js.map +7 -0
  265. package/dist/mcp/tools/model-update.js +121 -0
  266. package/dist/mcp/tools/model-update.js.map +7 -0
  267. package/dist/mcp/tools/model-validate.js +78 -0
  268. package/dist/mcp/tools/model-validate.js.map +7 -0
  269. package/dist/mcp/tools/relationship-tools.js +98 -0
  270. package/dist/mcp/tools/relationship-tools.js.map +7 -0
  271. package/dist/mcp/tools/shared.js +126 -0
  272. package/dist/mcp/tools/shared.js.map +7 -0
  273. package/dist/mcp/tools/spec-type.js +90 -0
  274. package/dist/mcp/tools/spec-type.js.map +7 -0
  275. package/dist/reports/model-layer-report-generator.js +5 -3
  276. package/dist/reports/model-layer-report-generator.js.map +2 -2
  277. package/dist/reports/model-readme-generator.js +116 -0
  278. package/dist/reports/model-readme-generator.js.map +7 -0
  279. package/dist/reports/model-report-data.js +37 -1
  280. package/dist/reports/model-report-data.js.map +2 -2
  281. package/dist/reports/model-report-orchestrator.js +29 -6
  282. package/dist/reports/model-report-orchestrator.js.map +2 -2
  283. package/dist/reports/model-report-utils.js +9 -0
  284. package/dist/reports/model-report-utils.js.map +7 -0
  285. package/dist/schemas/bundled/analyzers/cbm.json +1186 -68
  286. package/dist/schemas/bundled/analyzers/manifest.json +2 -2
  287. package/dist/schemas/bundled/api.json +1029 -1658
  288. package/dist/schemas/bundled/apm.json +499 -734
  289. package/dist/schemas/bundled/application.json +745 -370
  290. package/dist/schemas/bundled/base.json +3 -220
  291. package/dist/schemas/bundled/business.json +452 -366
  292. package/dist/schemas/bundled/data-model.json +403 -383
  293. package/dist/schemas/bundled/data-store.json +334 -558
  294. package/dist/schemas/bundled/manifest.json +18 -18
  295. package/dist/schemas/bundled/motivation.json +349 -368
  296. package/dist/schemas/bundled/navigation.json +415 -731
  297. package/dist/schemas/bundled/product.json +325 -159
  298. package/dist/schemas/bundled/security.json +864 -1232
  299. package/dist/schemas/bundled/technology.json +574 -703
  300. package/dist/schemas/bundled/testing.json +718 -1643
  301. package/dist/schemas/bundled/ux.json +739 -1352
  302. package/dist/server/schemas.js +8 -0
  303. package/dist/server/schemas.js.map +2 -2
  304. package/dist/server/server.js +234 -31
  305. package/dist/server/server.js.map +2 -2
  306. package/dist/server-entry.js +2 -1
  307. package/dist/server-entry.js.map +2 -2
  308. package/dist/telemetry/config.js +2 -40
  309. package/dist/telemetry/config.js.map +2 -2
  310. package/dist/telemetry/index.js +1 -1
  311. package/dist/types/index.js.map +2 -2
  312. package/dist/utils/ansi-suppressor.js +23 -0
  313. package/dist/utils/ansi-suppressor.js.map +7 -0
  314. package/dist/utils/attribute-patch.js +41 -0
  315. package/dist/utils/attribute-patch.js.map +7 -0
  316. package/dist/utils/color-utils.js +34 -0
  317. package/dist/utils/color-utils.js.map +7 -0
  318. package/dist/utils/element-reference-shape.js +15 -1
  319. package/dist/utils/element-reference-shape.js.map +3 -3
  320. package/dist/utils/error-hints.js +29 -0
  321. package/dist/utils/error-hints.js.map +7 -0
  322. package/dist/utils/errors.js +75 -10
  323. package/dist/utils/errors.js.map +2 -2
  324. package/dist/utils/globals.js +17 -1
  325. package/dist/utils/globals.js.map +2 -2
  326. package/dist/utils/project-paths.js +50 -3
  327. package/dist/utils/project-paths.js.map +2 -2
  328. package/dist/utils/reference-path-parser.js +49 -0
  329. package/dist/utils/reference-path-parser.js.map +7 -0
  330. package/dist/utils/source-reference.js +17 -10
  331. package/dist/utils/source-reference.js.map +2 -2
  332. package/dist/utils/spec-version.js +10 -2
  333. package/dist/utils/spec-version.js.map +2 -2
  334. package/dist/validators/composed-reference-validator.js +240 -0
  335. package/dist/validators/composed-reference-validator.js.map +7 -0
  336. package/dist/validators/reference-validator.js +57 -13
  337. package/dist/validators/reference-validator.js.map +3 -3
  338. package/dist/validators/relationship-schema-validator.js +33 -5
  339. package/dist/validators/relationship-schema-validator.js.map +3 -3
  340. package/dist/validators/schema-validator.js +27 -9
  341. package/dist/validators/schema-validator.js.map +2 -2
  342. package/dist/validators/types.js.map +1 -1
  343. package/dist/viewer/README.md +6 -6
  344. package/dist/viewer/assets/main-CxzcuU_o.js +84 -0
  345. package/dist/viewer/assets/main-j-7ULYpm.css +1 -0
  346. package/dist/viewer/index.html +2 -2
  347. package/dist/viewer/manifest.json +10 -10
  348. package/dist/viewer/version.json +1 -1
  349. package/package.json +7 -3
  350. package/dist/viewer/assets/main-B7AOQXXX.js +0 -81
  351. package/dist/viewer/assets/main-vdrFrG7q.css +0 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/commands/relationship.ts"],
4
- "sourcesContent": ["/**\n * Relationship subcommands for managing intra-layer and cross-layer relationships\n */\n\nimport { Command } from \"commander\";\nimport ansis from \"ansis\";\nimport { Model } from \"../core/model.js\";\nimport { StagingAreaManager } from \"../core/staging-area.js\";\nimport { findElementLayer } from \"../utils/element-utils.js\";\nimport { isValidLayerName } from \"../core/layers.js\";\nimport { CLIError, ErrorCategory, handleError, getErrorMessage } from \"../utils/errors.js\";\nimport {\n getValidRelationships,\n getValidPredicatesForSource,\n getValidDestinationsForSourceAndPredicate,\n} from \"../generated/relationship-index.js\";\nimport { normalizeNodeType } from \"../generated/node-types.js\";\nimport { ModelReportOrchestrator } from \"../reports/model-report-orchestrator.js\";\nimport { emitLog, SeverityNumber } from \"../telemetry/index.js\";\nimport { Element } from \"../core/element.js\";\nimport { Relationship } from \"../core/relationships.js\";\nimport { RelationshipCatalog } from \"../core/relationship-catalog.js\";\n\n/**\n * Pre-resolved element and layer information to avoid redundant lookups.\n * Ensures source and target pairs are consistent: if source is provided, both element and layerName must be present.\n * This prevents invalid states like {sourceElement: ..., sourceLayerName: undefined}.\n */\ninterface PreResolvedElements {\n source?: {\n element: Element;\n layerName: string;\n };\n target?: {\n element: Element;\n layerName: string;\n };\n}\n\n/**\n * Validate element properties and construct a SpecNodeId\n * @throws {CLIError} if element properties are invalid\n */\nfunction constructSpecNodeId(\n element: { layer_id?: unknown; type?: unknown },\n elementId: string\n): string {\n const layerId = element.layer_id;\n const type = element.type;\n\n if (typeof layerId !== \"string\" || !layerId) {\n throw new CLIError(\n `Invalid element ${elementId}: missing or invalid layer_id`,\n ErrorCategory.SYSTEM\n );\n }\n\n if (typeof type !== \"string\" || !type) {\n throw new CLIError(\n `Invalid element ${elementId}: missing or invalid type`,\n ErrorCategory.SYSTEM\n );\n }\n\n // Normalize type name for schema validation (e.g., \"process\" -> \"businessprocess\")\n const normalizedType = normalizeNodeType(layerId, type);\n\n return `${layerId}.${normalizedType}`;\n}\n\n/**\n * Validate a relationship combination using schema-driven registry\n * @returns {valid, suggestions} where suggestions are provided if invalid\n */\nexport function validateRelationshipCombination(\n sourceSpecNodeId: string,\n predicate: string,\n destSpecNodeId: string\n): { valid: boolean; suggestions?: string[] } {\n const valid =\n getValidRelationships(sourceSpecNodeId, predicate, destSpecNodeId)\n .length > 0;\n\n if (valid) {\n return { valid: true };\n }\n\n // Generate helpful suggestions\n const suggestions: string[] = [];\n const validPredicates = getValidPredicatesForSource(sourceSpecNodeId);\n\n if (validPredicates.length > 0) {\n suggestions.push(\n `Valid predicates for ${sourceSpecNodeId}: ${validPredicates.join(\", \")}`\n );\n } else {\n suggestions.push(`No valid relationships defined for ${sourceSpecNodeId}`);\n }\n\n // If predicate is provided, show valid destinations\n if (predicate) {\n const validDests = getValidDestinationsForSourceAndPredicate(\n sourceSpecNodeId,\n predicate\n );\n if (validDests.length > 0) {\n suggestions.push(\n `Valid destinations for --[${predicate}]-->: ${validDests.join(\", \")}`\n );\n } else {\n suggestions.push(\n `No valid destinations for ${sourceSpecNodeId} --[${predicate}]-->`\n );\n }\n }\n\n return { valid: false, suggestions };\n}\n\n/**\n * Get cardinality and strength info for a relationship\n */\nexport function getRelationshipConstraints(\n sourceSpecNodeId: string,\n predicate: string,\n destSpecNodeId: string\n): { cardinality: string; strength: string } | null {\n const rels = getValidRelationships(\n sourceSpecNodeId,\n predicate,\n destSpecNodeId\n );\n if (rels.length === 0) return null;\n\n const rel = rels[0];\n return {\n cardinality: rel.cardinality,\n strength: rel.strength,\n };\n}\n\n/**\n * Handler function for adding a relationship\n * Encapsulates the core logic of the add-relationship command\n * @internal Exported for testing purposes\n *\n * @param model - The architecture model\n * @param source - Source element ID\n * @param target - Target element ID\n * @param predicate - Relationship predicate\n * @param properties - Optional relationship properties\n * @param preResolved - Pre-resolved elements and layer names (optional, for performance)\n */\nexport async function addRelationshipHandler(\n model: Model,\n source: string,\n target: string,\n predicate: string,\n properties?: Record<string, unknown>,\n preResolved?: PreResolvedElements\n): Promise<boolean> {\n // Use pre-resolved elements if provided, otherwise resolve them\n let resolvedSourceLayerName = preResolved?.source?.layerName;\n let resolvedSourceElement = preResolved?.source?.element;\n let resolvedTargetLayerName = preResolved?.target?.layerName;\n let resolvedTargetElement = preResolved?.target?.element;\n\n if (!resolvedSourceLayerName) {\n resolvedSourceLayerName = await findElementLayer(model, source);\n if (!resolvedSourceLayerName) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n }\n\n if (!resolvedSourceElement) {\n const sourceLayer = await model.getLayer(resolvedSourceLayerName);\n if (!sourceLayer) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n resolvedSourceElement = sourceLayer.getElement(source);\n if (!resolvedSourceElement) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n }\n\n if (!resolvedTargetLayerName) {\n resolvedTargetLayerName = await findElementLayer(model, target);\n if (!resolvedTargetLayerName) {\n throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);\n }\n }\n\n if (!resolvedTargetElement) {\n const targetLayer = await model.getLayer(resolvedTargetLayerName);\n if (!targetLayer) {\n throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);\n }\n resolvedTargetElement = targetLayer.getElement(target);\n if (!resolvedTargetElement) {\n throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);\n }\n }\n\n // Schema-driven validation\n const sourceSpecNodeId = constructSpecNodeId(resolvedSourceElement, source);\n const targetSpecNodeId = constructSpecNodeId(resolvedTargetElement, target);\n\n const validation = validateRelationshipCombination(\n sourceSpecNodeId,\n predicate,\n targetSpecNodeId\n );\n\n if (!validation.valid) {\n throw new CLIError(\n `Invalid relationship: ${source} --[${predicate}]--> ${target}`,\n ErrorCategory.USER,\n validation.suggestions\n );\n }\n\n {\n const catalog = new RelationshipCatalog();\n await catalog.load();\n const relType = catalog.getTypeByPredicate(predicate);\n if (relType && !relType.semantics.reflexivity && source === target) {\n throw new CLIError(\n `Invalid relationship: predicate \"${predicate}\" does not allow reflexive relationships (${source})`,\n ErrorCategory.USER\n );\n }\n }\n\n // Guard against duplicate relationships before staging or writing\n if (model.relationships.find(source, target, predicate).length > 0) {\n console.warn(\n ansis.yellow(`Warning: Relationship ${source} --[${predicate}]--> ${target} already exists. Skipping.`)\n );\n return false;\n }\n\n // Check for active changeset \u2014 stage relationship instead of writing directly\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n const relData = {\n source,\n target,\n predicate,\n layer: resolvedSourceLayerName,\n ...(resolvedTargetLayerName !== resolvedSourceLayerName ? { targetLayer: resolvedTargetLayerName } : {}),\n category: \"structural\" as const,\n ...(properties ? { properties } : {}),\n };\n\n if (activeChangesetId) {\n // Stage the relationship change in the active changeset\n const compositeKey = `${source}::${predicate}::${target}`;\n await stagingManager.stage(activeChangesetId, {\n type: \"relationship-add\",\n elementId: compositeKey,\n layerName: resolvedSourceLayerName,\n after: relData,\n });\n } else {\n // No active changeset \u2014 write directly to relationships.yaml\n model.relationships.add(relData);\n await model.saveRelationships();\n await model.saveManifest();\n\n // Regenerate reports for all affected layers (including transitively related)\n try {\n const orchestrator = new ModelReportOrchestrator(model, model.rootPath);\n const affectedLayers = new Set<string>();\n\n // Compute affected layers for source layer\n if (isValidLayerName(resolvedSourceLayerName)) {\n for (const layer of orchestrator.computeAffectedLayers(resolvedSourceLayerName)) {\n affectedLayers.add(layer);\n }\n }\n\n // Compute affected layers for target layer\n if (isValidLayerName(resolvedTargetLayerName)) {\n for (const layer of orchestrator.computeAffectedLayers(resolvedTargetLayerName)) {\n affectedLayers.add(layer);\n }\n }\n\n await orchestrator.regenerate(affectedLayers);\n } catch (error) {\n emitLog(\n SeverityNumber.WARN,\n \"Failed to regenerate layer reports after relationship add\",\n {\n \"relationship.predicate\": predicate,\n \"relationship.sourceLayer\": resolvedSourceLayerName,\n \"relationship.targetLayer\": resolvedTargetLayerName,\n \"relationship.source\": source,\n \"relationship.target\": target,\n \"error.message\": getErrorMessage(error),\n }\n );\n }\n }\n\n return true;\n}\n\n/**\n * Handler function for deleting relationships\n * Encapsulates the core logic of the delete-relationship command\n * @internal Exported for testing purposes\n *\n * @param model - The architecture model\n * @param source - Source element ID\n * @param target - Target element ID\n * @param predicate - Optional relationship predicate\n * @param preResolved - Pre-resolved source layer name and relationships (optional, for performance)\n */\ninterface DeletePreResolved {\n sourceLayerName?: string;\n toDelete?: Relationship[];\n}\n\nexport async function deleteRelationshipHandler(\n model: Model,\n source: string,\n target: string,\n predicate?: string,\n preResolved?: DeletePreResolved\n): Promise<{ deletedCount: number }> {\n // Use pre-resolved source layer if provided, otherwise resolve it\n let resolvedSourceLayerName = preResolved?.sourceLayerName;\n if (!resolvedSourceLayerName) {\n resolvedSourceLayerName = await findElementLayer(model, source);\n if (!resolvedSourceLayerName) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n }\n\n // Use pre-found relationships if provided, otherwise find them\n let resolvedToDelete = preResolved?.toDelete;\n if (!resolvedToDelete) {\n resolvedToDelete = model.relationships.find(source, target, predicate);\n }\n\n if (resolvedToDelete.length === 0) {\n throw new CLIError(\"No matching relationships found\", ErrorCategory.USER);\n }\n\n // Check for active changeset \u2014 stage deletion instead of writing directly\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n if (activeChangesetId) {\n // Stage each relationship deletion in the active changeset\n for (const rel of resolvedToDelete) {\n const compositeKey = `${rel.source}::${rel.predicate}::${rel.target}`;\n await stagingManager.stage(activeChangesetId, {\n type: \"relationship-delete\",\n elementId: compositeKey,\n layerName: rel.layer,\n before: {\n source: rel.source,\n target: rel.target,\n predicate: rel.predicate,\n layer: rel.layer,\n ...(rel.targetLayer ? { targetLayer: rel.targetLayer } : {}),\n ...(rel.properties ? { properties: rel.properties } : {}),\n },\n });\n }\n } else {\n // No active changeset \u2014 write directly\n model.relationships.delete(source, target, predicate);\n await model.saveRelationships();\n await model.saveManifest();\n\n // Regenerate reports for all affected layers (including transitively related)\n try {\n const orchestrator = new ModelReportOrchestrator(model, model.rootPath);\n const affectedLayers = new Set<string>();\n\n // Compute affected layers for each deleted relationship's source and target\n for (const rel of resolvedToDelete) {\n // Compute affected layers for source layer\n if (rel.layer && isValidLayerName(rel.layer)) {\n for (const layer of orchestrator.computeAffectedLayers(rel.layer)) {\n affectedLayers.add(layer);\n }\n }\n\n // Compute affected layers for target layer\n if (rel.targetLayer && isValidLayerName(rel.targetLayer)) {\n for (const layer of orchestrator.computeAffectedLayers(rel.targetLayer)) {\n affectedLayers.add(layer);\n }\n }\n }\n\n await orchestrator.regenerate(affectedLayers);\n } catch (error) {\n emitLog(\n SeverityNumber.WARN,\n \"Failed to regenerate layer reports after relationship delete\",\n {\n \"relationship.predicate\": predicate,\n \"relationship.source\": source,\n \"relationship.target\": target,\n \"relationship.deleteCount\": resolvedToDelete.length,\n \"error.message\": getErrorMessage(error),\n }\n );\n }\n }\n\n return { deletedCount: resolvedToDelete.length };\n}\n\nexport function relationshipCommands(program: Command): void {\n program\n .command(\"add <source> <target>\")\n .description(\"Add a relationship between elements (intra-layer or cross-layer)\")\n .requiredOption(\n \"--predicate <predicate>\",\n \"Relationship predicate (e.g., depends-on, realizes, exposes)\"\n )\n .option(\"--properties <json>\", \"Relationship properties (JSON)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship add motivation.goal.goal-a motivation.goal.goal-b --predicate aggregates\n $ dr relationship add api.operation.create-order application.service.order-service --predicate exposes\n $ dr relationship add business.businessprocess.checkout application.applicationprocess.checkout --predicate aggregates\n $ dr relationship add element-1 element-2 --predicate realizes --properties '{\"strength\":\"high\"}'`\n )\n .action(async (source, target, options) => {\n try {\n // Load model\n const model = await Model.load();\n\n // Find source element for constraints info\n const sourceLayerName = await findElementLayer(model, source);\n if (!sourceLayerName) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n const sourceLayer = await model.getLayer(sourceLayerName);\n if (!sourceLayer) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n const sourceElement = sourceLayer.getElement(source);\n if (!sourceElement) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n\n // Find target element for constraints info\n const targetLayerName = await findElementLayer(model, target);\n if (!targetLayerName) {\n throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);\n }\n const targetLayer = await model.getLayer(targetLayerName);\n if (!targetLayer) {\n throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);\n }\n const targetElement = targetLayer.getElement(target);\n if (!targetElement) {\n throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);\n }\n\n // Get cardinality and strength info (before calling handler for CLI output)\n const sourceSpecNodeId = constructSpecNodeId(sourceElement, source);\n const targetSpecNodeId = constructSpecNodeId(targetElement, target);\n const constraints = getRelationshipConstraints(\n sourceSpecNodeId,\n options.predicate,\n targetSpecNodeId\n );\n\n // Parse properties if provided\n let properties: Record<string, unknown> | undefined;\n if (options.properties) {\n try {\n properties = JSON.parse(options.properties);\n } catch (e) {\n throw new CLIError(\"Invalid JSON in --properties\", ErrorCategory.USER);\n }\n }\n\n // Check for active changeset\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n // Call the handler function with pre-resolved elements to avoid duplicate lookups\n const added = await addRelationshipHandler(\n model,\n source,\n target,\n options.predicate,\n properties,\n {\n source: { element: sourceElement, layerName: sourceLayerName },\n target: { element: targetElement, layerName: targetLayerName },\n }\n );\n\n if (!added) return; // duplicate \u2014 warning already printed\n\n // Show cardinality and strength in output\n let message = `\u2713 Added relationship: ${ansis.bold(source)} ${options.predicate} ${ansis.bold(target)}`;\n if (constraints) {\n message += ansis.dim(\n ` (${constraints.cardinality}, ${constraints.strength} strength)`\n );\n }\n if (activeChangesetId) {\n message += ansis.dim(` [staged]`);\n }\n\n console.log(ansis.green(message));\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"delete <source> <target>\")\n .description(\"Delete a relationship\")\n .option(\n \"--predicate <predicate>\",\n \"Specific predicate to delete (optional, delete all if not specified)\"\n )\n .option(\"--force\", \"Skip confirmation prompt\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship delete element-1 element-2 --predicate depends-on\n $ dr relationship delete element-1 element-2 --force`\n )\n .action(async (source, target, options) => {\n try {\n // Load model\n const model = await Model.load();\n\n // Find source element and relationships to delete (for confirmation)\n const sourceLayerName = await findElementLayer(model, source);\n if (!sourceLayerName) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n\n // Find relationships to delete (to show confirmation count)\n const toDelete = model.relationships.find(source, target, options.predicate);\n\n if (toDelete.length === 0) {\n throw new CLIError(\"No matching relationships found\", ErrorCategory.USER);\n }\n\n // Confirm deletion unless --force or non-interactive environment\n // In non-interactive environments (CI, tests), skip confirmation\n const isInteractive = process.stdin.isTTY && process.stdout.isTTY;\n if (!options.force && isInteractive) {\n // Dynamic import of prompts is safe here: caught by outer try-catch\n // This allows lazy loading of the prompt library only when needed\n const { confirm } = await import(\"@clack/prompts\");\n const confirmed = await confirm({\n message: `Delete ${toDelete.length} relationship(s)? This cannot be undone.`,\n initialValue: false,\n });\n\n if (!confirmed) {\n console.log(ansis.dim(\"Cancelled\"));\n return;\n }\n }\n\n // Check for active changeset\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n // Call the handler function with pre-resolved values to avoid duplicate lookups\n const result = await deleteRelationshipHandler(\n model,\n source,\n target,\n options.predicate,\n {\n sourceLayerName,\n toDelete,\n }\n );\n\n const stagedSuffix = activeChangesetId ? \" [staged]\" : \"\";\n console.log(\n ansis.green(\n `\u2713 Deleted ${result.deletedCount} relationship(s) from ${ansis.bold(source)} to ${ansis.bold(target)}${stagedSuffix}`\n )\n );\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"list <id>\")\n .description(\"List relationships for an element\")\n .option(\"--direction <dir>\", \"Filter by direction (incoming/outgoing/all)\", \"all\")\n .option(\"--json\", \"Output as JSON\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship list api-endpoint-create-customer\n $ dr relationship list business-service-order --direction outgoing\n $ dr relationship list element-1 --json`\n )\n .action(async (id, options) => {\n try {\n // Load model\n const model = await Model.load();\n const layerName = await findElementLayer(model, id);\n\n if (!layerName) {\n throw new CLIError(`Element ${id} not found`, ErrorCategory.USER);\n }\n\n // Get relationships from centralized store\n const { outgoing, incoming } = model.relationships.getForElement(id);\n\n // Filter by direction\n let relationships: typeof outgoing = [];\n if (options.direction === \"outgoing\" || options.direction === \"all\") {\n relationships.push(...outgoing);\n }\n if (options.direction === \"incoming\" || options.direction === \"all\") {\n relationships.push(...incoming);\n }\n\n if (options.json) {\n console.log(JSON.stringify(relationships, null, 2));\n return;\n }\n\n if (relationships.length === 0) {\n console.log(ansis.yellow(`No ${options.direction} relationships for ${id}`));\n return;\n }\n\n console.log(\"\");\n console.log(\n ansis.bold(\n `${options.direction === \"all\" ? \"\" : options.direction + \" \"}relationships for ${ansis.cyan(id)}:`\n )\n );\n console.log(ansis.dim(\"\u2500\".repeat(80)));\n\n for (const rel of relationships) {\n const isOutgoing = rel.source === id;\n const direction = isOutgoing ? \"\u2192\" : \"\u2190\";\n const otherElement = isOutgoing ? rel.target : rel.source;\n const crossLayer = rel.targetLayer && rel.targetLayer !== rel.layer\n ? ansis.dim(` [${rel.layer} \u2192 ${rel.targetLayer}]`)\n : \"\";\n\n console.log(\n ` ${direction} ${ansis.magenta(rel.predicate)}: ${ansis.yellow(otherElement)}${crossLayer}`\n );\n\n if (rel.properties) {\n const propStr = Object.entries(rel.properties)\n .map(([k, v]) => `${k}=${v}`)\n .join(\", \");\n console.log(` ${ansis.dim(propStr)}`);\n }\n }\n\n console.log(ansis.dim(\"\u2500\".repeat(80)));\n console.log(ansis.dim(`Total: ${relationships.length} relationship(s)`));\n console.log(\"\");\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"show <source> <target>\")\n .description(\"Show relationship details\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship show api-endpoint-create-customer business-service-customer-mgmt\n $ dr relationship show application-component-api motivation-goal-sales-efficiency`\n )\n .action(async (source, target) => {\n try {\n // Load model\n const model = await Model.load();\n const sourceLayerName = await findElementLayer(model, source);\n\n if (!sourceLayerName) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n\n // Find relationships from centralized store\n const relationships = model.relationships.find(source, target);\n\n if (relationships.length === 0) {\n throw new CLIError(`No relationships from ${source} to ${target}`, ErrorCategory.USER);\n }\n\n console.log(\"\");\n console.log(\n ansis.bold(\n `Relationship${relationships.length > 1 ? \"s\" : \"\"} from ${ansis.cyan(source)} to ${ansis.yellow(target)}:`\n )\n );\n console.log(ansis.dim(\"\u2500\".repeat(60)));\n\n for (let i = 0; i < relationships.length; i++) {\n const rel = relationships[i];\n\n if (i > 0) {\n console.log(\"\");\n }\n\n console.log(`Predicate: ${ansis.magenta(rel.predicate)}`);\n console.log(`Layer: ${ansis.cyan(rel.layer)}`);\n if (rel.targetLayer && rel.targetLayer !== rel.layer) {\n console.log(`Target Layer: ${ansis.cyan(rel.targetLayer)}`);\n }\n\n if (rel.properties && Object.keys(rel.properties).length > 0) {\n console.log(\"Properties:\");\n for (const [key, value] of Object.entries(rel.properties)) {\n const displayValue =\n typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n console.log(` ${ansis.cyan(key)}: ${displayValue}`);\n }\n } else {\n console.log(\"Properties: none\");\n }\n }\n\n console.log(\"\");\n } catch (error) {\n handleError(error);\n }\n });\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Relationship subcommands for managing intra-layer and cross-layer relationships\n */\n\nimport { Command } from \"commander\";\nimport ansis from \"ansis\";\nimport { Model } from \"../core/model.js\";\nimport { StagingAreaManager } from \"../core/staging-area.js\";\nimport { findElementLayer } from \"../utils/element-utils.js\";\nimport { isValidLayerName } from \"../core/layers.js\";\nimport {\n CLIError,\n ErrorCategory,\n handleError,\n handleSuccess,\n handleInfo,\n getErrorMessage\n} from \"../utils/errors.js\";\nimport {\n getValidRelationships,\n getValidPredicatesForSource,\n getValidDestinationsForSourceAndPredicate\n} from \"../generated/relationship-index.js\";\nimport { normalizeNodeType } from \"../generated/node-types.js\";\nimport { ModelReportOrchestrator } from \"../reports/model-report-orchestrator.js\";\nimport { emitLog, SeverityNumber } from \"../telemetry/index.js\";\nimport { Element } from \"../core/element.js\";\nimport { Relationship, elementIdentifiers } from \"../core/relationships.js\";\nimport { RelationshipCatalog } from \"../core/relationship-catalog.js\";\nimport {\n collectKnownIdentifiers,\n findDanglingRelationships,\n type UnresolvedSide,\n} from \"../core/relationship-prune.js\";\nimport { isJson } from \"../utils/globals.js\";\nimport type { HintSurface } from \"../utils/error-hints.js\";\nimport { ChangesetGraph } from \"../core/changeset-graph.js\";\nimport type { Changeset } from \"../core/changeset.js\";\nimport {\n liveRelationshipsBetween,\n planRelationshipAdd,\n stageRelationshipDeletes,\n type StagedRelationshipDeleteResult,\n} from \"../core/relationship-staging.js\";\n\n/**\n * Pre-resolved element and layer information to avoid redundant lookups.\n * Ensures source and target pairs are consistent: if source is provided, both element and layerName must be present.\n * This prevents invalid states like {sourceElement: ..., sourceLayerName: undefined}.\n */\nexport interface PreResolvedElements {\n source?: {\n element: Element;\n layerName: string;\n };\n target?: {\n element: Element;\n layerName: string;\n };\n}\n\n/**\n * Validate element properties and construct a SpecNodeId\n * @throws {CLIError} if element properties are invalid\n */\nfunction constructSpecNodeId(\n element: { layer_id?: unknown; type?: unknown },\n elementId: string\n): string {\n const layerId = element.layer_id;\n const type = element.type;\n\n if (typeof layerId !== \"string\" || !layerId) {\n throw new CLIError(\n `Invalid element ${elementId}: missing or invalid layer_id`,\n ErrorCategory.SYSTEM\n );\n }\n\n if (typeof type !== \"string\" || !type) {\n throw new CLIError(\n `Invalid element ${elementId}: missing or invalid type`,\n ErrorCategory.SYSTEM\n );\n }\n\n // Normalize type name for schema validation (e.g., \"process\" -> \"businessprocess\")\n const normalizedType = normalizeNodeType(layerId, type);\n\n return `${layerId}.${normalizedType}`;\n}\n\n/**\n * Validate a relationship combination using schema-driven registry\n * @returns {valid, suggestions} where suggestions are provided if invalid\n */\nexport function validateRelationshipCombination(\n sourceSpecNodeId: string,\n predicate: string,\n destSpecNodeId: string\n): { valid: boolean; suggestions?: string[] } {\n const valid =\n getValidRelationships(sourceSpecNodeId, predicate, destSpecNodeId).length >\n 0;\n\n if (valid) {\n return { valid: true };\n }\n\n // Generate helpful suggestions\n const suggestions: string[] = [];\n const validPredicates = getValidPredicatesForSource(sourceSpecNodeId);\n\n if (validPredicates.length > 0) {\n suggestions.push(\n `Valid predicates for ${sourceSpecNodeId}: ${validPredicates.join(\", \")}`\n );\n } else {\n suggestions.push(`No valid relationships defined for ${sourceSpecNodeId}`);\n }\n\n // If predicate is provided, show valid destinations\n if (predicate) {\n const validDests = getValidDestinationsForSourceAndPredicate(\n sourceSpecNodeId,\n predicate\n );\n if (validDests.length > 0) {\n suggestions.push(\n `Valid destinations for --[${predicate}]-->: ${validDests.join(\", \")}`\n );\n } else {\n suggestions.push(\n `No valid destinations for ${sourceSpecNodeId} --[${predicate}]-->`\n );\n }\n }\n\n return { valid: false, suggestions };\n}\n\n/**\n * Get cardinality and strength info for a relationship\n */\nexport function getRelationshipConstraints(\n sourceSpecNodeId: string,\n predicate: string,\n destSpecNodeId: string\n): { cardinality: string; strength: string } | null {\n const rels = getValidRelationships(\n sourceSpecNodeId,\n predicate,\n destSpecNodeId\n );\n if (rels.length === 0) return null;\n\n const rel = rels[0];\n return {\n cardinality: rel.cardinality,\n strength: rel.strength\n };\n}\n\n/**\n * Handler function for adding a relationship\n * Encapsulates the core logic of the add-relationship command\n * @internal Exported for testing purposes\n *\n * @param model - The architecture model\n * @param source - Source element ID\n * @param target - Target element ID\n * @param predicate - Relationship predicate\n * @param properties - Optional relationship properties\n * @param preResolved - Pre-resolved elements and layer names (optional, for performance)\n */\nexport async function addRelationshipHandler(\n model: Model,\n source: string,\n target: string,\n predicate: string,\n properties?: Record<string, unknown>,\n preResolved?: PreResolvedElements\n): Promise<boolean> {\n const outcome = await addRelationship(model, source, target, predicate, properties, preResolved);\n return outcome !== \"duplicate\";\n}\n\n/**\n * What adding a relationship did:\n * - \"added\": written to relationships.yaml (no active changeset)\n * - \"staged\": staged in the active changeset\n * - \"restored\": the active changeset had staged its deletion; that deletion was unstaged\n * - \"duplicate\": already present (in the base model, or in the active changeset's projection); nothing written\n */\nexport type AddRelationshipOutcome = \"added\" | \"staged\" | \"restored\" | \"duplicate\";\n\n/** The active changeset when one is set and can accept changes, else null. */\nasync function activeStagedChangeset(manager: StagingAreaManager): Promise<Changeset | null> {\n const active = await manager.getActive();\n return active && active.status === \"staged\" ? active : null;\n}\n\n/**\n * Adds a relationship, validated against the catalog. Inside an active changeset the duplicate\n * check reads the changeset's projected graph (base plus staged relationships), so adding the same\n * relationship twice stages it once, and re-adding one the changeset deletes unstages the delete.\n */\nexport async function addRelationship(\n model: Model,\n source: string,\n target: string,\n predicate: string,\n properties?: Record<string, unknown>,\n preResolved?: PreResolvedElements\n): Promise<AddRelationshipOutcome> {\n // Use pre-resolved elements if provided, otherwise resolve them\n let resolvedSourceLayerName = preResolved?.source?.layerName;\n let resolvedSourceElement = preResolved?.source?.element;\n let resolvedTargetLayerName = preResolved?.target?.layerName;\n let resolvedTargetElement = preResolved?.target?.element;\n\n if (!resolvedSourceLayerName) {\n resolvedSourceLayerName = await findElementLayer(model, source);\n if (!resolvedSourceLayerName) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n if (!resolvedSourceElement) {\n const sourceLayer = await model.getLayer(resolvedSourceLayerName);\n if (!sourceLayer) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n resolvedSourceElement = sourceLayer.getElement(source);\n if (!resolvedSourceElement) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n if (!resolvedTargetLayerName) {\n resolvedTargetLayerName = await findElementLayer(model, target);\n if (!resolvedTargetLayerName) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n if (!resolvedTargetElement) {\n const targetLayer = await model.getLayer(resolvedTargetLayerName);\n if (!targetLayer) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n resolvedTargetElement = targetLayer.getElement(target);\n if (!resolvedTargetElement) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n // Schema-driven validation\n const sourceSpecNodeId = constructSpecNodeId(resolvedSourceElement, source);\n const targetSpecNodeId = constructSpecNodeId(resolvedTargetElement, target);\n\n const validation = validateRelationshipCombination(\n sourceSpecNodeId,\n predicate,\n targetSpecNodeId\n );\n\n if (!validation.valid) {\n throw new CLIError(\n `Invalid relationship: ${source} --[${predicate}]--> ${target}`,\n ErrorCategory.USER,\n validation.suggestions\n );\n }\n\n {\n const catalog = new RelationshipCatalog();\n await catalog.load();\n const relType = catalog.getTypeByPredicate(predicate);\n if (relType && !relType.semantics.reflexivity && source === target) {\n throw new CLIError(\n `Invalid relationship: predicate \"${predicate}\" does not allow reflexive relationships (${source})`,\n ErrorCategory.USER\n );\n }\n }\n\n // Check for active changeset \u2014 stage relationship instead of writing directly\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n const activeChangeset = activeChangesetId ? await activeStagedChangeset(stagingManager) : null;\n\n // Guard against duplicate relationships before staging or writing. Inside a changeset the\n // projected graph is the reference: it holds what this changeset already staged, and drops\n // what it deletes.\n if (activeChangeset) {\n const graph = await ChangesetGraph.build(model, activeChangeset);\n const plan = planRelationshipAdd(graph, activeChangeset, { source, predicate, target });\n if (plan.action === \"duplicate\") {\n return \"duplicate\";\n }\n if (plan.action === \"restore\") {\n for (const key of plan.keys) {\n await stagingManager.unstage(activeChangeset.id!, key);\n }\n return \"restored\";\n }\n } else if (model.relationships.find(source, target, predicate).length > 0) {\n return \"duplicate\";\n }\n\n const relData = {\n source,\n target,\n predicate,\n layer: resolvedSourceLayerName,\n ...(resolvedTargetLayerName !== resolvedSourceLayerName\n ? { targetLayer: resolvedTargetLayerName }\n : {}),\n category: \"structural\" as const,\n ...(properties ? { properties } : {})\n };\n\n if (activeChangesetId) {\n // Stage the relationship change in the active changeset\n const compositeKey = `${source}::${predicate}::${target}`;\n await stagingManager.stage(activeChangesetId, {\n type: \"relationship-add\",\n elementId: compositeKey,\n layerName: resolvedSourceLayerName,\n after: relData\n });\n } else {\n // No active changeset \u2014 write directly to relationships.yaml\n model.relationships.add(relData);\n await model.saveRelationships();\n await model.saveManifest();\n\n // Regenerate reports for all affected layers (including transitively related)\n try {\n const orchestrator = new ModelReportOrchestrator(model, model.rootPath);\n const affectedLayers = new Set<string>();\n\n // Compute affected layers for source layer\n if (isValidLayerName(resolvedSourceLayerName)) {\n for (const layer of orchestrator.computeAffectedLayers(\n resolvedSourceLayerName\n )) {\n affectedLayers.add(layer);\n }\n }\n\n // Compute affected layers for target layer\n if (isValidLayerName(resolvedTargetLayerName)) {\n for (const layer of orchestrator.computeAffectedLayers(\n resolvedTargetLayerName\n )) {\n affectedLayers.add(layer);\n }\n }\n\n await orchestrator.regenerate(affectedLayers);\n } catch (error) {\n emitLog(\n SeverityNumber.WARN,\n \"Failed to regenerate layer reports after relationship add\",\n {\n \"relationship.predicate\": predicate,\n \"relationship.sourceLayer\": resolvedSourceLayerName,\n \"relationship.targetLayer\": resolvedTargetLayerName,\n \"relationship.source\": source,\n \"relationship.target\": target,\n \"error.message\": getErrorMessage(error)\n }\n );\n }\n }\n\n return activeChangesetId ? \"staged\" : \"added\";\n}\n\n/**\n * Find relationships between two endpoints as they are recorded in relationships.yaml.\n *\n * Rows may name an element by UUID `id` or by dotted `path`, and the user may type\n * either form. Each endpoint matches a row when the row's value is the typed\n * identifier or any identifier of the element it resolves to. An endpoint that no\n * longer resolves to an element still matches rows that store the typed value.\n */\nexport async function findRelationshipsByEndpoints(\n model: Model,\n source: string,\n target: string,\n predicate?: string\n): Promise<Relationship[]> {\n const sourceIds = new Set(elementIdentifiers(model.getElementById(source) ?? {}, source));\n const targetIds = new Set(elementIdentifiers(model.getElementById(target) ?? {}, target));\n return model.relationships\n .getAll()\n .filter(\n (rel) =>\n sourceIds.has(rel.source) &&\n targetIds.has(rel.target) &&\n (!predicate || rel.predicate === predicate)\n );\n}\n\n/** Next steps when a relationship delete matches nothing, named for the caller's surface. */\nfunction noMatchingRelationshipHints(surface: HintSurface, source: string, inChangeset: boolean): string[] {\n if (surface === \"mcp\") {\n return [\n `Use \"model_show\" on ${source} to see its relationships`,\n inChangeset\n ? 'Use \"changeset_brief\" to see what this changeset already stages'\n : 'Use \"model_search\" to check the source and target element IDs',\n ];\n }\n return [\n `Use \"dr relationship list ${source}\" to see the relationships recorded for ${source}`,\n inChangeset\n ? 'Use \"dr changeset staged\" to see what the active changeset already stages'\n : 'Use \"dr relationship prune --dry-run\" to list rows whose endpoints no longer resolve',\n ];\n}\n\n/**\n * Handler function for deleting relationships\n * Encapsulates the core logic of the delete-relationship command\n * @internal Exported for testing purposes\n *\n * @param model - The architecture model\n * @param source - Source element ID\n * @param target - Target element ID\n * @param predicate - Optional relationship predicate\n * @param preResolved - Pre-resolved source layer name and relationships (optional, for performance)\n */\ninterface DeletePreResolved {\n sourceLayerName?: string;\n toDelete?: Relationship[];\n}\n\nexport async function deleteRelationshipHandler(\n model: Model,\n source: string,\n target: string,\n predicate?: string,\n preResolved?: DeletePreResolved,\n surface: HintSurface = \"cli\"\n): Promise<{ deletedCount: number; staged?: StagedRelationshipDeleteResult[] }> {\n // Inside a changeset, match against its projected graph: a relationship this changeset added is\n // unstaged (not deleted on top of itself), and one it already deletes is not matched again.\n const changesetManager = new StagingAreaManager(model.rootPath, model);\n const changeset = (await changesetManager.getActiveId())\n ? await activeStagedChangeset(changesetManager)\n : null;\n if (changeset) {\n const graph = await ChangesetGraph.build(model, changeset);\n const matches = liveRelationshipsBetween(graph, source, target, predicate);\n if (matches.length === 0) {\n throw new CLIError(\n \"No matching relationships found\",\n ErrorCategory.USER,\n noMatchingRelationshipHints(surface, source, true)\n );\n }\n const staged = await stageRelationshipDeletes(changesetManager, graph, changeset, matches);\n return { deletedCount: staged.length, staged };\n }\n\n // The source element need not resolve: a row whose endpoint was deleted is\n // exactly the row a user needs to remove (#963). The layer is informational only.\n let resolvedSourceLayerName = preResolved?.sourceLayerName;\n if (!resolvedSourceLayerName) {\n resolvedSourceLayerName = await findElementLayer(model, source);\n }\n\n // Use pre-found relationships if provided, otherwise find them\n let resolvedToDelete = preResolved?.toDelete;\n if (!resolvedToDelete) {\n resolvedToDelete = await findRelationshipsByEndpoints(model, source, target, predicate);\n }\n\n if (resolvedToDelete.length === 0) {\n throw new CLIError(\n \"No matching relationships found\",\n ErrorCategory.USER,\n noMatchingRelationshipHints(surface, source, false)\n );\n }\n\n // Check for active changeset \u2014 stage deletion instead of writing directly\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n if (activeChangesetId) {\n // Stage each relationship deletion in the active changeset\n for (const rel of resolvedToDelete) {\n const compositeKey = `${rel.source}::${rel.predicate}::${rel.target}`;\n await stagingManager.stage(activeChangesetId, {\n type: \"relationship-delete\",\n elementId: compositeKey,\n layerName: rel.layer,\n before: {\n source: rel.source,\n target: rel.target,\n predicate: rel.predicate,\n layer: rel.layer,\n ...(rel.targetLayer ? { targetLayer: rel.targetLayer } : {}),\n ...(rel.properties ? { properties: rel.properties } : {})\n }\n });\n }\n } else {\n // No active changeset \u2014 write directly\n for (const rel of resolvedToDelete) {\n model.relationships.delete(rel.source, rel.target, rel.predicate);\n }\n await model.saveRelationships();\n await model.saveManifest();\n\n // Regenerate reports for all affected layers (including transitively related)\n try {\n const orchestrator = new ModelReportOrchestrator(model, model.rootPath);\n const affectedLayers = new Set<string>();\n\n // Compute affected layers for each deleted relationship's source and target\n for (const rel of resolvedToDelete) {\n // Compute affected layers for source layer\n if (rel.layer && isValidLayerName(rel.layer)) {\n for (const layer of orchestrator.computeAffectedLayers(rel.layer)) {\n affectedLayers.add(layer);\n }\n }\n\n // Compute affected layers for target layer\n if (rel.targetLayer && isValidLayerName(rel.targetLayer)) {\n for (const layer of orchestrator.computeAffectedLayers(\n rel.targetLayer\n )) {\n affectedLayers.add(layer);\n }\n }\n }\n\n await orchestrator.regenerate(affectedLayers);\n } catch (error) {\n emitLog(\n SeverityNumber.WARN,\n \"Failed to regenerate layer reports after relationship delete\",\n {\n \"relationship.predicate\": predicate,\n \"relationship.source\": source,\n \"relationship.target\": target,\n \"relationship.deleteCount\": resolvedToDelete.length,\n \"error.message\": getErrorMessage(error)\n }\n );\n }\n }\n\n return { deletedCount: resolvedToDelete.length };\n}\n\nexport interface PruneRelationshipsOptions {\n model?: string;\n dryRun?: boolean;\n layers?: string[];\n format?: string;\n}\n\nexport interface PruneRelationshipsResult {\n scanned: number;\n dangling: number;\n removed: number;\n dryRun: boolean;\n staged: boolean;\n changeset?: string;\n layers?: string[];\n relationships: Array<{\n source: string;\n predicate: string;\n target: string;\n layer: string;\n targetLayer?: string;\n unresolved: UnresolvedSide;\n }>;\n}\n\n/**\n * `dr relationship prune`: remove rows whose source or target resolves to no element.\n *\n * Elements are matched by UUID id and by dotted path (both are legal in\n * relationships.yaml). Inside an active changeset the removals are staged as\n * relationship-delete changes; otherwise relationships.yaml is rewritten with the\n * surviving rows in their original order and its header comment preserved.\n *\n * @internal Exported for testing purposes\n */\nexport async function pruneRelationshipsCommand(\n options: PruneRelationshipsOptions\n): Promise<PruneRelationshipsResult> {\n const format = options.format ?? \"text\";\n if (format !== \"text\" && format !== \"json\") {\n throw new CLIError(`Invalid format: ${format}`, ErrorCategory.USER, [\n \"Use --format text or --format json\",\n ]);\n }\n const jsonOutput = format === \"json\" || isJson();\n\n const layers = options.layers?.length ? options.layers : undefined;\n if (layers) {\n const invalid = layers.filter((l) => !isValidLayerName(l));\n if (invalid.length > 0) {\n throw new CLIError(\n `Invalid layer name(s): ${invalid.join(\", \")}`,\n ErrorCategory.USER,\n ['Use canonical layer names, e.g. \"api\", \"data-model\", \"data-store\"']\n );\n }\n }\n\n const model = await Model.load(options.model || process.cwd());\n\n // Every identifier a current element is known by. getLayer() returns the projected\n // view, so staged adds count as present and staged deletes as absent.\n const elements: Element[] = [];\n for (const layerName of model.getLayerNames()) {\n const layer = await model.getLayer(layerName);\n if (layer) {\n elements.push(...layer.listElements());\n }\n }\n const known = collectKnownIdentifiers(elements);\n\n const analysis = findDanglingRelationships(model.relationships.getAll(), known, { layers });\n\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangeset = await stagingManager.getActive();\n const staging = !!activeChangeset && activeChangeset.status === \"staged\";\n\n const result: PruneRelationshipsResult = {\n scanned: analysis.scanned,\n dangling: analysis.dangling.length,\n removed: 0,\n dryRun: !!options.dryRun,\n staged: false,\n ...(staging ? { changeset: activeChangeset!.name } : {}),\n ...(layers ? { layers } : {}),\n relationships: analysis.dangling.map(({ relationship: rel, unresolved }) => ({\n source: rel.source,\n predicate: rel.predicate,\n target: rel.target,\n layer: rel.layer,\n ...(rel.targetLayer ? { targetLayer: rel.targetLayer } : {}),\n unresolved,\n })),\n };\n\n if (!options.dryRun && analysis.dangling.length > 0) {\n if (staging) {\n for (const { relationship: rel } of analysis.dangling) {\n await stagingManager.stage(activeChangeset!.id, {\n type: \"relationship-delete\",\n elementId: `${rel.source}::${rel.predicate}::${rel.target}`,\n layerName: rel.layer,\n before: {\n source: rel.source,\n target: rel.target,\n predicate: rel.predicate,\n layer: rel.layer,\n ...(rel.targetLayer ? { targetLayer: rel.targetLayer } : {}),\n ...(rel.properties ? { properties: rel.properties } : {}),\n },\n });\n }\n result.staged = true;\n } else {\n const danglingRows = new Set(analysis.dangling.map((d) => d.relationship));\n model.relationships.retain((rel) => !danglingRows.has(rel));\n await model.saveRelationships({ preserveHeader: true });\n await model.saveManifest();\n\n try {\n const orchestrator = new ModelReportOrchestrator(model, model.rootPath);\n const affectedLayers = new Set<string>();\n for (const { relationship: rel } of analysis.dangling) {\n for (const name of [rel.layer, rel.targetLayer]) {\n if (name && isValidLayerName(name)) {\n for (const affected of orchestrator.computeAffectedLayers(name)) {\n affectedLayers.add(affected);\n }\n }\n }\n }\n await orchestrator.regenerate(affectedLayers);\n } catch (error) {\n emitLog(SeverityNumber.WARN, \"Failed to regenerate layer reports after relationship prune\", {\n \"relationship.pruned\": analysis.dangling.length,\n \"error.message\": getErrorMessage(error),\n });\n }\n }\n result.removed = analysis.dangling.length;\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify({ status: \"ok\", ...result }, null, 2));\n return result;\n }\n\n const scope = layers ? ` in layer(s) ${layers.join(\", \")}` : \"\";\n handleInfo(\n `Scanned ${result.scanned} relationship(s)${scope}: ${result.dangling} dangling`\n );\n for (const row of result.relationships) {\n const side =\n row.unresolved === \"both\"\n ? \"source and target not found\"\n : `${row.unresolved} not found`;\n handleInfo(\n ` - ${ansis.yellow(row.source)} --[${ansis.magenta(row.predicate)}]--> ${ansis.yellow(row.target)} ${ansis.dim(`(${side})`)}`\n );\n }\n\n if (result.dangling === 0) {\n handleSuccess(\"No dangling relationships found\", {\n scanned: result.scanned,\n dangling: 0,\n removed: 0,\n });\n } else if (result.dryRun) {\n handleSuccess(`Dry run: would remove ${result.dangling} dangling relationship(s)`, {\n scanned: result.scanned,\n dangling: result.dangling,\n removed: 0,\n dryRun: true,\n });\n } else if (result.staged) {\n handleSuccess(\n `Staged removal of ${result.removed} dangling relationship(s) to ${ansis.bold(result.changeset!)}`,\n {\n scanned: result.scanned,\n dangling: result.dangling,\n removed: result.removed,\n changesetStatus: \"staged\",\n changeset: result.changeset,\n }\n );\n } else {\n handleSuccess(`Removed ${result.removed} dangling relationship(s)`, {\n scanned: result.scanned,\n dangling: result.dangling,\n removed: result.removed,\n });\n }\n\n return result;\n}\n\nexport function relationshipCommands(program: Command, rootProgram?: Command): void {\n program\n .command(\"add <source> <target>\")\n .description(\n \"Add a relationship between elements (intra-layer or cross-layer)\"\n )\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .requiredOption(\n \"--predicate <predicate>\",\n \"Relationship predicate (e.g., depends-on, realizes, exposes)\"\n )\n .option(\"--properties <json>\", \"Relationship properties (JSON)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship add motivation.goal.goal-a motivation.goal.goal-b --predicate aggregates\n $ dr relationship add api.operation.create-order application.service.order-service --predicate exposes\n $ dr relationship add business.businessprocess.checkout application.applicationprocess.checkout --predicate aggregates\n $ dr relationship add element-1 element-2 --predicate realizes --properties '{\"strength\":\"high\"}'`\n )\n .action(async (source, target, options) => {\n try {\n // Load model\n const model = await Model.load(options.model);\n\n // Find source element for constraints info\n const sourceLayerName = await findElementLayer(model, source);\n if (!sourceLayerName) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n const sourceLayer = await model.getLayer(sourceLayerName);\n if (!sourceLayer) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n const sourceElement = sourceLayer.getElement(source);\n if (!sourceElement) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n\n // Find target element for constraints info\n const targetLayerName = await findElementLayer(model, target);\n if (!targetLayerName) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n const targetLayer = await model.getLayer(targetLayerName);\n if (!targetLayer) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n const targetElement = targetLayer.getElement(target);\n if (!targetElement) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n\n // Get cardinality and strength info (before calling handler for CLI output)\n const sourceSpecNodeId = constructSpecNodeId(sourceElement, source);\n const targetSpecNodeId = constructSpecNodeId(targetElement, target);\n const constraints = getRelationshipConstraints(\n sourceSpecNodeId,\n options.predicate,\n targetSpecNodeId\n );\n\n // Parse properties if provided\n let properties: Record<string, unknown> | undefined;\n if (options.properties) {\n try {\n properties = JSON.parse(options.properties);\n } catch (e) {\n throw new CLIError(\n \"Invalid JSON in --properties\",\n ErrorCategory.USER\n );\n }\n }\n\n // Check for active changeset\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n // Call the handler function with pre-resolved elements to avoid duplicate lookups\n const outcome = await addRelationship(\n model,\n source,\n target,\n options.predicate,\n properties,\n {\n source: { element: sourceElement, layerName: sourceLayerName },\n target: { element: targetElement, layerName: targetLayerName }\n }\n );\n\n if (outcome === \"duplicate\") {\n // duplicate \u2014 emit JSON response indicating relationship already exists\n // (in the base model, or already staged by the active changeset)\n handleSuccess(\n `Relationship ${source} --[${options.predicate}]--> ${target} already exists` +\n (activeChangesetId ? \" (in the model or the active changeset); nothing staged\" : \"\"),\n {\n source,\n target,\n predicate: options.predicate,\n layer: sourceLayerName,\n duplicate: true,\n ...(activeChangesetId ? { changesetStatus: \"unchanged\" } : {}),\n },\n { verbose: options.verbose }\n );\n return;\n }\n\n if (outcome === \"restored\") {\n handleSuccess(\n `Restored relationship: ${ansis.bold(source)} ${options.predicate} ${ansis.bold(target)}` +\n ansis.dim(\" [the active changeset's staged deletion of it was unstaged]\"),\n {\n source,\n target,\n predicate: options.predicate,\n layer: sourceLayerName,\n restored: true,\n changesetStatus: \"unstaged\",\n },\n { verbose: options.verbose }\n );\n return;\n }\n\n // Show cardinality and strength in output\n let message = `Added relationship: ${ansis.bold(source)} ${options.predicate} ${ansis.bold(target)}`;\n const details: Record<string, unknown> = {\n source,\n target,\n predicate: options.predicate,\n layer: sourceLayerName,\n };\n if (constraints) {\n message += ansis.dim(\n ` (${constraints.cardinality}, ${constraints.strength} strength)`\n );\n details.cardinality = constraints.cardinality;\n details.strength = constraints.strength;\n }\n if (activeChangesetId) {\n message += ansis.dim(` [staged]`);\n details.changesetStatus = \"staged\";\n }\n\n handleSuccess(message, details, { verbose: options.verbose });\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"delete <source> <target>\")\n .description(\"Delete a relationship\")\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .option(\n \"--predicate <predicate>\",\n \"Specific predicate to delete (optional, delete all if not specified)\"\n )\n .option(\"--force\", \"Skip confirmation prompt\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship delete element-1 element-2 --predicate depends-on\n $ dr relationship delete element-1 element-2 --force`\n )\n .action(async (source, target, options) => {\n try {\n // Load model\n const model = await Model.load(options.model);\n\n // Find relationships to delete (to show confirmation count). Endpoints are\n // matched by the value recorded in the row, so a row whose source or target\n // element has already been deleted can still be removed.\n // Inside a changeset the candidates come from its projected graph, so a relationship the\n // changeset itself added can be removed (which unstages it).\n const activeForDelete = await activeStagedChangeset(\n new StagingAreaManager(model.rootPath, model)\n );\n const toDelete = activeForDelete\n ? liveRelationshipsBetween(\n await ChangesetGraph.build(model, activeForDelete),\n source,\n target,\n options.predicate\n )\n : await findRelationshipsByEndpoints(model, source, target, options.predicate);\n\n if (toDelete.length === 0) {\n throw new CLIError(\n \"No matching relationships found\",\n ErrorCategory.USER,\n [\n `Use \"dr relationship list ${source}\" to see the relationships recorded for ${source}`,\n 'Use \"dr relationship prune --dry-run\" to list rows whose endpoints no longer resolve',\n ]\n );\n }\n\n // The source layer is informational; fall back to the row's layer when the\n // source element no longer exists.\n const sourceLayerName =\n (await findElementLayer(model, source)) ?? toDelete[0].layer;\n\n // Confirm deletion unless --force or non-interactive environment\n // In non-interactive environments (CI, tests), skip confirmation\n const isInteractive = process.stdin.isTTY && process.stdout.isTTY;\n if (!options.force && isInteractive) {\n // Dynamic import of prompts is safe here: caught by outer try-catch\n // This allows lazy loading of the prompt library only when needed\n const { confirm } = await import(\"@clack/prompts\");\n const confirmed = await confirm({\n message: `Delete ${toDelete.length} relationship(s)? This cannot be undone.`,\n initialValue: false\n });\n\n if (!confirmed) {\n handleSuccess(\"Deletion cancelled\", {\n source,\n target,\n status: \"cancelled\",\n });\n return;\n }\n }\n\n // Check for active changeset\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n // Call the handler function with pre-resolved values to avoid duplicate lookups\n const result = await deleteRelationshipHandler(\n model,\n source,\n target,\n options.predicate,\n {\n sourceLayerName,\n // In a changeset the handler re-reads the projected graph itself.\n toDelete: activeForDelete ? undefined : (toDelete as Relationship[])\n }\n );\n\n const stagedSuffix = activeChangesetId ? \" [staged]\" : \"\";\n const deleteDetails: Record<string, unknown> = {\n source,\n target,\n layer: sourceLayerName,\n deletedCount: result.deletedCount,\n ...(result.staged ? { relationships: result.staged } : {}),\n };\n if (options.predicate) {\n deleteDetails.predicate = options.predicate;\n }\n if (activeChangesetId) {\n deleteDetails.changesetStatus = \"staged\";\n }\n handleSuccess(\n `Deleted ${result.deletedCount} relationship(s) from ${ansis.bold(source)} to ${ansis.bold(target)}${stagedSuffix}`,\n deleteDetails,\n { verbose: options.verbose }\n );\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"prune\")\n .description(\n \"Remove relationship rows whose source or target no longer resolves to an element\"\n )\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .option(\"--dry-run\", \"List the rows that would be removed without writing\")\n .option(\n \"--layers <layers...>\",\n \"Only scan rows whose source or target layer is one of these canonical layer names\"\n )\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nA row is dangling when its source or target matches neither the UUID id nor the\ndotted path of any current element. Kept rows keep their order and the file's\nheader comment is preserved. Inside an active changeset the removals are staged\nas relationship deletions instead of being written to relationships.yaml.\n\nExamples:\n $ dr relationship prune --dry-run\n $ dr relationship prune\n $ dr relationship prune --layers api application --format json`\n )\n .action(async (options) => {\n try {\n await pruneRelationshipsCommand({\n model: options.model,\n dryRun: !!options.dryRun,\n layers: options.layers,\n format: options.format,\n });\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"list <id>\")\n .description(\"List relationships for an element\")\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .option(\n \"--direction <dir>\",\n \"Filter by direction (incoming/outgoing/all)\",\n \"all\"\n )\n .option(\"--json\", \"Output as JSON\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship list api-endpoint-create-customer\n $ dr relationship list business-service-order --direction outgoing\n $ dr relationship list element-1 --json`\n )\n .action(async (id, options) => {\n try {\n // Load model\n const model = await Model.load(options.model);\n const layerName = await findElementLayer(model, id);\n\n if (!layerName) {\n throw new CLIError(`Element ${id} not found`, ErrorCategory.USER);\n }\n\n // Get relationships from centralized store\n const { outgoing, incoming } = model.relationships.getForElement(id);\n\n // Filter by direction\n let relationships: typeof outgoing = [];\n if (options.direction === \"outgoing\" || options.direction === \"all\") {\n relationships.push(...outgoing);\n }\n if (options.direction === \"incoming\" || options.direction === \"all\") {\n relationships.push(...incoming);\n }\n\n const shouldOutputJson = options.json ?? (rootProgram?.opts().json);\n if (shouldOutputJson) {\n console.log(JSON.stringify(relationships, null, 2));\n return;\n }\n\n if (relationships.length === 0) {\n handleInfo(\n ansis.yellow(`No ${options.direction} relationships for ${id}`)\n );\n return;\n }\n\n handleInfo(\"\");\n handleInfo(\n ansis.bold(\n `${options.direction === \"all\" ? \"\" : options.direction + \" \"}relationships for ${ansis.cyan(id)}:`\n )\n );\n handleInfo(ansis.dim(\"\u2500\".repeat(80)));\n\n for (const rel of relationships) {\n const isOutgoing = rel.source === id;\n const direction = isOutgoing ? \"\u2192\" : \"\u2190\";\n const otherElement = isOutgoing ? rel.target : rel.source;\n const crossLayer =\n rel.targetLayer && rel.targetLayer !== rel.layer\n ? ansis.dim(` [${rel.layer} \u2192 ${rel.targetLayer}]`)\n : \"\";\n\n handleInfo(\n ` ${direction} ${ansis.magenta(rel.predicate)}: ${ansis.yellow(otherElement)}${crossLayer}`\n );\n\n if (rel.properties) {\n const propStr = Object.entries(rel.properties)\n .map(([k, v]) => `${k}=${v}`)\n .join(\", \");\n handleInfo(` ${ansis.dim(propStr)}`);\n }\n }\n\n handleInfo(ansis.dim(\"\u2500\".repeat(80)));\n handleInfo(ansis.dim(`Total: ${relationships.length} relationship(s)`));\n handleInfo(\"\");\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"show <source> <target>\")\n .description(\"Show relationship details\")\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship show api-endpoint-create-customer business-service-customer-mgmt\n $ dr relationship show application-component-api motivation-goal-sales-efficiency`\n )\n .action(async (source, target, options) => {\n try {\n // Load model\n const model = await Model.load(options.model);\n const sourceLayerName = await findElementLayer(model, source);\n\n if (!sourceLayerName) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n\n // Find relationships from centralized store\n const relationships = model.relationships.find(source, target);\n\n if (relationships.length === 0) {\n throw new CLIError(\n `No relationships from ${source} to ${target}`,\n ErrorCategory.USER\n );\n }\n\n handleInfo(\"\");\n handleInfo(\n ansis.bold(\n `Relationship${relationships.length > 1 ? \"s\" : \"\"} from ${ansis.cyan(source)} to ${ansis.yellow(target)}:`\n )\n );\n handleInfo(ansis.dim(\"\u2500\".repeat(60)));\n\n for (let i = 0; i < relationships.length; i++) {\n const rel = relationships[i];\n\n if (i > 0) {\n handleInfo(\"\");\n }\n\n handleInfo(`Predicate: ${ansis.magenta(rel.predicate)}`);\n handleInfo(`Layer: ${ansis.cyan(rel.layer)}`);\n if (rel.targetLayer && rel.targetLayer !== rel.layer) {\n handleInfo(`Target Layer: ${ansis.cyan(rel.targetLayer)}`);\n }\n\n if (rel.properties && Object.keys(rel.properties).length > 0) {\n handleInfo(\"Properties:\");\n for (const [key, value] of Object.entries(rel.properties)) {\n const displayValue =\n typeof value === \"string\"\n ? value\n : JSON.stringify(value, null, 2);\n handleInfo(` ${ansis.cyan(key)}: ${displayValue}`);\n }\n } else {\n handleInfo(\"Properties: none\");\n }\n }\n\n handleInfo(\"\");\n } catch (error) {\n handleError(error);\n }\n });\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -24,7 +24,7 @@ async function regenerateLayerReports(projectRoot) {
24
24
  const reportDir = path.join(projectRoot, "documentation-robotics", "reports");
25
25
  console.log(ansis.dim("Removing existing reports...")), await fs.rm(reportDir, { recursive: !0, force: !0 }), console.log(ansis.dim("Loading model..."));
26
26
  const model = await Model.load(projectRoot), orchestrator = new ModelReportOrchestrator(model, projectRoot);
27
- console.log(ansis.dim("Generating 13 layer reports...")), await orchestrator.regenerateAll(), console.log(ansis.green("\u2713 All 13 layer reports regenerated")), console.log(ansis.dim(" Reports written to: documentation-robotics/reports/"));
27
+ console.log(ansis.dim("Generating 13 layer reports and README...")), await orchestrator.regenerateAll(), console.log(ansis.green("\u2713 All 13 layer reports and README regenerated")), console.log(ansis.dim(" Reports written to: documentation-robotics/reports/")), console.log(ansis.dim(" README written to: documentation-robotics/README.md"));
28
28
  }
29
29
  async function hasLayerReports(projectRoot) {
30
30
  const reportDir = path.join(projectRoot, "documentation-robotics", "reports");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/commands/reports.ts"],
4
- "sourcesContent": ["/**\n * Reports subcommands for managing the maintained set of markdown layer reports\n */\n\nimport { Command } from \"commander\";\nimport ansis from \"ansis\";\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { Model } from \"../core/model.js\";\nimport { ModelReportOrchestrator } from \"../reports/model-report-orchestrator.js\";\nimport { findProjectRoot } from \"../utils/project-paths.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\nexport function reportsCommands(parent: Command): void {\n parent\n .command(\"regenerate\")\n .description(\"Delete existing layer reports and regenerate all 13 markdown reports\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr reports regenerate # Delete existing reports and regenerate all 13 layer reports`\n )\n .action(async () => {\n await reportsRegenerateCommand();\n });\n}\n\n/**\n * Delete existing layer reports and regenerate all 13 markdown reports.\n */\nexport async function reportsRegenerateCommand(): Promise<void> {\n try {\n const projectRoot = await findProjectRoot();\n if (!projectRoot) {\n console.error(ansis.red(\"Error: No DR project found\"));\n console.error(ansis.dim('Run \"dr init\" to create a new project'));\n process.exit(1);\n }\n\n await regenerateLayerReports(projectRoot);\n } catch (error) {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n process.exit(1);\n }\n}\n\n/**\n * Delete existing reports directory and regenerate all 13 layer reports.\n * Exported for use in the upgrade command.\n */\nexport async function regenerateLayerReports(projectRoot: string): Promise<void> {\n const reportDir = path.join(projectRoot, \"documentation-robotics\", \"reports\");\n\n // Remove the entire reports directory so stale reports from removed/renamed layers don't linger.\n // force: true means no error if the directory doesn't exist yet.\n // ModelReportOrchestrator.regenerateAll() recreates the directory before writing.\n console.log(ansis.dim(\"Removing existing reports...\"));\n await fs.rm(reportDir, { recursive: true, force: true });\n\n // Load model and regenerate all reports\n console.log(ansis.dim(\"Loading model...\"));\n const model = await Model.load(projectRoot);\n\n const orchestrator = new ModelReportOrchestrator(model, projectRoot);\n console.log(ansis.dim(\"Generating 13 layer reports...\"));\n await orchestrator.regenerateAll();\n\n console.log(ansis.green(\"\u2713 All 13 layer reports regenerated\"));\n console.log(ansis.dim(\" Reports written to: documentation-robotics/reports/\"));\n}\n\n/**\n * Check whether any layer reports exist in the reports directory.\n * Returns false if the directory doesn't exist or contains no .md files.\n */\nexport async function hasLayerReports(projectRoot: string): Promise<boolean> {\n const reportDir = path.join(projectRoot, \"documentation-robotics\", \"reports\");\n try {\n const entries = await fs.readdir(reportDir);\n return entries.some((f) => f.endsWith(\".md\"));\n } catch (error: unknown) {\n const err = error as NodeJS.ErrnoException;\n if (err.code === \"ENOENT\") return false;\n throw error;\n }\n}\n"],
5
- "mappings": "AAKA,OAAO,WAAW;AAClB,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,aAAa;AACtB,SAAS,+BAA+B;AACxC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAE1B,SAAU,gBAAgB,QAAe;AAC7C,SACG,QAAQ,YAAY,EACpB,YAAY,sEAAsE,EAClF,YACC,SACA;;2FAEqF,EAEtF,OAAO,YAAW;AACjB,UAAM,yBAAwB;EAChC,CAAC;AACL;AAKA,eAAsB,2BAAwB;AAC5C,MAAI;AACF,UAAM,cAAc,MAAM,gBAAe;AACzC,IAAK,gBACH,QAAQ,MAAM,MAAM,IAAI,4BAA4B,CAAC,GACrD,QAAQ,MAAM,MAAM,IAAI,uCAAuC,CAAC,GAChE,QAAQ,KAAK,CAAC,IAGhB,MAAM,uBAAuB,WAAW;EAC1C,SAAS,OAAO;AACd,YAAQ,MAAM,MAAM,IAAI,UAAU,gBAAgB,KAAK,CAAC,EAAE,CAAC,GAC3D,QAAQ,KAAK,CAAC;EAChB;AACF;AAMA,eAAsB,uBAAuB,aAAmB;AAC9D,QAAM,YAAY,KAAK,KAAK,aAAa,0BAA0B,SAAS;AAK5E,UAAQ,IAAI,MAAM,IAAI,8BAA8B,CAAC,GACrD,MAAM,GAAG,GAAG,WAAW,EAAE,WAAW,IAAM,OAAO,GAAI,CAAE,GAGvD,QAAQ,IAAI,MAAM,IAAI,kBAAkB,CAAC;AACzC,QAAM,QAAQ,MAAM,MAAM,KAAK,WAAW,GAEpC,eAAe,IAAI,wBAAwB,OAAO,WAAW;AACnE,UAAQ,IAAI,MAAM,IAAI,gCAAgC,CAAC,GACvD,MAAM,aAAa,cAAa,GAEhC,QAAQ,IAAI,MAAM,MAAM,yCAAoC,CAAC,GAC7D,QAAQ,IAAI,MAAM,IAAI,uDAAuD,CAAC;AAChF;AAMA,eAAsB,gBAAgB,aAAmB;AACvD,QAAM,YAAY,KAAK,KAAK,aAAa,0BAA0B,SAAS;AAC5E,MAAI;AAEF,YADgB,MAAM,GAAG,QAAQ,SAAS,GAC3B,KAAK,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC;EAC9C,SAAS,OAAgB;AAEvB,QADY,MACJ,SAAS;AAAU,aAAO;AAClC,UAAM;EACR;AACF;",
4
+ "sourcesContent": ["/**\n * Reports subcommands for managing the maintained set of markdown layer reports\n */\n\nimport { Command } from \"commander\";\nimport ansis from \"ansis\";\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { Model } from \"../core/model.js\";\nimport { ModelReportOrchestrator } from \"../reports/model-report-orchestrator.js\";\nimport { findProjectRoot } from \"../utils/project-paths.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\nexport function reportsCommands(parent: Command): void {\n parent\n .command(\"regenerate\")\n .description(\"Delete existing layer reports and regenerate all 13 markdown reports\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr reports regenerate # Delete existing reports and regenerate all 13 layer reports`\n )\n .action(async () => {\n await reportsRegenerateCommand();\n });\n}\n\n/**\n * Delete existing layer reports and regenerate all 13 markdown reports.\n */\nexport async function reportsRegenerateCommand(): Promise<void> {\n try {\n const projectRoot = await findProjectRoot();\n if (!projectRoot) {\n console.error(ansis.red(\"Error: No DR project found\"));\n console.error(ansis.dim('Run \"dr init\" to create a new project'));\n process.exit(1);\n }\n\n await regenerateLayerReports(projectRoot);\n } catch (error) {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n process.exit(1);\n }\n}\n\n/**\n * Delete existing reports directory and regenerate all 13 layer reports and the README.\n * Exported for use in the upgrade command.\n */\nexport async function regenerateLayerReports(projectRoot: string): Promise<void> {\n const reportDir = path.join(projectRoot, \"documentation-robotics\", \"reports\");\n\n // Remove the entire reports directory so stale reports from removed/renamed layers don't linger.\n // force: true means no error if the directory doesn't exist yet.\n // ModelReportOrchestrator.regenerateAll() recreates the directory before writing.\n console.log(ansis.dim(\"Removing existing reports...\"));\n await fs.rm(reportDir, { recursive: true, force: true });\n\n // Load model and regenerate all reports\n console.log(ansis.dim(\"Loading model...\"));\n const model = await Model.load(projectRoot);\n\n const orchestrator = new ModelReportOrchestrator(model, projectRoot);\n console.log(ansis.dim(\"Generating 13 layer reports and README...\"));\n await orchestrator.regenerateAll();\n\n console.log(ansis.green(\"\u2713 All 13 layer reports and README regenerated\"));\n console.log(ansis.dim(\" Reports written to: documentation-robotics/reports/\"));\n console.log(ansis.dim(\" README written to: documentation-robotics/README.md\"));\n}\n\n/**\n * Check whether any layer reports exist in the reports directory.\n * Returns false if the directory doesn't exist or contains no .md files.\n */\nexport async function hasLayerReports(projectRoot: string): Promise<boolean> {\n const reportDir = path.join(projectRoot, \"documentation-robotics\", \"reports\");\n try {\n const entries = await fs.readdir(reportDir);\n return entries.some((f) => f.endsWith(\".md\"));\n } catch (error: unknown) {\n const err = error as NodeJS.ErrnoException;\n if (err.code === \"ENOENT\") return false;\n throw error;\n }\n}\n"],
5
+ "mappings": "AAKA,OAAO,WAAW;AAClB,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,aAAa;AACtB,SAAS,+BAA+B;AACxC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAE1B,SAAU,gBAAgB,QAAe;AAC7C,SACG,QAAQ,YAAY,EACpB,YAAY,sEAAsE,EAClF,YACC,SACA;;2FAEqF,EAEtF,OAAO,YAAW;AACjB,UAAM,yBAAwB;EAChC,CAAC;AACL;AAKA,eAAsB,2BAAwB;AAC5C,MAAI;AACF,UAAM,cAAc,MAAM,gBAAe;AACzC,IAAK,gBACH,QAAQ,MAAM,MAAM,IAAI,4BAA4B,CAAC,GACrD,QAAQ,MAAM,MAAM,IAAI,uCAAuC,CAAC,GAChE,QAAQ,KAAK,CAAC,IAGhB,MAAM,uBAAuB,WAAW;EAC1C,SAAS,OAAO;AACd,YAAQ,MAAM,MAAM,IAAI,UAAU,gBAAgB,KAAK,CAAC,EAAE,CAAC,GAC3D,QAAQ,KAAK,CAAC;EAChB;AACF;AAMA,eAAsB,uBAAuB,aAAmB;AAC9D,QAAM,YAAY,KAAK,KAAK,aAAa,0BAA0B,SAAS;AAK5E,UAAQ,IAAI,MAAM,IAAI,8BAA8B,CAAC,GACrD,MAAM,GAAG,GAAG,WAAW,EAAE,WAAW,IAAM,OAAO,GAAI,CAAE,GAGvD,QAAQ,IAAI,MAAM,IAAI,kBAAkB,CAAC;AACzC,QAAM,QAAQ,MAAM,MAAM,KAAK,WAAW,GAEpC,eAAe,IAAI,wBAAwB,OAAO,WAAW;AACnE,UAAQ,IAAI,MAAM,IAAI,2CAA2C,CAAC,GAClE,MAAM,aAAa,cAAa,GAEhC,QAAQ,IAAI,MAAM,MAAM,oDAA+C,CAAC,GACxE,QAAQ,IAAI,MAAM,IAAI,uDAAuD,CAAC,GAC9E,QAAQ,IAAI,MAAM,IAAI,uDAAuD,CAAC;AAChF;AAMA,eAAsB,gBAAgB,aAAmB;AACvD,QAAM,YAAY,KAAK,KAAK,aAAa,0BAA0B,SAAS;AAC5E,MAAI;AAEF,YADgB,MAAM,GAAG,QAAQ,SAAS,GAC3B,KAAK,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC;EAC9C,SAAS,OAAgB;AAEvB,QADY,MACJ,SAAS;AAAU,aAAO;AAClC,UAAM;EACR;AACF;",
6
6
  "names": []
7
7
  }
@@ -1,15 +1,23 @@
1
1
  import ansis from "ansis";
2
2
  import { Model } from "../core/model.js";
3
3
  import { MutationHandler } from "../core/mutation-handler.js";
4
+ import { setStagedSourceReference } from "../core/staged-source-reference.js";
4
5
  import { StagingAreaManager } from "../core/staging-area.js";
5
6
  import { StagedChangesetStorage } from "../core/staged-changeset-storage.js";
7
+ import { changedFields as snapshotChangedFields } from "../core/changeset-summary.js";
6
8
  import { findElementLayer } from "../utils/element-utils.js";
7
- import { CLIError, handleError, findSimilar, formatValidOptions } from "../utils/errors.js";
9
+ import { CLIError, handleError, handleSuccess, handleInfo, handleWarning, findSimilar, formatValidOptions } from "../utils/errors.js";
8
10
  import { isValidNodeType, getNodeTypesForLayer, normalizeNodeType } from "../generated/node-types.js";
9
11
  import { Element } from "../core/element.js";
10
12
  import { Layer } from "../core/layer.js";
11
- import { SchemaValidator } from "../validators/schema-validator.js";
13
+ import { SchemaValidator, suggestNodeTypes } from "../validators/schema-validator.js";
12
14
  import { validateSourceReferenceOptions, buildSourceReference } from "../utils/source-reference.js";
15
+ import { schemaLookupHint, undefinedTypeWarning } from "../utils/error-hints.js";
16
+ import { effectiveAttributePatch, parseJsonObjectOption, resolveAttributeUpdate } from "../utils/attribute-patch.js";
17
+ function undefinedTypeCheck(layer, elementId, type) {
18
+ if (!isValidNodeType(layer, type))
19
+ return undefinedTypeWarning("cli", layer, elementId, type, suggestNodeTypes(layer, type));
20
+ }
13
21
  import { startSpan, endSpan } from "../telemetry/index.js";
14
22
  const isTelemetryEnabled = !1;
15
23
  function validateUpdateSourceReferenceOptions(options) {
@@ -20,14 +28,16 @@ function validateUpdateSourceReferenceOptions(options) {
20
28
  }
21
29
  async function updateCommand(id, options) {
22
30
  const changedFields = [];
23
- options.name && changedFields.push("name"), options.description && changedFields.push("description"), options.type && changedFields.push("type"), options.attributes && changedFields.push("attributes"), (options.sourceFile || options.clearSourceReference) && changedFields.push("sourceReference");
31
+ options.name && changedFields.push("name"), options.description && changedFields.push("description"), options.type && changedFields.push("type"), (options.attributes || options.attributePatch) && changedFields.push("attributes"), (options.sourceFile || options.clearSourceReference) && changedFields.push("sourceReference");
24
32
  const span = isTelemetryEnabled ? startSpan("element.update", {
25
33
  "element.id": id,
26
34
  "element.changed_fields": changedFields.join(",")
27
35
  }) : null;
28
36
  try {
29
37
  validateUpdateSourceReferenceOptions(options);
30
- const model = await Model.load(), layerName = await findElementLayer(model, id);
38
+ const parsedPatch = options.attributePatch !== void 0 ? parseJsonObjectOption(options.attributePatch, "--attribute-patch") : void 0, attributeFlags = { attributes: "--attributes", attributePatch: "--attribute-patch" };
39
+ options.attributes !== void 0 && parsedPatch !== void 0 && resolveAttributeUpdate(void 0, { attributes: {}, attributePatch: parsedPatch }, attributeFlags);
40
+ const attributePatch = effectiveAttributePatch(parsedPatch), model = await Model.load(options.model), layerName = await findElementLayer(model, id);
31
41
  if (!layerName) {
32
42
  const stagingManager = new StagingAreaManager(model.rootPath, model), storage = new StagedChangesetStorage(model.rootPath), activeId = await stagingManager.getActiveId();
33
43
  if (activeId) {
@@ -35,8 +45,8 @@ async function updateCommand(id, options) {
35
45
  if (changeset) {
36
46
  const addChange = changeset.changes.find((c) => c.type === "add" && c.elementId === id);
37
47
  if (addChange && addChange.after) {
38
- if (!(options.name || options.description !== void 0 || options.attributes || options.sourceFile || options.clearSourceReference || options.type)) {
39
- console.log(ansis.yellow("No fields specified for update"));
48
+ if (!(options.name || options.description !== void 0 || options.attributes || attributePatch || options.sourceFile || options.clearSourceReference || options.type)) {
49
+ handleInfo(ansis.yellow("No fields specified for update"));
40
50
  return;
41
51
  }
42
52
  const after = { ...addChange.after };
@@ -58,13 +68,14 @@ async function updateCommand(id, options) {
58
68
  "Ensure your JSON is valid and properly formatted"
59
69
  ]);
60
70
  }
71
+ else attributePatch && (after.attributes = resolveAttributeUpdate(after.attributes, { attributePatch }, attributeFlags));
61
72
  if (options.clearSourceReference)
62
- delete after.source_reference;
73
+ setStagedSourceReference(after, void 0);
63
74
  else if (options.sourceFile) {
64
75
  const newRef = buildSourceReference(options);
65
- newRef && (after.source_reference = newRef);
76
+ newRef && setStagedSourceReference(after, newRef);
66
77
  }
67
- if (options.type || options.attributes) {
78
+ if (options.type || options.attributes || attributePatch) {
68
79
  const stagedLayerName = addChange.layerName, tempElem = Element.fromSpecNode({
69
80
  id: String(after.id ?? addChange.elementId ?? "staged"),
70
81
  path: String(after.path ?? addChange.elementId ?? ""),
@@ -75,15 +86,16 @@ async function updateCommand(id, options) {
75
86
  attributes: after.attributes || {}
76
87
  }), schemaValidator = new SchemaValidator(), tempLayer = new Layer(stagedLayerName);
77
88
  tempLayer.addElement(tempElem);
78
- const attrValidation = await schemaValidator.validateLayer(tempLayer);
79
- if (!attrValidation.isValid()) {
80
- const errorMessages = attrValidation.errors.map((e) => ` ${e.message}`).join(`
89
+ const attrValidation = await schemaValidator.validateLayer(tempLayer), undefinedTypeHint = undefinedTypeCheck(stagedLayerName, id, String(after.type ?? "")), blocking = undefinedTypeHint ? attrValidation.errors.filter((e) => e.location !== "/type") : attrValidation.errors;
90
+ if (blocking.length > 0) {
91
+ const errorMessages = blocking.map((e) => ` ${e.message}`).join(`
81
92
  `);
82
93
  throw new CLIError(`Updated attributes fail schema validation:
83
94
  ${errorMessages}`, 1, [
84
- options.type ? `Incompatible attributes must be manually cleaned up before changing type. Run "dr schema ${stagedLayerName} ${after.type}" to see the required attributes` : `Run "dr schema ${stagedLayerName} ${after.type}" to see the required attributes`
95
+ undefinedTypeHint ? undefinedTypeHint.hint : (options.type ? "Incompatible attributes must be manually cleaned up before changing type. " : "") + schemaLookupHint("cli", stagedLayerName, String(after.type))
85
96
  ]);
86
97
  }
98
+ undefinedTypeHint && handleWarning(undefinedTypeHint.message, [undefinedTypeHint.hint]);
87
99
  }
88
100
  await storage.updateChange(activeId, id, {
89
101
  type: addChange.type,
@@ -91,7 +103,12 @@ ${errorMessages}`, 1, [
91
103
  layerName: addChange.layerName,
92
104
  before: addChange.before,
93
105
  after
94
- }), console.log(ansis.green(`\u2713 Updated staged element ${ansis.bold(id)}`));
106
+ }), handleSuccess(`Updated staged element ${ansis.bold(id)}`, {
107
+ elementId: id,
108
+ layer: addChange.layerName,
109
+ changesetStatus: "staged",
110
+ changedFields: snapshotChangedFields(addChange.after, after)
111
+ }, { verbose: options.verbose });
95
112
  return;
96
113
  }
97
114
  }
@@ -104,11 +121,12 @@ ${errorMessages}`, 1, [
104
121
  const element = layer.getElement(id);
105
122
  if (!element)
106
123
  throw new CLIError(`Element ${id} not found`, 1);
107
- if (!(options.name || options.description !== void 0 || options.type || options.attributes || options.sourceFile || options.clearSourceReference)) {
108
- console.log(ansis.yellow("No fields specified for update"));
124
+ if (!(options.name || options.description !== void 0 || options.type || options.attributes || attributePatch || options.sourceFile || options.clearSourceReference)) {
125
+ handleInfo(ansis.yellow("No fields specified for update"));
109
126
  return;
110
127
  }
111
- await new MutationHandler(model, id, layerName).executeUpdate(element, async (elem, after) => {
128
+ const handler = new MutationHandler(model, id, layerName);
129
+ await handler.executeUpdate(element, async (elem, after) => {
112
130
  let resolvedNewType;
113
131
  if (options.type) {
114
132
  if (!isValidNodeType(layerName, options.type)) {
@@ -126,6 +144,7 @@ ${errorMessages}`, 1, [
126
144
  "Ensure your JSON is valid and properly formatted"
127
145
  ]);
128
146
  }
147
+ else attributePatch && (parsedAttributes = resolveAttributeUpdate(elem.attributes, { attributePatch }, attributeFlags));
129
148
  if (resolvedNewType || parsedAttributes) {
130
149
  const candidateType = resolvedNewType ?? elem.type, tempElem = new Element({
131
150
  ...elem.toJSON(),
@@ -134,24 +153,37 @@ ${errorMessages}`, 1, [
134
153
  attributes: parsedAttributes ?? elem.attributes
135
154
  }), schemaValidator = new SchemaValidator(), tempLayer = new Layer(layerName);
136
155
  tempLayer.addElement(tempElem);
137
- const attrValidation = await schemaValidator.validateLayer(tempLayer);
138
- if (!attrValidation.isValid()) {
139
- const errorMessages = attrValidation.errors.map((e) => ` ${e.message}`).join(`
156
+ const attrValidation = await schemaValidator.validateLayer(tempLayer), undefinedTypeHint = undefinedTypeCheck(layerName, id, candidateType), blocking = undefinedTypeHint ? attrValidation.errors.filter((e) => e.location !== "/type") : attrValidation.errors;
157
+ if (blocking.length > 0) {
158
+ const errorMessages = blocking.map((e) => ` ${e.message}`).join(`
140
159
  `);
141
160
  throw new CLIError(`Updated attributes fail schema validation:
142
161
  ${errorMessages}`, 1, [
143
- resolvedNewType ? `Incompatible attributes must be manually cleaned up before changing type. Run "dr schema ${layerName} ${candidateType}" to see the required attributes` : `Run "dr schema ${layerName} ${elem.type}" to see the required attributes`
162
+ undefinedTypeHint ? undefinedTypeHint.hint : resolvedNewType ? "Incompatible attributes must be manually cleaned up before changing type. " + schemaLookupHint("cli", layerName, candidateType) : schemaLookupHint("cli", layerName, elem.type)
144
163
  ]);
145
164
  }
165
+ undefinedTypeHint && handleWarning(undefinedTypeHint.message, [undefinedTypeHint.hint]);
146
166
  }
147
167
  if (resolvedNewType && (elem.type = resolvedNewType, after.type = resolvedNewType, elem.spec_node_id = `${layerName}.${resolvedNewType}`, after.spec_node_id = `${layerName}.${resolvedNewType}`), options.name && (elem.name = options.name, after.name = options.name), options.description !== void 0 && (elem.description = options.description || void 0, after.description = options.description || void 0), parsedAttributes && (elem.attributes = parsedAttributes, after.attributes = parsedAttributes), options.clearSourceReference)
148
- elem.setSourceReference(void 0), after.sourceReference = void 0;
168
+ elem.setSourceReference(void 0), setStagedSourceReference(after, void 0);
149
169
  else if (options.sourceFile) {
150
170
  const newRef = buildSourceReference(options);
151
- newRef && (elem.setSourceReference(newRef), after.sourceReference = newRef);
171
+ newRef && (elem.setSourceReference(newRef), setStagedSourceReference(after, newRef));
152
172
  }
153
173
  layer.updateElement(elem);
154
- }), console.log(ansis.green(`\u2713 Updated element ${ansis.bold(id)}`)), options.verbose && (console.log(ansis.dim(` Layer: ${layerName}`)), options.type && console.log(ansis.dim(` Type: ${options.type}`)), options.name && console.log(ansis.dim(` Name: ${options.name}`)), options.description && console.log(ansis.dim(` Description: ${options.description}`)), options.sourceFile && console.log(ansis.dim(` Source: ${options.sourceFile}`)), options.clearSourceReference && console.log(ansis.dim(" Source: cleared")));
174
+ });
175
+ const changes = {};
176
+ options.type && (changes.type = options.type), options.name && (changes.name = options.name), options.description !== void 0 && (changes.description = options.description), options.sourceFile && (changes.source = options.sourceFile), options.clearSourceReference && (changes.source = "cleared");
177
+ const details = {
178
+ elementId: id,
179
+ layer: layerName,
180
+ name: element.name,
181
+ changes,
182
+ changedFields: handler.getChangedFields(),
183
+ // The active changeset adds this element: the update was folded into that add.
184
+ ...handler.wasFoldedIntoAdd() ? { foldedIntoAdd: !0 } : {}
185
+ };
186
+ handleSuccess(`Updated ${handler.wasFoldedIntoAdd() ? "staged " : ""}element ${ansis.bold(id)}` + (handler.getChangedFields().length > 0 ? ` (${handler.getChangedFields().join(", ")})` : ""), details, { verbose: options.verbose });
155
187
  } catch (error) {
156
188
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({ code: 2, message: error.message })), handleError(error);
157
189
  } finally {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/commands/update.ts"],
4
- "sourcesContent": ["/**\n * Update an element\n */\n\nimport ansis from \"ansis\";\nimport { Model } from \"../core/model.js\";\nimport { MutationHandler } from \"../core/mutation-handler.js\";\nimport { StagingAreaManager } from \"../core/staging-area.js\";\nimport { StagedChangesetStorage } from \"../core/staged-changeset-storage.js\";\nimport { findElementLayer } from \"../utils/element-utils.js\";\nimport { CLIError, handleError, findSimilar, formatValidOptions } from \"../utils/errors.js\";\nimport { isValidNodeType, getNodeTypesForLayer, normalizeNodeType } from \"../generated/node-types.js\";\nimport { Element } from \"../core/element.js\";\nimport { Layer } from \"../core/layer.js\";\nimport { SchemaValidator } from \"../validators/schema-validator.js\";\nimport { validateSourceReferenceOptions, buildSourceReference } from \"../utils/source-reference.js\";\nimport { startSpan, endSpan } from \"../telemetry/index.js\";\n\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== \"undefined\" ? TELEMETRY_ENABLED : false;\n\nexport interface UpdateOptions {\n name?: string;\n description?: string;\n type?: string;\n attributes?: string;\n sourceFile?: string;\n sourceSymbol?: string;\n sourceProvenance?: string;\n sourceRepoRemote?: string;\n sourceRepoCommit?: string;\n clearSourceReference?: boolean;\n verbose?: boolean;\n debug?: boolean;\n}\n\n/**\n * Validate update-specific source reference options\n */\nfunction validateUpdateSourceReferenceOptions(options: UpdateOptions): void {\n const hasSourceOptions =\n options.sourceFile ||\n options.sourceSymbol ||\n options.sourceProvenance ||\n options.sourceRepoRemote ||\n options.sourceRepoCommit;\n\n if (options.clearSourceReference && hasSourceOptions) {\n throw new CLIError(\n \"Cannot use --clear-source-reference with other source reference options\",\n 1,\n [\"Specify either --clear-source-reference or other source options, not both\"]\n );\n }\n\n // Use shared validation for source reference options if any are provided\n if (hasSourceOptions) {\n validateSourceReferenceOptions(options);\n }\n}\n\nexport async function updateCommand(id: string, options: UpdateOptions): Promise<void> {\n const changedFields: string[] = [];\n if (options.name) changedFields.push(\"name\");\n if (options.description) changedFields.push(\"description\");\n if (options.type) changedFields.push(\"type\");\n if (options.attributes) changedFields.push(\"attributes\");\n if (options.sourceFile || options.clearSourceReference) changedFields.push(\"sourceReference\");\n\n const span = isTelemetryEnabled\n ? startSpan(\"element.update\", {\n \"element.id\": id,\n \"element.changed_fields\": changedFields.join(\",\"),\n })\n : null;\n\n try {\n // Validate source reference options\n validateUpdateSourceReferenceOptions(options);\n\n // Load model\n const model = await Model.load();\n\n // Find element\n const layerName = await findElementLayer(model, id);\n if (!layerName) {\n // Not in committed model \u2014 check active changeset for a staged ADD\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const storage = new StagedChangesetStorage(model.rootPath);\n const activeId = await stagingManager.getActiveId();\n\n if (activeId) {\n const changeset = await storage.load(activeId);\n if (changeset) {\n const addChange = changeset.changes.find(\n (c) => c.type === \"add\" && c.elementId === id\n );\n if (addChange && addChange.after) {\n const hasUpdates =\n options.name ||\n options.description !== undefined ||\n options.attributes ||\n options.sourceFile ||\n options.clearSourceReference ||\n options.type;\n\n if (!hasUpdates) {\n console.log(ansis.yellow(\"No fields specified for update\"));\n return;\n }\n\n const after: Record<string, unknown> = { ...addChange.after };\n\n if (options.type) {\n const stagedLayerName = addChange.layerName;\n if (!isValidNodeType(stagedLayerName, options.type)) {\n const validNodeTypes = getNodeTypesForLayer(stagedLayerName);\n const typeNames = validNodeTypes.map((t) => t.type).sort();\n const similar = findSimilar(options.type, typeNames, 3);\n const suggestions: string[] = [`Valid types for ${stagedLayerName}: ${formatValidOptions(typeNames)}`];\n if (similar.length > 0) suggestions.unshift(`Did you mean: ${similar.join(\" or \")}?`);\n throw new CLIError(`Invalid element type \"${options.type}\" for layer \"${stagedLayerName}\"`, 1, suggestions);\n }\n const resolvedNewType = normalizeNodeType(stagedLayerName, options.type);\n after.type = resolvedNewType;\n after.spec_node_id = `${stagedLayerName}.${resolvedNewType}`;\n }\n if (options.name) after.name = options.name;\n if (options.description !== undefined) {\n after.description = options.description || undefined;\n }\n if (options.attributes) {\n try {\n const parsed = JSON.parse(options.attributes);\n after.attributes = parsed;\n } catch {\n throw new CLIError(\"Invalid JSON in --attributes\", 1, [\n \"Ensure your JSON is valid and properly formatted\",\n ]);\n }\n }\n if (options.clearSourceReference) {\n delete after.source_reference;\n } else if (options.sourceFile) {\n const newRef = buildSourceReference(options);\n if (newRef) after.source_reference = newRef;\n }\n\n // Validate schema if type or attributes changed in staged element\n if (options.type || options.attributes) {\n const stagedLayerName = addChange.layerName;\n const tempElem = Element.fromSpecNode({\n id: String(after.id ?? addChange.elementId ?? \"staged\"),\n path: String(after.path ?? addChange.elementId ?? \"\"),\n spec_node_id: String(after.spec_node_id ?? \"\"),\n type: String(after.type ?? \"\"),\n layer_id: String(after.layer_id ?? stagedLayerName),\n name: String(after.name ?? \"\"),\n attributes: (after.attributes as Record<string, unknown>) || {},\n });\n const schemaValidator = new SchemaValidator();\n const tempLayer = new Layer(stagedLayerName);\n tempLayer.addElement(tempElem);\n const attrValidation = await schemaValidator.validateLayer(tempLayer);\n if (!attrValidation.isValid()) {\n const errorMessages = attrValidation.errors\n .map((e) => ` ${e.message}`)\n .join(\"\\n\");\n throw new CLIError(\n `Updated attributes fail schema validation:\\n${errorMessages}`,\n 1,\n [\n options.type\n ? `Incompatible attributes must be manually cleaned up before changing type. Run \"dr schema ${stagedLayerName} ${after.type}\" to see the required attributes`\n : `Run \"dr schema ${stagedLayerName} ${after.type}\" to see the required attributes`,\n ]\n );\n }\n }\n\n await storage.updateChange(activeId, id, {\n type: addChange.type,\n elementId: addChange.elementId,\n layerName: addChange.layerName,\n before: addChange.before,\n after,\n });\n\n console.log(ansis.green(`\u2713 Updated staged element ${ansis.bold(id)}`));\n return;\n }\n }\n }\n\n throw new CLIError(`Element ${id} not found`, 1);\n }\n\n const layer = await model.getLayer(layerName);\n if (!layer) {\n throw new CLIError(`Layer ${layerName} not found`, 1);\n }\n\n const element = layer.getElement(id);\n if (!element) {\n throw new CLIError(`Element ${id} not found`, 1);\n }\n\n // Validate that at least one field is specified\n const hasUpdates =\n options.name ||\n options.description !== undefined ||\n options.type ||\n options.attributes ||\n options.sourceFile ||\n options.clearSourceReference;\n\n if (!hasUpdates) {\n console.log(ansis.yellow(\"No fields specified for update\"));\n return;\n }\n\n // Single unified mutation handler for update\n const handler = new MutationHandler(model, id, layerName);\n\n // Execute update through unified path (handles staging and base model consistently)\n // The mutator function applies all updates in a single pass with validated JSON parsing\n await handler.executeUpdate(element, async (elem, after) => {\n // Resolve new type (validate name only \u2014 don't mutate live elem yet)\n let resolvedNewType: string | undefined;\n if (options.type) {\n if (!isValidNodeType(layerName, options.type)) {\n const validNodeTypes = getNodeTypesForLayer(layerName);\n const typeNames = validNodeTypes.map((t) => t.type).sort();\n const similar = findSimilar(options.type, typeNames, 3);\n const suggestions: string[] = [`Valid types for ${layerName}: ${formatValidOptions(typeNames)}`];\n if (similar.length > 0) suggestions.unshift(`Did you mean: ${similar.join(\" or \")}?`);\n throw new CLIError(`Invalid element type \"${options.type}\" for layer \"${layerName}\"`, 1, suggestions);\n }\n resolvedNewType = normalizeNodeType(layerName, options.type);\n }\n\n // Parse attributes (don't mutate yet)\n let parsedAttributes: Record<string, unknown> | undefined;\n if (options.attributes) {\n try {\n parsedAttributes = JSON.parse(options.attributes) as Record<string, unknown>;\n } catch (e) {\n throw new CLIError(\"Invalid JSON in --attributes\", 1, [\n \"Ensure your JSON is valid and properly formatted\",\n ]);\n }\n }\n\n // Validate against schema using a temp element BEFORE mutating the live elem\n if (resolvedNewType || parsedAttributes) {\n const candidateType = resolvedNewType ?? elem.type;\n const tempElem = new Element({\n ...elem.toJSON(),\n type: candidateType,\n spec_node_id: `${layerName}.${candidateType}`,\n attributes: parsedAttributes ?? elem.attributes,\n });\n const schemaValidator = new SchemaValidator();\n const tempLayer = new Layer(layerName);\n tempLayer.addElement(tempElem);\n const attrValidation = await schemaValidator.validateLayer(tempLayer);\n if (!attrValidation.isValid()) {\n const errorMessages = attrValidation.errors\n .map((e) => ` ${e.message}`)\n .join(\"\\n\");\n throw new CLIError(\n `Updated attributes fail schema validation:\\n${errorMessages}`,\n 1,\n [\n resolvedNewType\n ? `Incompatible attributes must be manually cleaned up before changing type. Run \"dr schema ${layerName} ${candidateType}\" to see the required attributes`\n : `Run \"dr schema ${layerName} ${elem.type}\" to see the required attributes`,\n ]\n );\n }\n }\n\n // Validation passed \u2014 apply all mutations to live element\n if (resolvedNewType) {\n elem.type = resolvedNewType;\n after.type = resolvedNewType;\n elem.spec_node_id = `${layerName}.${resolvedNewType}`;\n after.spec_node_id = `${layerName}.${resolvedNewType}`;\n }\n\n if (options.name) {\n elem.name = options.name;\n after.name = options.name;\n }\n\n if (options.description !== undefined) {\n elem.description = options.description || undefined;\n after.description = options.description || undefined;\n }\n\n if (parsedAttributes) {\n elem.attributes = parsedAttributes;\n after.attributes = parsedAttributes;\n }\n\n if (options.clearSourceReference) {\n elem.setSourceReference(undefined);\n after.sourceReference = undefined;\n } else if (options.sourceFile) {\n const newRef = buildSourceReference(options);\n if (newRef) {\n elem.setSourceReference(newRef);\n after.sourceReference = newRef;\n }\n }\n\n // Update element in layer graph to persist mutations\n layer.updateElement(elem);\n });\n\n console.log(ansis.green(`\u2713 Updated element ${ansis.bold(id)}`));\n if (options.verbose) {\n console.log(ansis.dim(` Layer: ${layerName}`));\n if (options.type) {\n console.log(ansis.dim(` Type: ${options.type}`));\n }\n if (options.name) {\n console.log(ansis.dim(` Name: ${options.name}`));\n }\n if (options.description) {\n console.log(ansis.dim(` Description: ${options.description}`));\n }\n if (options.sourceFile) {\n console.log(ansis.dim(` Source: ${options.sourceFile}`));\n }\n if (options.clearSourceReference) {\n console.log(ansis.dim(` Source: cleared`));\n }\n }\n } catch (error) {\n if (isTelemetryEnabled && span) {\n (span as any).recordException(error as Error);\n (span as any).setStatus({ code: 2, message: (error as Error).message });\n }\n handleError(error);\n } finally {\n if (isTelemetryEnabled) {\n endSpan(span);\n }\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Update an element\n */\n\nimport ansis from \"ansis\";\nimport { Model } from \"../core/model.js\";\nimport { MutationHandler } from \"../core/mutation-handler.js\";\nimport { setStagedSourceReference } from \"../core/staged-source-reference.js\";\nimport { StagingAreaManager } from \"../core/staging-area.js\";\nimport { StagedChangesetStorage } from \"../core/staged-changeset-storage.js\";\nimport { changedFields as snapshotChangedFields } from \"../core/changeset-summary.js\";\nimport { findElementLayer } from \"../utils/element-utils.js\";\nimport { CLIError, handleError, handleSuccess, handleInfo, handleWarning, findSimilar, formatValidOptions } from \"../utils/errors.js\";\nimport { isValidNodeType, getNodeTypesForLayer, normalizeNodeType } from \"../generated/node-types.js\";\nimport { Element } from \"../core/element.js\";\nimport { Layer } from \"../core/layer.js\";\nimport { SchemaValidator, suggestNodeTypes } from \"../validators/schema-validator.js\";\nimport { validateSourceReferenceOptions, buildSourceReference } from \"../utils/source-reference.js\";\nimport { schemaLookupHint, undefinedTypeWarning } from \"../utils/error-hints.js\";\nimport { effectiveAttributePatch, parseJsonObjectOption, resolveAttributeUpdate } from \"../utils/attribute-patch.js\";\n\n/**\n * When the element's type (after any requested type change) is one the spec does not define, the\n * warning and type-change hint to give instead of refusing the update; undefined when the type is\n * valid.\n */\nfunction undefinedTypeCheck(\n layer: string,\n elementId: string,\n type: string\n): { message: string; hint: string } | undefined {\n if (isValidNodeType(layer, type)) return undefined;\n return undefinedTypeWarning(\"cli\", layer, elementId, type, suggestNodeTypes(layer, type));\n}\nimport { startSpan, endSpan } from \"../telemetry/index.js\";\n\ndeclare const TELEMETRY_ENABLED: boolean | undefined;\nconst isTelemetryEnabled = typeof TELEMETRY_ENABLED !== \"undefined\" ? TELEMETRY_ENABLED : false;\n\nexport interface UpdateOptions {\n model?: string;\n name?: string;\n description?: string;\n type?: string;\n attributes?: string;\n /** JSON object merged into the element's current attributes; a null value removes a key. */\n attributePatch?: string;\n sourceFile?: string;\n sourceSymbol?: string;\n sourceProvenance?: string;\n sourceRepoRemote?: string;\n sourceRepoCommit?: string;\n clearSourceReference?: boolean;\n verbose?: boolean;\n debug?: boolean;\n}\n\n/**\n * Validate update-specific source reference options\n */\nfunction validateUpdateSourceReferenceOptions(options: UpdateOptions): void {\n const hasSourceOptions =\n options.sourceFile ||\n options.sourceSymbol ||\n options.sourceProvenance ||\n options.sourceRepoRemote ||\n options.sourceRepoCommit;\n\n if (options.clearSourceReference && hasSourceOptions) {\n throw new CLIError(\n \"Cannot use --clear-source-reference with other source reference options\",\n 1,\n [\"Specify either --clear-source-reference or other source options, not both\"]\n );\n }\n\n // Use shared validation for source reference options if any are provided\n if (hasSourceOptions) {\n validateSourceReferenceOptions(options);\n }\n}\n\nexport async function updateCommand(id: string, options: UpdateOptions): Promise<void> {\n const changedFields: string[] = [];\n if (options.name) changedFields.push(\"name\");\n if (options.description) changedFields.push(\"description\");\n if (options.type) changedFields.push(\"type\");\n if (options.attributes || options.attributePatch) changedFields.push(\"attributes\");\n if (options.sourceFile || options.clearSourceReference) changedFields.push(\"sourceReference\");\n\n const span = isTelemetryEnabled\n ? startSpan(\"element.update\", {\n \"element.id\": id,\n \"element.changed_fields\": changedFields.join(\",\"),\n })\n : null;\n\n try {\n // Validate source reference options\n validateUpdateSourceReferenceOptions(options);\n\n // --attribute-patch must be a JSON object, and cannot be combined with --attributes.\n const parsedPatch =\n options.attributePatch !== undefined ? parseJsonObjectOption(options.attributePatch, \"--attribute-patch\") : undefined;\n const attributeFlags = { attributes: \"--attributes\", attributePatch: \"--attribute-patch\" };\n if (options.attributes !== undefined && parsedPatch !== undefined) {\n resolveAttributeUpdate(undefined, { attributes: {}, attributePatch: parsedPatch }, attributeFlags);\n }\n // An empty patch names no key: it is not an update.\n const attributePatch = effectiveAttributePatch(parsedPatch);\n\n // Load model\n const model = await Model.load(options.model);\n\n // Find element\n const layerName = await findElementLayer(model, id);\n if (!layerName) {\n // Not in committed model \u2014 check active changeset for a staged ADD\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const storage = new StagedChangesetStorage(model.rootPath);\n const activeId = await stagingManager.getActiveId();\n\n if (activeId) {\n const changeset = await storage.load(activeId);\n if (changeset) {\n const addChange = changeset.changes.find(\n (c) => c.type === \"add\" && c.elementId === id\n );\n if (addChange && addChange.after) {\n const hasUpdates =\n options.name ||\n options.description !== undefined ||\n options.attributes ||\n attributePatch ||\n options.sourceFile ||\n options.clearSourceReference ||\n options.type;\n\n if (!hasUpdates) {\n handleInfo(ansis.yellow(\"No fields specified for update\"));\n return;\n }\n\n const after: Record<string, unknown> = { ...addChange.after };\n\n if (options.type) {\n const stagedLayerName = addChange.layerName;\n if (!isValidNodeType(stagedLayerName, options.type)) {\n const validNodeTypes = getNodeTypesForLayer(stagedLayerName);\n const typeNames = validNodeTypes.map((t) => t.type).sort();\n const similar = findSimilar(options.type, typeNames, 3);\n const suggestions: string[] = [`Valid types for ${stagedLayerName}: ${formatValidOptions(typeNames)}`];\n if (similar.length > 0) suggestions.unshift(`Did you mean: ${similar.join(\" or \")}?`);\n throw new CLIError(`Invalid element type \"${options.type}\" for layer \"${stagedLayerName}\"`, 1, suggestions);\n }\n const resolvedNewType = normalizeNodeType(stagedLayerName, options.type);\n after.type = resolvedNewType;\n after.spec_node_id = `${stagedLayerName}.${resolvedNewType}`;\n }\n if (options.name) after.name = options.name;\n if (options.description !== undefined) {\n after.description = options.description || undefined;\n }\n if (options.attributes) {\n try {\n const parsed = JSON.parse(options.attributes);\n after.attributes = parsed;\n } catch {\n throw new CLIError(\"Invalid JSON in --attributes\", 1, [\n \"Ensure your JSON is valid and properly formatted\",\n ]);\n }\n } else if (attributePatch) {\n after.attributes = resolveAttributeUpdate(\n after.attributes as Record<string, unknown> | undefined,\n { attributePatch },\n attributeFlags\n );\n }\n if (options.clearSourceReference) {\n setStagedSourceReference(after, undefined);\n } else if (options.sourceFile) {\n const newRef = buildSourceReference(options);\n if (newRef) setStagedSourceReference(after, newRef);\n }\n\n // Validate schema if type or attributes changed in staged element\n if (options.type || options.attributes || attributePatch) {\n const stagedLayerName = addChange.layerName;\n const tempElem = Element.fromSpecNode({\n id: String(after.id ?? addChange.elementId ?? \"staged\"),\n path: String(after.path ?? addChange.elementId ?? \"\"),\n spec_node_id: String(after.spec_node_id ?? \"\"),\n type: String(after.type ?? \"\"),\n layer_id: String(after.layer_id ?? stagedLayerName),\n name: String(after.name ?? \"\"),\n attributes: (after.attributes as Record<string, unknown>) || {},\n });\n const schemaValidator = new SchemaValidator();\n const tempLayer = new Layer(stagedLayerName);\n tempLayer.addElement(tempElem);\n const attrValidation = await schemaValidator.validateLayer(tempLayer);\n const undefinedTypeHint = undefinedTypeCheck(stagedLayerName, id, String(after.type ?? \"\"));\n const blocking = undefinedTypeHint\n ? attrValidation.errors.filter((e) => e.location !== \"/type\")\n : attrValidation.errors;\n if (blocking.length > 0) {\n const errorMessages = blocking\n .map((e) => ` ${e.message}`)\n .join(\"\\n\");\n throw new CLIError(\n `Updated attributes fail schema validation:\\n${errorMessages}`,\n 1,\n [\n undefinedTypeHint\n ? undefinedTypeHint.hint\n : (options.type\n ? \"Incompatible attributes must be manually cleaned up before changing type. \"\n : \"\") + schemaLookupHint(\"cli\", stagedLayerName, String(after.type)),\n ]\n );\n }\n if (undefinedTypeHint) handleWarning(undefinedTypeHint.message, [undefinedTypeHint.hint]);\n }\n\n await storage.updateChange(activeId, id, {\n type: addChange.type,\n elementId: addChange.elementId,\n layerName: addChange.layerName,\n before: addChange.before,\n after,\n });\n\n handleSuccess(`Updated staged element ${ansis.bold(id)}`, {\n elementId: id,\n layer: addChange.layerName,\n changesetStatus: \"staged\",\n changedFields: snapshotChangedFields(addChange.after, after),\n }, { verbose: options.verbose });\n return;\n }\n }\n }\n\n throw new CLIError(`Element ${id} not found`, 1);\n }\n\n const layer = await model.getLayer(layerName);\n if (!layer) {\n throw new CLIError(`Layer ${layerName} not found`, 1);\n }\n\n const element = layer.getElement(id);\n if (!element) {\n throw new CLIError(`Element ${id} not found`, 1);\n }\n\n // Validate that at least one field is specified\n const hasUpdates =\n options.name ||\n options.description !== undefined ||\n options.type ||\n options.attributes ||\n attributePatch ||\n options.sourceFile ||\n options.clearSourceReference;\n\n if (!hasUpdates) {\n handleInfo(ansis.yellow(\"No fields specified for update\"));\n return;\n }\n\n // Single unified mutation handler for update\n const handler = new MutationHandler(model, id, layerName);\n\n // Execute update through unified path (handles staging and base model consistently)\n // The mutator function applies all updates in a single pass with validated JSON parsing\n await handler.executeUpdate(element, async (elem, after) => {\n // Resolve new type (validate name only \u2014 don't mutate live elem yet)\n let resolvedNewType: string | undefined;\n if (options.type) {\n if (!isValidNodeType(layerName, options.type)) {\n const validNodeTypes = getNodeTypesForLayer(layerName);\n const typeNames = validNodeTypes.map((t) => t.type).sort();\n const similar = findSimilar(options.type, typeNames, 3);\n const suggestions: string[] = [`Valid types for ${layerName}: ${formatValidOptions(typeNames)}`];\n if (similar.length > 0) suggestions.unshift(`Did you mean: ${similar.join(\" or \")}?`);\n throw new CLIError(`Invalid element type \"${options.type}\" for layer \"${layerName}\"`, 1, suggestions);\n }\n resolvedNewType = normalizeNodeType(layerName, options.type);\n }\n\n // Parse attributes (don't mutate yet)\n let parsedAttributes: Record<string, unknown> | undefined;\n if (options.attributes) {\n try {\n parsedAttributes = JSON.parse(options.attributes) as Record<string, unknown>;\n } catch (e) {\n throw new CLIError(\"Invalid JSON in --attributes\", 1, [\n \"Ensure your JSON is valid and properly formatted\",\n ]);\n }\n } else if (attributePatch) {\n // The element is the projected one when a changeset is active, so this merges over staged values.\n parsedAttributes = resolveAttributeUpdate(elem.attributes, { attributePatch }, attributeFlags);\n }\n\n // Validate against schema using a temp element BEFORE mutating the live elem\n if (resolvedNewType || parsedAttributes) {\n const candidateType = resolvedNewType ?? elem.type;\n const tempElem = new Element({\n ...elem.toJSON(),\n type: candidateType,\n spec_node_id: `${layerName}.${candidateType}`,\n attributes: parsedAttributes ?? elem.attributes,\n });\n const schemaValidator = new SchemaValidator();\n const tempLayer = new Layer(layerName);\n tempLayer.addElement(tempElem);\n const attrValidation = await schemaValidator.validateLayer(tempLayer);\n const undefinedTypeHint = undefinedTypeCheck(layerName, id, candidateType);\n const blocking = undefinedTypeHint\n ? attrValidation.errors.filter((e) => e.location !== \"/type\")\n : attrValidation.errors;\n if (blocking.length > 0) {\n const errorMessages = blocking\n .map((e) => ` ${e.message}`)\n .join(\"\\n\");\n throw new CLIError(\n `Updated attributes fail schema validation:\\n${errorMessages}`,\n 1,\n [\n undefinedTypeHint\n ? undefinedTypeHint.hint\n : resolvedNewType\n ? \"Incompatible attributes must be manually cleaned up before changing type. \" +\n schemaLookupHint(\"cli\", layerName, candidateType)\n : schemaLookupHint(\"cli\", layerName, elem.type),\n ]\n );\n }\n if (undefinedTypeHint) handleWarning(undefinedTypeHint.message, [undefinedTypeHint.hint]);\n }\n\n // Validation passed \u2014 apply all mutations to live element\n if (resolvedNewType) {\n elem.type = resolvedNewType;\n after.type = resolvedNewType;\n elem.spec_node_id = `${layerName}.${resolvedNewType}`;\n after.spec_node_id = `${layerName}.${resolvedNewType}`;\n }\n\n if (options.name) {\n elem.name = options.name;\n after.name = options.name;\n }\n\n if (options.description !== undefined) {\n elem.description = options.description || undefined;\n after.description = options.description || undefined;\n }\n\n if (parsedAttributes) {\n elem.attributes = parsedAttributes;\n after.attributes = parsedAttributes;\n }\n\n if (options.clearSourceReference) {\n elem.setSourceReference(undefined);\n setStagedSourceReference(after, undefined);\n } else if (options.sourceFile) {\n const newRef = buildSourceReference(options);\n if (newRef) {\n elem.setSourceReference(newRef);\n setStagedSourceReference(after, newRef);\n }\n }\n\n // Update element in layer graph to persist mutations\n layer.updateElement(elem);\n });\n\n const changes: Record<string, unknown> = {};\n if (options.type) changes.type = options.type;\n if (options.name) changes.name = options.name;\n if (options.description !== undefined) changes.description = options.description;\n if (options.sourceFile) changes.source = options.sourceFile;\n if (options.clearSourceReference) changes.source = \"cleared\";\n\n const details: Record<string, unknown> = {\n elementId: id,\n layer: layerName,\n name: element.name,\n changes,\n changedFields: handler.getChangedFields(),\n // The active changeset adds this element: the update was folded into that add.\n ...(handler.wasFoldedIntoAdd() ? { foldedIntoAdd: true } : {}),\n };\n\n handleSuccess(\n `Updated ${handler.wasFoldedIntoAdd() ? \"staged \" : \"\"}element ${ansis.bold(id)}` +\n (handler.getChangedFields().length > 0 ? ` (${handler.getChangedFields().join(\", \")})` : \"\"),\n details,\n { verbose: options.verbose }\n );\n } catch (error) {\n if (isTelemetryEnabled && span) {\n (span as any).recordException(error as Error);\n (span as any).setStatus({ code: 2, message: (error as Error).message });\n }\n handleError(error);\n } finally {\n if (isTelemetryEnabled) {\n endSpan(span);\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }