@documentation-robotics/cli 0.1.12 → 0.2.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 (189) hide show
  1. package/README.md +39 -1
  2. package/dist/analyzers/verify-engine.js +22 -19
  3. package/dist/analyzers/verify-engine.js.map +2 -2
  4. package/dist/cli.js +101 -27
  5. package/dist/cli.js.map +3 -3
  6. package/dist/coding-agents/agents/claude-code.js +3 -1
  7. package/dist/coding-agents/agents/claude-code.js.map +2 -2
  8. package/dist/coding-agents/claude-code-client.js +2 -1
  9. package/dist/coding-agents/claude-code-client.js.map +2 -2
  10. package/dist/coding-agents/copilot-client.js +17 -12
  11. package/dist/coding-agents/copilot-client.js.map +2 -2
  12. package/dist/coding-agents/default-permissions.js +122 -0
  13. package/dist/coding-agents/default-permissions.js.map +7 -0
  14. package/dist/commands/add.js +10 -6
  15. package/dist/commands/add.js.map +2 -2
  16. package/dist/commands/analyzer.js +18 -10
  17. package/dist/commands/analyzer.js.map +2 -2
  18. package/dist/commands/audit.js +6 -6
  19. package/dist/commands/audit.js.map +2 -2
  20. package/dist/commands/changeset.js +238 -145
  21. package/dist/commands/changeset.js.map +2 -2
  22. package/dist/commands/delete.js +45 -18
  23. package/dist/commands/delete.js.map +3 -3
  24. package/dist/commands/element.js +3 -2
  25. package/dist/commands/element.js.map +2 -2
  26. package/dist/commands/farm.js +657 -0
  27. package/dist/commands/farm.js.map +7 -0
  28. package/dist/commands/init.js +11 -1
  29. package/dist/commands/init.js.map +2 -2
  30. package/dist/commands/mcp.js +107 -0
  31. package/dist/commands/mcp.js.map +7 -0
  32. package/dist/commands/relationship.js +53 -30
  33. package/dist/commands/relationship.js.map +2 -2
  34. package/dist/commands/reports.js +1 -1
  35. package/dist/commands/reports.js.map +2 -2
  36. package/dist/commands/update.js +19 -6
  37. package/dist/commands/update.js.map +2 -2
  38. package/dist/commands/validate.js +41 -3
  39. package/dist/commands/validate.js.map +2 -2
  40. package/dist/commands/version.js +2 -2
  41. package/dist/commands/version.js.map +2 -2
  42. package/dist/config.js +83 -0
  43. package/dist/config.js.map +7 -0
  44. package/dist/core/annotation-store.js +138 -0
  45. package/dist/core/annotation-store.js.map +7 -0
  46. package/dist/core/farm-manifest.js +134 -0
  47. package/dist/core/farm-manifest.js.map +7 -0
  48. package/dist/core/farm-sync-engine.js +346 -0
  49. package/dist/core/farm-sync-engine.js.map +7 -0
  50. package/dist/core/farm-sync-state.js +159 -0
  51. package/dist/core/farm-sync-state.js.map +7 -0
  52. package/dist/core/manifest.js +6 -3
  53. package/dist/core/manifest.js.map +2 -2
  54. package/dist/core/migration-registry.js +55 -1
  55. package/dist/core/migration-registry.js.map +2 -2
  56. package/dist/core/model.js +177 -16
  57. package/dist/core/model.js.map +3 -3
  58. package/dist/core/virtual-projection.js +1 -0
  59. package/dist/core/virtual-projection.js.map +2 -2
  60. package/dist/generated/node-types.js +1 -1
  61. package/dist/generated/node-types.js.map +2 -2
  62. package/dist/generated/relationship-index.js +45 -9
  63. package/dist/generated/relationship-index.js.map +2 -2
  64. package/dist/integrations/claude_code/docs/MCP_SERVER.md +55 -0
  65. package/dist/integrations/claude_code/docs/README.md +4 -0
  66. package/dist/mcp/api-key-manager.js +98 -0
  67. package/dist/mcp/api-key-manager.js.map +7 -0
  68. package/dist/mcp/http-transport.js +176 -0
  69. package/dist/mcp/http-transport.js.map +7 -0
  70. package/dist/mcp/resource-registry.js +97 -0
  71. package/dist/mcp/resource-registry.js.map +7 -0
  72. package/dist/mcp/tool-registry.js +44 -0
  73. package/dist/mcp/tool-registry.js.map +7 -0
  74. package/dist/mcp/tools/annotation-create.js +39 -0
  75. package/dist/mcp/tools/annotation-create.js.map +7 -0
  76. package/dist/mcp/tools/annotation-delete.js +29 -0
  77. package/dist/mcp/tools/annotation-delete.js.map +7 -0
  78. package/dist/mcp/tools/annotation-get.js +29 -0
  79. package/dist/mcp/tools/annotation-get.js.map +7 -0
  80. package/dist/mcp/tools/annotation-list.js +24 -0
  81. package/dist/mcp/tools/annotation-list.js.map +7 -0
  82. package/dist/mcp/tools/annotation-reply.js +34 -0
  83. package/dist/mcp/tools/annotation-reply.js.map +7 -0
  84. package/dist/mcp/tools/annotation-shared.js +10 -0
  85. package/dist/mcp/tools/annotation-shared.js.map +7 -0
  86. package/dist/mcp/tools/annotation-update.js +39 -0
  87. package/dist/mcp/tools/annotation-update.js.map +7 -0
  88. package/dist/mcp/tools/changeset-list.js +33 -0
  89. package/dist/mcp/tools/changeset-list.js.map +7 -0
  90. package/dist/mcp/tools/changeset-show.js +39 -0
  91. package/dist/mcp/tools/changeset-show.js.map +7 -0
  92. package/dist/mcp/tools/chat-launch.js +50 -0
  93. package/dist/mcp/tools/chat-launch.js.map +7 -0
  94. package/dist/mcp/tools/chat-status.js +26 -0
  95. package/dist/mcp/tools/chat-status.js.map +7 -0
  96. package/dist/mcp/tools/index.js +47 -0
  97. package/dist/mcp/tools/index.js.map +7 -0
  98. package/dist/mcp/tools/model-add.js +106 -0
  99. package/dist/mcp/tools/model-add.js.map +7 -0
  100. package/dist/mcp/tools/model-delete.js +99 -0
  101. package/dist/mcp/tools/model-delete.js.map +7 -0
  102. package/dist/mcp/tools/model-export.js +72 -0
  103. package/dist/mcp/tools/model-export.js.map +7 -0
  104. package/dist/mcp/tools/model-info.js +51 -0
  105. package/dist/mcp/tools/model-info.js.map +7 -0
  106. package/dist/mcp/tools/model-list.js +53 -0
  107. package/dist/mcp/tools/model-list.js.map +7 -0
  108. package/dist/mcp/tools/model-reload.js +34 -0
  109. package/dist/mcp/tools/model-reload.js.map +7 -0
  110. package/dist/mcp/tools/model-search.js +88 -0
  111. package/dist/mcp/tools/model-search.js.map +7 -0
  112. package/dist/mcp/tools/model-show.js +41 -0
  113. package/dist/mcp/tools/model-show.js.map +7 -0
  114. package/dist/mcp/tools/model-stats.js +22 -0
  115. package/dist/mcp/tools/model-stats.js.map +7 -0
  116. package/dist/mcp/tools/model-trace.js +55 -0
  117. package/dist/mcp/tools/model-trace.js.map +7 -0
  118. package/dist/mcp/tools/model-update.js +105 -0
  119. package/dist/mcp/tools/model-update.js.map +7 -0
  120. package/dist/mcp/tools/model-validate.js +78 -0
  121. package/dist/mcp/tools/model-validate.js.map +7 -0
  122. package/dist/mcp/tools/shared.js +103 -0
  123. package/dist/mcp/tools/shared.js.map +7 -0
  124. package/dist/reports/model-layer-report-generator.js +5 -3
  125. package/dist/reports/model-layer-report-generator.js.map +2 -2
  126. package/dist/reports/model-readme-generator.js +116 -0
  127. package/dist/reports/model-readme-generator.js.map +7 -0
  128. package/dist/reports/model-report-data.js +37 -1
  129. package/dist/reports/model-report-data.js.map +2 -2
  130. package/dist/reports/model-report-orchestrator.js +29 -6
  131. package/dist/reports/model-report-orchestrator.js.map +2 -2
  132. package/dist/reports/model-report-utils.js +9 -0
  133. package/dist/reports/model-report-utils.js.map +7 -0
  134. package/dist/schemas/bundled/analyzers/cbm.json +2 -2
  135. package/dist/schemas/bundled/analyzers/manifest.json +2 -2
  136. package/dist/schemas/bundled/api.json +1 -1
  137. package/dist/schemas/bundled/apm.json +1 -1
  138. package/dist/schemas/bundled/application.json +12 -1
  139. package/dist/schemas/bundled/base.json +1 -1
  140. package/dist/schemas/bundled/business.json +1 -1
  141. package/dist/schemas/bundled/data-model.json +38 -2
  142. package/dist/schemas/bundled/data-store.json +1 -1
  143. package/dist/schemas/bundled/manifest.json +4 -4
  144. package/dist/schemas/bundled/motivation.json +1 -1
  145. package/dist/schemas/bundled/navigation.json +1 -1
  146. package/dist/schemas/bundled/product.json +1 -1
  147. package/dist/schemas/bundled/security.json +1 -1
  148. package/dist/schemas/bundled/technology.json +1 -1
  149. package/dist/schemas/bundled/testing.json +1 -1
  150. package/dist/schemas/bundled/ux.json +1 -1
  151. package/dist/server/server.js +45 -7
  152. package/dist/server/server.js.map +2 -2
  153. package/dist/telemetry/config.js +2 -40
  154. package/dist/telemetry/config.js.map +2 -2
  155. package/dist/telemetry/index.js +1 -1
  156. package/dist/types/index.js.map +2 -2
  157. package/dist/utils/ansi-suppressor.js +25 -0
  158. package/dist/utils/ansi-suppressor.js.map +7 -0
  159. package/dist/utils/color-utils.js +34 -0
  160. package/dist/utils/color-utils.js.map +7 -0
  161. package/dist/utils/element-reference-shape.js +15 -1
  162. package/dist/utils/element-reference-shape.js.map +3 -3
  163. package/dist/utils/errors.js +69 -10
  164. package/dist/utils/errors.js.map +2 -2
  165. package/dist/utils/globals.js +17 -1
  166. package/dist/utils/globals.js.map +2 -2
  167. package/dist/utils/project-paths.js +24 -2
  168. package/dist/utils/project-paths.js.map +2 -2
  169. package/dist/utils/reference-path-parser.js +49 -0
  170. package/dist/utils/reference-path-parser.js.map +7 -0
  171. package/dist/utils/source-reference.js +5 -0
  172. package/dist/utils/source-reference.js.map +2 -2
  173. package/dist/utils/spec-version.js +10 -2
  174. package/dist/utils/spec-version.js.map +2 -2
  175. package/dist/validators/composed-reference-validator.js +262 -0
  176. package/dist/validators/composed-reference-validator.js.map +7 -0
  177. package/dist/validators/reference-validator.js +59 -8
  178. package/dist/validators/reference-validator.js.map +3 -3
  179. package/dist/validators/relationship-schema-validator.js +30 -2
  180. package/dist/validators/relationship-schema-validator.js.map +3 -3
  181. package/dist/viewer/README.md +6 -6
  182. package/dist/viewer/assets/main-B7AOQXXX.js +81 -0
  183. package/dist/viewer/assets/main-vdrFrG7q.css +1 -0
  184. package/dist/viewer/index.html +2 -2
  185. package/dist/viewer/manifest.json +10 -10
  186. package/dist/viewer/version.json +1 -1
  187. package/package.json +6 -3
  188. package/dist/viewer/assets/main-BRPZyc36.css +0 -1
  189. package/dist/viewer/assets/main-BrpLargo.js +0 -81
@@ -7,7 +7,8 @@ import { ValidationFormatter } from "../validators/validation-formatter.js";
7
7
  import * as prompts from "@clack/prompts";
8
8
  import path from "path";
9
9
  import { isTelemetryEnabled, startSpan, endSpan, startActiveSpan } from "../telemetry/index.js";
10
- import { getErrorMessage } from "../utils/errors.js";
10
+ import { getErrorMessage, handleSuccess, handleInfo, handleWarning } from "../utils/errors.js";
11
+ import { isJson } from "../utils/globals.js";
11
12
  import { findElementLayer } from "../utils/element-utils.js";
12
13
  function generateImportedChangesetId() {
13
14
  return `imported-${Date.now()}`;
@@ -18,8 +19,8 @@ async function changesetCreateCommand(name, options) {
18
19
  "changeset.hasDescription": !!options.description
19
20
  }) : null;
20
21
  try {
21
- const model = await Model.load(process.cwd(), { lazyLoad: !1 }), manager = new StagingAreaManager(model.rootPath, model);
22
- await manager.load(name) && (console.error(ansis.red(`Error: Changeset '${name}' already exists`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset already exists" }), endSpan(span), process.exit(1));
22
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !1 }), manager = new StagingAreaManager(model.rootPath, model);
23
+ await manager.load(name) && (isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: `Changeset '${name}' already exists` })) : console.error(ansis.red(`Error: Changeset '${name}' already exists`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset already exists" }), endSpan(span), process.exit(1));
23
24
  let description = options.description;
24
25
  if (!description) {
25
26
  const isInteractive = process.stdin.isTTY;
@@ -31,24 +32,30 @@ async function changesetCreateCommand(name, options) {
31
32
  }
32
33
  }
33
34
  const changeset = await manager.create(name, description || void 0), previouslyActive = await manager.getActiveId();
34
- if (previouslyActive) {
35
+ if (previouslyActive && !isJson()) {
35
36
  const previous = await manager.load(previouslyActive);
36
37
  console.log(ansis.yellow(` Deactivating changeset: ${ansis.bold(previous?.name ?? previouslyActive)}`));
37
38
  }
38
- await manager.setActive(changeset.id), isTelemetryEnabled && span && (span.setAttribute("changeset.id", changeset.id), span.setStatus({ code: 0 })), console.log(ansis.green(`\u2713 Created and activated changeset: ${ansis.bold(name)}`)), changeset.description && console.log(ansis.dim(` ${changeset.description}`)), console.log(ansis.dim(` Path: documentation-robotics/changesets/${changeset.id}/`)), console.log();
39
+ await manager.setActive(changeset.id), isTelemetryEnabled && span && (span.setAttribute("changeset.id", changeset.id), span.setStatus({ code: 0 }));
40
+ const createDetails = {
41
+ changesetId: changeset.id,
42
+ changesetName: name,
43
+ path: `documentation-robotics/changesets/${changeset.id}/`
44
+ };
45
+ changeset.description && (createDetails.description = changeset.description), handleSuccess(`Created and activated changeset: ${ansis.bold(name)}`, createDetails, { verbose: !0 });
39
46
  } catch (error) {
40
47
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
41
48
  code: 2,
42
49
  message: getErrorMessage(error)
43
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
50
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
44
51
  } finally {
45
52
  endSpan(span);
46
53
  }
47
54
  }
48
- async function changesetListCommand() {
55
+ async function changesetListCommand(options = {}) {
49
56
  const span = isTelemetryEnabled ? startSpan("changeset.list") : null;
50
57
  try {
51
- const model = await Model.load(process.cwd(), { lazyLoad: !0 }), changesets = await new StagingAreaManager(model.rootPath, model).list();
58
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !0 }), changesets = await new StagingAreaManager(model.rootPath, model).list();
52
59
  if (isTelemetryEnabled && span && span.setAttribute("changeset.count", changesets.length), changesets.length === 0) {
53
60
  console.log(ansis.yellow("No changesets found")), console.log(), isTelemetryEnabled && span && span.setStatus({ code: 0 }), endSpan(span);
54
61
  return;
@@ -71,7 +78,7 @@ Changesets (${changesets.length}):
71
78
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
72
79
  code: 2,
73
80
  message: getErrorMessage(error)
74
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
81
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
75
82
  } finally {
76
83
  endSpan(span);
77
84
  }
@@ -83,92 +90,122 @@ async function changesetApplyCommand(name, options) {
83
90
  "apply.force": options?.force === !0
84
91
  }) : null;
85
92
  try {
86
- const model = await Model.load(process.cwd(), { lazyLoad: !1 }), manager = new StagingAreaManager(model.rootPath, model), changeset = await manager.load(name);
87
- changeset || (console.error(ansis.red(`Error: Changeset '${name}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset not found" }), endSpan(span), process.exit(1)), isTelemetryEnabled && span && (span.setAttribute("changeset.id", changeset.id), span.setAttribute("changeset.changeCount", changeset.changes.length)), console.log(ansis.bold(`
93
+ const model = await Model.load(options?.model || process.cwd(), { lazyLoad: !1 }), manager = new StagingAreaManager(model.rootPath, model), changeset = await manager.load(name);
94
+ if (changeset || (isJson() ? console.log(JSON.stringify({ status: "error", code: 2, message: `Changeset '${name}' not found` })) : console.error(ansis.red(`Error: Changeset '${name}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset not found" }), endSpan(span), process.exit(1)), isTelemetryEnabled && span && (span.setAttribute("changeset.id", changeset.id), span.setAttribute("changeset.changeCount", changeset.changes.length)), !isJson()) {
95
+ console.log(ansis.bold(`
88
96
  Applying changeset: ${ansis.cyan(name)}
89
97
  `)), console.log(ansis.dim(`Changes: ${changeset.changes.length}`));
90
- const preApplyStats = ValidationFormatter.calculateStats(model);
91
- preApplyStats.orphanedElements.length > 0 && console.log(ansis.dim(`Model health before apply: ${preApplyStats.orphanedElements.length} orphaned element(s) \u2014 run 'dr validate --orphans' for details`));
98
+ const preApplyStats = ValidationFormatter.calculateStats(model);
99
+ preApplyStats.orphanedElements.length > 0 && console.log(ansis.dim(`Model health before apply: ${preApplyStats.orphanedElements.length} orphaned element(s) \u2014 run 'dr validate --orphans' for details`));
100
+ }
92
101
  const changesetId = changeset.id || name;
93
- changesetId || (console.error(ansis.red("Error: Changeset ID could not be determined") + `
102
+ if (!changesetId) {
103
+ const errMsg = "Changeset ID could not be determined";
104
+ isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: errMsg })) : console.error(ansis.red("Error: " + errMsg) + `
94
105
  ` + ansis.dim("This indicates a corrupted changeset. The changeset exists but has no ID field.") + `
95
106
  ` + ansis.dim(`Try:
96
107
  `) + ansis.dim(` 1. Run 'dr changeset list' to see available changesets
97
108
  `) + ansis.dim(` 2. Delete and recreate the changeset if possible
98
- `) + ansis.dim(" 3. Contact support if this persists")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset ID missing" }), endSpan(span), process.exit(1));
109
+ `) + ansis.dim(" 3. Contact support if this persists")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset ID missing" }), endSpan(span), process.exit(1);
110
+ }
99
111
  const result = await manager.apply(model, changesetId, {
100
112
  validate: options?.validate,
101
113
  force: options?.force
102
114
  });
103
- if (console.log(), console.log(ansis.green(`\u2713 Applied ${result.committed} change(s) from changeset`)), isTelemetryEnabled && span && (span.setAttribute("apply.committed", result.committed), span.setAttribute("apply.failed", result.failed), span.setAttribute("apply.validationPassed", result.validation.passed)), result.failed > 0) {
104
- console.log(ansis.red(`\u2717 Failed to apply ${result.failed} change(s):`));
115
+ handleInfo(""), isTelemetryEnabled && span && (span.setAttribute("apply.committed", result.committed), span.setAttribute("apply.failed", result.failed), span.setAttribute("apply.validationPassed", result.validation.passed));
116
+ const applyDetails = {
117
+ changesetName: name,
118
+ changesetId: changeset.id,
119
+ committed: result.committed,
120
+ failed: result.failed,
121
+ validationPassed: result.validation.passed
122
+ };
123
+ if (result.failed > 0 && (applyDetails.errors = result.validation.errors, !isJson())) {
124
+ handleInfo(ansis.red(`\u2717 Failed to apply ${result.failed} change(s):`));
105
125
  for (const error of result.validation.errors)
106
- console.log(ansis.dim(` - ${error}`));
126
+ handleInfo(ansis.dim(` - ${error}`));
107
127
  }
108
- model.manifest.changeset_history || (model.manifest.changeset_history = []), model.manifest.changeset_history.push({
128
+ handleSuccess(`Applied ${result.committed} change(s) from changeset`, applyDetails), model.manifest.changeset_history || (model.manifest.changeset_history = []), model.manifest.changeset_history.push({
109
129
  name,
110
130
  committed_at: (/* @__PURE__ */ new Date()).toISOString(),
111
131
  action: "committed"
112
- }), await model.saveDirtyLayers(), await model.saveManifest(), result.failed === 0 && console.log(ansis.dim("Changeset marked as committed")), isTelemetryEnabled && span && span.setStatus({ code: 0 }), console.log();
132
+ }), await model.saveDirtyLayers(), await model.saveManifest(), result.failed === 0 && handleInfo(ansis.dim("Changeset marked as committed")), isTelemetryEnabled && span && span.setStatus({ code: 0 }), handleInfo("");
113
133
  } catch (error) {
114
134
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
115
135
  code: 2,
116
136
  message: getErrorMessage(error)
117
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
137
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
118
138
  } finally {
119
139
  endSpan(span);
120
140
  }
121
141
  }
122
- async function changesetRevertCommand(name) {
142
+ async function changesetRevertCommand(name, options = {}) {
123
143
  const span = isTelemetryEnabled ? startSpan("changeset.revert", {
124
144
  "changeset.name": name
125
145
  }) : null;
126
146
  try {
127
- const model = await Model.load(process.cwd(), { lazyLoad: !1 }), manager = new StagingAreaManager(model.rootPath, model), changeset = await manager.load(name);
128
- changeset || (console.error(ansis.red(`Error: Changeset '${name}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset not found" }), endSpan(span), process.exit(1)), isTelemetryEnabled && span && (span.setAttribute("changeset.id", changeset.id), span.setAttribute("changeset.changeCount", changeset.changes.length)), console.log(ansis.bold(`
147
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !1 }), manager = new StagingAreaManager(model.rootPath, model), changeset = await manager.load(name);
148
+ changeset || (isJson() ? console.log(JSON.stringify({ status: "error", code: 2, message: `Changeset '${name}' not found` })) : console.error(ansis.red(`Error: Changeset '${name}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset not found" }), endSpan(span), process.exit(1)), isTelemetryEnabled && span && (span.setAttribute("changeset.id", changeset.id), span.setAttribute("changeset.changeCount", changeset.changes.length)), isJson() || (console.log(ansis.bold(`
129
149
  Reverting changeset: ${ansis.cyan(name)}
130
- `)), console.log(ansis.dim(`Changes to discard: ${changeset.changes.length}`));
150
+ `)), console.log(ansis.dim(`Changes to discard: ${changeset.changes.length}`)));
131
151
  const changesetId = changeset.id || name;
132
- changesetId || (console.error(ansis.red("Error: Changeset ID could not be determined")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset ID missing" }), endSpan(span), process.exit(1)), await manager.revert(changesetId), console.log(), console.log(ansis.green(`\u2713 Reverted changeset: ${name}`)), console.log(ansis.dim("Changeset marked as discarded")), isTelemetryEnabled && span && span.setStatus({ code: 0 }), console.log();
152
+ if (!changesetId) {
153
+ const errMsg = "Changeset ID could not be determined";
154
+ isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: errMsg })) : console.error(ansis.red("Error: " + errMsg) + `
155
+ ` + ansis.dim("The changeset must have an ID to proceed with revert.")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset ID missing" }), endSpan(span), process.exit(1);
156
+ }
157
+ await manager.revert(changesetId), handleInfo(""), handleSuccess(`Reverted changeset: ${name}`, {
158
+ changesetName: name,
159
+ changesetId,
160
+ changesetStatus: "discarded"
161
+ }), isTelemetryEnabled && span && span.setStatus({ code: 0 }), handleInfo("");
133
162
  } catch (error) {
134
163
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
135
164
  code: 2,
136
165
  message: getErrorMessage(error)
137
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
166
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
138
167
  } finally {
139
168
  endSpan(span);
140
169
  }
141
170
  }
142
- async function changesetActivateCommand(name) {
171
+ async function changesetActivateCommand(name, options = {}) {
143
172
  const span = isTelemetryEnabled ? startSpan("changeset.activate", {
144
173
  "changeset.name": name
145
174
  }) : null;
146
175
  try {
147
- const model = await Model.load(process.cwd(), { lazyLoad: !0 });
148
- await new StagingAreaManager(model.rootPath, model).setActive(name), console.log(ansis.green(`\u2713 Activated changeset: ${ansis.bold(name)}`)), console.log(ansis.dim(" All model changes will now be tracked in this changeset")), isTelemetryEnabled && span && span.setStatus({ code: 0 });
176
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), changeset = await manager.load(name);
177
+ changeset || (isJson() ? console.log(JSON.stringify({ status: "error", code: 2, message: `Changeset '${name}' not found` })) : console.error(ansis.red(`Error: Changeset '${name}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset not found" }), endSpan(span), process.exit(1)), await manager.setActive(name), handleSuccess(`Activated changeset: ${ansis.bold(name)}`, {
178
+ changesetName: name,
179
+ changesetId: changeset.id
180
+ }), isTelemetryEnabled && span && span.setStatus({ code: 0 });
149
181
  } catch (error) {
150
182
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
151
183
  code: 2,
152
184
  message: getErrorMessage(error)
153
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
185
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
154
186
  } finally {
155
187
  endSpan(span);
156
188
  }
157
189
  }
158
- async function changesetDeactivateCommand() {
190
+ async function changesetDeactivateCommand(options = {}) {
159
191
  const span = isTelemetryEnabled ? startSpan("changeset.deactivate") : null;
160
192
  try {
161
- const model = await Model.load(process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), active = await manager.getActiveId();
193
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), active = await manager.getActiveId();
162
194
  if (!active) {
163
- console.log(ansis.yellow("No active changeset")), isTelemetryEnabled && span && (span.setAttribute("changeset.wasActive", !1), span.setStatus({ code: 0 })), endSpan(span);
195
+ handleInfo(ansis.yellow("No active changeset")), isTelemetryEnabled && span && (span.setAttribute("changeset.wasActive", !1), span.setStatus({ code: 0 })), endSpan(span);
164
196
  return;
165
197
  }
166
- isTelemetryEnabled && span && (span.setAttribute("changeset.name", active), span.setAttribute("changeset.wasActive", !0)), await manager.clearActive(), console.log(ansis.green(`\u2713 Deactivated changeset: ${ansis.bold(active)}`)), isTelemetryEnabled && span && span.setStatus({ code: 0 });
198
+ isTelemetryEnabled && span && (span.setAttribute("changeset.name", active), span.setAttribute("changeset.wasActive", !0));
199
+ const changeset = await manager.load(active);
200
+ await manager.clearActive(), handleSuccess(`Deactivated changeset: ${ansis.bold(active)}`, {
201
+ changesetId: active,
202
+ name: changeset?.name || active
203
+ }), isTelemetryEnabled && span && span.setStatus({ code: 0 });
167
204
  } catch (error) {
168
205
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
169
206
  code: 2,
170
207
  message: getErrorMessage(error)
171
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
208
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
172
209
  } finally {
173
210
  endSpan(span);
174
211
  }
@@ -179,34 +216,39 @@ async function changesetDeleteCommand(name, options) {
179
216
  "delete.force": options.force === !0
180
217
  }) : null;
181
218
  try {
182
- const model = await Model.load(process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), changeset = await manager.load(name);
183
- if (changeset || (console.error(ansis.red(`Error: Changeset '${name}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset not found" }), endSpan(span), process.exit(1)), await manager.getActiveId() === changeset.id && (console.error(ansis.red(`Error: Cannot delete active changeset '${name}'`)), console.log(ansis.dim(" Run `dr changeset deactivate` first")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Cannot delete active changeset" }), endSpan(span), process.exit(1)), !options.force) {
219
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), changeset = await manager.load(name);
220
+ if (changeset || (isJson() ? console.log(JSON.stringify({ status: "error", code: 2, message: `Changeset '${name}' not found` })) : console.error(ansis.red(`Error: Changeset '${name}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset not found" }), endSpan(span), process.exit(1)), await manager.getActiveId() === changeset.id && (isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: `Cannot delete active changeset '${name}'` })) : (console.error(ansis.red(`Error: Cannot delete active changeset '${name}'`)), console.log(ansis.dim(" Run `dr changeset deactivate` first"))), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Cannot delete active changeset" }), endSpan(span), process.exit(1)), !options.force) {
184
221
  const isInteractive = process.stdin.isTTY && process.stdout.isTTY;
185
222
  if (isTelemetryEnabled && span && span.setAttribute("cli.interactive", isInteractive), isInteractive) {
186
223
  const confirm = await prompts.confirm({
187
224
  message: `Delete changeset '${name}'? This cannot be undone.`
188
225
  });
189
226
  if (!confirm || typeof confirm != "boolean") {
190
- console.log(ansis.yellow("Deletion cancelled")), isTelemetryEnabled && span && (span.setAttribute("delete.cancelled", !0), span.setStatus({ code: 0 })), endSpan(span);
227
+ handleSuccess("Deletion cancelled", {
228
+ status: "cancelled"
229
+ }), isTelemetryEnabled && span && (span.setAttribute("delete.cancelled", !0), span.setStatus({ code: 0 })), endSpan(span);
191
230
  return;
192
231
  }
193
232
  } else
194
- console.error(ansis.red("Error: Cannot confirm deletion in non-interactive environment")), console.log(ansis.dim(" Use --force flag to confirm deletion")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Interactive confirmation required" }), endSpan(span), process.exit(1);
233
+ isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: "Cannot confirm deletion in non-interactive environment" })) : (console.error(ansis.red("Error: Cannot confirm deletion in non-interactive environment")), console.log(ansis.dim(" Use --force flag to confirm deletion"))), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Interactive confirmation required" }), endSpan(span), process.exit(1);
195
234
  }
196
- await manager.delete(name), console.log(ansis.green(`\u2713 Deleted changeset: ${ansis.bold(name)}`)), isTelemetryEnabled && span && span.setStatus({ code: 0 });
235
+ await manager.delete(name), handleSuccess(`Deleted changeset: ${ansis.bold(name)}`, {
236
+ changesetName: name,
237
+ changesetId: changeset.id
238
+ }), isTelemetryEnabled && span && span.setStatus({ code: 0 });
197
239
  } catch (error) {
198
240
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
199
241
  code: 2,
200
242
  message: getErrorMessage(error)
201
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
243
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
202
244
  } finally {
203
245
  endSpan(span);
204
246
  }
205
247
  }
206
- async function changesetStatusCommand() {
248
+ async function changesetStatusCommand(options = {}) {
207
249
  const span = isTelemetryEnabled ? startSpan("changeset.status") : null;
208
250
  try {
209
- const model = await Model.load(process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), active = await manager.getActiveId();
251
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), active = await manager.getActiveId();
210
252
  if (!active) {
211
253
  console.log(ansis.dim("No active changeset")), isTelemetryEnabled && span && (span.setAttribute("changeset.hasActive", !1), span.setStatus({ code: 0 })), endSpan(span);
212
254
  return;
@@ -225,7 +267,7 @@ async function changesetStatusCommand() {
225
267
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
226
268
  code: 2,
227
269
  message: getErrorMessage(error)
228
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
270
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
229
271
  } finally {
230
272
  endSpan(span);
231
273
  }
@@ -235,49 +277,65 @@ async function changesetStagedCommand(options) {
235
277
  "staged.layer": options.layer
236
278
  }) : null;
237
279
  try {
238
- const model = await Model.load(process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), activeChangeset = await manager.getActiveId();
280
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), activeChangeset = await manager.getActiveId();
239
281
  if (!activeChangeset) {
240
- console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "No active changeset" }), endSpan(span);
282
+ isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: "No active changeset" })) : console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "No active changeset" }), endSpan(span);
241
283
  return;
242
284
  }
243
285
  const changeset = await manager.load(activeChangeset);
244
- changeset || (console.error(ansis.red(`Error: Changeset '${activeChangeset}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset not found" }), endSpan(span), process.exit(1));
286
+ changeset || (isJson() ? console.log(JSON.stringify({ status: "error", code: 2, message: `Changeset '${activeChangeset}' not found` })) : console.error(ansis.red(`Error: Changeset '${activeChangeset}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset not found" }), endSpan(span), process.exit(1));
245
287
  let changes = changeset.changes;
246
288
  if (options.layer && (changes = changes.filter((c) => c.layerName === options.layer)), isTelemetryEnabled && span && (span.setAttribute("staged.changeCount", changes.length), span.setAttribute("staged.totalChanges", changeset.changes.length)), changes.length === 0) {
247
- console.log(ansis.yellow("No staged changes")), isTelemetryEnabled && span && span.setStatus({ code: 0 }), endSpan(span);
289
+ handleSuccess("No staged changes", {
290
+ changesetId: activeChangeset,
291
+ changeCount: 0,
292
+ changes: []
293
+ }, { verbose: !0 }), isTelemetryEnabled && span && span.setStatus({ code: 0 }), endSpan(span);
248
294
  return;
249
295
  }
250
- console.log(ansis.bold(`
296
+ if (!isJson()) {
297
+ console.log(ansis.bold(`
251
298
  Staged Changes (${changes.length}):
252
299
  `));
253
- const tableData = changes.map((c) => ({
254
- "Element ID": c.elementId,
255
- Layer: c.layerName,
256
- Type: c.type,
257
- Timestamp: new Date(c.timestamp || Date.now()).toISOString()
258
- }));
259
- console.table(tableData), isTelemetryEnabled && span && span.setStatus({ code: 0 });
300
+ const tableData = changes.map((c) => ({
301
+ "Element ID": c.elementId,
302
+ Layer: c.layerName,
303
+ Type: c.type,
304
+ Timestamp: new Date(c.timestamp || Date.now()).toISOString()
305
+ }));
306
+ console.table(tableData);
307
+ }
308
+ handleSuccess(`Listed ${changes.length} staged change(s)`, {
309
+ changesetId: activeChangeset,
310
+ changeCount: changes.length,
311
+ changes: changes.map((c) => ({
312
+ elementId: c.elementId,
313
+ layer: c.layerName,
314
+ operation: c.type,
315
+ timestamp: new Date(c.timestamp || Date.now()).toISOString()
316
+ }))
317
+ }), isTelemetryEnabled && span && span.setStatus({ code: 0 });
260
318
  } catch (error) {
261
319
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
262
320
  code: 2,
263
321
  message: getErrorMessage(error)
264
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
322
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
265
323
  } finally {
266
324
  endSpan(span);
267
325
  }
268
326
  }
269
- async function changesetExplicitStageCommand(elementId) {
327
+ async function changesetExplicitStageCommand(elementId, options = {}) {
270
328
  const span = isTelemetryEnabled ? startSpan("changeset.stage-explicit", { "stage.elementId": elementId }) : null;
271
329
  try {
272
- const model = await Model.load(process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await manager.getActiveId();
330
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await manager.getActiveId();
273
331
  if (!activeChangesetId) {
274
- console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "No active changeset" }), endSpan(span);
332
+ isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: "No active changeset" })) : console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "No active changeset" }), endSpan(span);
275
333
  return;
276
334
  }
277
335
  const layerName = await findElementLayer(model, elementId);
278
- layerName || (console.error(ansis.red(`Error: Element '${elementId}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Element not found" }), endSpan(span), process.exit(1));
336
+ layerName || (isJson() ? console.log(JSON.stringify({ status: "error", code: 2, message: `Element '${elementId}' not found` })) : console.error(ansis.red(`Error: Element '${elementId}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Element not found" }), endSpan(span), process.exit(1));
279
337
  const element = (await model.getLayer(layerName))?.getElement(elementId);
280
- if (element || (console.error(ansis.red(`Error: Element '${elementId}' not found in layer '${layerName}'`)), endSpan(span), process.exit(1)), (await manager.load(activeChangesetId))?.changes.some((c) => c.elementId === elementId)) {
338
+ if (element || (isJson() ? console.log(JSON.stringify({ status: "error", code: 2, message: `Element '${elementId}' not found in layer '${layerName}'` })) : console.error(ansis.red(`Error: Element '${elementId}' not found in layer '${layerName}'`)), endSpan(span), process.exit(1)), (await manager.load(activeChangesetId))?.changes.some((c) => c.elementId === elementId)) {
281
339
  console.warn(ansis.yellow(`Warning: Element '${elementId}' is already staged in the active changeset. Skipping.`)), endSpan(span);
282
340
  return;
283
341
  }
@@ -286,63 +344,74 @@ async function changesetExplicitStageCommand(elementId) {
286
344
  elementId,
287
345
  layerName,
288
346
  after: element.toJSON()
289
- }), isTelemetryEnabled && span && (span.setAttribute("stage.layerName", layerName), span.setStatus({ code: 0 })), console.log(ansis.green(`\u2713 Staged element: ${ansis.bold(elementId)}`)), console.log(ansis.dim(` Layer: ${layerName} | Changeset: ${activeChangesetId}`));
347
+ }), isTelemetryEnabled && span && (span.setAttribute("stage.layerName", layerName), span.setStatus({ code: 0 })), handleSuccess(`Staged element: ${elementId}`, {
348
+ elementId,
349
+ layer: layerName,
350
+ changesetId: activeChangesetId,
351
+ operation: "add"
352
+ }, { verbose: !0 });
290
353
  } catch (error) {
291
- isTelemetryEnabled && span && (span.recordException(error), span.setStatus({ code: 2, message: getErrorMessage(error) })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
354
+ isTelemetryEnabled && span && (span.recordException(error), span.setStatus({ code: 2, message: getErrorMessage(error) })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
292
355
  } finally {
293
356
  endSpan(span);
294
357
  }
295
358
  }
296
- async function changesetUnstageCommand(elementId) {
359
+ async function changesetUnstageCommand(elementId, options = {}) {
297
360
  const span = isTelemetryEnabled ? startSpan("changeset.unstage", {
298
361
  "unstage.elementId": elementId
299
362
  }) : null;
300
363
  try {
301
- const model = await Model.load(process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await manager.getActiveId();
364
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await manager.getActiveId();
302
365
  if (!activeChangesetId) {
303
- console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "No active changeset" }), endSpan(span);
366
+ isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: "No active changeset" })) : console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "No active changeset" }), endSpan(span);
304
367
  return;
305
368
  }
306
369
  const changeset = await manager.load(activeChangesetId);
307
- changeset || (console.error(ansis.red(`Error: Changeset '${activeChangesetId}' not found`)), process.exit(1));
370
+ changeset || (isJson() ? console.log(JSON.stringify({ status: "error", code: 2, message: `Changeset '${activeChangesetId}' not found` })) : console.error(ansis.red(`Error: Changeset '${activeChangesetId}' not found`)), process.exit(1));
308
371
  const initialCount = changeset.changes.length;
309
372
  await manager.unstage(activeChangesetId, elementId);
310
373
  const updated = await manager.load(activeChangesetId);
311
374
  if (updated && updated.changes.length === initialCount) {
312
- console.error(ansis.yellow(`Warning: Element '${elementId}' not found in staged changes`)), isTelemetryEnabled && span && (span.setAttribute("unstage.found", !1), span.setStatus({ code: 0 })), endSpan(span);
375
+ handleWarning(`Element '${elementId}' not found in staged changes`), isTelemetryEnabled && span && (span.setAttribute("unstage.found", !1), span.setStatus({ code: 0 })), endSpan(span);
313
376
  return;
314
377
  }
315
- isTelemetryEnabled && span && (span.setAttribute("unstage.found", !0), span.setAttribute("unstage.remainingChanges", updated?.getChangeCount() || 0)), console.log(ansis.green(`\u2713 Unstaged element: ${ansis.bold(elementId)}`)), console.log(ansis.dim(` Remaining staged changes: ${updated?.getChangeCount() || 0}`)), isTelemetryEnabled && span && span.setStatus({ code: 0 });
378
+ isTelemetryEnabled && span && (span.setAttribute("unstage.found", !0), span.setAttribute("unstage.remainingChanges", updated?.getChangeCount() || 0)), handleSuccess(`Unstaged element: ${elementId}`, {
379
+ changesetId: activeChangesetId,
380
+ elementId,
381
+ remainingChanges: updated?.getChangeCount() || 0
382
+ }, { verbose: !0 }), isTelemetryEnabled && span && span.setStatus({ code: 0 });
316
383
  } catch (error) {
317
384
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
318
385
  code: 2,
319
386
  message: getErrorMessage(error)
320
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
387
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
321
388
  } finally {
322
389
  endSpan(span);
323
390
  }
324
391
  }
325
- async function changesetDiscardCommand(elementId) {
392
+ async function changesetDiscardCommand(elementId, options = {}) {
326
393
  const span = isTelemetryEnabled ? startSpan("changeset.discard", {
327
394
  "discard.elementId": elementId,
328
395
  "discard.all": !elementId
329
396
  }) : null;
330
397
  try {
331
- const model = await Model.load(process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await manager.getActiveId();
398
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !0 }), manager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await manager.getActiveId();
332
399
  if (!activeChangesetId) {
333
- console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "No active changeset" }), endSpan(span);
400
+ isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: "No active changeset" })) : console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "No active changeset" }), endSpan(span);
334
401
  return;
335
402
  }
336
403
  const changeset = await manager.load(activeChangesetId);
337
- if (changeset || (console.error(ansis.red(`Error: Changeset '${activeChangesetId}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset not found" }), endSpan(span), process.exit(1)), isTelemetryEnabled && span && span.setAttribute("discard.changeCount", changeset.changes.length), elementId) {
404
+ if (changeset || (isJson() ? console.log(JSON.stringify({ status: "error", code: 2, message: `Changeset '${activeChangesetId}' not found` })) : console.error(ansis.red(`Error: Changeset '${activeChangesetId}' not found`)), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset not found" }), endSpan(span), process.exit(1)), isTelemetryEnabled && span && span.setAttribute("discard.changeCount", changeset.changes.length), elementId) {
338
405
  const initialCount = changeset.changes.length;
339
406
  await manager.unstage(activeChangesetId, elementId);
340
407
  const updated = await manager.load(activeChangesetId);
341
408
  if (updated && updated.changes.length === initialCount) {
342
- console.error(ansis.yellow(`Warning: Element '${elementId}' not found in staged changes`)), isTelemetryEnabled && span && (span.setAttribute("discard.found", !1), span.setStatus({ code: 0 })), endSpan(span);
409
+ handleWarning(`Element '${elementId}' not found in staged changes`), isTelemetryEnabled && span && (span.setAttribute("discard.found", !1), span.setStatus({ code: 0 })), endSpan(span);
343
410
  return;
344
411
  }
345
- isTelemetryEnabled && span && span.setAttribute("discard.found", !0), console.log(ansis.green(`\u2713 Discarded changes for element: ${ansis.bold(elementId)}`));
412
+ isTelemetryEnabled && span && span.setAttribute("discard.found", !0), handleSuccess(`Discarded changes for element: ${elementId}`, {
413
+ elementId
414
+ }, { verbose: !0 });
346
415
  } else {
347
416
  const isInteractive = process.stdin.isTTY && process.stdout.isTTY;
348
417
  if (isTelemetryEnabled && span && span.setAttribute("cli.interactive", isInteractive), isInteractive) {
@@ -350,19 +419,23 @@ async function changesetDiscardCommand(elementId) {
350
419
  message: `Discard all ${changeset.changes.length} staged changes? This cannot be undone.`
351
420
  });
352
421
  if (!confirmed || typeof confirmed != "boolean") {
353
- console.log(ansis.dim("Cancelled")), isTelemetryEnabled && span && (span.setAttribute("discard.cancelled", !0), span.setStatus({ code: 0 })), endSpan(span);
422
+ handleSuccess("Discard cancelled", {
423
+ status: "cancelled"
424
+ }), isTelemetryEnabled && span && (span.setAttribute("discard.cancelled", !0), span.setStatus({ code: 0 })), endSpan(span);
354
425
  return;
355
426
  }
356
427
  } else
357
428
  console.error(ansis.red("Error: Cannot confirm discard of all changes in non-interactive environment")), console.log(ansis.dim(" Specify an element ID to discard only that element")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Interactive confirmation required" }), endSpan(span), process.exit(1);
358
- await manager.discard(activeChangesetId), console.log(ansis.green("\u2713 Discarded all staged changes")), console.log(ansis.dim(" Changeset status: discarded"));
429
+ await manager.discard(activeChangesetId), handleSuccess("Discarded all staged changes", {
430
+ changesetStatus: "discarded"
431
+ }, { verbose: !0 });
359
432
  }
360
- isTelemetryEnabled && span && span.setStatus({ code: 0 }), console.log();
433
+ isTelemetryEnabled && span && span.setStatus({ code: 0 }), isJson() || console.log();
361
434
  } catch (error) {
362
435
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
363
436
  code: 2,
364
437
  message: getErrorMessage(error)
365
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
438
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
366
439
  } finally {
367
440
  endSpan(span);
368
441
  }
@@ -372,7 +445,7 @@ async function changesetPreviewCommand(options) {
372
445
  "preview.layer": options.layer
373
446
  }) : null;
374
447
  try {
375
- const model = await Model.load(process.cwd(), { lazyLoad: !1 }), manager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await manager.getActiveId();
448
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !1 }), manager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await manager.getActiveId();
376
449
  if (!activeChangesetId) {
377
450
  console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "No active changeset" }), endSpan(span);
378
451
  return;
@@ -425,7 +498,7 @@ async function changesetDiffCommand(options) {
425
498
  "diff.layer": options.layer
426
499
  }) : null;
427
500
  try {
428
- const model = await Model.load(process.cwd(), { lazyLoad: !1 }), manager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await manager.getActiveId();
501
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !1 }), manager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await manager.getActiveId();
429
502
  if (!activeChangesetId) {
430
503
  console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "No active changeset" }), endSpan(span);
431
504
  return;
@@ -463,48 +536,52 @@ Diff: Base Model vs Staged Changes
463
536
  async function changesetCommitCommand(options) {
464
537
  await startActiveSpan("changeset.commit", async (span) => {
465
538
  try {
466
- const model = await Model.load(process.cwd(), { lazyLoad: !1 }), stagingManager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await stagingManager.getActiveId();
539
+ const model = await Model.load(options?.model || process.cwd(), { lazyLoad: !1 }), stagingManager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await stagingManager.getActiveId();
467
540
  if (!activeChangesetId) {
468
- console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span.setStatus({ code: 2, message: "No active changeset" });
541
+ isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: "No active changeset" })) : console.error(ansis.red("Error: No active changeset")), isTelemetryEnabled && span.setStatus({ code: 2, message: "No active changeset" });
469
542
  return;
470
543
  }
471
544
  const changeset = await stagingManager.load(activeChangesetId);
472
- changeset || (console.error(ansis.red(`Error: Changeset '${activeChangesetId}' not found`)), isTelemetryEnabled && span.setStatus({ code: 2, message: "Changeset not found" }), span.end(), process.exit(1));
545
+ changeset || (isJson() ? console.log(JSON.stringify({ status: "error", code: 2, message: `Changeset '${activeChangesetId}' not found` })) : console.error(ansis.red(`Error: Changeset '${activeChangesetId}' not found`)), isTelemetryEnabled && span.setStatus({ code: 2, message: "Changeset not found" }), span.end(), process.exit(1));
473
546
  const changeCount = changeset.changes.length;
474
547
  if (isTelemetryEnabled && (span.setAttribute("changeset.id", activeChangesetId), span.setAttribute("changeset.name", changeset.name), span.setAttribute("changeset.changeCount", changeCount)), changeCount === 0) {
475
- console.log(ansis.yellow("No staged changes to commit")), isTelemetryEnabled && span.setStatus({ code: 0 });
548
+ handleSuccess("No staged changes to commit", {
549
+ name: changeset.name,
550
+ changesetId: activeChangesetId,
551
+ stagedChanges: 0
552
+ }, { verbose: !0 }), isTelemetryEnabled && span.setStatus({ code: 0 });
476
553
  return;
477
554
  }
478
- console.log(ansis.bold(`
479
- Committing changeset: ${ansis.cyan(changeset.name)}`)), console.log(ansis.dim(`Staged changes: ${changeCount}`)), console.log();
555
+ isJson() || (console.log(ansis.bold(`
556
+ Committing changeset: ${ansis.cyan(changeset.name)}`)), console.log(ansis.dim(`Staged changes: ${changeCount}`)), console.log());
480
557
  try {
481
558
  const result = await stagingManager.commit(model, activeChangesetId, {
482
559
  validate: options?.validate !== !1,
483
560
  force: options?.force === !0
484
561
  });
485
- if (await stagingManager.clearActive(), console.log(ansis.green(`\u2713 Committed ${result.committed} change(s)`)), (result.skipped ?? 0) > 0) {
486
- const skipped = result.skipped, details = result.skippedDetails ?? [];
487
- console.log(ansis.yellow(`\u26A0 Skipped ${skipped} duplicate element(s):`));
488
- const shown = details.slice(0, 10);
489
- for (const detail of shown)
490
- console.log(ansis.dim(` ${detail}`));
491
- details.length > 10 && console.log(ansis.dim(` ... and ${details.length - 10} more`));
492
- }
493
- isTelemetryEnabled && (span.setAttribute("commit.committed", result.committed), span.setAttribute("commit.skipped", result.skipped), span.setAttribute("commit.failed", result.failed), span.setAttribute("commit.validationPassed", result.validation.passed));
562
+ await stagingManager.clearActive(), isTelemetryEnabled && (span.setAttribute("commit.committed", result.committed), span.setAttribute("commit.skipped", result.skipped), span.setAttribute("commit.failed", result.failed), span.setAttribute("commit.validationPassed", result.validation.passed));
563
+ const commitDetails = {
564
+ name: changeset.name,
565
+ changesetId: activeChangesetId,
566
+ committedCount: result.committed,
567
+ stagedChanges: changeCount,
568
+ validationPassed: result.validation.passed
569
+ };
570
+ (result.skipped ?? 0) > 0 && (commitDetails.skipped = result.skipped, commitDetails.skippedDetails = (result.skippedDetails ?? []).slice(0, 10)), result.failed > 0 && (commitDetails.failed = result.failed);
494
571
  const accountedFor = result.committed + (result.skipped ?? 0) + result.failed;
495
572
  if (accountedFor < changeCount) {
496
573
  const unaccounted = changeCount - accountedFor;
497
- console.log(ansis.yellow(`\u26A0 Warning: ${unaccounted} staged change(s) were not applied, skipped, or reported as failed. This is unexpected \u2014 check the changeset log for details.`));
574
+ commitDetails.unaccountedChanges = unaccounted, isJson() || console.log(ansis.yellow(`\u26A0 Warning: ${unaccounted} staged change(s) were not applied, skipped, or reported as failed. This is unexpected \u2014 check the changeset log for details.`));
498
575
  }
499
- result.driftWarning && (console.log(ansis.yellow("\u26A0 Warning: Model had drifted since changeset creation (--force was used)")), isTelemetryEnabled && span.setAttribute("commit.driftDetected", !0)), isTelemetryEnabled && span.setStatus({ code: 0 }), console.log();
576
+ result.driftWarning && (commitDetails.driftDetected = !0, isJson() || console.log(ansis.yellow("\u26A0 Warning: Model had drifted since changeset creation (--force was used)")), isTelemetryEnabled && span.setAttribute("commit.driftDetected", !0)), isTelemetryEnabled && span.setStatus({ code: 0 }), handleSuccess(`Committed ${result.committed} change(s)`, commitDetails, { verbose: !0 }), isJson() || console.log();
500
577
  } catch (error) {
501
- throw console.log(ansis.red(`\u2717 Commit failed and rolled back: ${getErrorMessage(error)}`)), isTelemetryEnabled && span.setAttribute("commit.rolledBack", !0), error;
578
+ throw isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: `Commit failed and rolled back: ${getErrorMessage(error)}` })) : console.log(ansis.red(`\u2717 Commit failed and rolled back: ${getErrorMessage(error)}`)), isTelemetryEnabled && span.setAttribute("commit.rolledBack", !0), error;
502
579
  }
503
580
  } catch (error) {
504
581
  isTelemetryEnabled && (span.recordException(error), span.setStatus({
505
582
  code: 2,
506
583
  message: getErrorMessage(error)
507
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), span.end(), process.exit(1);
584
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), span.end(), process.exit(1);
508
585
  }
509
586
  }, {
510
587
  "commit.validate": options?.validate !== !1,
@@ -517,13 +594,17 @@ async function changesetExportCommand(changesetId, options) {
517
594
  "export.format": format
518
595
  }) : null;
519
596
  try {
520
- const model = await Model.load(process.cwd(), { lazyLoad: !0 }), exporter = new ChangesetExporter(model.rootPath), ext = format === "patch" ? "patch" : format, outputPath = options.output || `${changesetId}.${ext}`, absolutePath = path.isAbsolute(outputPath) ? outputPath : path.join(process.cwd(), outputPath);
521
- isTelemetryEnabled && span && span.setAttribute("export.outputPath", outputPath), await exporter.exportToFile(changesetId, absolutePath, format), console.log(ansis.green(`\u2713 Exported changeset to ${ansis.cyan(outputPath)}`)), console.log(ansis.dim(` Format: ${format}`)), isTelemetryEnabled && span && span.setStatus({ code: 0 });
597
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !0 }), exporter = new ChangesetExporter(model.rootPath), ext = format === "patch" ? "patch" : format, outputPath = options.output || `${changesetId}.${ext}`, absolutePath = path.isAbsolute(outputPath) ? outputPath : path.join(process.cwd(), outputPath);
598
+ isTelemetryEnabled && span && span.setAttribute("export.outputPath", outputPath), await exporter.exportToFile(changesetId, absolutePath, format), handleSuccess(`Exported changeset to ${outputPath}`, {
599
+ changesetId,
600
+ outputPath,
601
+ format
602
+ }, { verbose: !0 }), isTelemetryEnabled && span && span.setStatus({ code: 0 });
522
603
  } catch (error) {
523
604
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
524
605
  code: 2,
525
606
  message: getErrorMessage(error)
526
- })), console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
607
+ })), isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: getErrorMessage(error) })) : console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), endSpan(span), process.exit(1);
527
608
  } finally {
528
609
  endSpan(span);
529
610
  }
@@ -534,23 +615,35 @@ async function changesetImportCommand(file, options = {}) {
534
615
  "import.force": options.force === !0
535
616
  }) : null;
536
617
  try {
537
- const model = await Model.load(process.cwd(), { lazyLoad: !1 }), exporter = new ChangesetExporter(model.rootPath), absolutePath = path.isAbsolute(file) ? file : path.join(process.cwd(), file), imported = await exporter.importFromFile(absolutePath);
618
+ const model = await Model.load(options.model || process.cwd(), { lazyLoad: !1 }), exporter = new ChangesetExporter(model.rootPath), absolutePath = path.isAbsolute(file) ? file : path.join(process.cwd(), file), imported = await exporter.importFromFile(absolutePath);
538
619
  isTelemetryEnabled && span && (span.setAttribute("changeset.name", imported.name), span.setAttribute("changeset.changeCount", imported.changes.length));
539
620
  const compatibility = await exporter.validateCompatibility(imported, model);
540
621
  if (isTelemetryEnabled && span && (span.setAttribute("import.compatible", compatibility.compatible), span.setAttribute("import.baseSnapshotMatch", compatibility.baseSnapshotMatch)), !compatibility.compatible) {
541
- console.error(ansis.red("\u2717 Import failed: Changeset is incompatible")), console.error(ansis.dim(" Issues:"));
542
- for (const warning of compatibility.warnings)
543
- console.error(ansis.dim(` - ${warning}`));
622
+ if (isJson())
623
+ console.log(JSON.stringify({ status: "error", code: 1, message: "Changeset is incompatible", warnings: compatibility.warnings }));
624
+ else {
625
+ console.error(ansis.red("\u2717 Import failed: Changeset is incompatible")), console.error(ansis.dim(" Issues:"));
626
+ for (const warning of compatibility.warnings)
627
+ console.error(ansis.dim(` - ${warning}`));
628
+ }
544
629
  isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Changeset incompatible" }), endSpan(span), process.exit(1);
545
630
  }
546
- compatibility.baseSnapshotMatch || (options.force || (console.error(ansis.red("Error: Imported changeset has base model drift") + `
631
+ compatibility.baseSnapshotMatch || (options.force || (isJson() ? console.log(JSON.stringify({ status: "error", code: 1, message: "Imported changeset has base model drift" })) : console.error(ansis.red("Error: Imported changeset has base model drift") + `
547
632
  ` + ansis.dim("The model has been modified since this changeset was created.") + `
548
633
  ` + ansis.dim("This may cause conflicts or unexpected behavior when committing.") + `
549
634
 
550
635
  ` + ansis.dim("To import anyway, use: --force")), isTelemetryEnabled && span && span.setStatus({ code: 2, message: "Drift detected, force required" }), endSpan(span), process.exit(1)), console.warn(ansis.yellow("\u26A0 Warning: Base model drift detected (--force used)") + `
551
636
  ` + ansis.dim("Review changes carefully before committing.")), console.log(), isTelemetryEnabled && span && span.setAttribute("import.driftOverridden", !0));
552
637
  const newId = generateImportedChangesetId();
553
- imported.id = newId, await new StagedChangesetStorage(model.rootPath).save(imported), console.log(ansis.green(`\u2713 Imported changeset: ${ansis.cyan(imported.name)}`)), console.log(ansis.dim(` ID: ${newId}`)), console.log(ansis.dim(` Changes: +${imported.stats?.additions || 0} ~${imported.stats?.modifications || 0} -${imported.stats?.deletions || 0}`)), compatibility.baseSnapshotMatch || console.log(ansis.yellow(" \u26A0 Base model drift detected - review before committing")), isTelemetryEnabled && span && (span.setAttribute("changeset.id", newId), span.setStatus({ code: 0 })), console.log();
638
+ imported.id = newId, await new StagedChangesetStorage(model.rootPath).save(imported);
639
+ const importDetails = {
640
+ changesetName: imported.name,
641
+ changesetId: newId,
642
+ additions: imported.stats?.additions || 0,
643
+ modifications: imported.stats?.modifications || 0,
644
+ deletions: imported.stats?.deletions || 0
645
+ };
646
+ compatibility.baseSnapshotMatch || (importDetails.driftDetected = !0), handleSuccess(`Imported changeset: ${imported.name}`, importDetails, { verbose: !0 }), isTelemetryEnabled && span && (span.setAttribute("changeset.id", newId), span.setStatus({ code: 0 }));
554
647
  } catch (error) {
555
648
  isTelemetryEnabled && span && (span.recordException(error), span.setStatus({
556
649
  code: 2,
@@ -562,37 +655,37 @@ async function changesetImportCommand(file, options = {}) {
562
655
  }
563
656
  function changesetCommands(program) {
564
657
  const changesetGroup = program.command("changeset").description("Manage changesets");
565
- changesetGroup.command("create <name>").description("Create a new changeset").option("--description <desc>", "Changeset description").addHelpText("after", `
658
+ changesetGroup.command("create <name>").description("Create a new changeset").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("--description <desc>", "Changeset description").addHelpText("after", `
566
659
  Examples:
567
660
  $ dr changeset create "v1.1 migration"
568
661
  $ dr changeset create "api-refactoring" --description "Refactor API layer endpoints"`).action(async (name, options) => {
569
662
  await changesetCreateCommand(name, options);
570
- }), changesetGroup.command("list").description("List all changesets").addHelpText("after", `
663
+ }), changesetGroup.command("list").description("List all changesets").option("--model <path>", "Path to model root (contains model/manifest.yaml)").addHelpText("after", `
571
664
  Examples:
572
- $ dr changeset list`).action(async () => {
573
- await changesetListCommand();
574
- }), changesetGroup.command("apply <name>").description("Apply a changeset to the model").option("--no-validate", "Skip validation before applying").option("--force", "Force apply even if base model has drifted").addHelpText("after", `
665
+ $ dr changeset list`).action(async (options) => {
666
+ await changesetListCommand(options);
667
+ }), changesetGroup.command("apply <name>").description("Apply a changeset to the model").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("--no-validate", "Skip validation before applying").option("--force", "Force apply even if base model has drifted").addHelpText("after", `
575
668
  Examples:
576
669
  $ dr changeset apply "v1.1 migration"
577
670
  $ dr changeset apply "v1.1 migration" --no-validate
578
671
  $ dr changeset apply "v1.1 migration" --force`).action(async (name, options) => {
579
672
  await changesetApplyCommand(name, options);
580
- }), changesetGroup.command("revert <name>").description("Revert a changeset from the model").addHelpText("after", `
673
+ }), changesetGroup.command("revert <name>").description("Revert a changeset from the model").option("--model <path>", "Path to model root (contains model/manifest.yaml)").addHelpText("after", `
581
674
  Examples:
582
- $ dr changeset revert "v1.1 migration"`).action(async (name) => {
583
- await changesetRevertCommand(name);
584
- }), changesetGroup.command("activate <name>").description("Activate a changeset for automatic change tracking").addHelpText("after", `
675
+ $ dr changeset revert "v1.1 migration"`).action(async (name, options) => {
676
+ await changesetRevertCommand(name, options);
677
+ }), changesetGroup.command("activate <name>").description("Activate a changeset for automatic change tracking").option("--model <path>", "Path to model root (contains model/manifest.yaml)").addHelpText("after", `
585
678
  Examples:
586
- $ dr changeset activate "v1.1 migration"`).action(async (name) => {
587
- await changesetActivateCommand(name);
588
- }), changesetGroup.command("deactivate").description("Deactivate the currently active changeset").addHelpText("after", `
679
+ $ dr changeset activate "v1.1 migration"`).action(async (name, options) => {
680
+ await changesetActivateCommand(name, options);
681
+ }), changesetGroup.command("deactivate").description("Deactivate the currently active changeset").option("--model <path>", "Path to model root (contains model/manifest.yaml)").addHelpText("after", `
589
682
  Examples:
590
- $ dr changeset deactivate`).action(async () => {
591
- await changesetDeactivateCommand();
592
- }), changesetGroup.command("status").description("Show the currently active changeset").addHelpText("after", `
683
+ $ dr changeset deactivate`).action(async (options) => {
684
+ await changesetDeactivateCommand(options);
685
+ }), changesetGroup.command("status").description("Show the currently active changeset").option("--model <path>", "Path to model root (contains model/manifest.yaml)").addHelpText("after", `
593
686
  Examples:
594
- $ dr changeset status`).action(async () => {
595
- await changesetStatusCommand();
687
+ $ dr changeset status`).action(async (options) => {
688
+ await changesetStatusCommand(options);
596
689
  }), changesetGroup.command("show [name]").description("Show changeset details (use: status, staged, diff, or preview)").addHelpText("after", `
597
690
  To inspect a changeset, use one of:
598
691
  $ dr changeset status # Show the active changeset
@@ -607,54 +700,54 @@ To inspect a changeset, use one of:
607
700
  dr changeset staged \u2014 list all staged changes
608
701
  dr changeset diff \u2014 show a diff of staged changes
609
702
  dr changeset preview \u2014 preview what will be committed`), process.exit(1);
610
- }), changesetGroup.command("delete <name>").description("Delete a changeset permanently").option("-f, --force", "Skip confirmation prompt").addHelpText("after", `
703
+ }), changesetGroup.command("delete <name>").description("Delete a changeset permanently").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("-f, --force", "Skip confirmation prompt").addHelpText("after", `
611
704
  Examples:
612
705
  $ dr changeset delete my-feature
613
706
  $ dr changeset delete my-feature --force`).action(async (name, options) => {
614
707
  await changesetDeleteCommand(name, options);
615
- }), changesetGroup.command("staged").description("List all staged changes in the active changeset").option("-l, --layer <layer>", "Filter by layer name").addHelpText("after", `
708
+ }), changesetGroup.command("staged").description("List all staged changes in the active changeset").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("-l, --layer <layer>", "Filter by layer name").addHelpText("after", `
616
709
  Examples:
617
710
  $ dr changeset staged
618
711
  $ dr changeset staged --layer api`).action(async (options) => {
619
712
  await changesetStagedCommand(options);
620
- }), changesetGroup.command("stage <element-id>").description("Stage a specific element into the active changeset").addHelpText("after", `
713
+ }), changesetGroup.command("stage <element-id>").description("Stage a specific element into the active changeset").option("--model <path>", "Path to model root (contains model/manifest.yaml)").addHelpText("after", `
621
714
  Examples:
622
715
  $ dr changeset stage api.operation.get-users
623
- $ dr changeset stage ux.uicomponent.login-form`).action(async (elementId) => {
624
- await changesetExplicitStageCommand(elementId);
625
- }), changesetGroup.command("unstage <element-id>").description("Remove specific element from staging area").addHelpText("after", `
716
+ $ dr changeset stage ux.uicomponent.login-form`).action(async (elementId, options) => {
717
+ await changesetExplicitStageCommand(elementId, options);
718
+ }), changesetGroup.command("unstage <element-id>").description("Remove specific element from staging area").option("--model <path>", "Path to model root (contains model/manifest.yaml)").addHelpText("after", `
626
719
  Examples:
627
- $ dr changeset unstage api-endpoint-create-customer`).action(async (elementId) => {
628
- await changesetUnstageCommand(elementId);
629
- }), changesetGroup.command("discard [element-id]").description("Discard all or single staged changes").addHelpText("after", `
720
+ $ dr changeset unstage api-endpoint-create-customer`).action(async (elementId, options) => {
721
+ await changesetUnstageCommand(elementId, options);
722
+ }), changesetGroup.command("discard [element-id]").description("Discard all or single staged changes").option("--model <path>", "Path to model root (contains model/manifest.yaml)").addHelpText("after", `
630
723
  Examples:
631
724
  $ dr changeset discard
632
- $ dr changeset discard api-endpoint-create-customer`).action(async (elementId) => {
633
- await changesetDiscardCommand(elementId);
634
- }), changesetGroup.command("preview").description("Preview the merged model state with staged changes applied").option("-l, --layer <layer>", "Preview specific layer only").addHelpText("after", `
725
+ $ dr changeset discard api-endpoint-create-customer`).action(async (elementId, options) => {
726
+ await changesetDiscardCommand(elementId, options);
727
+ }), changesetGroup.command("preview").description("Preview the merged model state with staged changes applied").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("-l, --layer <layer>", "Preview specific layer only").addHelpText("after", `
635
728
  Examples:
636
729
  $ dr changeset preview
637
730
  $ dr changeset preview --layer application`).action(async (options) => {
638
731
  await changesetPreviewCommand(options);
639
- }), changesetGroup.command("diff").description("Show delta between base model and staged changes").option("-l, --layer <layer>", "Show diff for specific layer only").addHelpText("after", `
732
+ }), changesetGroup.command("diff").description("Show delta between base model and staged changes").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("-l, --layer <layer>", "Show diff for specific layer only").addHelpText("after", `
640
733
  Examples:
641
734
  $ dr changeset diff
642
735
  $ dr changeset diff --layer api`).action(async (options) => {
643
736
  await changesetDiffCommand(options);
644
- }), changesetGroup.command("commit").description("Apply staged changes to the base model").option("--validate", "Run validation before commit (default: true)", !0).option("--force", "Commit despite drift warnings", !1).addHelpText("after", `
737
+ }), changesetGroup.command("commit").description("Apply staged changes to the base model").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("--validate", "Run validation before commit (default: true)", !0).option("--force", "Commit despite drift warnings", !1).addHelpText("after", `
645
738
  Examples:
646
739
  $ dr changeset commit
647
740
  $ dr changeset commit --validate
648
741
  $ dr changeset commit --force`).action(async (options) => {
649
742
  await changesetCommitCommand(options);
650
- }), changesetGroup.command("export <changeset-id>").description("Export changeset to portable file").option("-o, --output <file>", "Output file path").option("-f, --format <format>", "Export format (yaml|json|patch)", "yaml").addHelpText("after", `
743
+ }), changesetGroup.command("export <changeset-id>").description("Export changeset to portable file").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("-o, --output <file>", "Output file path").option("-f, --format <format>", "Export format (yaml|json|patch)", "yaml").addHelpText("after", `
651
744
  Examples:
652
745
  $ dr changeset export api-updates
653
746
  $ dr changeset export api-updates --output changes.yaml
654
747
  $ dr changeset export api-updates --format json --output changes.json
655
748
  $ dr changeset export api-updates --format patch --output changes.patch`).action(async (changesetId, options) => {
656
749
  await changesetExportCommand(changesetId, options);
657
- }), changesetGroup.command("import <file>").description("Import changeset from file").option("-f, --force", "Import despite base model drift", !1).addHelpText("after", `
750
+ }), changesetGroup.command("import <file>").description("Import changeset from file").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("-f, --force", "Import despite base model drift", !1).addHelpText("after", `
658
751
  Examples:
659
752
  $ dr changeset import changes.yaml
660
753
  $ dr changeset import ../team-changes.json