@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.
- package/README.md +36 -2
- package/dist/analysis/relationship-classifier.js +2 -9
- package/dist/analysis/relationship-classifier.js.map +2 -2
- package/dist/analyzers/call-graph-utils.js +2 -2
- package/dist/analyzers/call-graph-utils.js.map +2 -2
- package/dist/analyzers/cards/build.js +171 -0
- package/dist/analyzers/cards/build.js.map +7 -0
- package/dist/analyzers/cards/classify.js +42 -0
- package/dist/analyzers/cards/classify.js.map +7 -0
- package/dist/analyzers/cards/edge-index.js +44 -0
- package/dist/analyzers/cards/edge-index.js.map +7 -0
- package/dist/analyzers/cards/facts.js +46 -0
- package/dist/analyzers/cards/facts.js.map +7 -0
- package/dist/analyzers/cards/graph.js +42 -0
- package/dist/analyzers/cards/graph.js.map +7 -0
- package/dist/analyzers/cards/index.js +8 -0
- package/dist/analyzers/cards/index.js.map +7 -0
- package/dist/analyzers/cards/tier0.js +18 -0
- package/dist/analyzers/cards/tier0.js.map +7 -0
- package/dist/analyzers/cards/types.js +1 -0
- package/dist/analyzers/cards/types.js.map +7 -0
- package/dist/analyzers/cbm-analyzer.js +195 -171
- package/dist/analyzers/cbm-analyzer.js.map +2 -2
- package/dist/analyzers/cbm-responses.js +336 -0
- package/dist/analyzers/cbm-responses.js.map +7 -0
- package/dist/analyzers/edge-relationships.js +45 -0
- package/dist/analyzers/edge-relationships.js.map +7 -0
- package/dist/analyzers/mapping-loader.js +9 -0
- package/dist/analyzers/mapping-loader.js.map +2 -2
- package/dist/analyzers/tier0-rules.js +153 -0
- package/dist/analyzers/tier0-rules.js.map +7 -0
- package/dist/analyzers/types.js.map +1 -1
- package/dist/audit/relationships/ai/prompts.js +10 -10
- package/dist/audit/relationships/ai/prompts.js.map +2 -2
- package/dist/audit/relationships/analysis/layer-templates.js +52 -52
- package/dist/audit/relationships/analysis/layer-templates.js.map +1 -1
- package/dist/cli.js +12 -2
- package/dist/cli.js.map +2 -2
- package/dist/coding-agents/default-permissions.js +31 -1
- package/dist/coding-agents/default-permissions.js.map +2 -2
- package/dist/coding-agents/drbot-mcp.js +167 -0
- package/dist/coding-agents/drbot-mcp.js.map +7 -0
- package/dist/commands/add.js +3 -2
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +117 -14
- package/dist/commands/analyzer.js.map +2 -2
- package/dist/commands/changeset-verify.js +55 -0
- package/dist/commands/changeset-verify.js.map +7 -0
- package/dist/commands/changeset.js +43 -22
- package/dist/commands/changeset.js.map +2 -2
- package/dist/commands/delete.js +10 -4
- package/dist/commands/delete.js.map +2 -2
- package/dist/commands/farm.js +176 -60
- package/dist/commands/farm.js.map +2 -2
- package/dist/commands/mcp.js +19 -4
- package/dist/commands/mcp.js.map +2 -2
- package/dist/commands/relationship.js +207 -26
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/update.js +42 -23
- package/dist/commands/update.js.map +2 -2
- package/dist/commands/upgrade.js +99 -11
- package/dist/commands/upgrade.js.map +3 -3
- package/dist/commands/version.js +1 -1
- package/dist/commands/visualize.js +4 -3
- package/dist/commands/visualize.js.map +2 -2
- package/dist/core/catalog-migration.js +33 -0
- package/dist/core/catalog-migration.js.map +7 -0
- package/dist/core/changeset-analysis.js +421 -0
- package/dist/core/changeset-analysis.js.map +7 -0
- package/dist/core/changeset-base-index.js +153 -0
- package/dist/core/changeset-base-index.js.map +7 -0
- package/dist/core/changeset-brief-delta.js +102 -0
- package/dist/core/changeset-brief-delta.js.map +7 -0
- package/dist/core/changeset-graph.js +281 -0
- package/dist/core/changeset-graph.js.map +7 -0
- package/dist/core/changeset-only-guard.js +32 -0
- package/dist/core/changeset-only-guard.js.map +7 -0
- package/dist/core/changeset-summary.js +68 -0
- package/dist/core/changeset-summary.js.map +7 -0
- package/dist/core/changeset-validator.js +66 -20
- package/dist/core/changeset-validator.js.map +2 -2
- package/dist/core/changeset-verify.js +518 -0
- package/dist/core/changeset-verify.js.map +7 -0
- package/dist/core/changeset.js +56 -9
- package/dist/core/changeset.js.map +2 -2
- package/dist/core/element-type-migration.js +145 -0
- package/dist/core/element-type-migration.js.map +7 -0
- package/dist/core/farm-manifest.js +12 -6
- package/dist/core/farm-manifest.js.map +2 -2
- package/dist/core/farm-sync-engine.js +1 -1
- package/dist/core/farm-sync-engine.js.map +2 -2
- package/dist/core/farm-sync-state.js +10 -2
- package/dist/core/farm-sync-state.js.map +2 -2
- package/dist/core/migration-registry.js +75 -46
- package/dist/core/migration-registry.js.map +2 -2
- package/dist/core/model-upgrade.js +102 -0
- package/dist/core/model-upgrade.js.map +7 -0
- package/dist/core/model.js +82 -30
- package/dist/core/model.js.map +2 -2
- package/dist/core/mutation-handler.js +71 -6
- package/dist/core/mutation-handler.js.map +2 -2
- package/dist/core/relationship-migration-table.js +6639 -0
- package/dist/core/relationship-migration-table.js.map +7 -0
- package/dist/core/relationship-migration.js +272 -0
- package/dist/core/relationship-migration.js.map +7 -0
- package/dist/core/relationship-prune.js +49 -0
- package/dist/core/relationship-prune.js.map +7 -0
- package/dist/core/relationship-staging.js +68 -0
- package/dist/core/relationship-staging.js.map +7 -0
- package/dist/core/relationships.js +26 -4
- package/dist/core/relationships.js.map +2 -2
- package/dist/core/report-data-model.js +7 -13
- package/dist/core/report-data-model.js.map +2 -2
- package/dist/core/staged-changeset-storage.js +64 -17
- package/dist/core/staged-changeset-storage.js.map +2 -2
- package/dist/core/staged-source-reference.js +28 -0
- package/dist/core/staged-source-reference.js.map +7 -0
- package/dist/core/staging-area.js +83 -18
- package/dist/core/staging-area.js.map +2 -2
- package/dist/core/virtual-projection.js +13 -5
- package/dist/core/virtual-projection.js.map +2 -2
- package/dist/export/archimate-exporter.js +1 -0
- package/dist/export/archimate-exporter.js.map +2 -2
- package/dist/generated/compiled-validators.js +2 -2
- package/dist/generated/compiled-validators.js.map +2 -2
- package/dist/generated/layer-registry.js +16 -16
- package/dist/generated/layer-registry.js.map +2 -2
- package/dist/generated/node-types.js +186 -168
- package/dist/generated/node-types.js.map +2 -2
- package/dist/generated/relationship-index.js +2236 -7790
- package/dist/generated/relationship-index.js.map +2 -2
- package/dist/integrations/claude_code/agents/dr-architect.md +16 -3
- package/dist/integrations/claude_code/agents/dr-extractor.md +1 -1
- package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
- package/dist/integrations/claude_code/commands/dr-map.md +13 -0
- package/dist/integrations/claude_code/commands/dr-plan.md +40 -0
- package/dist/integrations/claude_code/commands/dr-relate.md +106 -96
- package/dist/integrations/claude_code/commands/dr-verify.md +45 -2
- package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +14 -0
- package/dist/integrations/claude_code/docs/MCP_SERVER.md +26 -2
- package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
- package/dist/integrations/claude_code/docs/README.md +48 -1
- package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +93 -72
- package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +163 -126
- package/dist/integrations/claude_code/skills/dr_03_product_layer/SKILL.md +161 -126
- package/dist/integrations/claude_code/skills/dr_04_security_layer/SKILL.md +153 -133
- package/dist/integrations/claude_code/skills/dr_05_application_layer/SKILL.md +129 -100
- package/dist/integrations/claude_code/skills/dr_06_technology_layer/SKILL.md +111 -94
- package/dist/integrations/claude_code/skills/dr_07_api_layer/SKILL.md +143 -157
- package/dist/integrations/claude_code/skills/dr_08_data_model_layer/SKILL.md +117 -33
- package/dist/integrations/claude_code/skills/dr_09_dataset_layer/SKILL.md +74 -25
- package/dist/integrations/claude_code/skills/dr_10_ux_layer/SKILL.md +88 -12
- package/dist/integrations/claude_code/skills/dr_11_navigation_layer/SKILL.md +83 -24
- package/dist/integrations/claude_code/skills/dr_12_apm_layer/SKILL.md +57 -12
- package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +92 -15
- package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +119 -0
- package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +3 -0
- package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +1 -1
- package/dist/integrations/github_copilot/agents/dr-architect.md +1 -1
- package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +182 -102
- package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +266 -148
- package/dist/integrations/github_copilot/skills/dr_03_product_layer/SKILL.md +547 -86
- package/dist/integrations/github_copilot/skills/dr_04_security_layer/SKILL.md +164 -169
- package/dist/integrations/github_copilot/skills/dr_05_application_layer/SKILL.md +420 -150
- package/dist/integrations/github_copilot/skills/dr_06_technology_layer/SKILL.md +331 -138
- package/dist/integrations/github_copilot/skills/dr_07_api_layer/SKILL.md +265 -201
- package/dist/integrations/github_copilot/skills/dr_08_data_model_layer/SKILL.md +181 -58
- package/dist/integrations/github_copilot/skills/dr_09_dataset_layer/SKILL.md +209 -57
- package/dist/integrations/github_copilot/skills/dr_10_ux_layer/SKILL.md +277 -112
- package/dist/integrations/github_copilot/skills/dr_11_navigation_layer/SKILL.md +219 -70
- package/dist/integrations/github_copilot/skills/dr_12_apm_layer/SKILL.md +189 -105
- package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +222 -102
- package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +119 -0
- package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +3 -0
- package/dist/integrations/hash-utils.js.map +2 -2
- package/dist/mcp/api-key-manager.js +14 -1
- package/dist/mcp/api-key-manager.js.map +2 -2
- package/dist/mcp/changeset-only.js +34 -0
- package/dist/mcp/changeset-only.js.map +7 -0
- package/dist/mcp/tool-registry.js +19 -3
- package/dist/mcp/tool-registry.js.map +2 -2
- package/dist/mcp/tools/changeset-analysis-tools.js +78 -0
- package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
- package/dist/mcp/tools/changeset-editing.js +184 -0
- package/dist/mcp/tools/changeset-editing.js.map +7 -0
- package/dist/mcp/tools/changeset-lifecycle.js +83 -0
- package/dist/mcp/tools/changeset-lifecycle.js.map +7 -0
- package/dist/mcp/tools/changeset-shared.js +31 -0
- package/dist/mcp/tools/changeset-shared.js.map +7 -0
- package/dist/mcp/tools/changeset-show.js +17 -1
- package/dist/mcp/tools/changeset-show.js.map +2 -2
- package/dist/mcp/tools/changeset-verify.js +43 -0
- package/dist/mcp/tools/changeset-verify.js.map +7 -0
- package/dist/mcp/tools/index.js +19 -1
- package/dist/mcp/tools/index.js.map +2 -2
- package/dist/mcp/tools/model-add.js +6 -5
- package/dist/mcp/tools/model-add.js.map +2 -2
- package/dist/mcp/tools/model-delete.js +2 -2
- package/dist/mcp/tools/model-delete.js.map +2 -2
- package/dist/mcp/tools/model-search.js +14 -0
- package/dist/mcp/tools/model-search.js.map +2 -2
- package/dist/mcp/tools/model-show.js +29 -2
- package/dist/mcp/tools/model-show.js.map +2 -2
- package/dist/mcp/tools/model-trace.js +93 -30
- package/dist/mcp/tools/model-trace.js.map +2 -2
- package/dist/mcp/tools/model-update.js +35 -19
- package/dist/mcp/tools/model-update.js.map +2 -2
- package/dist/mcp/tools/relationship-tools.js +98 -0
- package/dist/mcp/tools/relationship-tools.js.map +7 -0
- package/dist/mcp/tools/shared.js +25 -2
- package/dist/mcp/tools/shared.js.map +2 -2
- package/dist/mcp/tools/spec-type.js +90 -0
- package/dist/mcp/tools/spec-type.js.map +7 -0
- package/dist/schemas/bundled/analyzers/cbm.json +1186 -68
- package/dist/schemas/bundled/analyzers/manifest.json +2 -2
- package/dist/schemas/bundled/api.json +1029 -1658
- package/dist/schemas/bundled/apm.json +499 -734
- package/dist/schemas/bundled/application.json +735 -371
- package/dist/schemas/bundled/base.json +3 -220
- package/dist/schemas/bundled/business.json +452 -366
- package/dist/schemas/bundled/data-model.json +395 -411
- package/dist/schemas/bundled/data-store.json +334 -558
- package/dist/schemas/bundled/manifest.json +18 -18
- package/dist/schemas/bundled/motivation.json +349 -368
- package/dist/schemas/bundled/navigation.json +415 -731
- package/dist/schemas/bundled/product.json +325 -159
- package/dist/schemas/bundled/security.json +864 -1232
- package/dist/schemas/bundled/technology.json +574 -703
- package/dist/schemas/bundled/testing.json +718 -1643
- package/dist/schemas/bundled/ux.json +739 -1352
- package/dist/server/schemas.js +8 -0
- package/dist/server/schemas.js.map +2 -2
- package/dist/server/server.js +218 -34
- package/dist/server/server.js.map +2 -2
- package/dist/server-entry.js +2 -1
- package/dist/server-entry.js.map +2 -2
- package/dist/telemetry/index.js +1 -1
- package/dist/utils/ansi-suppressor.js +6 -8
- package/dist/utils/ansi-suppressor.js.map +2 -2
- package/dist/utils/attribute-patch.js +41 -0
- package/dist/utils/attribute-patch.js.map +7 -0
- package/dist/utils/error-hints.js +29 -0
- package/dist/utils/error-hints.js.map +7 -0
- package/dist/utils/errors.js +9 -3
- package/dist/utils/errors.js.map +2 -2
- package/dist/utils/project-paths.js +26 -1
- package/dist/utils/project-paths.js.map +2 -2
- package/dist/utils/source-reference.js +14 -12
- package/dist/utils/source-reference.js.map +2 -2
- package/dist/utils/spec-version.js +2 -2
- package/dist/utils/spec-version.js.map +1 -1
- package/dist/validators/composed-reference-validator.js +5 -27
- package/dist/validators/composed-reference-validator.js.map +2 -2
- package/dist/validators/reference-validator.js +0 -7
- package/dist/validators/reference-validator.js.map +2 -2
- package/dist/validators/relationship-schema-validator.js +3 -3
- package/dist/validators/relationship-schema-validator.js.map +2 -2
- package/dist/validators/schema-validator.js +27 -9
- package/dist/validators/schema-validator.js.map +2 -2
- package/dist/validators/types.js.map +1 -1
- package/dist/viewer/README.md +6 -6
- package/dist/viewer/assets/main-CxzcuU_o.js +84 -0
- package/dist/viewer/assets/main-j-7ULYpm.css +1 -0
- package/dist/viewer/index.html +2 -2
- package/dist/viewer/manifest.json +10 -10
- package/dist/viewer/version.json +1 -1
- package/package.json +2 -1
- package/dist/viewer/assets/main-B7AOQXXX.js +0 -81
- package/dist/viewer/assets/main-vdrFrG7q.css +0 -1
package/dist/commands/update.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
73
|
+
setStagedSourceReference(after, void 0);
|
|
63
74
|
else if (options.sourceFile) {
|
|
64
75
|
const newRef = buildSourceReference(options);
|
|
65
|
-
newRef && (after
|
|
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 (
|
|
80
|
-
const errorMessages =
|
|
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 ?
|
|
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
|
-
|
|
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 (
|
|
143
|
-
const errorMessages =
|
|
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 ?
|
|
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
|
|
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
|
|
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)}
|
|
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": "AAIA,OAAO,WAAW;AAClB,SAAS,aAAa;AACtB,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,wBAAwB;AACjC,SAAS,UAAU,aAAa,eAAe,YAAY,aAAa,0BAA0B;
|
|
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
|
}
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -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
|
|
273
|
-
|
|
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
|
|
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
|
-
|
|
281
|
-
|
|
282
|
-
});
|
|
283
|
-
for (const
|
|
284
|
-
console.log(ansis.green(` \u2713 ${
|
|
285
|
-
|
|
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,
|