@documentation-robotics/cli 0.2.0 → 0.4.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 +46 -16
- package/dist/analysis/relationship-classifier.js +2 -9
- package/dist/analysis/relationship-classifier.js.map +2 -2
- package/dist/analyzers/active-analyzer.js +62 -0
- package/dist/analyzers/active-analyzer.js.map +7 -0
- 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 +191 -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/extract.js +138 -0
- package/dist/analyzers/cards/extract.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/routes.js +96 -0
- package/dist/analyzers/cards/routes.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 +270 -174
- package/dist/analyzers/cbm-analyzer.js.map +2 -2
- package/dist/analyzers/cbm-responses.js +342 -0
- package/dist/analyzers/cbm-responses.js.map +7 -0
- package/dist/analyzers/code-changes.js +159 -0
- package/dist/analyzers/code-changes.js.map +7 -0
- package/dist/analyzers/edge-relationships.js +49 -0
- package/dist/analyzers/edge-relationships.js.map +7 -0
- package/dist/analyzers/extraction-plan.js +541 -0
- package/dist/analyzers/extraction-plan.js.map +7 -0
- package/dist/analyzers/index-job.js +229 -0
- package/dist/analyzers/index-job.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 +23 -11
- 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 +269 -0
- package/dist/coding-agents/drbot-mcp.js.map +7 -0
- package/dist/commands/add.js +7 -4
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +143 -40
- package/dist/commands/analyzer.js.map +2 -2
- package/dist/commands/changeset-verify.js +63 -0
- package/dist/commands/changeset-verify.js.map +7 -0
- package/dist/commands/changeset.js +80 -29
- 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/init.js +9 -26
- package/dist/commands/init.js.map +2 -2
- package/dist/commands/mcp.js +40 -21
- package/dist/commands/mcp.js.map +3 -3
- package/dist/commands/relationship.js +208 -37
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/reports.js +3 -3
- package/dist/commands/reports.js.map +2 -2
- package/dist/commands/update.js +52 -32
- package/dist/commands/update.js.map +2 -2
- package/dist/commands/upgrade.js +99 -103
- package/dist/commands/upgrade.js.map +3 -3
- package/dist/commands/validate.js +19 -3
- package/dist/commands/validate.js.map +2 -2
- package/dist/commands/version.js +1 -1
- package/dist/commands/visualize.js +34 -15
- package/dist/commands/visualize.js.map +2 -2
- package/dist/core/annotation-store.js +15 -5
- package/dist/core/annotation-store.js.map +2 -2
- package/dist/core/catalog-migration.js +34 -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 +160 -0
- package/dist/core/changeset-base-index.js.map +7 -0
- package/dist/core/changeset-brief-compact.js +256 -0
- package/dist/core/changeset-brief-compact.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 +848 -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/extraction-observability.js +161 -0
- package/dist/core/extraction-observability.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 +88 -47
- 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/project-init.js +53 -0
- package/dist/core/project-init.js.map +7 -0
- 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 +161 -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 +145 -18
- 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 +166 -24
- package/dist/core/staging-area.js.map +2 -2
- package/dist/core/upgrade-plan.js +117 -0
- package/dist/core/upgrade-plan.js.map +7 -0
- 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 +2468 -7913
- package/dist/generated/relationship-index.js.map +2 -2
- package/dist/integrations/claude_code/.claude-plugin/plugin.json +24 -0
- package/dist/integrations/claude_code/agents/dr-architect.md +30 -3
- package/dist/integrations/claude_code/agents/dr-extractor.md +8 -2
- package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
- package/dist/integrations/claude_code/commands/dr-changeset.md +2 -1
- package/dist/integrations/claude_code/commands/dr-map.md +20 -1
- package/dist/integrations/claude_code/commands/dr-plan.md +66 -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 +47 -26
- package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
- package/dist/integrations/claude_code/docs/README.md +68 -2
- package/dist/integrations/claude_code/plugin-agents/dr-advisor.md +255 -0
- package/dist/integrations/claude_code/plugin-agents/dr-architect.md +306 -0
- 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 +95 -15
- package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +178 -0
- package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +8 -0
- package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +6 -1
- package/dist/integrations/github_copilot/agents/dr-architect.md +3 -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 +225 -102
- package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +177 -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 +45 -0
- package/dist/mcp/changeset-only.js.map +7 -0
- package/dist/mcp/project-root.js +85 -0
- package/dist/mcp/project-root.js.map +7 -0
- package/dist/mcp/server-instructions.js +27 -0
- package/dist/mcp/server-instructions.js.map +7 -0
- package/dist/mcp/strict-schema.js +52 -0
- package/dist/mcp/strict-schema.js.map +7 -0
- package/dist/mcp/tool-registry.js +55 -5
- package/dist/mcp/tool-registry.js.map +2 -2
- package/dist/mcp/tools/changeset-analysis-tools.js +98 -0
- package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
- package/dist/mcp/tools/changeset-commit.js +224 -0
- package/dist/mcp/tools/changeset-commit.js.map +7 -0
- package/dist/mcp/tools/changeset-editing.js +260 -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 +49 -0
- package/dist/mcp/tools/changeset-verify.js.map +7 -0
- package/dist/mcp/tools/codebase-extract.js +836 -0
- package/dist/mcp/tools/codebase-extract.js.map +7 -0
- package/dist/mcp/tools/codebase-index.js +125 -0
- package/dist/mcp/tools/codebase-index.js.map +7 -0
- package/dist/mcp/tools/codebase-shared.js +265 -0
- package/dist/mcp/tools/codebase-shared.js.map +7 -0
- package/dist/mcp/tools/codebase-verify.js +48 -0
- package/dist/mcp/tools/codebase-verify.js.map +7 -0
- package/dist/mcp/tools/index.js +34 -1
- package/dist/mcp/tools/index.js.map +2 -2
- package/dist/mcp/tools/model-add.js +191 -74
- 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 +46 -26
- package/dist/mcp/tools/model-update.js.map +2 -2
- package/dist/mcp/tools/model-validate.js +46 -4
- package/dist/mcp/tools/model-validate.js.map +2 -2
- package/dist/mcp/tools/project-status-collectors.js +381 -0
- package/dist/mcp/tools/project-status-collectors.js.map +7 -0
- package/dist/mcp/tools/project-status.js +237 -0
- package/dist/mcp/tools/project-status.js.map +7 -0
- package/dist/mcp/tools/project-tools.js +505 -0
- package/dist/mcp/tools/project-tools.js.map +7 -0
- package/dist/mcp/tools/relationship-tools.js +167 -0
- package/dist/mcp/tools/relationship-tools.js.map +7 -0
- package/dist/mcp/tools/review-open.js +210 -0
- package/dist/mcp/tools/review-open.js.map +7 -0
- package/dist/mcp/tools/shared.js +35 -4
- 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/reports/model-report-orchestrator.js +31 -2
- package/dist/reports/model-report-orchestrator.js.map +2 -2
- package/dist/schemas/bundled/analyzers/cbm.json +1200 -70
- 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 +865 -1646
- 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 +686 -231
- package/dist/server/server.js.map +3 -3
- package/dist/server/viewer-registry.js +264 -0
- package/dist/server/viewer-registry.js.map +7 -0
- 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/id-generator.js +5 -2
- package/dist/utils/id-generator.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 +64 -31
- 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/model-warnings.js +28 -0
- package/dist/validators/model-warnings.js.map +7 -0
- 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-CUOQGGRA.css +1 -0
- package/dist/viewer/assets/main-DvH3gYrI.js +84 -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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/commands/relationship.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Relationship subcommands for managing intra-layer and cross-layer relationships\n */\n\nimport { Command } from \"commander\";\nimport ansis from \"ansis\";\nimport { Model } from \"../core/model.js\";\nimport { StagingAreaManager } from \"../core/staging-area.js\";\nimport { findElementLayer } from \"../utils/element-utils.js\";\nimport { isValidLayerName } from \"../core/layers.js\";\nimport {\n CLIError,\n ErrorCategory,\n handleError,\n handleSuccess,\n handleInfo,\n getErrorMessage\n} from \"../utils/errors.js\";\nimport {\n getValidRelationships,\n getValidPredicatesForSource,\n getValidDestinationsForSourceAndPredicate\n} from \"../generated/relationship-index.js\";\nimport { normalizeNodeType } from \"../generated/node-types.js\";\nimport { ModelReportOrchestrator } from \"../reports/model-report-orchestrator.js\";\nimport { emitLog, SeverityNumber } from \"../telemetry/index.js\";\nimport { Element } from \"../core/element.js\";\nimport { Relationship } from \"../core/relationships.js\";\nimport { RelationshipCatalog } from \"../core/relationship-catalog.js\";\n\n/**\n * Pre-resolved element and layer information to avoid redundant lookups.\n * Ensures source and target pairs are consistent: if source is provided, both element and layerName must be present.\n * This prevents invalid states like {sourceElement: ..., sourceLayerName: undefined}.\n */\ninterface PreResolvedElements {\n source?: {\n element: Element;\n layerName: string;\n };\n target?: {\n element: Element;\n layerName: string;\n };\n}\n\n/**\n * Validate element properties and construct a SpecNodeId\n * @throws {CLIError} if element properties are invalid\n */\nfunction constructSpecNodeId(\n element: { layer_id?: unknown; type?: unknown },\n elementId: string\n): string {\n const layerId = element.layer_id;\n const type = element.type;\n\n if (typeof layerId !== \"string\" || !layerId) {\n throw new CLIError(\n `Invalid element ${elementId}: missing or invalid layer_id`,\n ErrorCategory.SYSTEM\n );\n }\n\n if (typeof type !== \"string\" || !type) {\n throw new CLIError(\n `Invalid element ${elementId}: missing or invalid type`,\n ErrorCategory.SYSTEM\n );\n }\n\n // Normalize type name for schema validation (e.g., \"process\" -> \"businessprocess\")\n const normalizedType = normalizeNodeType(layerId, type);\n\n return `${layerId}.${normalizedType}`;\n}\n\n/**\n * Validate a relationship combination using schema-driven registry\n * @returns {valid, suggestions} where suggestions are provided if invalid\n */\nexport function validateRelationshipCombination(\n sourceSpecNodeId: string,\n predicate: string,\n destSpecNodeId: string\n): { valid: boolean; suggestions?: string[] } {\n const valid =\n getValidRelationships(sourceSpecNodeId, predicate, destSpecNodeId).length >\n 0;\n\n if (valid) {\n return { valid: true };\n }\n\n // Generate helpful suggestions\n const suggestions: string[] = [];\n const validPredicates = getValidPredicatesForSource(sourceSpecNodeId);\n\n if (validPredicates.length > 0) {\n suggestions.push(\n `Valid predicates for ${sourceSpecNodeId}: ${validPredicates.join(\", \")}`\n );\n } else {\n suggestions.push(`No valid relationships defined for ${sourceSpecNodeId}`);\n }\n\n // If predicate is provided, show valid destinations\n if (predicate) {\n const validDests = getValidDestinationsForSourceAndPredicate(\n sourceSpecNodeId,\n predicate\n );\n if (validDests.length > 0) {\n suggestions.push(\n `Valid destinations for --[${predicate}]-->: ${validDests.join(\", \")}`\n );\n } else {\n suggestions.push(\n `No valid destinations for ${sourceSpecNodeId} --[${predicate}]-->`\n );\n }\n }\n\n return { valid: false, suggestions };\n}\n\n/**\n * Get cardinality and strength info for a relationship\n */\nexport function getRelationshipConstraints(\n sourceSpecNodeId: string,\n predicate: string,\n destSpecNodeId: string\n): { cardinality: string; strength: string } | null {\n const rels = getValidRelationships(\n sourceSpecNodeId,\n predicate,\n destSpecNodeId\n );\n if (rels.length === 0) return null;\n\n const rel = rels[0];\n return {\n cardinality: rel.cardinality,\n strength: rel.strength\n };\n}\n\n/**\n * Handler function for adding a relationship\n * Encapsulates the core logic of the add-relationship command\n * @internal Exported for testing purposes\n *\n * @param model - The architecture model\n * @param source - Source element ID\n * @param target - Target element ID\n * @param predicate - Relationship predicate\n * @param properties - Optional relationship properties\n * @param preResolved - Pre-resolved elements and layer names (optional, for performance)\n */\nexport async function addRelationshipHandler(\n model: Model,\n source: string,\n target: string,\n predicate: string,\n properties?: Record<string, unknown>,\n preResolved?: PreResolvedElements\n): Promise<boolean> {\n // Use pre-resolved elements if provided, otherwise resolve them\n let resolvedSourceLayerName = preResolved?.source?.layerName;\n let resolvedSourceElement = preResolved?.source?.element;\n let resolvedTargetLayerName = preResolved?.target?.layerName;\n let resolvedTargetElement = preResolved?.target?.element;\n\n if (!resolvedSourceLayerName) {\n resolvedSourceLayerName = await findElementLayer(model, source);\n if (!resolvedSourceLayerName) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n if (!resolvedSourceElement) {\n const sourceLayer = await model.getLayer(resolvedSourceLayerName);\n if (!sourceLayer) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n resolvedSourceElement = sourceLayer.getElement(source);\n if (!resolvedSourceElement) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n if (!resolvedTargetLayerName) {\n resolvedTargetLayerName = await findElementLayer(model, target);\n if (!resolvedTargetLayerName) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n if (!resolvedTargetElement) {\n const targetLayer = await model.getLayer(resolvedTargetLayerName);\n if (!targetLayer) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n resolvedTargetElement = targetLayer.getElement(target);\n if (!resolvedTargetElement) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n // Schema-driven validation\n const sourceSpecNodeId = constructSpecNodeId(resolvedSourceElement, source);\n const targetSpecNodeId = constructSpecNodeId(resolvedTargetElement, target);\n\n const validation = validateRelationshipCombination(\n sourceSpecNodeId,\n predicate,\n targetSpecNodeId\n );\n\n if (!validation.valid) {\n throw new CLIError(\n `Invalid relationship: ${source} --[${predicate}]--> ${target}`,\n ErrorCategory.USER,\n validation.suggestions\n );\n }\n\n {\n const catalog = new RelationshipCatalog();\n await catalog.load();\n const relType = catalog.getTypeByPredicate(predicate);\n if (relType && !relType.semantics.reflexivity && source === target) {\n throw new CLIError(\n `Invalid relationship: predicate \"${predicate}\" does not allow reflexive relationships (${source})`,\n ErrorCategory.USER\n );\n }\n }\n\n // Guard against duplicate relationships before staging or writing\n if (model.relationships.find(source, target, predicate).length > 0) {\n // Return false to signal duplicate; caller will emit appropriate output\n return false;\n }\n\n // Check for active changeset \u2014 stage relationship instead of writing directly\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n const relData = {\n source,\n target,\n predicate,\n layer: resolvedSourceLayerName,\n ...(resolvedTargetLayerName !== resolvedSourceLayerName\n ? { targetLayer: resolvedTargetLayerName }\n : {}),\n category: \"structural\" as const,\n ...(properties ? { properties } : {})\n };\n\n if (activeChangesetId) {\n // Stage the relationship change in the active changeset\n const compositeKey = `${source}::${predicate}::${target}`;\n await stagingManager.stage(activeChangesetId, {\n type: \"relationship-add\",\n elementId: compositeKey,\n layerName: resolvedSourceLayerName,\n after: relData\n });\n } else {\n // No active changeset \u2014 write directly to relationships.yaml\n model.relationships.add(relData);\n await model.saveRelationships();\n await model.saveManifest();\n\n // Regenerate reports for all affected layers (including transitively related)\n try {\n const orchestrator = new ModelReportOrchestrator(model, model.rootPath);\n const affectedLayers = new Set<string>();\n\n // Compute affected layers for source layer\n if (isValidLayerName(resolvedSourceLayerName)) {\n for (const layer of orchestrator.computeAffectedLayers(\n resolvedSourceLayerName\n )) {\n affectedLayers.add(layer);\n }\n }\n\n // Compute affected layers for target layer\n if (isValidLayerName(resolvedTargetLayerName)) {\n for (const layer of orchestrator.computeAffectedLayers(\n resolvedTargetLayerName\n )) {\n affectedLayers.add(layer);\n }\n }\n\n await orchestrator.regenerate(affectedLayers);\n } catch (error) {\n emitLog(\n SeverityNumber.WARN,\n \"Failed to regenerate layer reports after relationship add\",\n {\n \"relationship.predicate\": predicate,\n \"relationship.sourceLayer\": resolvedSourceLayerName,\n \"relationship.targetLayer\": resolvedTargetLayerName,\n \"relationship.source\": source,\n \"relationship.target\": target,\n \"error.message\": getErrorMessage(error)\n }\n );\n }\n }\n\n return true;\n}\n\n/**\n * Handler function for deleting relationships\n * Encapsulates the core logic of the delete-relationship command\n * @internal Exported for testing purposes\n *\n * @param model - The architecture model\n * @param source - Source element ID\n * @param target - Target element ID\n * @param predicate - Optional relationship predicate\n * @param preResolved - Pre-resolved source layer name and relationships (optional, for performance)\n */\ninterface DeletePreResolved {\n sourceLayerName?: string;\n toDelete?: Relationship[];\n}\n\nexport async function deleteRelationshipHandler(\n model: Model,\n source: string,\n target: string,\n predicate?: string,\n preResolved?: DeletePreResolved\n): Promise<{ deletedCount: number }> {\n // Use pre-resolved source layer if provided, otherwise resolve it\n let resolvedSourceLayerName = preResolved?.sourceLayerName;\n if (!resolvedSourceLayerName) {\n resolvedSourceLayerName = await findElementLayer(model, source);\n if (!resolvedSourceLayerName) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n // Use pre-found relationships if provided, otherwise find them\n let resolvedToDelete = preResolved?.toDelete;\n if (!resolvedToDelete) {\n resolvedToDelete = model.relationships.find(source, target, predicate);\n }\n\n if (resolvedToDelete.length === 0) {\n throw new CLIError(\"No matching relationships found\", ErrorCategory.USER);\n }\n\n // Check for active changeset \u2014 stage deletion instead of writing directly\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n if (activeChangesetId) {\n // Stage each relationship deletion in the active changeset\n for (const rel of resolvedToDelete) {\n const compositeKey = `${rel.source}::${rel.predicate}::${rel.target}`;\n await stagingManager.stage(activeChangesetId, {\n type: \"relationship-delete\",\n elementId: compositeKey,\n layerName: rel.layer,\n before: {\n source: rel.source,\n target: rel.target,\n predicate: rel.predicate,\n layer: rel.layer,\n ...(rel.targetLayer ? { targetLayer: rel.targetLayer } : {}),\n ...(rel.properties ? { properties: rel.properties } : {})\n }\n });\n }\n } else {\n // No active changeset \u2014 write directly\n model.relationships.delete(source, target, predicate);\n await model.saveRelationships();\n await model.saveManifest();\n\n // Regenerate reports for all affected layers (including transitively related)\n try {\n const orchestrator = new ModelReportOrchestrator(model, model.rootPath);\n const affectedLayers = new Set<string>();\n\n // Compute affected layers for each deleted relationship's source and target\n for (const rel of resolvedToDelete) {\n // Compute affected layers for source layer\n if (rel.layer && isValidLayerName(rel.layer)) {\n for (const layer of orchestrator.computeAffectedLayers(rel.layer)) {\n affectedLayers.add(layer);\n }\n }\n\n // Compute affected layers for target layer\n if (rel.targetLayer && isValidLayerName(rel.targetLayer)) {\n for (const layer of orchestrator.computeAffectedLayers(\n rel.targetLayer\n )) {\n affectedLayers.add(layer);\n }\n }\n }\n\n await orchestrator.regenerate(affectedLayers);\n } catch (error) {\n emitLog(\n SeverityNumber.WARN,\n \"Failed to regenerate layer reports after relationship delete\",\n {\n \"relationship.predicate\": predicate,\n \"relationship.source\": source,\n \"relationship.target\": target,\n \"relationship.deleteCount\": resolvedToDelete.length,\n \"error.message\": getErrorMessage(error)\n }\n );\n }\n }\n\n return { deletedCount: resolvedToDelete.length };\n}\n\nexport function relationshipCommands(program: Command, rootProgram?: Command): void {\n program\n .command(\"add <source> <target>\")\n .description(\n \"Add a relationship between elements (intra-layer or cross-layer)\"\n )\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .requiredOption(\n \"--predicate <predicate>\",\n \"Relationship predicate (e.g., depends-on, realizes, exposes)\"\n )\n .option(\"--properties <json>\", \"Relationship properties (JSON)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship add motivation.goal.goal-a motivation.goal.goal-b --predicate aggregates\n $ dr relationship add api.operation.create-order application.service.order-service --predicate exposes\n $ dr relationship add business.businessprocess.checkout application.applicationprocess.checkout --predicate aggregates\n $ dr relationship add element-1 element-2 --predicate realizes --properties '{\"strength\":\"high\"}'`\n )\n .action(async (source, target, options) => {\n try {\n // Load model\n const model = await Model.load(options.model || process.cwd());\n\n // Find source element for constraints info\n const sourceLayerName = await findElementLayer(model, source);\n if (!sourceLayerName) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n const sourceLayer = await model.getLayer(sourceLayerName);\n if (!sourceLayer) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n const sourceElement = sourceLayer.getElement(source);\n if (!sourceElement) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n\n // Find target element for constraints info\n const targetLayerName = await findElementLayer(model, target);\n if (!targetLayerName) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n const targetLayer = await model.getLayer(targetLayerName);\n if (!targetLayer) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n const targetElement = targetLayer.getElement(target);\n if (!targetElement) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n\n // Get cardinality and strength info (before calling handler for CLI output)\n const sourceSpecNodeId = constructSpecNodeId(sourceElement, source);\n const targetSpecNodeId = constructSpecNodeId(targetElement, target);\n const constraints = getRelationshipConstraints(\n sourceSpecNodeId,\n options.predicate,\n targetSpecNodeId\n );\n\n // Parse properties if provided\n let properties: Record<string, unknown> | undefined;\n if (options.properties) {\n try {\n properties = JSON.parse(options.properties);\n } catch (e) {\n throw new CLIError(\n \"Invalid JSON in --properties\",\n ErrorCategory.USER\n );\n }\n }\n\n // Check for active changeset\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n // Call the handler function with pre-resolved elements to avoid duplicate lookups\n const added = await addRelationshipHandler(\n model,\n source,\n target,\n options.predicate,\n properties,\n {\n source: { element: sourceElement, layerName: sourceLayerName },\n target: { element: targetElement, layerName: targetLayerName }\n }\n );\n\n if (!added) {\n // duplicate \u2014 emit JSON response indicating relationship already exists\n handleSuccess(\n `Relationship ${source} --[${options.predicate}]--> ${target} already exists`,\n {\n source,\n target,\n predicate: options.predicate,\n layer: sourceLayerName,\n duplicate: true,\n },\n { verbose: options.verbose }\n );\n return;\n }\n\n // Show cardinality and strength in output\n let message = `Added relationship: ${ansis.bold(source)} ${options.predicate} ${ansis.bold(target)}`;\n const details: Record<string, unknown> = {\n source,\n target,\n predicate: options.predicate,\n layer: sourceLayerName,\n };\n if (constraints) {\n message += ansis.dim(\n ` (${constraints.cardinality}, ${constraints.strength} strength)`\n );\n details.cardinality = constraints.cardinality;\n details.strength = constraints.strength;\n }\n if (activeChangesetId) {\n message += ansis.dim(` [staged]`);\n details.changesetStatus = \"staged\";\n }\n\n handleSuccess(message, details, { verbose: options.verbose });\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"delete <source> <target>\")\n .description(\"Delete a relationship\")\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .option(\n \"--predicate <predicate>\",\n \"Specific predicate to delete (optional, delete all if not specified)\"\n )\n .option(\"--force\", \"Skip confirmation prompt\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship delete element-1 element-2 --predicate depends-on\n $ dr relationship delete element-1 element-2 --force`\n )\n .action(async (source, target, options) => {\n try {\n // Load model\n const model = await Model.load(options.model || process.cwd());\n\n // Find source element and relationships to delete (for confirmation)\n const sourceLayerName = await findElementLayer(model, source);\n if (!sourceLayerName) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n\n // Find relationships to delete (to show confirmation count)\n const toDelete = model.relationships.find(\n source,\n target,\n options.predicate\n );\n\n if (toDelete.length === 0) {\n throw new CLIError(\n \"No matching relationships found\",\n ErrorCategory.USER\n );\n }\n\n // Confirm deletion unless --force or non-interactive environment\n // In non-interactive environments (CI, tests), skip confirmation\n const isInteractive = process.stdin.isTTY && process.stdout.isTTY;\n if (!options.force && isInteractive) {\n // Dynamic import of prompts is safe here: caught by outer try-catch\n // This allows lazy loading of the prompt library only when needed\n const { confirm } = await import(\"@clack/prompts\");\n const confirmed = await confirm({\n message: `Delete ${toDelete.length} relationship(s)? This cannot be undone.`,\n initialValue: false\n });\n\n if (!confirmed) {\n handleSuccess(\"Deletion cancelled\", {\n source,\n target,\n status: \"cancelled\",\n });\n return;\n }\n }\n\n // Check for active changeset\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n // Call the handler function with pre-resolved values to avoid duplicate lookups\n const result = await deleteRelationshipHandler(\n model,\n source,\n target,\n options.predicate,\n {\n sourceLayerName,\n toDelete\n }\n );\n\n const stagedSuffix = activeChangesetId ? \" [staged]\" : \"\";\n const deleteDetails: Record<string, unknown> = {\n source,\n target,\n layer: sourceLayerName,\n deletedCount: result.deletedCount,\n };\n if (options.predicate) {\n deleteDetails.predicate = options.predicate;\n }\n if (activeChangesetId) {\n deleteDetails.changesetStatus = \"staged\";\n }\n handleSuccess(\n `Deleted ${result.deletedCount} relationship(s) from ${ansis.bold(source)} to ${ansis.bold(target)}${stagedSuffix}`,\n deleteDetails,\n { verbose: options.verbose }\n );\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"list <id>\")\n .description(\"List relationships for an element\")\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .option(\n \"--direction <dir>\",\n \"Filter by direction (incoming/outgoing/all)\",\n \"all\"\n )\n .option(\"--json\", \"Output as JSON\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship list api-endpoint-create-customer\n $ dr relationship list business-service-order --direction outgoing\n $ dr relationship list element-1 --json`\n )\n .action(async (id, options) => {\n try {\n // Load model\n const model = await Model.load(options.model || process.cwd());\n const layerName = await findElementLayer(model, id);\n\n if (!layerName) {\n throw new CLIError(`Element ${id} not found`, ErrorCategory.USER);\n }\n\n // Get relationships from centralized store\n const { outgoing, incoming } = model.relationships.getForElement(id);\n\n // Filter by direction\n let relationships: typeof outgoing = [];\n if (options.direction === \"outgoing\" || options.direction === \"all\") {\n relationships.push(...outgoing);\n }\n if (options.direction === \"incoming\" || options.direction === \"all\") {\n relationships.push(...incoming);\n }\n\n const shouldOutputJson = options.json ?? (rootProgram?.opts().json);\n if (shouldOutputJson) {\n console.log(JSON.stringify(relationships, null, 2));\n return;\n }\n\n if (relationships.length === 0) {\n handleInfo(\n ansis.yellow(`No ${options.direction} relationships for ${id}`)\n );\n return;\n }\n\n handleInfo(\"\");\n handleInfo(\n ansis.bold(\n `${options.direction === \"all\" ? \"\" : options.direction + \" \"}relationships for ${ansis.cyan(id)}:`\n )\n );\n handleInfo(ansis.dim(\"\u2500\".repeat(80)));\n\n for (const rel of relationships) {\n const isOutgoing = rel.source === id;\n const direction = isOutgoing ? \"\u2192\" : \"\u2190\";\n const otherElement = isOutgoing ? rel.target : rel.source;\n const crossLayer =\n rel.targetLayer && rel.targetLayer !== rel.layer\n ? ansis.dim(` [${rel.layer} \u2192 ${rel.targetLayer}]`)\n : \"\";\n\n handleInfo(\n ` ${direction} ${ansis.magenta(rel.predicate)}: ${ansis.yellow(otherElement)}${crossLayer}`\n );\n\n if (rel.properties) {\n const propStr = Object.entries(rel.properties)\n .map(([k, v]) => `${k}=${v}`)\n .join(\", \");\n handleInfo(` ${ansis.dim(propStr)}`);\n }\n }\n\n handleInfo(ansis.dim(\"\u2500\".repeat(80)));\n handleInfo(ansis.dim(`Total: ${relationships.length} relationship(s)`));\n handleInfo(\"\");\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"show <source> <target>\")\n .description(\"Show relationship details\")\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship show api-endpoint-create-customer business-service-customer-mgmt\n $ dr relationship show application-component-api motivation-goal-sales-efficiency`\n )\n .action(async (source, target, options) => {\n try {\n // Load model\n const model = await Model.load(options.model || process.cwd());\n const sourceLayerName = await findElementLayer(model, source);\n\n if (!sourceLayerName) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n\n // Find relationships from centralized store\n const relationships = model.relationships.find(source, target);\n\n if (relationships.length === 0) {\n throw new CLIError(\n `No relationships from ${source} to ${target}`,\n ErrorCategory.USER\n );\n }\n\n handleInfo(\"\");\n handleInfo(\n ansis.bold(\n `Relationship${relationships.length > 1 ? \"s\" : \"\"} from ${ansis.cyan(source)} to ${ansis.yellow(target)}:`\n )\n );\n handleInfo(ansis.dim(\"\u2500\".repeat(60)));\n\n for (let i = 0; i < relationships.length; i++) {\n const rel = relationships[i];\n\n if (i > 0) {\n handleInfo(\"\");\n }\n\n handleInfo(`Predicate: ${ansis.magenta(rel.predicate)}`);\n handleInfo(`Layer: ${ansis.cyan(rel.layer)}`);\n if (rel.targetLayer && rel.targetLayer !== rel.layer) {\n handleInfo(`Target Layer: ${ansis.cyan(rel.targetLayer)}`);\n }\n\n if (rel.properties && Object.keys(rel.properties).length > 0) {\n handleInfo(\"Properties:\");\n for (const [key, value] of Object.entries(rel.properties)) {\n const displayValue =\n typeof value === \"string\"\n ? value\n : JSON.stringify(value, null, 2);\n handleInfo(` ${ansis.cyan(key)}: ${displayValue}`);\n }\n } else {\n handleInfo(\"Properties: none\");\n }\n }\n\n handleInfo(\"\");\n } catch (error) {\n handleError(error);\n }\n });\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Relationship subcommands for managing intra-layer and cross-layer relationships\n */\n\nimport { Command } from \"commander\";\nimport ansis from \"ansis\";\nimport { Model } from \"../core/model.js\";\nimport { StagingAreaManager } from \"../core/staging-area.js\";\nimport { findElementLayer } from \"../utils/element-utils.js\";\nimport { isValidLayerName } from \"../core/layers.js\";\nimport {\n CLIError,\n ErrorCategory,\n handleError,\n handleSuccess,\n handleInfo,\n getErrorMessage\n} from \"../utils/errors.js\";\nimport { getValidRelationships } from \"../generated/relationship-index.js\";\nimport { normalizeNodeType } from \"../generated/node-types.js\";\nimport { ModelReportOrchestrator } from \"../reports/model-report-orchestrator.js\";\nimport { emitLog, SeverityNumber } from \"../telemetry/index.js\";\nimport { Element } from \"../core/element.js\";\nimport { Relationship, elementIdentifiers } from \"../core/relationships.js\";\nimport { RelationshipCatalog } from \"../core/relationship-catalog.js\";\nimport {\n collectKnownIdentifiers,\n findDanglingRelationships,\n type UnresolvedSide,\n} from \"../core/relationship-prune.js\";\nimport { isJson } from \"../utils/globals.js\";\nimport type { HintSurface } from \"../utils/error-hints.js\";\nimport { ChangesetGraph } from \"../core/changeset-graph.js\";\nimport type { Changeset } from \"../core/changeset.js\";\nimport {\n liveRelationshipsBetween,\n planRelationshipAdd,\n stageRelationshipDeletes,\n validateRelationshipCombination,\n type StagedRelationshipDeleteResult,\n} from \"../core/relationship-staging.js\";\n\nexport { validateRelationshipCombination };\n\n/**\n * Pre-resolved element and layer information to avoid redundant lookups.\n * Ensures source and target pairs are consistent: if source is provided, both element and layerName must be present.\n * This prevents invalid states like {sourceElement: ..., sourceLayerName: undefined}.\n */\nexport interface PreResolvedElements {\n source?: {\n element: Element;\n layerName: string;\n };\n target?: {\n element: Element;\n layerName: string;\n };\n}\n\n/**\n * Validate element properties and construct a SpecNodeId\n * @throws {CLIError} if element properties are invalid\n */\nfunction constructSpecNodeId(\n element: { layer_id?: unknown; type?: unknown },\n elementId: string\n): string {\n const layerId = element.layer_id;\n const type = element.type;\n\n if (typeof layerId !== \"string\" || !layerId) {\n throw new CLIError(\n `Invalid element ${elementId}: missing or invalid layer_id`,\n ErrorCategory.SYSTEM\n );\n }\n\n if (typeof type !== \"string\" || !type) {\n throw new CLIError(\n `Invalid element ${elementId}: missing or invalid type`,\n ErrorCategory.SYSTEM\n );\n }\n\n // Normalize type name for schema validation (e.g., \"process\" -> \"businessprocess\")\n const normalizedType = normalizeNodeType(layerId, type);\n\n return `${layerId}.${normalizedType}`;\n}\n\n/**\n * Get cardinality and strength info for a relationship\n */\nexport function getRelationshipConstraints(\n sourceSpecNodeId: string,\n predicate: string,\n destSpecNodeId: string\n): { cardinality: string; strength: string } | null {\n const rels = getValidRelationships(\n sourceSpecNodeId,\n predicate,\n destSpecNodeId\n );\n if (rels.length === 0) return null;\n\n const rel = rels[0];\n return {\n cardinality: rel.cardinality,\n strength: rel.strength\n };\n}\n\n/**\n * Handler function for adding a relationship\n * Encapsulates the core logic of the add-relationship command\n * @internal Exported for testing purposes\n *\n * @param model - The architecture model\n * @param source - Source element ID\n * @param target - Target element ID\n * @param predicate - Relationship predicate\n * @param properties - Optional relationship properties\n * @param preResolved - Pre-resolved elements and layer names (optional, for performance)\n */\nexport async function addRelationshipHandler(\n model: Model,\n source: string,\n target: string,\n predicate: string,\n properties?: Record<string, unknown>,\n preResolved?: PreResolvedElements\n): Promise<boolean> {\n const outcome = await addRelationship(model, source, target, predicate, properties, preResolved);\n return outcome !== \"duplicate\";\n}\n\n/**\n * What adding a relationship did:\n * - \"added\": written to relationships.yaml (no active changeset)\n * - \"staged\": staged in the active changeset\n * - \"restored\": the active changeset had staged its deletion; that deletion was unstaged\n * - \"duplicate\": already present (in the base model, or in the active changeset's projection); nothing written\n */\nexport type AddRelationshipOutcome = \"added\" | \"staged\" | \"restored\" | \"duplicate\";\n\n/** The active changeset when one is set and can accept changes, else null. */\nasync function activeStagedChangeset(manager: StagingAreaManager): Promise<Changeset | null> {\n const active = await manager.getActive();\n return active && active.status === \"staged\" ? active : null;\n}\n\n/**\n * Adds a relationship, validated against the catalog. Inside an active changeset the duplicate\n * check reads the changeset's projected graph (base plus staged relationships), so adding the same\n * relationship twice stages it once, and re-adding one the changeset deletes unstages the delete.\n */\nexport async function addRelationship(\n model: Model,\n source: string,\n target: string,\n predicate: string,\n properties?: Record<string, unknown>,\n preResolved?: PreResolvedElements\n): Promise<AddRelationshipOutcome> {\n // Use pre-resolved elements if provided, otherwise resolve them\n let resolvedSourceLayerName = preResolved?.source?.layerName;\n let resolvedSourceElement = preResolved?.source?.element;\n let resolvedTargetLayerName = preResolved?.target?.layerName;\n let resolvedTargetElement = preResolved?.target?.element;\n\n if (!resolvedSourceLayerName) {\n resolvedSourceLayerName = await findElementLayer(model, source);\n if (!resolvedSourceLayerName) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n if (!resolvedSourceElement) {\n const sourceLayer = await model.getLayer(resolvedSourceLayerName);\n if (!sourceLayer) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n resolvedSourceElement = sourceLayer.getElement(source);\n if (!resolvedSourceElement) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n if (!resolvedTargetLayerName) {\n resolvedTargetLayerName = await findElementLayer(model, target);\n if (!resolvedTargetLayerName) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n if (!resolvedTargetElement) {\n const targetLayer = await model.getLayer(resolvedTargetLayerName);\n if (!targetLayer) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n resolvedTargetElement = targetLayer.getElement(target);\n if (!resolvedTargetElement) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n }\n\n // Schema-driven validation\n const sourceSpecNodeId = constructSpecNodeId(resolvedSourceElement, source);\n const targetSpecNodeId = constructSpecNodeId(resolvedTargetElement, target);\n\n const validation = validateRelationshipCombination(\n sourceSpecNodeId,\n predicate,\n targetSpecNodeId\n );\n\n if (!validation.valid) {\n throw new CLIError(\n `Invalid relationship: ${source} --[${predicate}]--> ${target}`,\n ErrorCategory.USER,\n validation.suggestions\n );\n }\n\n {\n const catalog = new RelationshipCatalog();\n await catalog.load();\n const relType = catalog.getTypeByPredicate(predicate);\n if (relType && !relType.semantics.reflexivity && source === target) {\n throw new CLIError(\n `Invalid relationship: predicate \"${predicate}\" does not allow reflexive relationships (${source})`,\n ErrorCategory.USER\n );\n }\n }\n\n // Check for active changeset \u2014 stage relationship instead of writing directly\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n const activeChangeset = activeChangesetId ? await activeStagedChangeset(stagingManager) : null;\n\n // Guard against duplicate relationships before staging or writing. Inside a changeset the\n // projected graph is the reference: it holds what this changeset already staged, and drops\n // what it deletes.\n if (activeChangeset) {\n const graph = await ChangesetGraph.build(model, activeChangeset);\n const plan = planRelationshipAdd(graph, activeChangeset, { source, predicate, target });\n if (plan.action === \"duplicate\") {\n return \"duplicate\";\n }\n if (plan.action === \"restore\") {\n for (const key of plan.keys) {\n await stagingManager.unstage(activeChangeset.id!, key);\n }\n return \"restored\";\n }\n } else if (model.relationships.find(source, target, predicate).length > 0) {\n return \"duplicate\";\n }\n\n const relData = {\n source,\n target,\n predicate,\n layer: resolvedSourceLayerName,\n ...(resolvedTargetLayerName !== resolvedSourceLayerName\n ? { targetLayer: resolvedTargetLayerName }\n : {}),\n category: \"structural\" as const,\n ...(properties ? { properties } : {})\n };\n\n if (activeChangesetId) {\n // Stage the relationship change in the active changeset\n const compositeKey = `${source}::${predicate}::${target}`;\n await stagingManager.stage(activeChangesetId, {\n type: \"relationship-add\",\n elementId: compositeKey,\n layerName: resolvedSourceLayerName,\n after: relData\n });\n } else {\n // No active changeset \u2014 write directly to relationships.yaml\n model.relationships.add(relData);\n await model.saveRelationships();\n await model.saveManifest();\n\n // Regenerate reports for all affected layers (including transitively related)\n try {\n const orchestrator = new ModelReportOrchestrator(model, model.rootPath);\n const affectedLayers = new Set<string>();\n\n // Compute affected layers for source layer\n if (isValidLayerName(resolvedSourceLayerName)) {\n for (const layer of orchestrator.computeAffectedLayers(\n resolvedSourceLayerName\n )) {\n affectedLayers.add(layer);\n }\n }\n\n // Compute affected layers for target layer\n if (isValidLayerName(resolvedTargetLayerName)) {\n for (const layer of orchestrator.computeAffectedLayers(\n resolvedTargetLayerName\n )) {\n affectedLayers.add(layer);\n }\n }\n\n await orchestrator.regenerate(affectedLayers);\n } catch (error) {\n emitLog(\n SeverityNumber.WARN,\n \"Failed to regenerate layer reports after relationship add\",\n {\n \"relationship.predicate\": predicate,\n \"relationship.sourceLayer\": resolvedSourceLayerName,\n \"relationship.targetLayer\": resolvedTargetLayerName,\n \"relationship.source\": source,\n \"relationship.target\": target,\n \"error.message\": getErrorMessage(error)\n }\n );\n }\n }\n\n return activeChangesetId ? \"staged\" : \"added\";\n}\n\n/**\n * Find relationships between two endpoints as they are recorded in relationships.yaml.\n *\n * Rows may name an element by UUID `id` or by dotted `path`, and the user may type\n * either form. Each endpoint matches a row when the row's value is the typed\n * identifier or any identifier of the element it resolves to. An endpoint that no\n * longer resolves to an element still matches rows that store the typed value.\n */\nexport async function findRelationshipsByEndpoints(\n model: Model,\n source: string,\n target: string,\n predicate?: string\n): Promise<Relationship[]> {\n const sourceIds = new Set(elementIdentifiers(model.getElementById(source) ?? {}, source));\n const targetIds = new Set(elementIdentifiers(model.getElementById(target) ?? {}, target));\n return model.relationships\n .getAll()\n .filter(\n (rel) =>\n sourceIds.has(rel.source) &&\n targetIds.has(rel.target) &&\n (!predicate || rel.predicate === predicate)\n );\n}\n\n/** Next steps when a relationship delete matches nothing, named for the caller's surface. */\nfunction noMatchingRelationshipHints(surface: HintSurface, source: string, inChangeset: boolean): string[] {\n if (surface === \"mcp\") {\n return [\n `Use \"model_show\" on ${source} to see its relationships`,\n inChangeset\n ? 'Use \"changeset_brief\" to see what this changeset already stages'\n : 'Use \"model_search\" to check the source and target element IDs',\n ];\n }\n return [\n `Use \"dr relationship list ${source}\" to see the relationships recorded for ${source}`,\n inChangeset\n ? 'Use \"dr changeset staged\" to see what the active changeset already stages'\n : 'Use \"dr relationship prune --dry-run\" to list rows whose endpoints no longer resolve',\n ];\n}\n\n/**\n * Handler function for deleting relationships\n * Encapsulates the core logic of the delete-relationship command\n * @internal Exported for testing purposes\n *\n * @param model - The architecture model\n * @param source - Source element ID\n * @param target - Target element ID\n * @param predicate - Optional relationship predicate\n * @param preResolved - Pre-resolved source layer name and relationships (optional, for performance)\n */\ninterface DeletePreResolved {\n sourceLayerName?: string;\n toDelete?: Relationship[];\n}\n\nexport async function deleteRelationshipHandler(\n model: Model,\n source: string,\n target: string,\n predicate?: string,\n preResolved?: DeletePreResolved,\n surface: HintSurface = \"cli\"\n): Promise<{ deletedCount: number; staged?: StagedRelationshipDeleteResult[] }> {\n // Inside a changeset, match against its projected graph: a relationship this changeset added is\n // unstaged (not deleted on top of itself), and one it already deletes is not matched again.\n const changesetManager = new StagingAreaManager(model.rootPath, model);\n const changeset = (await changesetManager.getActiveId())\n ? await activeStagedChangeset(changesetManager)\n : null;\n if (changeset) {\n const graph = await ChangesetGraph.build(model, changeset);\n const matches = liveRelationshipsBetween(graph, source, target, predicate);\n if (matches.length === 0) {\n throw new CLIError(\n \"No matching relationships found\",\n ErrorCategory.USER,\n noMatchingRelationshipHints(surface, source, true)\n );\n }\n const staged = await stageRelationshipDeletes(changesetManager, graph, changeset, matches);\n return { deletedCount: staged.length, staged };\n }\n\n // The source element need not resolve: a row whose endpoint was deleted is\n // exactly the row a user needs to remove (#963). The layer is informational only.\n let resolvedSourceLayerName = preResolved?.sourceLayerName;\n if (!resolvedSourceLayerName) {\n resolvedSourceLayerName = await findElementLayer(model, source);\n }\n\n // Use pre-found relationships if provided, otherwise find them\n let resolvedToDelete = preResolved?.toDelete;\n if (!resolvedToDelete) {\n resolvedToDelete = await findRelationshipsByEndpoints(model, source, target, predicate);\n }\n\n if (resolvedToDelete.length === 0) {\n throw new CLIError(\n \"No matching relationships found\",\n ErrorCategory.USER,\n noMatchingRelationshipHints(surface, source, false)\n );\n }\n\n // Check for active changeset \u2014 stage deletion instead of writing directly\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n if (activeChangesetId) {\n // Stage each relationship deletion in the active changeset\n for (const rel of resolvedToDelete) {\n const compositeKey = `${rel.source}::${rel.predicate}::${rel.target}`;\n await stagingManager.stage(activeChangesetId, {\n type: \"relationship-delete\",\n elementId: compositeKey,\n layerName: rel.layer,\n before: {\n source: rel.source,\n target: rel.target,\n predicate: rel.predicate,\n layer: rel.layer,\n ...(rel.targetLayer ? { targetLayer: rel.targetLayer } : {}),\n ...(rel.properties ? { properties: rel.properties } : {})\n }\n });\n }\n } else {\n // No active changeset \u2014 write directly\n for (const rel of resolvedToDelete) {\n model.relationships.delete(rel.source, rel.target, rel.predicate);\n }\n await model.saveRelationships();\n await model.saveManifest();\n\n // Regenerate reports for all affected layers (including transitively related)\n try {\n const orchestrator = new ModelReportOrchestrator(model, model.rootPath);\n const affectedLayers = new Set<string>();\n\n // Compute affected layers for each deleted relationship's source and target\n for (const rel of resolvedToDelete) {\n // Compute affected layers for source layer\n if (rel.layer && isValidLayerName(rel.layer)) {\n for (const layer of orchestrator.computeAffectedLayers(rel.layer)) {\n affectedLayers.add(layer);\n }\n }\n\n // Compute affected layers for target layer\n if (rel.targetLayer && isValidLayerName(rel.targetLayer)) {\n for (const layer of orchestrator.computeAffectedLayers(\n rel.targetLayer\n )) {\n affectedLayers.add(layer);\n }\n }\n }\n\n await orchestrator.regenerate(affectedLayers);\n } catch (error) {\n emitLog(\n SeverityNumber.WARN,\n \"Failed to regenerate layer reports after relationship delete\",\n {\n \"relationship.predicate\": predicate,\n \"relationship.source\": source,\n \"relationship.target\": target,\n \"relationship.deleteCount\": resolvedToDelete.length,\n \"error.message\": getErrorMessage(error)\n }\n );\n }\n }\n\n return { deletedCount: resolvedToDelete.length };\n}\n\nexport interface PruneRelationshipsOptions {\n model?: string;\n dryRun?: boolean;\n layers?: string[];\n format?: string;\n}\n\nexport interface PruneRelationshipsResult {\n scanned: number;\n dangling: number;\n removed: number;\n dryRun: boolean;\n staged: boolean;\n changeset?: string;\n layers?: string[];\n relationships: Array<{\n source: string;\n predicate: string;\n target: string;\n layer: string;\n targetLayer?: string;\n unresolved: UnresolvedSide;\n }>;\n}\n\n/**\n * `dr relationship prune`: remove rows whose source or target resolves to no element.\n *\n * Elements are matched by UUID id and by dotted path (both are legal in\n * relationships.yaml). Inside an active changeset the removals are staged as\n * relationship-delete changes; otherwise relationships.yaml is rewritten with the\n * surviving rows in their original order and its header comment preserved.\n *\n * @internal Exported for testing purposes\n */\nexport async function pruneRelationshipsCommand(\n options: PruneRelationshipsOptions\n): Promise<PruneRelationshipsResult> {\n const format = options.format ?? \"text\";\n if (format !== \"text\" && format !== \"json\") {\n throw new CLIError(`Invalid format: ${format}`, ErrorCategory.USER, [\n \"Use --format text or --format json\",\n ]);\n }\n const jsonOutput = format === \"json\" || isJson();\n\n const layers = options.layers?.length ? options.layers : undefined;\n if (layers) {\n const invalid = layers.filter((l) => !isValidLayerName(l));\n if (invalid.length > 0) {\n throw new CLIError(\n `Invalid layer name(s): ${invalid.join(\", \")}`,\n ErrorCategory.USER,\n ['Use canonical layer names, e.g. \"api\", \"data-model\", \"data-store\"']\n );\n }\n }\n\n const model = await Model.load(options.model || process.cwd());\n\n // Every identifier a current element is known by. getLayer() returns the projected\n // view, so staged adds count as present and staged deletes as absent.\n const elements: Element[] = [];\n for (const layerName of model.getLayerNames()) {\n const layer = await model.getLayer(layerName);\n if (layer) {\n elements.push(...layer.listElements());\n }\n }\n const known = collectKnownIdentifiers(elements);\n\n const analysis = findDanglingRelationships(model.relationships.getAll(), known, { layers });\n\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangeset = await stagingManager.getActive();\n const staging = !!activeChangeset && activeChangeset.status === \"staged\";\n\n const result: PruneRelationshipsResult = {\n scanned: analysis.scanned,\n dangling: analysis.dangling.length,\n removed: 0,\n dryRun: !!options.dryRun,\n staged: false,\n ...(staging ? { changeset: activeChangeset!.name } : {}),\n ...(layers ? { layers } : {}),\n relationships: analysis.dangling.map(({ relationship: rel, unresolved }) => ({\n source: rel.source,\n predicate: rel.predicate,\n target: rel.target,\n layer: rel.layer,\n ...(rel.targetLayer ? { targetLayer: rel.targetLayer } : {}),\n unresolved,\n })),\n };\n\n if (!options.dryRun && analysis.dangling.length > 0) {\n if (staging) {\n for (const { relationship: rel } of analysis.dangling) {\n await stagingManager.stage(activeChangeset!.id, {\n type: \"relationship-delete\",\n elementId: `${rel.source}::${rel.predicate}::${rel.target}`,\n layerName: rel.layer,\n before: {\n source: rel.source,\n target: rel.target,\n predicate: rel.predicate,\n layer: rel.layer,\n ...(rel.targetLayer ? { targetLayer: rel.targetLayer } : {}),\n ...(rel.properties ? { properties: rel.properties } : {}),\n },\n });\n }\n result.staged = true;\n } else {\n const danglingRows = new Set(analysis.dangling.map((d) => d.relationship));\n model.relationships.retain((rel) => !danglingRows.has(rel));\n await model.saveRelationships({ preserveHeader: true });\n await model.saveManifest();\n\n try {\n const orchestrator = new ModelReportOrchestrator(model, model.rootPath);\n const affectedLayers = new Set<string>();\n for (const { relationship: rel } of analysis.dangling) {\n for (const name of [rel.layer, rel.targetLayer]) {\n if (name && isValidLayerName(name)) {\n for (const affected of orchestrator.computeAffectedLayers(name)) {\n affectedLayers.add(affected);\n }\n }\n }\n }\n await orchestrator.regenerate(affectedLayers);\n } catch (error) {\n emitLog(SeverityNumber.WARN, \"Failed to regenerate layer reports after relationship prune\", {\n \"relationship.pruned\": analysis.dangling.length,\n \"error.message\": getErrorMessage(error),\n });\n }\n }\n result.removed = analysis.dangling.length;\n }\n\n if (jsonOutput) {\n console.log(JSON.stringify({ status: \"ok\", ...result }, null, 2));\n return result;\n }\n\n const scope = layers ? ` in layer(s) ${layers.join(\", \")}` : \"\";\n handleInfo(\n `Scanned ${result.scanned} relationship(s)${scope}: ${result.dangling} dangling`\n );\n for (const row of result.relationships) {\n const side =\n row.unresolved === \"both\"\n ? \"source and target not found\"\n : `${row.unresolved} not found`;\n handleInfo(\n ` - ${ansis.yellow(row.source)} --[${ansis.magenta(row.predicate)}]--> ${ansis.yellow(row.target)} ${ansis.dim(`(${side})`)}`\n );\n }\n\n if (result.dangling === 0) {\n handleSuccess(\"No dangling relationships found\", {\n scanned: result.scanned,\n dangling: 0,\n removed: 0,\n });\n } else if (result.dryRun) {\n handleSuccess(`Dry run: would remove ${result.dangling} dangling relationship(s)`, {\n scanned: result.scanned,\n dangling: result.dangling,\n removed: 0,\n dryRun: true,\n });\n } else if (result.staged) {\n handleSuccess(\n `Staged removal of ${result.removed} dangling relationship(s) to ${ansis.bold(result.changeset!)}`,\n {\n scanned: result.scanned,\n dangling: result.dangling,\n removed: result.removed,\n changesetStatus: \"staged\",\n changeset: result.changeset,\n }\n );\n } else {\n handleSuccess(`Removed ${result.removed} dangling relationship(s)`, {\n scanned: result.scanned,\n dangling: result.dangling,\n removed: result.removed,\n });\n }\n\n return result;\n}\n\nexport function relationshipCommands(program: Command, rootProgram?: Command): void {\n program\n .command(\"add <source> <target>\")\n .description(\n \"Add a relationship between elements (intra-layer or cross-layer)\"\n )\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .requiredOption(\n \"--predicate <predicate>\",\n \"Relationship predicate (e.g., depends-on, realizes, exposes)\"\n )\n .option(\"--properties <json>\", \"Relationship properties (JSON)\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship add motivation.goal.goal-a motivation.goal.goal-b --predicate aggregates\n $ dr relationship add api.operation.create-order application.service.order-service --predicate exposes\n $ dr relationship add business.businessprocess.checkout application.applicationprocess.checkout --predicate aggregates\n $ dr relationship add element-1 element-2 --predicate realizes --properties '{\"strength\":\"high\"}'`\n )\n .action(async (source, target, options) => {\n try {\n // Load model\n const model = await Model.load(options.model);\n\n // Find source element for constraints info\n const sourceLayerName = await findElementLayer(model, source);\n if (!sourceLayerName) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n const sourceLayer = await model.getLayer(sourceLayerName);\n if (!sourceLayer) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n const sourceElement = sourceLayer.getElement(source);\n if (!sourceElement) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n\n // Find target element for constraints info\n const targetLayerName = await findElementLayer(model, target);\n if (!targetLayerName) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n const targetLayer = await model.getLayer(targetLayerName);\n if (!targetLayer) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n const targetElement = targetLayer.getElement(target);\n if (!targetElement) {\n throw new CLIError(\n `Target element ${target} not found`,\n ErrorCategory.USER\n );\n }\n\n // Get cardinality and strength info (before calling handler for CLI output)\n const sourceSpecNodeId = constructSpecNodeId(sourceElement, source);\n const targetSpecNodeId = constructSpecNodeId(targetElement, target);\n const constraints = getRelationshipConstraints(\n sourceSpecNodeId,\n options.predicate,\n targetSpecNodeId\n );\n\n // Parse properties if provided\n let properties: Record<string, unknown> | undefined;\n if (options.properties) {\n try {\n properties = JSON.parse(options.properties);\n } catch (e) {\n throw new CLIError(\n \"Invalid JSON in --properties\",\n ErrorCategory.USER\n );\n }\n }\n\n // Check for active changeset\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n // Call the handler function with pre-resolved elements to avoid duplicate lookups\n const outcome = await addRelationship(\n model,\n source,\n target,\n options.predicate,\n properties,\n {\n source: { element: sourceElement, layerName: sourceLayerName },\n target: { element: targetElement, layerName: targetLayerName }\n }\n );\n\n if (outcome === \"duplicate\") {\n // duplicate \u2014 emit JSON response indicating relationship already exists\n // (in the base model, or already staged by the active changeset)\n handleSuccess(\n `Relationship ${source} --[${options.predicate}]--> ${target} already exists` +\n (activeChangesetId ? \" (in the model or the active changeset); nothing staged\" : \"\"),\n {\n source,\n target,\n predicate: options.predicate,\n layer: sourceLayerName,\n duplicate: true,\n ...(activeChangesetId ? { changesetStatus: \"unchanged\" } : {}),\n },\n { verbose: options.verbose }\n );\n return;\n }\n\n if (outcome === \"restored\") {\n handleSuccess(\n `Restored relationship: ${ansis.bold(source)} ${options.predicate} ${ansis.bold(target)}` +\n ansis.dim(\" [the active changeset's staged deletion of it was unstaged]\"),\n {\n source,\n target,\n predicate: options.predicate,\n layer: sourceLayerName,\n restored: true,\n changesetStatus: \"unstaged\",\n },\n { verbose: options.verbose }\n );\n return;\n }\n\n // Show cardinality and strength in output\n let message = `Added relationship: ${ansis.bold(source)} ${options.predicate} ${ansis.bold(target)}`;\n const details: Record<string, unknown> = {\n source,\n target,\n predicate: options.predicate,\n layer: sourceLayerName,\n };\n if (constraints) {\n message += ansis.dim(\n ` (${constraints.cardinality}, ${constraints.strength} strength)`\n );\n details.cardinality = constraints.cardinality;\n details.strength = constraints.strength;\n }\n if (activeChangesetId) {\n message += ansis.dim(` [staged]`);\n details.changesetStatus = \"staged\";\n }\n\n handleSuccess(message, details, { verbose: options.verbose });\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"delete <source> <target>\")\n .description(\"Delete a relationship\")\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .option(\n \"--predicate <predicate>\",\n \"Specific predicate to delete (optional, delete all if not specified)\"\n )\n .option(\"--force\", \"Skip confirmation prompt\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship delete element-1 element-2 --predicate depends-on\n $ dr relationship delete element-1 element-2 --force`\n )\n .action(async (source, target, options) => {\n try {\n // Load model\n const model = await Model.load(options.model);\n\n // Find relationships to delete (to show confirmation count). Endpoints are\n // matched by the value recorded in the row, so a row whose source or target\n // element has already been deleted can still be removed.\n // Inside a changeset the candidates come from its projected graph, so a relationship the\n // changeset itself added can be removed (which unstages it).\n const activeForDelete = await activeStagedChangeset(\n new StagingAreaManager(model.rootPath, model)\n );\n const toDelete = activeForDelete\n ? liveRelationshipsBetween(\n await ChangesetGraph.build(model, activeForDelete),\n source,\n target,\n options.predicate\n )\n : await findRelationshipsByEndpoints(model, source, target, options.predicate);\n\n if (toDelete.length === 0) {\n throw new CLIError(\n \"No matching relationships found\",\n ErrorCategory.USER,\n [\n `Use \"dr relationship list ${source}\" to see the relationships recorded for ${source}`,\n 'Use \"dr relationship prune --dry-run\" to list rows whose endpoints no longer resolve',\n ]\n );\n }\n\n // The source layer is informational; fall back to the row's layer when the\n // source element no longer exists.\n const sourceLayerName =\n (await findElementLayer(model, source)) ?? toDelete[0].layer;\n\n // Confirm deletion unless --force or non-interactive environment\n // In non-interactive environments (CI, tests), skip confirmation\n const isInteractive = process.stdin.isTTY && process.stdout.isTTY;\n if (!options.force && isInteractive) {\n // Dynamic import of prompts is safe here: caught by outer try-catch\n // This allows lazy loading of the prompt library only when needed\n const { confirm } = await import(\"@clack/prompts\");\n const confirmed = await confirm({\n message: `Delete ${toDelete.length} relationship(s)? This cannot be undone.`,\n initialValue: false\n });\n\n if (!confirmed) {\n handleSuccess(\"Deletion cancelled\", {\n source,\n target,\n status: \"cancelled\",\n });\n return;\n }\n }\n\n // Check for active changeset\n const stagingManager = new StagingAreaManager(model.rootPath, model);\n const activeChangesetId = await stagingManager.getActiveId();\n\n // Call the handler function with pre-resolved values to avoid duplicate lookups\n const result = await deleteRelationshipHandler(\n model,\n source,\n target,\n options.predicate,\n {\n sourceLayerName,\n // In a changeset the handler re-reads the projected graph itself.\n toDelete: activeForDelete ? undefined : (toDelete as Relationship[])\n }\n );\n\n const stagedSuffix = activeChangesetId ? \" [staged]\" : \"\";\n const deleteDetails: Record<string, unknown> = {\n source,\n target,\n layer: sourceLayerName,\n deletedCount: result.deletedCount,\n ...(result.staged ? { relationships: result.staged } : {}),\n };\n if (options.predicate) {\n deleteDetails.predicate = options.predicate;\n }\n if (activeChangesetId) {\n deleteDetails.changesetStatus = \"staged\";\n }\n handleSuccess(\n `Deleted ${result.deletedCount} relationship(s) from ${ansis.bold(source)} to ${ansis.bold(target)}${stagedSuffix}`,\n deleteDetails,\n { verbose: options.verbose }\n );\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"prune\")\n .description(\n \"Remove relationship rows whose source or target no longer resolves to an element\"\n )\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .option(\"--dry-run\", \"List the rows that would be removed without writing\")\n .option(\n \"--layers <layers...>\",\n \"Only scan rows whose source or target layer is one of these canonical layer names\"\n )\n .option(\"--format <format>\", \"Output format: text, json\", \"text\")\n .addHelpText(\n \"after\",\n `\nA row is dangling when its source or target matches neither the UUID id nor the\ndotted path of any current element. Kept rows keep their order and the file's\nheader comment is preserved. Inside an active changeset the removals are staged\nas relationship deletions instead of being written to relationships.yaml.\n\nExamples:\n $ dr relationship prune --dry-run\n $ dr relationship prune\n $ dr relationship prune --layers api application --format json`\n )\n .action(async (options) => {\n try {\n await pruneRelationshipsCommand({\n model: options.model,\n dryRun: !!options.dryRun,\n layers: options.layers,\n format: options.format,\n });\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"list <id>\")\n .description(\"List relationships for an element\")\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .option(\n \"--direction <dir>\",\n \"Filter by direction (incoming/outgoing/all)\",\n \"all\"\n )\n .option(\"--json\", \"Output as JSON\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship list api-endpoint-create-customer\n $ dr relationship list business-service-order --direction outgoing\n $ dr relationship list element-1 --json`\n )\n .action(async (id, options) => {\n try {\n // Load model\n const model = await Model.load(options.model);\n const layerName = await findElementLayer(model, id);\n\n if (!layerName) {\n throw new CLIError(`Element ${id} not found`, ErrorCategory.USER);\n }\n\n // Get relationships from centralized store\n const { outgoing, incoming } = model.relationships.getForElement(id);\n\n // Filter by direction\n let relationships: typeof outgoing = [];\n if (options.direction === \"outgoing\" || options.direction === \"all\") {\n relationships.push(...outgoing);\n }\n if (options.direction === \"incoming\" || options.direction === \"all\") {\n relationships.push(...incoming);\n }\n\n const shouldOutputJson = options.json ?? (rootProgram?.opts().json);\n if (shouldOutputJson) {\n console.log(JSON.stringify(relationships, null, 2));\n return;\n }\n\n if (relationships.length === 0) {\n handleInfo(\n ansis.yellow(`No ${options.direction} relationships for ${id}`)\n );\n return;\n }\n\n handleInfo(\"\");\n handleInfo(\n ansis.bold(\n `${options.direction === \"all\" ? \"\" : options.direction + \" \"}relationships for ${ansis.cyan(id)}:`\n )\n );\n handleInfo(ansis.dim(\"\u2500\".repeat(80)));\n\n for (const rel of relationships) {\n const isOutgoing = rel.source === id;\n const direction = isOutgoing ? \"\u2192\" : \"\u2190\";\n const otherElement = isOutgoing ? rel.target : rel.source;\n const crossLayer =\n rel.targetLayer && rel.targetLayer !== rel.layer\n ? ansis.dim(` [${rel.layer} \u2192 ${rel.targetLayer}]`)\n : \"\";\n\n handleInfo(\n ` ${direction} ${ansis.magenta(rel.predicate)}: ${ansis.yellow(otherElement)}${crossLayer}`\n );\n\n if (rel.properties) {\n const propStr = Object.entries(rel.properties)\n .map(([k, v]) => `${k}=${v}`)\n .join(\", \");\n handleInfo(` ${ansis.dim(propStr)}`);\n }\n }\n\n handleInfo(ansis.dim(\"\u2500\".repeat(80)));\n handleInfo(ansis.dim(`Total: ${relationships.length} relationship(s)`));\n handleInfo(\"\");\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"show <source> <target>\")\n .description(\"Show relationship details\")\n .option(\n \"--model <path>\",\n \"Path to model root (contains model/manifest.yaml)\"\n )\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr relationship show api-endpoint-create-customer business-service-customer-mgmt\n $ dr relationship show application-component-api motivation-goal-sales-efficiency`\n )\n .action(async (source, target, options) => {\n try {\n // Load model\n const model = await Model.load(options.model);\n const sourceLayerName = await findElementLayer(model, source);\n\n if (!sourceLayerName) {\n throw new CLIError(\n `Source element ${source} not found`,\n ErrorCategory.USER\n );\n }\n\n // Find relationships from centralized store\n const relationships = model.relationships.find(source, target);\n\n if (relationships.length === 0) {\n throw new CLIError(\n `No relationships from ${source} to ${target}`,\n ErrorCategory.USER\n );\n }\n\n handleInfo(\"\");\n handleInfo(\n ansis.bold(\n `Relationship${relationships.length > 1 ? \"s\" : \"\"} from ${ansis.cyan(source)} to ${ansis.yellow(target)}:`\n )\n );\n handleInfo(ansis.dim(\"\u2500\".repeat(60)));\n\n for (let i = 0; i < relationships.length; i++) {\n const rel = relationships[i];\n\n if (i > 0) {\n handleInfo(\"\");\n }\n\n handleInfo(`Predicate: ${ansis.magenta(rel.predicate)}`);\n handleInfo(`Layer: ${ansis.cyan(rel.layer)}`);\n if (rel.targetLayer && rel.targetLayer !== rel.layer) {\n handleInfo(`Target Layer: ${ansis.cyan(rel.targetLayer)}`);\n }\n\n if (rel.properties && Object.keys(rel.properties).length > 0) {\n handleInfo(\"Properties:\");\n for (const [key, value] of Object.entries(rel.properties)) {\n const displayValue =\n typeof value === \"string\"\n ? value\n : JSON.stringify(value, null, 2);\n handleInfo(` ${ansis.cyan(key)}: ${displayValue}`);\n }\n } else {\n handleInfo(\"Properties: none\");\n }\n }\n\n handleInfo(\"\");\n } catch (error) {\n handleError(error);\n }\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/commands/reports.js
CHANGED
|
@@ -20,11 +20,11 @@ async function reportsRegenerateCommand() {
|
|
|
20
20
|
console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), process.exit(1);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
async function regenerateLayerReports(projectRoot) {
|
|
23
|
+
async function regenerateLayerReports(projectRoot, log = (message) => console.log(message)) {
|
|
24
24
|
const reportDir = path.join(projectRoot, "documentation-robotics", "reports");
|
|
25
|
-
|
|
25
|
+
log(ansis.dim("Removing existing reports...")), await fs.rm(reportDir, { recursive: !0, force: !0 }), log(ansis.dim("Loading model..."));
|
|
26
26
|
const model = await Model.load(projectRoot), orchestrator = new ModelReportOrchestrator(model, projectRoot);
|
|
27
|
-
|
|
27
|
+
log(ansis.dim("Generating 13 layer reports and README...")), await orchestrator.regenerateAll(), log(ansis.green("\u2713 All 13 layer reports and README regenerated")), log(ansis.dim(" Reports written to: documentation-robotics/reports/")), log(ansis.dim(" README written to: documentation-robotics/README.md"));
|
|
28
28
|
}
|
|
29
29
|
async function hasLayerReports(projectRoot) {
|
|
30
30
|
const reportDir = path.join(projectRoot, "documentation-robotics", "reports");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/commands/reports.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Reports subcommands for managing the maintained set of markdown layer reports\n */\n\nimport { Command } from \"commander\";\nimport ansis from \"ansis\";\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { Model } from \"../core/model.js\";\nimport { ModelReportOrchestrator } from \"../reports/model-report-orchestrator.js\";\nimport { findProjectRoot } from \"../utils/project-paths.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\nexport function reportsCommands(parent: Command): void {\n parent\n .command(\"regenerate\")\n .description(\"Delete existing layer reports and regenerate all 13 markdown reports\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr reports regenerate # Delete existing reports and regenerate all 13 layer reports`\n )\n .action(async () => {\n await reportsRegenerateCommand();\n });\n}\n\n/**\n * Delete existing layer reports and regenerate all 13 markdown reports.\n */\nexport async function reportsRegenerateCommand(): Promise<void> {\n try {\n const projectRoot = await findProjectRoot();\n if (!projectRoot) {\n console.error(ansis.red(\"Error: No DR project found\"));\n console.error(ansis.dim('Run \"dr init\" to create a new project'));\n process.exit(1);\n }\n\n await regenerateLayerReports(projectRoot);\n } catch (error) {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n process.exit(1);\n }\n}\n\n/**\n * Delete existing reports directory and regenerate all 13 layer reports and the README.\n * Exported for use in the upgrade command.\n */\nexport async function regenerateLayerReports(projectRoot: string): Promise<void> {\n const reportDir = path.join(projectRoot, \"documentation-robotics\", \"reports\");\n\n // Remove the entire reports directory so stale reports from removed/renamed layers don't linger.\n // force: true means no error if the directory doesn't exist yet.\n // ModelReportOrchestrator.regenerateAll() recreates the directory before writing.\n
|
|
5
|
-
"mappings": "AAKA,OAAO,WAAW;AAClB,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,aAAa;AACtB,SAAS,+BAA+B;AACxC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAE1B,SAAU,gBAAgB,QAAe;AAC7C,SACG,QAAQ,YAAY,EACpB,YAAY,sEAAsE,EAClF,YACC,SACA;;2FAEqF,EAEtF,OAAO,YAAW;AACjB,UAAM,yBAAwB;EAChC,CAAC;AACL;AAKA,eAAsB,2BAAwB;AAC5C,MAAI;AACF,UAAM,cAAc,MAAM,gBAAe;AACzC,IAAK,gBACH,QAAQ,MAAM,MAAM,IAAI,4BAA4B,CAAC,GACrD,QAAQ,MAAM,MAAM,IAAI,uCAAuC,CAAC,GAChE,QAAQ,KAAK,CAAC,IAGhB,MAAM,uBAAuB,WAAW;EAC1C,SAAS,OAAO;AACd,YAAQ,MAAM,MAAM,IAAI,UAAU,gBAAgB,KAAK,CAAC,EAAE,CAAC,GAC3D,QAAQ,KAAK,CAAC;EAChB;AACF;
|
|
4
|
+
"sourcesContent": ["/**\n * Reports subcommands for managing the maintained set of markdown layer reports\n */\n\nimport { Command } from \"commander\";\nimport ansis from \"ansis\";\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport { Model } from \"../core/model.js\";\nimport { ModelReportOrchestrator } from \"../reports/model-report-orchestrator.js\";\nimport { findProjectRoot } from \"../utils/project-paths.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\nexport function reportsCommands(parent: Command): void {\n parent\n .command(\"regenerate\")\n .description(\"Delete existing layer reports and regenerate all 13 markdown reports\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr reports regenerate # Delete existing reports and regenerate all 13 layer reports`\n )\n .action(async () => {\n await reportsRegenerateCommand();\n });\n}\n\n/**\n * Delete existing layer reports and regenerate all 13 markdown reports.\n */\nexport async function reportsRegenerateCommand(): Promise<void> {\n try {\n const projectRoot = await findProjectRoot();\n if (!projectRoot) {\n console.error(ansis.red(\"Error: No DR project found\"));\n console.error(ansis.dim('Run \"dr init\" to create a new project'));\n process.exit(1);\n }\n\n await regenerateLayerReports(projectRoot);\n } catch (error) {\n console.error(ansis.red(`Error: ${getErrorMessage(error)}`));\n process.exit(1);\n }\n}\n\n/**\n * Delete existing reports directory and regenerate all 13 layer reports and the README.\n * Exported for use in the upgrade command.\n *\n * @param log - where the progress lines go (default stdout); the MCP server passes its own,\n * since its stdout carries the protocol\n */\nexport async function regenerateLayerReports(\n projectRoot: string,\n log: (message: string) => void = (message) => console.log(message)\n): Promise<void> {\n const reportDir = path.join(projectRoot, \"documentation-robotics\", \"reports\");\n\n // Remove the entire reports directory so stale reports from removed/renamed layers don't linger.\n // force: true means no error if the directory doesn't exist yet.\n // ModelReportOrchestrator.regenerateAll() recreates the directory before writing.\n log(ansis.dim(\"Removing existing reports...\"));\n await fs.rm(reportDir, { recursive: true, force: true });\n\n // Load model and regenerate all reports\n log(ansis.dim(\"Loading model...\"));\n const model = await Model.load(projectRoot);\n\n const orchestrator = new ModelReportOrchestrator(model, projectRoot);\n log(ansis.dim(\"Generating 13 layer reports and README...\"));\n await orchestrator.regenerateAll();\n\n log(ansis.green(\"\u2713 All 13 layer reports and README regenerated\"));\n log(ansis.dim(\" Reports written to: documentation-robotics/reports/\"));\n log(ansis.dim(\" README written to: documentation-robotics/README.md\"));\n}\n\n/**\n * Check whether any layer reports exist in the reports directory.\n * Returns false if the directory doesn't exist or contains no .md files.\n */\nexport async function hasLayerReports(projectRoot: string): Promise<boolean> {\n const reportDir = path.join(projectRoot, \"documentation-robotics\", \"reports\");\n try {\n const entries = await fs.readdir(reportDir);\n return entries.some((f) => f.endsWith(\".md\"));\n } catch (error: unknown) {\n const err = error as NodeJS.ErrnoException;\n if (err.code === \"ENOENT\") return false;\n throw error;\n }\n}\n"],
|
|
5
|
+
"mappings": "AAKA,OAAO,WAAW;AAClB,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,aAAa;AACtB,SAAS,+BAA+B;AACxC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAE1B,SAAU,gBAAgB,QAAe;AAC7C,SACG,QAAQ,YAAY,EACpB,YAAY,sEAAsE,EAClF,YACC,SACA;;2FAEqF,EAEtF,OAAO,YAAW;AACjB,UAAM,yBAAwB;EAChC,CAAC;AACL;AAKA,eAAsB,2BAAwB;AAC5C,MAAI;AACF,UAAM,cAAc,MAAM,gBAAe;AACzC,IAAK,gBACH,QAAQ,MAAM,MAAM,IAAI,4BAA4B,CAAC,GACrD,QAAQ,MAAM,MAAM,IAAI,uCAAuC,CAAC,GAChE,QAAQ,KAAK,CAAC,IAGhB,MAAM,uBAAuB,WAAW;EAC1C,SAAS,OAAO;AACd,YAAQ,MAAM,MAAM,IAAI,UAAU,gBAAgB,KAAK,CAAC,EAAE,CAAC,GAC3D,QAAQ,KAAK,CAAC;EAChB;AACF;AASA,eAAsB,uBACpB,aACA,MAAiC,CAAC,YAAY,QAAQ,IAAI,OAAO,GAAC;AAElE,QAAM,YAAY,KAAK,KAAK,aAAa,0BAA0B,SAAS;AAK5E,MAAI,MAAM,IAAI,8BAA8B,CAAC,GAC7C,MAAM,GAAG,GAAG,WAAW,EAAE,WAAW,IAAM,OAAO,GAAI,CAAE,GAGvD,IAAI,MAAM,IAAI,kBAAkB,CAAC;AACjC,QAAM,QAAQ,MAAM,MAAM,KAAK,WAAW,GAEpC,eAAe,IAAI,wBAAwB,OAAO,WAAW;AACnE,MAAI,MAAM,IAAI,2CAA2C,CAAC,GAC1D,MAAM,aAAa,cAAa,GAEhC,IAAI,MAAM,MAAM,oDAA+C,CAAC,GAChE,IAAI,MAAM,IAAI,uDAAuD,CAAC,GACtE,IAAI,MAAM,IAAI,uDAAuD,CAAC;AACxE;AAMA,eAAsB,gBAAgB,aAAmB;AACvD,QAAM,YAAY,KAAK,KAAK,aAAa,0BAA0B,SAAS;AAC5E,MAAI;AAEF,YADgB,MAAM,GAAG,QAAQ,SAAS,GAC3B,KAAK,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC;EAC9C,SAAS,OAAgB;AAEvB,QADY,MACJ,SAAS;AAAU,aAAO;AAClC,UAAM;EACR;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/commands/update.js
CHANGED
|
@@ -1,33 +1,43 @@
|
|
|
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, stagedSourceReference } 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";
|
|
12
|
-
import {
|
|
13
|
+
import { SchemaValidator, suggestNodeTypes } from "../validators/schema-validator.js";
|
|
14
|
+
import { resolveSourceReferenceOptions, buildSourceReference, precheckUpdateSourceReferenceOptions } 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) {
|
|
16
24
|
const hasSourceOptions = options.sourceFile || options.sourceSymbol || options.sourceProvenance || options.sourceRepoRemote || options.sourceRepoCommit;
|
|
17
25
|
if (options.clearSourceReference && hasSourceOptions)
|
|
18
26
|
throw new CLIError("Cannot use --clear-source-reference with other source reference options", 1, ["Specify either --clear-source-reference or other source options, not both"]);
|
|
19
|
-
hasSourceOptions &&
|
|
27
|
+
hasSourceOptions && precheckUpdateSourceReferenceOptions(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.sourceSymbol || options.sourceProvenance || 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,11 +45,11 @@ 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
|
-
|
|
39
|
-
|
|
48
|
+
const after = { ...addChange.after }, currentStaged = stagedSourceReference(after), stagedSource = resolveSourceReferenceOptions(options, "cli", currentStaged);
|
|
49
|
+
if (stagedSource.warnings.forEach((warning) => console.warn(ansis.yellow(`Warning: ${warning}`))), !(options.name || options.description !== void 0 || options.attributes || attributePatch || stagedSource.options.sourceProvenance || options.clearSourceReference || options.type)) {
|
|
50
|
+
handleInfo(ansis.yellow(stagedSource.warnings.length > 0 ? "Nothing left to update" : "No fields specified for update"));
|
|
40
51
|
return;
|
|
41
52
|
}
|
|
42
|
-
const after = { ...addChange.after };
|
|
43
53
|
if (options.type) {
|
|
44
54
|
const stagedLayerName = addChange.layerName;
|
|
45
55
|
if (!isValidNodeType(stagedLayerName, options.type)) {
|
|
@@ -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
|
-
|
|
63
|
-
else
|
|
64
|
-
const newRef = buildSourceReference(options);
|
|
65
|
-
newRef && (after
|
|
73
|
+
setStagedSourceReference(after, void 0);
|
|
74
|
+
else {
|
|
75
|
+
const newRef = buildSourceReference(stagedSource.options, currentStaged);
|
|
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,13 @@ ${errorMessages}`, 1, [
|
|
|
108
121
|
const element = layer.getElement(id);
|
|
109
122
|
if (!element)
|
|
110
123
|
throw new CLIError(`Element ${id} not found`, 1);
|
|
111
|
-
|
|
112
|
-
|
|
124
|
+
const currentSource = element.getSourceReference(), source = resolveSourceReferenceOptions(options, "cli", currentSource);
|
|
125
|
+
if (source.warnings.forEach((warning) => console.warn(ansis.yellow(`Warning: ${warning}`))), !(options.name || options.description !== void 0 || options.type || options.attributes || attributePatch || source.options.sourceProvenance || options.clearSourceReference)) {
|
|
126
|
+
handleInfo(ansis.yellow(source.warnings.length > 0 ? "Nothing left to update" : "No fields specified for update"));
|
|
113
127
|
return;
|
|
114
128
|
}
|
|
115
|
-
|
|
129
|
+
const handler = new MutationHandler(model, id, layerName);
|
|
130
|
+
await handler.executeUpdate(element, async (elem, after) => {
|
|
116
131
|
let resolvedNewType;
|
|
117
132
|
if (options.type) {
|
|
118
133
|
if (!isValidNodeType(layerName, options.type)) {
|
|
@@ -130,6 +145,7 @@ ${errorMessages}`, 1, [
|
|
|
130
145
|
"Ensure your JSON is valid and properly formatted"
|
|
131
146
|
]);
|
|
132
147
|
}
|
|
148
|
+
else attributePatch && (parsedAttributes = resolveAttributeUpdate(elem.attributes, { attributePatch }, attributeFlags));
|
|
133
149
|
if (resolvedNewType || parsedAttributes) {
|
|
134
150
|
const candidateType = resolvedNewType ?? elem.type, tempElem = new Element({
|
|
135
151
|
...elem.toJSON(),
|
|
@@ -138,21 +154,22 @@ ${errorMessages}`, 1, [
|
|
|
138
154
|
attributes: parsedAttributes ?? elem.attributes
|
|
139
155
|
}), schemaValidator = new SchemaValidator(), tempLayer = new Layer(layerName);
|
|
140
156
|
tempLayer.addElement(tempElem);
|
|
141
|
-
const attrValidation = await schemaValidator.validateLayer(tempLayer);
|
|
142
|
-
if (
|
|
143
|
-
const errorMessages =
|
|
157
|
+
const attrValidation = await schemaValidator.validateLayer(tempLayer), undefinedTypeHint = undefinedTypeCheck(layerName, id, candidateType), blocking = undefinedTypeHint ? attrValidation.errors.filter((e) => e.location !== "/type") : attrValidation.errors;
|
|
158
|
+
if (blocking.length > 0) {
|
|
159
|
+
const errorMessages = blocking.map((e) => ` ${e.message}`).join(`
|
|
144
160
|
`);
|
|
145
161
|
throw new CLIError(`Updated attributes fail schema validation:
|
|
146
162
|
${errorMessages}`, 1, [
|
|
147
|
-
resolvedNewType ?
|
|
163
|
+
undefinedTypeHint ? undefinedTypeHint.hint : resolvedNewType ? "Incompatible attributes must be manually cleaned up before changing type. " + schemaLookupHint("cli", layerName, candidateType) : schemaLookupHint("cli", layerName, elem.type)
|
|
148
164
|
]);
|
|
149
165
|
}
|
|
166
|
+
undefinedTypeHint && handleWarning(undefinedTypeHint.message, [undefinedTypeHint.hint]);
|
|
150
167
|
}
|
|
151
168
|
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
|
|
153
|
-
else if (options.
|
|
154
|
-
const newRef = buildSourceReference(options);
|
|
155
|
-
newRef && (elem.setSourceReference(newRef), after
|
|
169
|
+
elem.setSourceReference(void 0), setStagedSourceReference(after, void 0);
|
|
170
|
+
else if (source.options.sourceProvenance) {
|
|
171
|
+
const newRef = buildSourceReference(source.options, currentSource);
|
|
172
|
+
newRef && (elem.setSourceReference(newRef), setStagedSourceReference(after, newRef));
|
|
156
173
|
}
|
|
157
174
|
layer.updateElement(elem);
|
|
158
175
|
});
|
|
@@ -162,9 +179,12 @@ ${errorMessages}`, 1, [
|
|
|
162
179
|
elementId: id,
|
|
163
180
|
layer: layerName,
|
|
164
181
|
name: element.name,
|
|
165
|
-
changes
|
|
182
|
+
changes,
|
|
183
|
+
changedFields: handler.getChangedFields(),
|
|
184
|
+
// The active changeset adds this element: the update was folded into that add.
|
|
185
|
+
...handler.wasFoldedIntoAdd() ? { foldedIntoAdd: !0 } : {}
|
|
166
186
|
};
|
|
167
|
-
handleSuccess(`Updated element ${ansis.bold(id)}
|
|
187
|
+
handleSuccess(`Updated ${handler.wasFoldedIntoAdd() ? "staged " : ""}element ${ansis.bold(id)}` + (handler.getChangedFields().length > 0 ? ` (${handler.getChangedFields().join(", ")})` : ""), details, { verbose: options.verbose });
|
|
168
188
|
} catch (error) {
|
|
169
189
|
isTelemetryEnabled && span && (span.recordException(error), span.setStatus({ code: 2, message: error.message })), handleError(error);
|
|
170
190
|
} finally {
|