@documentation-robotics/cli 0.2.0 → 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 (269) hide show
  1. package/README.md +36 -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/audit/relationships/ai/prompts.js +10 -10
  34. package/dist/audit/relationships/ai/prompts.js.map +2 -2
  35. package/dist/audit/relationships/analysis/layer-templates.js +52 -52
  36. package/dist/audit/relationships/analysis/layer-templates.js.map +1 -1
  37. package/dist/cli.js +12 -2
  38. package/dist/cli.js.map +2 -2
  39. package/dist/coding-agents/default-permissions.js +31 -1
  40. package/dist/coding-agents/default-permissions.js.map +2 -2
  41. package/dist/coding-agents/drbot-mcp.js +167 -0
  42. package/dist/coding-agents/drbot-mcp.js.map +7 -0
  43. package/dist/commands/add.js +3 -2
  44. package/dist/commands/add.js.map +2 -2
  45. package/dist/commands/analyzer.js +117 -14
  46. package/dist/commands/analyzer.js.map +2 -2
  47. package/dist/commands/changeset-verify.js +55 -0
  48. package/dist/commands/changeset-verify.js.map +7 -0
  49. package/dist/commands/changeset.js +43 -22
  50. package/dist/commands/changeset.js.map +2 -2
  51. package/dist/commands/delete.js +10 -4
  52. package/dist/commands/delete.js.map +2 -2
  53. package/dist/commands/farm.js +176 -60
  54. package/dist/commands/farm.js.map +2 -2
  55. package/dist/commands/mcp.js +19 -4
  56. package/dist/commands/mcp.js.map +2 -2
  57. package/dist/commands/relationship.js +207 -26
  58. package/dist/commands/relationship.js.map +2 -2
  59. package/dist/commands/update.js +42 -23
  60. package/dist/commands/update.js.map +2 -2
  61. package/dist/commands/upgrade.js +99 -11
  62. package/dist/commands/upgrade.js.map +3 -3
  63. package/dist/commands/version.js +1 -1
  64. package/dist/commands/visualize.js +4 -3
  65. package/dist/commands/visualize.js.map +2 -2
  66. package/dist/core/catalog-migration.js +33 -0
  67. package/dist/core/catalog-migration.js.map +7 -0
  68. package/dist/core/changeset-analysis.js +421 -0
  69. package/dist/core/changeset-analysis.js.map +7 -0
  70. package/dist/core/changeset-base-index.js +153 -0
  71. package/dist/core/changeset-base-index.js.map +7 -0
  72. package/dist/core/changeset-brief-delta.js +102 -0
  73. package/dist/core/changeset-brief-delta.js.map +7 -0
  74. package/dist/core/changeset-graph.js +281 -0
  75. package/dist/core/changeset-graph.js.map +7 -0
  76. package/dist/core/changeset-only-guard.js +32 -0
  77. package/dist/core/changeset-only-guard.js.map +7 -0
  78. package/dist/core/changeset-summary.js +68 -0
  79. package/dist/core/changeset-summary.js.map +7 -0
  80. package/dist/core/changeset-validator.js +66 -20
  81. package/dist/core/changeset-validator.js.map +2 -2
  82. package/dist/core/changeset-verify.js +518 -0
  83. package/dist/core/changeset-verify.js.map +7 -0
  84. package/dist/core/changeset.js +56 -9
  85. package/dist/core/changeset.js.map +2 -2
  86. package/dist/core/element-type-migration.js +145 -0
  87. package/dist/core/element-type-migration.js.map +7 -0
  88. package/dist/core/farm-manifest.js +12 -6
  89. package/dist/core/farm-manifest.js.map +2 -2
  90. package/dist/core/farm-sync-engine.js +1 -1
  91. package/dist/core/farm-sync-engine.js.map +2 -2
  92. package/dist/core/farm-sync-state.js +10 -2
  93. package/dist/core/farm-sync-state.js.map +2 -2
  94. package/dist/core/migration-registry.js +75 -46
  95. package/dist/core/migration-registry.js.map +2 -2
  96. package/dist/core/model-upgrade.js +102 -0
  97. package/dist/core/model-upgrade.js.map +7 -0
  98. package/dist/core/model.js +82 -30
  99. package/dist/core/model.js.map +2 -2
  100. package/dist/core/mutation-handler.js +71 -6
  101. package/dist/core/mutation-handler.js.map +2 -2
  102. package/dist/core/relationship-migration-table.js +6639 -0
  103. package/dist/core/relationship-migration-table.js.map +7 -0
  104. package/dist/core/relationship-migration.js +272 -0
  105. package/dist/core/relationship-migration.js.map +7 -0
  106. package/dist/core/relationship-prune.js +49 -0
  107. package/dist/core/relationship-prune.js.map +7 -0
  108. package/dist/core/relationship-staging.js +68 -0
  109. package/dist/core/relationship-staging.js.map +7 -0
  110. package/dist/core/relationships.js +26 -4
  111. package/dist/core/relationships.js.map +2 -2
  112. package/dist/core/report-data-model.js +7 -13
  113. package/dist/core/report-data-model.js.map +2 -2
  114. package/dist/core/staged-changeset-storage.js +64 -17
  115. package/dist/core/staged-changeset-storage.js.map +2 -2
  116. package/dist/core/staged-source-reference.js +28 -0
  117. package/dist/core/staged-source-reference.js.map +7 -0
  118. package/dist/core/staging-area.js +83 -18
  119. package/dist/core/staging-area.js.map +2 -2
  120. package/dist/core/virtual-projection.js +13 -5
  121. package/dist/core/virtual-projection.js.map +2 -2
  122. package/dist/export/archimate-exporter.js +1 -0
  123. package/dist/export/archimate-exporter.js.map +2 -2
  124. package/dist/generated/compiled-validators.js +2 -2
  125. package/dist/generated/compiled-validators.js.map +2 -2
  126. package/dist/generated/layer-registry.js +16 -16
  127. package/dist/generated/layer-registry.js.map +2 -2
  128. package/dist/generated/node-types.js +186 -168
  129. package/dist/generated/node-types.js.map +2 -2
  130. package/dist/generated/relationship-index.js +2236 -7790
  131. package/dist/generated/relationship-index.js.map +2 -2
  132. package/dist/integrations/claude_code/agents/dr-architect.md +16 -3
  133. package/dist/integrations/claude_code/agents/dr-extractor.md +1 -1
  134. package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
  135. package/dist/integrations/claude_code/commands/dr-map.md +13 -0
  136. package/dist/integrations/claude_code/commands/dr-plan.md +40 -0
  137. package/dist/integrations/claude_code/commands/dr-relate.md +106 -96
  138. package/dist/integrations/claude_code/commands/dr-verify.md +45 -2
  139. package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +14 -0
  140. package/dist/integrations/claude_code/docs/MCP_SERVER.md +26 -2
  141. package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
  142. package/dist/integrations/claude_code/docs/README.md +48 -1
  143. package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +93 -72
  144. package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +163 -126
  145. package/dist/integrations/claude_code/skills/dr_03_product_layer/SKILL.md +161 -126
  146. package/dist/integrations/claude_code/skills/dr_04_security_layer/SKILL.md +153 -133
  147. package/dist/integrations/claude_code/skills/dr_05_application_layer/SKILL.md +129 -100
  148. package/dist/integrations/claude_code/skills/dr_06_technology_layer/SKILL.md +111 -94
  149. package/dist/integrations/claude_code/skills/dr_07_api_layer/SKILL.md +143 -157
  150. package/dist/integrations/claude_code/skills/dr_08_data_model_layer/SKILL.md +117 -33
  151. package/dist/integrations/claude_code/skills/dr_09_dataset_layer/SKILL.md +74 -25
  152. package/dist/integrations/claude_code/skills/dr_10_ux_layer/SKILL.md +88 -12
  153. package/dist/integrations/claude_code/skills/dr_11_navigation_layer/SKILL.md +83 -24
  154. package/dist/integrations/claude_code/skills/dr_12_apm_layer/SKILL.md +57 -12
  155. package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +92 -15
  156. package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +119 -0
  157. package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +3 -0
  158. package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +1 -1
  159. package/dist/integrations/github_copilot/agents/dr-architect.md +1 -1
  160. package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +182 -102
  161. package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +266 -148
  162. package/dist/integrations/github_copilot/skills/dr_03_product_layer/SKILL.md +547 -86
  163. package/dist/integrations/github_copilot/skills/dr_04_security_layer/SKILL.md +164 -169
  164. package/dist/integrations/github_copilot/skills/dr_05_application_layer/SKILL.md +420 -150
  165. package/dist/integrations/github_copilot/skills/dr_06_technology_layer/SKILL.md +331 -138
  166. package/dist/integrations/github_copilot/skills/dr_07_api_layer/SKILL.md +265 -201
  167. package/dist/integrations/github_copilot/skills/dr_08_data_model_layer/SKILL.md +181 -58
  168. package/dist/integrations/github_copilot/skills/dr_09_dataset_layer/SKILL.md +209 -57
  169. package/dist/integrations/github_copilot/skills/dr_10_ux_layer/SKILL.md +277 -112
  170. package/dist/integrations/github_copilot/skills/dr_11_navigation_layer/SKILL.md +219 -70
  171. package/dist/integrations/github_copilot/skills/dr_12_apm_layer/SKILL.md +189 -105
  172. package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +222 -102
  173. package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +119 -0
  174. package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +3 -0
  175. package/dist/integrations/hash-utils.js.map +2 -2
  176. package/dist/mcp/api-key-manager.js +14 -1
  177. package/dist/mcp/api-key-manager.js.map +2 -2
  178. package/dist/mcp/changeset-only.js +34 -0
  179. package/dist/mcp/changeset-only.js.map +7 -0
  180. package/dist/mcp/tool-registry.js +19 -3
  181. package/dist/mcp/tool-registry.js.map +2 -2
  182. package/dist/mcp/tools/changeset-analysis-tools.js +78 -0
  183. package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
  184. package/dist/mcp/tools/changeset-editing.js +184 -0
  185. package/dist/mcp/tools/changeset-editing.js.map +7 -0
  186. package/dist/mcp/tools/changeset-lifecycle.js +83 -0
  187. package/dist/mcp/tools/changeset-lifecycle.js.map +7 -0
  188. package/dist/mcp/tools/changeset-shared.js +31 -0
  189. package/dist/mcp/tools/changeset-shared.js.map +7 -0
  190. package/dist/mcp/tools/changeset-show.js +17 -1
  191. package/dist/mcp/tools/changeset-show.js.map +2 -2
  192. package/dist/mcp/tools/changeset-verify.js +43 -0
  193. package/dist/mcp/tools/changeset-verify.js.map +7 -0
  194. package/dist/mcp/tools/index.js +19 -1
  195. package/dist/mcp/tools/index.js.map +2 -2
  196. package/dist/mcp/tools/model-add.js +6 -5
  197. package/dist/mcp/tools/model-add.js.map +2 -2
  198. package/dist/mcp/tools/model-delete.js +2 -2
  199. package/dist/mcp/tools/model-delete.js.map +2 -2
  200. package/dist/mcp/tools/model-search.js +14 -0
  201. package/dist/mcp/tools/model-search.js.map +2 -2
  202. package/dist/mcp/tools/model-show.js +29 -2
  203. package/dist/mcp/tools/model-show.js.map +2 -2
  204. package/dist/mcp/tools/model-trace.js +93 -30
  205. package/dist/mcp/tools/model-trace.js.map +2 -2
  206. package/dist/mcp/tools/model-update.js +35 -19
  207. package/dist/mcp/tools/model-update.js.map +2 -2
  208. package/dist/mcp/tools/relationship-tools.js +98 -0
  209. package/dist/mcp/tools/relationship-tools.js.map +7 -0
  210. package/dist/mcp/tools/shared.js +25 -2
  211. package/dist/mcp/tools/shared.js.map +2 -2
  212. package/dist/mcp/tools/spec-type.js +90 -0
  213. package/dist/mcp/tools/spec-type.js.map +7 -0
  214. package/dist/schemas/bundled/analyzers/cbm.json +1186 -68
  215. package/dist/schemas/bundled/analyzers/manifest.json +2 -2
  216. package/dist/schemas/bundled/api.json +1029 -1658
  217. package/dist/schemas/bundled/apm.json +499 -734
  218. package/dist/schemas/bundled/application.json +735 -371
  219. package/dist/schemas/bundled/base.json +3 -220
  220. package/dist/schemas/bundled/business.json +452 -366
  221. package/dist/schemas/bundled/data-model.json +395 -411
  222. package/dist/schemas/bundled/data-store.json +334 -558
  223. package/dist/schemas/bundled/manifest.json +18 -18
  224. package/dist/schemas/bundled/motivation.json +349 -368
  225. package/dist/schemas/bundled/navigation.json +415 -731
  226. package/dist/schemas/bundled/product.json +325 -159
  227. package/dist/schemas/bundled/security.json +864 -1232
  228. package/dist/schemas/bundled/technology.json +574 -703
  229. package/dist/schemas/bundled/testing.json +718 -1643
  230. package/dist/schemas/bundled/ux.json +739 -1352
  231. package/dist/server/schemas.js +8 -0
  232. package/dist/server/schemas.js.map +2 -2
  233. package/dist/server/server.js +218 -34
  234. package/dist/server/server.js.map +2 -2
  235. package/dist/server-entry.js +2 -1
  236. package/dist/server-entry.js.map +2 -2
  237. package/dist/telemetry/index.js +1 -1
  238. package/dist/utils/ansi-suppressor.js +6 -8
  239. package/dist/utils/ansi-suppressor.js.map +2 -2
  240. package/dist/utils/attribute-patch.js +41 -0
  241. package/dist/utils/attribute-patch.js.map +7 -0
  242. package/dist/utils/error-hints.js +29 -0
  243. package/dist/utils/error-hints.js.map +7 -0
  244. package/dist/utils/errors.js +9 -3
  245. package/dist/utils/errors.js.map +2 -2
  246. package/dist/utils/project-paths.js +26 -1
  247. package/dist/utils/project-paths.js.map +2 -2
  248. package/dist/utils/source-reference.js +14 -12
  249. package/dist/utils/source-reference.js.map +2 -2
  250. package/dist/utils/spec-version.js +2 -2
  251. package/dist/utils/spec-version.js.map +1 -1
  252. package/dist/validators/composed-reference-validator.js +5 -27
  253. package/dist/validators/composed-reference-validator.js.map +2 -2
  254. package/dist/validators/reference-validator.js +0 -7
  255. package/dist/validators/reference-validator.js.map +2 -2
  256. package/dist/validators/relationship-schema-validator.js +3 -3
  257. package/dist/validators/relationship-schema-validator.js.map +2 -2
  258. package/dist/validators/schema-validator.js +27 -9
  259. package/dist/validators/schema-validator.js.map +2 -2
  260. package/dist/validators/types.js.map +1 -1
  261. package/dist/viewer/README.md +6 -6
  262. package/dist/viewer/assets/main-CxzcuU_o.js +84 -0
  263. package/dist/viewer/assets/main-j-7ULYpm.css +1 -0
  264. package/dist/viewer/index.html +2 -2
  265. package/dist/viewer/manifest.json +10 -10
  266. package/dist/viewer/version.json +1 -1
  267. package/package.json +2 -1
  268. package/dist/viewer/assets/main-B7AOQXXX.js +0 -81
  269. package/dist/viewer/assets/main-vdrFrG7q.css +0 -1
@@ -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, handleSuccess, handleInfo, 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(options.model || process.cwd()), 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,7 +45,7 @@ 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)) {
48
+ if (!(options.name || options.description !== void 0 || options.attributes || attributePatch || options.sourceFile || options.clearSourceReference || options.type)) {
39
49
  handleInfo(ansis.yellow("No fields specified for update"));
40
50
  return;
41
51
  }
@@ -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,
@@ -94,7 +106,8 @@ ${errorMessages}`, 1, [
94
106
  }), handleSuccess(`Updated staged element ${ansis.bold(id)}`, {
95
107
  elementId: id,
96
108
  layer: addChange.layerName,
97
- changesetStatus: "staged"
109
+ changesetStatus: "staged",
110
+ changedFields: snapshotChangedFields(addChange.after, after)
98
111
  }, { verbose: options.verbose });
99
112
  return;
100
113
  }
@@ -108,11 +121,12 @@ ${errorMessages}`, 1, [
108
121
  const element = layer.getElement(id);
109
122
  if (!element)
110
123
  throw new CLIError(`Element ${id} not found`, 1);
111
- if (!(options.name || options.description !== void 0 || options.type || options.attributes || options.sourceFile || options.clearSourceReference)) {
124
+ if (!(options.name || options.description !== void 0 || options.type || options.attributes || attributePatch || options.sourceFile || options.clearSourceReference)) {
112
125
  handleInfo(ansis.yellow("No fields specified for update"));
113
126
  return;
114
127
  }
115
- 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) => {
116
130
  let resolvedNewType;
117
131
  if (options.type) {
118
132
  if (!isValidNodeType(layerName, options.type)) {
@@ -130,6 +144,7 @@ ${errorMessages}`, 1, [
130
144
  "Ensure your JSON is valid and properly formatted"
131
145
  ]);
132
146
  }
147
+ else attributePatch && (parsedAttributes = resolveAttributeUpdate(elem.attributes, { attributePatch }, attributeFlags));
133
148
  if (resolvedNewType || parsedAttributes) {
134
149
  const candidateType = resolvedNewType ?? elem.type, tempElem = new Element({
135
150
  ...elem.toJSON(),
@@ -138,21 +153,22 @@ ${errorMessages}`, 1, [
138
153
  attributes: parsedAttributes ?? elem.attributes
139
154
  }), schemaValidator = new SchemaValidator(), tempLayer = new Layer(layerName);
140
155
  tempLayer.addElement(tempElem);
141
- const attrValidation = await schemaValidator.validateLayer(tempLayer);
142
- if (!attrValidation.isValid()) {
143
- 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(`
144
159
  `);
145
160
  throw new CLIError(`Updated attributes fail schema validation:
146
161
  ${errorMessages}`, 1, [
147
- 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)
148
163
  ]);
149
164
  }
165
+ undefinedTypeHint && handleWarning(undefinedTypeHint.message, [undefinedTypeHint.hint]);
150
166
  }
151
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)
152
- elem.setSourceReference(void 0), after.sourceReference = void 0;
168
+ elem.setSourceReference(void 0), setStagedSourceReference(after, void 0);
153
169
  else if (options.sourceFile) {
154
170
  const newRef = buildSourceReference(options);
155
- newRef && (elem.setSourceReference(newRef), after.sourceReference = newRef);
171
+ newRef && (elem.setSourceReference(newRef), setStagedSourceReference(after, newRef));
156
172
  }
157
173
  layer.updateElement(elem);
158
174
  });
@@ -162,9 +178,12 @@ ${errorMessages}`, 1, [
162
178
  elementId: id,
163
179
  layer: layerName,
164
180
  name: element.name,
165
- changes
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 } : {}
166
185
  };
167
- handleSuccess(`Updated element ${ansis.bold(id)}`, details, { verbose: options.verbose });
186
+ handleSuccess(`Updated ${handler.wasFoldedIntoAdd() ? "staged " : ""}element ${ansis.bold(id)}` + (handler.getChangedFields().length > 0 ? ` (${handler.getChangedFields().join(", ")})` : ""), details, { verbose: options.verbose });
168
187
  } catch (error) {
169
188
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({ code: 2, message: error.message })), handleError(error);
170
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, handleSuccess, handleInfo, 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 model?: string;\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(options.model || process.cwd());\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 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 }\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 handleSuccess(`Updated staged element ${ansis.bold(id)}`, {\n elementId: id,\n layer: addChange.layerName,\n changesetStatus: \"staged\",\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 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 }\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 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 };\n\n handleSuccess(`Updated element ${ansis.bold(id)}`, details, { verbose: options.verbose });\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
  }
@@ -3,8 +3,11 @@ import { confirm } from "@clack/prompts";
3
3
  import { findProjectRoot, getSpecReferencePath, getModelPath } from "../utils/project-paths.js";
4
4
  import { getCliVersion, getCliBundledSpecVersion, getInstalledSpecVersion, getModelSpecVersion } from "../utils/spec-version.js";
5
5
  import { MigrationRegistry } from "../core/migration-registry.js";
6
- import { installSpecReference } from "../utils/spec-installer.js";
7
6
  import { Model } from "../core/model.js";
7
+ import { pendingCatalogMigrations } from "../core/catalog-migration.js";
8
+ import { upgradeModel } from "../core/model-upgrade.js";
9
+ import { summarizeRelationshipChanges } from "../core/relationship-migration.js";
10
+ import { installSpecReference } from "../utils/spec-installer.js";
8
11
  import { ClaudeIntegrationManager } from "../integrations/claude-manager.js";
9
12
  import { CopilotIntegrationManager } from "../integrations/copilot-manager.js";
10
13
  import { getErrorMessage } from "../utils/errors.js";
@@ -178,6 +181,9 @@ Available migrations:`));
178
181
  toVersion: targetSpecVersion,
179
182
  details: migrationDetails
180
183
  });
184
+ } else {
185
+ const catalogAction = await buildCatalogAction(projectRoot, targetSpecVersion);
186
+ catalogAction && actions.push(catalogAction);
181
187
  }
182
188
  const { actions: integrationActions, upToDate: integrationUpToDate } = await buildIntegrationActions(cliVersion, options.force ?? !1);
183
189
  if (actions.push(...integrationActions), actions.length === 0) {
@@ -259,6 +265,27 @@ async function executeSpecUpgrade(projectRoot, action) {
259
265
  endSpan(operationSpan);
260
266
  }
261
267
  }
268
+ async function buildCatalogAction(projectRoot, version) {
269
+ let pending;
270
+ try {
271
+ pending = await pendingCatalogMigrations(await Model.load(projectRoot, { lazyLoad: !1 }));
272
+ } catch (error) {
273
+ return console.log(ansis.yellow(`\u26A0 Could not check the model against the catalog: ${getErrorMessage(error)}`)), null;
274
+ }
275
+ const details = [
276
+ ...pending.elementTypes > 0 ? [`Rename ${pending.elementTypes} element(s) whose type was renamed`] : [],
277
+ ...pending.relationships > 0 ? [`Rewrite or drop ${pending.relationships} relationship(s) of retired types`] : [],
278
+ ...pending.stagedRelationships > 0 ? [`Rewrite ${pending.stagedRelationships} staged relationship change(s)`] : []
279
+ ];
280
+ return details.length === 0 ? null : {
281
+ type: "model",
282
+ description: `Apply catalog changes to the model (spec v${version})`,
283
+ fromVersion: version,
284
+ toVersion: version,
285
+ details,
286
+ catalogOnly: !0
287
+ };
288
+ }
262
289
  async function executeModelMigration(action, options) {
263
290
  const operationSpan = isTelemetryEnabled ? startSpan("upgrade.model", {
264
291
  "upgrade.model.from_version": action.fromVersion || "unknown",
@@ -269,20 +296,24 @@ async function executeModelMigration(action, options) {
269
296
  try {
270
297
  if (action.versionBumpOnly) {
271
298
  console.log(ansis.dim(`Bumping model spec version from v${action.fromVersion} to v${action.toVersion}...`));
272
- const model2 = await Model.load(process.cwd(), { lazyLoad: !0 });
273
- model2.manifest.specVersion = action.toVersion, await model2.saveManifest(), console.log(ansis.green(`\u2713 Model spec version updated to v${action.toVersion}`)), operationSpan && operationSpan.setAttribute("upgrade.model.result", "version_bumped");
299
+ const result2 = await upgradeModel(process.cwd(), {
300
+ fromVersion: action.fromVersion,
301
+ toVersion: action.toVersion,
302
+ versionBumpOnly: !0
303
+ });
304
+ console.log(ansis.green(`\u2713 Model spec version updated to v${action.toVersion}`)), printChangesetRebaseline(result2.changesets), operationSpan && (operationSpan.setAttribute("upgrade.model.result", "version_bumped"), operationSpan.setAttribute("upgrade.model.changesets_rebaselined", result2.changesets.rebaselined.length));
274
305
  return;
275
306
  }
276
- console.log(ansis.dim(`Migrating model from v${action.fromVersion} to v${action.toVersion}...`));
277
- const model = await Model.load(process.cwd(), { lazyLoad: !1 }), result = await new MigrationRegistry().applyMigrations(model, {
307
+ console.log(ansis.dim(action.catalogOnly ? `Applying catalog changes to the model (v${action.toVersion})...` : `Migrating model from v${action.fromVersion} to v${action.toVersion}...`));
308
+ const result = await upgradeModel(process.cwd(), {
278
309
  fromVersion: action.fromVersion,
279
310
  toVersion: action.toVersion,
280
- dryRun: !1,
281
- validate: !options.force
282
- });
283
- for (const applied of result.applied)
284
- console.log(ansis.green(` \u2713 ${applied.from} \u2192 ${applied.to}: ${applied.description}`)), applied.changes?.filesModified && console.log(ansis.dim(` Files modified: ${applied.changes.filesModified}`));
285
- await model.saveManifest(), await model.saveDirtyLayers(), console.log(ansis.green(`\u2713 Model migrated to v${action.toVersion}`)), operationSpan && (operationSpan.setAttribute("upgrade.model.result", "migrated"), operationSpan.setAttribute("upgrade.model.migrations_applied", result.applied.length));
311
+ validate: !options.force,
312
+ catalogOnly: action.catalogOnly
313
+ }), applied = result.migration?.applied ?? [];
314
+ for (const migration of applied)
315
+ console.log(ansis.green(` \u2713 ${migration.from} \u2192 ${migration.to}: ${migration.description}`)), migration.changes?.filesModified && console.log(ansis.dim(` Files modified: ${migration.changes.filesModified}`)), printElementTypeChanges(migration.changes?.details?.elementTypeChanges), printRelationshipChanges(migration.changes?.details?.relationshipChanges), printStagedRelationshipChanges(migration.changes?.details?.stagedRelationshipChanges);
316
+ console.log(ansis.green(action.catalogOnly ? `\u2713 Model in line with the v${action.toVersion} catalog` : `\u2713 Model migrated to v${action.toVersion}`)), printChangesetRebaseline(result.changesets), operationSpan && (operationSpan.setAttribute("upgrade.model.result", "migrated"), operationSpan.setAttribute("upgrade.model.migrations_applied", applied.length), operationSpan.setAttribute("upgrade.model.changesets_rebaselined", result.changesets.rebaselined.length));
286
317
  } catch (error) {
287
318
  throw operationSpan && (operationSpan.recordException(error), operationSpan.setStatus({
288
319
  code: 2,
@@ -293,6 +324,63 @@ async function executeModelMigration(action, options) {
293
324
  endSpan(operationSpan);
294
325
  }
295
326
  }
327
+ function printElementTypeChanges(changes) {
328
+ if (!Array.isArray(changes) || changes.length === 0)
329
+ return;
330
+ const byType = /* @__PURE__ */ new Map();
331
+ for (const c of changes) {
332
+ const key = `${c.fromType} \u2192 ${c.toType}`;
333
+ byType.set(key, (byType.get(key) ?? 0) + 1);
334
+ }
335
+ for (const [key, n] of byType)
336
+ console.log(ansis.dim(` Renamed ${n} element(s): ${key}`));
337
+ }
338
+ function printRelationshipChanges(changes) {
339
+ if (!Array.isArray(changes) || changes.length === 0)
340
+ return;
341
+ const relationshipChanges = changes;
342
+ console.log(ansis.dim(` ${summarizeRelationshipChanges(relationshipChanges)}`));
343
+ for (const change of relationshipChanges)
344
+ change.action === "dropped-duplicate" && change.after ? console.log(ansis.dim(` dropped ${formatRelationship(change.before)} (now the same as ${formatRelationship(change.after)})`)) : change.action === "dropped" && console.log(ansis.dim(` dropped ${formatRelationship(change.before)} (no replacement in the catalog)`));
345
+ }
346
+ function printStagedRelationshipChanges(changes) {
347
+ if (!Array.isArray(changes) || changes.length === 0)
348
+ return;
349
+ const byChangeset = /* @__PURE__ */ new Map();
350
+ for (const change of changes)
351
+ byChangeset.set(change.changeset, [...byChangeset.get(change.changeset) ?? [], change]);
352
+ for (const [changeset, staged] of byChangeset) {
353
+ console.log(ansis.dim(` ${summarizeRelationshipChanges(staged, `changeset ${changeset}, staged relationships`)}`));
354
+ for (const change of staged) {
355
+ if (change.action === "rewritten")
356
+ continue;
357
+ const kind = change.stagedAs === "relationship-add" ? "add" : "delete";
358
+ console.log(ansis.dim(` dropped staged ${kind} of ${formatRelationship(change.before)} (${stagedDropReason(change)})`));
359
+ }
360
+ }
361
+ }
362
+ function stagedDropReason(change) {
363
+ if (change.action === "dropped" || !change.after)
364
+ return "no replacement in the catalog";
365
+ const sameAs = `now the same as ${formatRelationship(change.after)}`;
366
+ switch (change.duplicateOf) {
367
+ case "model":
368
+ return `${sameAs}, already in the model`;
369
+ case "kept":
370
+ return `${sameAs}, which also stands for a relationship the changeset keeps`;
371
+ default:
372
+ return change.stagedAs === "relationship-add" ? `${sameAs}, which the changeset already adds` : `${sameAs}, which the changeset already deletes`;
373
+ }
374
+ }
375
+ function formatRelationship(rel) {
376
+ return `${rel.source} --[${rel.predicate}]--> ${rel.target}`;
377
+ }
378
+ function printChangesetRebaseline(result) {
379
+ const names = (refs) => refs.map((ref) => ref.name).join(", "), count = (n) => `${n} staged changeset${n === 1 ? "" : "s"}`;
380
+ result.rebaselined.length > 0 && console.log(ansis.green(`\u2713 Re-baselined ${count(result.rebaselined.length)} on the upgraded model: ${names(result.rebaselined)}`)), result.drifted.length > 0 && console.log(ansis.yellow(`\u26A0 ${count(result.drifted.length)} had drifted from the model before the upgrade and still ${result.drifted.length === 1 ? "needs" : "need"} --force to commit: ${names(result.drifted)}`));
381
+ for (const error of result.errors)
382
+ console.log(ansis.yellow(`\u26A0 ${error}`));
383
+ }
296
384
  async function executeIntegrationUpdate(label, updateFn) {
297
385
  const operationSpan = isTelemetryEnabled ? startSpan("upgrade.integration", {
298
386
  "upgrade.integration.label": label,