@documentation-robotics/cli 0.1.13 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -2
- package/dist/analysis/relationship-classifier.js +2 -9
- package/dist/analysis/relationship-classifier.js.map +2 -2
- package/dist/analyzers/call-graph-utils.js +2 -2
- package/dist/analyzers/call-graph-utils.js.map +2 -2
- package/dist/analyzers/cards/build.js +171 -0
- package/dist/analyzers/cards/build.js.map +7 -0
- package/dist/analyzers/cards/classify.js +42 -0
- package/dist/analyzers/cards/classify.js.map +7 -0
- package/dist/analyzers/cards/edge-index.js +44 -0
- package/dist/analyzers/cards/edge-index.js.map +7 -0
- package/dist/analyzers/cards/facts.js +46 -0
- package/dist/analyzers/cards/facts.js.map +7 -0
- package/dist/analyzers/cards/graph.js +42 -0
- package/dist/analyzers/cards/graph.js.map +7 -0
- package/dist/analyzers/cards/index.js +8 -0
- package/dist/analyzers/cards/index.js.map +7 -0
- package/dist/analyzers/cards/tier0.js +18 -0
- package/dist/analyzers/cards/tier0.js.map +7 -0
- package/dist/analyzers/cards/types.js +1 -0
- package/dist/analyzers/cards/types.js.map +7 -0
- package/dist/analyzers/cbm-analyzer.js +195 -171
- package/dist/analyzers/cbm-analyzer.js.map +2 -2
- package/dist/analyzers/cbm-responses.js +336 -0
- package/dist/analyzers/cbm-responses.js.map +7 -0
- package/dist/analyzers/edge-relationships.js +45 -0
- package/dist/analyzers/edge-relationships.js.map +7 -0
- package/dist/analyzers/mapping-loader.js +9 -0
- package/dist/analyzers/mapping-loader.js.map +2 -2
- package/dist/analyzers/tier0-rules.js +153 -0
- package/dist/analyzers/tier0-rules.js.map +7 -0
- package/dist/analyzers/types.js.map +1 -1
- package/dist/analyzers/verify-engine.js +22 -19
- package/dist/analyzers/verify-engine.js.map +2 -2
- 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 +112 -28
- package/dist/cli.js.map +3 -3
- package/dist/coding-agents/agents/claude-code.js +3 -1
- package/dist/coding-agents/agents/claude-code.js.map +2 -2
- package/dist/coding-agents/claude-code-client.js +2 -1
- package/dist/coding-agents/claude-code-client.js.map +2 -2
- package/dist/coding-agents/copilot-client.js +17 -12
- package/dist/coding-agents/copilot-client.js.map +2 -2
- package/dist/coding-agents/default-permissions.js +152 -0
- package/dist/coding-agents/default-permissions.js.map +7 -0
- package/dist/coding-agents/drbot-mcp.js +167 -0
- package/dist/coding-agents/drbot-mcp.js.map +7 -0
- package/dist/commands/add.js +12 -7
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +134 -23
- package/dist/commands/analyzer.js.map +2 -2
- package/dist/commands/audit.js +6 -6
- package/dist/commands/audit.js.map +2 -2
- package/dist/commands/changeset-verify.js +55 -0
- package/dist/commands/changeset-verify.js.map +7 -0
- package/dist/commands/changeset.js +261 -147
- package/dist/commands/changeset.js.map +2 -2
- package/dist/commands/delete.js +52 -19
- package/dist/commands/delete.js.map +3 -3
- package/dist/commands/element.js +3 -2
- package/dist/commands/element.js.map +2 -2
- package/dist/commands/farm.js +773 -0
- package/dist/commands/farm.js.map +7 -0
- package/dist/commands/init.js +11 -1
- package/dist/commands/init.js.map +2 -2
- package/dist/commands/mcp.js +122 -0
- package/dist/commands/mcp.js.map +7 -0
- package/dist/commands/relationship.js +251 -47
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/reports.js +1 -1
- package/dist/commands/reports.js.map +2 -2
- package/dist/commands/update.js +56 -24
- package/dist/commands/update.js.map +2 -2
- package/dist/commands/upgrade.js +99 -11
- package/dist/commands/upgrade.js.map +3 -3
- package/dist/commands/validate.js +41 -3
- package/dist/commands/validate.js.map +2 -2
- package/dist/commands/version.js +2 -2
- package/dist/commands/version.js.map +2 -2
- package/dist/commands/visualize.js +4 -3
- package/dist/commands/visualize.js.map +2 -2
- package/dist/config.js +83 -0
- package/dist/config.js.map +7 -0
- package/dist/core/annotation-store.js +138 -0
- package/dist/core/annotation-store.js.map +7 -0
- package/dist/core/catalog-migration.js +33 -0
- package/dist/core/catalog-migration.js.map +7 -0
- package/dist/core/changeset-analysis.js +421 -0
- package/dist/core/changeset-analysis.js.map +7 -0
- package/dist/core/changeset-base-index.js +153 -0
- package/dist/core/changeset-base-index.js.map +7 -0
- package/dist/core/changeset-brief-delta.js +102 -0
- package/dist/core/changeset-brief-delta.js.map +7 -0
- package/dist/core/changeset-graph.js +281 -0
- package/dist/core/changeset-graph.js.map +7 -0
- package/dist/core/changeset-only-guard.js +32 -0
- package/dist/core/changeset-only-guard.js.map +7 -0
- package/dist/core/changeset-summary.js +68 -0
- package/dist/core/changeset-summary.js.map +7 -0
- package/dist/core/changeset-validator.js +66 -20
- package/dist/core/changeset-validator.js.map +2 -2
- package/dist/core/changeset-verify.js +518 -0
- package/dist/core/changeset-verify.js.map +7 -0
- package/dist/core/changeset.js +56 -9
- package/dist/core/changeset.js.map +2 -2
- package/dist/core/element-type-migration.js +145 -0
- package/dist/core/element-type-migration.js.map +7 -0
- package/dist/core/farm-manifest.js +140 -0
- package/dist/core/farm-manifest.js.map +7 -0
- package/dist/core/farm-sync-engine.js +346 -0
- package/dist/core/farm-sync-engine.js.map +7 -0
- package/dist/core/farm-sync-state.js +167 -0
- package/dist/core/farm-sync-state.js.map +7 -0
- package/dist/core/manifest.js +6 -3
- package/dist/core/manifest.js.map +2 -2
- package/dist/core/migration-registry.js +84 -1
- 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 +257 -44
- package/dist/core/model.js.map +3 -3
- package/dist/core/mutation-handler.js +71 -6
- package/dist/core/mutation-handler.js.map +2 -2
- package/dist/core/relationship-migration-table.js +6639 -0
- package/dist/core/relationship-migration-table.js.map +7 -0
- package/dist/core/relationship-migration.js +272 -0
- package/dist/core/relationship-migration.js.map +7 -0
- package/dist/core/relationship-prune.js +49 -0
- package/dist/core/relationship-prune.js.map +7 -0
- package/dist/core/relationship-staging.js +68 -0
- package/dist/core/relationship-staging.js.map +7 -0
- package/dist/core/relationships.js +26 -4
- package/dist/core/relationships.js.map +2 -2
- package/dist/core/report-data-model.js +7 -13
- package/dist/core/report-data-model.js.map +2 -2
- package/dist/core/staged-changeset-storage.js +64 -17
- package/dist/core/staged-changeset-storage.js.map +2 -2
- package/dist/core/staged-source-reference.js +28 -0
- package/dist/core/staged-source-reference.js.map +7 -0
- package/dist/core/staging-area.js +83 -18
- package/dist/core/staging-area.js.map +2 -2
- package/dist/core/virtual-projection.js +14 -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 +2209 -7727
- package/dist/generated/relationship-index.js.map +2 -2
- package/dist/integrations/claude_code/agents/dr-architect.md +16 -3
- package/dist/integrations/claude_code/agents/dr-extractor.md +1 -1
- package/dist/integrations/claude_code/commands/dr-analyzer.md +565 -0
- package/dist/integrations/claude_code/commands/dr-map.md +13 -0
- package/dist/integrations/claude_code/commands/dr-plan.md +40 -0
- package/dist/integrations/claude_code/commands/dr-relate.md +106 -96
- package/dist/integrations/claude_code/commands/dr-verify.md +45 -2
- package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +14 -0
- package/dist/integrations/claude_code/docs/MCP_SERVER.md +79 -0
- package/dist/integrations/claude_code/docs/QUICK_START.md +37 -8
- package/dist/integrations/claude_code/docs/README.md +52 -1
- package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +93 -72
- package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +163 -126
- package/dist/integrations/claude_code/skills/dr_03_product_layer/SKILL.md +161 -126
- package/dist/integrations/claude_code/skills/dr_04_security_layer/SKILL.md +153 -133
- package/dist/integrations/claude_code/skills/dr_05_application_layer/SKILL.md +129 -100
- package/dist/integrations/claude_code/skills/dr_06_technology_layer/SKILL.md +111 -94
- package/dist/integrations/claude_code/skills/dr_07_api_layer/SKILL.md +143 -157
- package/dist/integrations/claude_code/skills/dr_08_data_model_layer/SKILL.md +117 -33
- package/dist/integrations/claude_code/skills/dr_09_dataset_layer/SKILL.md +74 -25
- package/dist/integrations/claude_code/skills/dr_10_ux_layer/SKILL.md +88 -12
- package/dist/integrations/claude_code/skills/dr_11_navigation_layer/SKILL.md +83 -24
- package/dist/integrations/claude_code/skills/dr_12_apm_layer/SKILL.md +57 -12
- package/dist/integrations/claude_code/skills/dr_13_testing_layer/SKILL.md +92 -15
- package/dist/integrations/claude_code/skills/dr_change_planning/SKILL.md +119 -0
- package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +3 -0
- package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +1 -1
- package/dist/integrations/github_copilot/agents/dr-architect.md +1 -1
- package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +182 -102
- package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +266 -148
- package/dist/integrations/github_copilot/skills/dr_03_product_layer/SKILL.md +547 -86
- package/dist/integrations/github_copilot/skills/dr_04_security_layer/SKILL.md +164 -169
- package/dist/integrations/github_copilot/skills/dr_05_application_layer/SKILL.md +420 -150
- package/dist/integrations/github_copilot/skills/dr_06_technology_layer/SKILL.md +331 -138
- package/dist/integrations/github_copilot/skills/dr_07_api_layer/SKILL.md +265 -201
- package/dist/integrations/github_copilot/skills/dr_08_data_model_layer/SKILL.md +181 -58
- package/dist/integrations/github_copilot/skills/dr_09_dataset_layer/SKILL.md +209 -57
- package/dist/integrations/github_copilot/skills/dr_10_ux_layer/SKILL.md +277 -112
- package/dist/integrations/github_copilot/skills/dr_11_navigation_layer/SKILL.md +219 -70
- package/dist/integrations/github_copilot/skills/dr_12_apm_layer/SKILL.md +189 -105
- package/dist/integrations/github_copilot/skills/dr_13_testing_layer/SKILL.md +222 -102
- package/dist/integrations/github_copilot/skills/dr_change_planning/SKILL.md +119 -0
- package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +3 -0
- package/dist/integrations/hash-utils.js.map +2 -2
- package/dist/mcp/api-key-manager.js +111 -0
- package/dist/mcp/api-key-manager.js.map +7 -0
- package/dist/mcp/changeset-only.js +34 -0
- package/dist/mcp/changeset-only.js.map +7 -0
- package/dist/mcp/http-transport.js +176 -0
- package/dist/mcp/http-transport.js.map +7 -0
- package/dist/mcp/resource-registry.js +97 -0
- package/dist/mcp/resource-registry.js.map +7 -0
- package/dist/mcp/tool-registry.js +60 -0
- package/dist/mcp/tool-registry.js.map +7 -0
- package/dist/mcp/tools/annotation-create.js +39 -0
- package/dist/mcp/tools/annotation-create.js.map +7 -0
- package/dist/mcp/tools/annotation-delete.js +29 -0
- package/dist/mcp/tools/annotation-delete.js.map +7 -0
- package/dist/mcp/tools/annotation-get.js +29 -0
- package/dist/mcp/tools/annotation-get.js.map +7 -0
- package/dist/mcp/tools/annotation-list.js +24 -0
- package/dist/mcp/tools/annotation-list.js.map +7 -0
- package/dist/mcp/tools/annotation-reply.js +34 -0
- package/dist/mcp/tools/annotation-reply.js.map +7 -0
- package/dist/mcp/tools/annotation-shared.js +10 -0
- package/dist/mcp/tools/annotation-shared.js.map +7 -0
- package/dist/mcp/tools/annotation-update.js +39 -0
- package/dist/mcp/tools/annotation-update.js.map +7 -0
- package/dist/mcp/tools/changeset-analysis-tools.js +78 -0
- package/dist/mcp/tools/changeset-analysis-tools.js.map +7 -0
- package/dist/mcp/tools/changeset-editing.js +184 -0
- package/dist/mcp/tools/changeset-editing.js.map +7 -0
- package/dist/mcp/tools/changeset-lifecycle.js +83 -0
- package/dist/mcp/tools/changeset-lifecycle.js.map +7 -0
- package/dist/mcp/tools/changeset-list.js +33 -0
- package/dist/mcp/tools/changeset-list.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 +55 -0
- package/dist/mcp/tools/changeset-show.js.map +7 -0
- package/dist/mcp/tools/changeset-verify.js +43 -0
- package/dist/mcp/tools/changeset-verify.js.map +7 -0
- package/dist/mcp/tools/chat-launch.js +50 -0
- package/dist/mcp/tools/chat-launch.js.map +7 -0
- package/dist/mcp/tools/chat-status.js +26 -0
- package/dist/mcp/tools/chat-status.js.map +7 -0
- package/dist/mcp/tools/index.js +65 -0
- package/dist/mcp/tools/index.js.map +7 -0
- package/dist/mcp/tools/model-add.js +107 -0
- package/dist/mcp/tools/model-add.js.map +7 -0
- package/dist/mcp/tools/model-delete.js +99 -0
- package/dist/mcp/tools/model-delete.js.map +7 -0
- package/dist/mcp/tools/model-export.js +72 -0
- package/dist/mcp/tools/model-export.js.map +7 -0
- package/dist/mcp/tools/model-info.js +51 -0
- package/dist/mcp/tools/model-info.js.map +7 -0
- package/dist/mcp/tools/model-list.js +53 -0
- package/dist/mcp/tools/model-list.js.map +7 -0
- package/dist/mcp/tools/model-reload.js +34 -0
- package/dist/mcp/tools/model-reload.js.map +7 -0
- package/dist/mcp/tools/model-search.js +102 -0
- package/dist/mcp/tools/model-search.js.map +7 -0
- package/dist/mcp/tools/model-show.js +68 -0
- package/dist/mcp/tools/model-show.js.map +7 -0
- package/dist/mcp/tools/model-stats.js +22 -0
- package/dist/mcp/tools/model-stats.js.map +7 -0
- package/dist/mcp/tools/model-trace.js +118 -0
- package/dist/mcp/tools/model-trace.js.map +7 -0
- package/dist/mcp/tools/model-update.js +121 -0
- package/dist/mcp/tools/model-update.js.map +7 -0
- package/dist/mcp/tools/model-validate.js +78 -0
- package/dist/mcp/tools/model-validate.js.map +7 -0
- package/dist/mcp/tools/relationship-tools.js +98 -0
- package/dist/mcp/tools/relationship-tools.js.map +7 -0
- package/dist/mcp/tools/shared.js +126 -0
- package/dist/mcp/tools/shared.js.map +7 -0
- package/dist/mcp/tools/spec-type.js +90 -0
- package/dist/mcp/tools/spec-type.js.map +7 -0
- package/dist/reports/model-layer-report-generator.js +5 -3
- package/dist/reports/model-layer-report-generator.js.map +2 -2
- package/dist/reports/model-readme-generator.js +116 -0
- package/dist/reports/model-readme-generator.js.map +7 -0
- package/dist/reports/model-report-data.js +37 -1
- package/dist/reports/model-report-data.js.map +2 -2
- package/dist/reports/model-report-orchestrator.js +29 -6
- package/dist/reports/model-report-orchestrator.js.map +2 -2
- package/dist/reports/model-report-utils.js +9 -0
- package/dist/reports/model-report-utils.js.map +7 -0
- package/dist/schemas/bundled/analyzers/cbm.json +1186 -68
- package/dist/schemas/bundled/analyzers/manifest.json +2 -2
- package/dist/schemas/bundled/api.json +1029 -1658
- package/dist/schemas/bundled/apm.json +499 -734
- package/dist/schemas/bundled/application.json +745 -370
- package/dist/schemas/bundled/base.json +3 -220
- package/dist/schemas/bundled/business.json +452 -366
- package/dist/schemas/bundled/data-model.json +403 -383
- package/dist/schemas/bundled/data-store.json +334 -558
- package/dist/schemas/bundled/manifest.json +18 -18
- package/dist/schemas/bundled/motivation.json +349 -368
- package/dist/schemas/bundled/navigation.json +415 -731
- package/dist/schemas/bundled/product.json +325 -159
- package/dist/schemas/bundled/security.json +864 -1232
- package/dist/schemas/bundled/technology.json +574 -703
- package/dist/schemas/bundled/testing.json +718 -1643
- package/dist/schemas/bundled/ux.json +739 -1352
- package/dist/server/schemas.js +8 -0
- package/dist/server/schemas.js.map +2 -2
- package/dist/server/server.js +234 -31
- package/dist/server/server.js.map +2 -2
- package/dist/server-entry.js +2 -1
- package/dist/server-entry.js.map +2 -2
- package/dist/telemetry/config.js +2 -40
- package/dist/telemetry/config.js.map +2 -2
- package/dist/telemetry/index.js +1 -1
- package/dist/types/index.js.map +2 -2
- package/dist/utils/ansi-suppressor.js +23 -0
- package/dist/utils/ansi-suppressor.js.map +7 -0
- package/dist/utils/attribute-patch.js +41 -0
- package/dist/utils/attribute-patch.js.map +7 -0
- package/dist/utils/color-utils.js +34 -0
- package/dist/utils/color-utils.js.map +7 -0
- package/dist/utils/element-reference-shape.js +15 -1
- package/dist/utils/element-reference-shape.js.map +3 -3
- package/dist/utils/error-hints.js +29 -0
- package/dist/utils/error-hints.js.map +7 -0
- package/dist/utils/errors.js +75 -10
- package/dist/utils/errors.js.map +2 -2
- package/dist/utils/globals.js +17 -1
- package/dist/utils/globals.js.map +2 -2
- package/dist/utils/project-paths.js +50 -3
- package/dist/utils/project-paths.js.map +2 -2
- package/dist/utils/reference-path-parser.js +49 -0
- package/dist/utils/reference-path-parser.js.map +7 -0
- package/dist/utils/source-reference.js +17 -10
- package/dist/utils/source-reference.js.map +2 -2
- package/dist/utils/spec-version.js +10 -2
- package/dist/utils/spec-version.js.map +2 -2
- package/dist/validators/composed-reference-validator.js +240 -0
- package/dist/validators/composed-reference-validator.js.map +7 -0
- package/dist/validators/reference-validator.js +57 -13
- package/dist/validators/reference-validator.js.map +3 -3
- package/dist/validators/relationship-schema-validator.js +33 -5
- package/dist/validators/relationship-schema-validator.js.map +3 -3
- package/dist/validators/schema-validator.js +27 -9
- package/dist/validators/schema-validator.js.map +2 -2
- package/dist/validators/types.js.map +1 -1
- package/dist/viewer/README.md +6 -6
- package/dist/viewer/assets/main-CxzcuU_o.js +84 -0
- package/dist/viewer/assets/main-j-7ULYpm.css +1 -0
- package/dist/viewer/index.html +2 -2
- package/dist/viewer/manifest.json +10 -10
- package/dist/viewer/version.json +1 -1
- package/package.json +7 -3
- package/dist/viewer/assets/main-B7AOQXXX.js +0 -81
- package/dist/viewer/assets/main-vdrFrG7q.css +0 -1
|
@@ -3,12 +3,17 @@ import { Model } from "../core/model.js";
|
|
|
3
3
|
import { StagingAreaManager } from "../core/staging-area.js";
|
|
4
4
|
import { findElementLayer } from "../utils/element-utils.js";
|
|
5
5
|
import { isValidLayerName } from "../core/layers.js";
|
|
6
|
-
import { CLIError, ErrorCategory, handleError, getErrorMessage } from "../utils/errors.js";
|
|
6
|
+
import { CLIError, ErrorCategory, handleError, handleSuccess, handleInfo, getErrorMessage } from "../utils/errors.js";
|
|
7
7
|
import { getValidRelationships, getValidPredicatesForSource, getValidDestinationsForSourceAndPredicate } from "../generated/relationship-index.js";
|
|
8
8
|
import { normalizeNodeType } from "../generated/node-types.js";
|
|
9
9
|
import { ModelReportOrchestrator } from "../reports/model-report-orchestrator.js";
|
|
10
10
|
import { emitLog, SeverityNumber } from "../telemetry/index.js";
|
|
11
|
+
import { elementIdentifiers } from "../core/relationships.js";
|
|
11
12
|
import { RelationshipCatalog } from "../core/relationship-catalog.js";
|
|
13
|
+
import { collectKnownIdentifiers, findDanglingRelationships } from "../core/relationship-prune.js";
|
|
14
|
+
import { isJson } from "../utils/globals.js";
|
|
15
|
+
import { ChangesetGraph } from "../core/changeset-graph.js";
|
|
16
|
+
import { liveRelationshipsBetween, planRelationshipAdd, stageRelationshipDeletes } from "../core/relationship-staging.js";
|
|
12
17
|
function constructSpecNodeId(element, elementId) {
|
|
13
18
|
const layerId = element.layer_id, type = element.type;
|
|
14
19
|
if (typeof layerId != "string" || !layerId)
|
|
@@ -39,6 +44,13 @@ function getRelationshipConstraints(sourceSpecNodeId, predicate, destSpecNodeId)
|
|
|
39
44
|
};
|
|
40
45
|
}
|
|
41
46
|
async function addRelationshipHandler(model, source, target, predicate, properties, preResolved) {
|
|
47
|
+
return await addRelationship(model, source, target, predicate, properties, preResolved) !== "duplicate";
|
|
48
|
+
}
|
|
49
|
+
async function activeStagedChangeset(manager) {
|
|
50
|
+
const active = await manager.getActive();
|
|
51
|
+
return active && active.status === "staged" ? active : null;
|
|
52
|
+
}
|
|
53
|
+
async function addRelationship(model, source, target, predicate, properties, preResolved) {
|
|
42
54
|
let resolvedSourceLayerName = preResolved?.source?.layerName, resolvedSourceElement = preResolved?.source?.element, resolvedTargetLayerName = preResolved?.target?.layerName, resolvedTargetElement = preResolved?.target?.element;
|
|
43
55
|
if (!resolvedSourceLayerName && (resolvedSourceLayerName = await findElementLayer(model, source), !resolvedSourceLayerName))
|
|
44
56
|
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
@@ -68,9 +80,19 @@ async function addRelationshipHandler(model, source, target, predicate, properti
|
|
|
68
80
|
if (relType && !relType.semantics.reflexivity && source === target)
|
|
69
81
|
throw new CLIError(`Invalid relationship: predicate "${predicate}" does not allow reflexive relationships (${source})`, ErrorCategory.USER);
|
|
70
82
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
83
|
+
const stagingManager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await stagingManager.getActiveId(), activeChangeset = activeChangesetId ? await activeStagedChangeset(stagingManager) : null;
|
|
84
|
+
if (activeChangeset) {
|
|
85
|
+
const graph = await ChangesetGraph.build(model, activeChangeset), plan = planRelationshipAdd(graph, activeChangeset, { source, predicate, target });
|
|
86
|
+
if (plan.action === "duplicate")
|
|
87
|
+
return "duplicate";
|
|
88
|
+
if (plan.action === "restore") {
|
|
89
|
+
for (const key of plan.keys)
|
|
90
|
+
await stagingManager.unstage(activeChangeset.id, key);
|
|
91
|
+
return "restored";
|
|
92
|
+
}
|
|
93
|
+
} else if (model.relationships.find(source, target, predicate).length > 0)
|
|
94
|
+
return "duplicate";
|
|
95
|
+
const relData = {
|
|
74
96
|
source,
|
|
75
97
|
target,
|
|
76
98
|
predicate,
|
|
@@ -109,15 +131,35 @@ async function addRelationshipHandler(model, source, target, predicate, properti
|
|
|
109
131
|
});
|
|
110
132
|
}
|
|
111
133
|
}
|
|
112
|
-
return
|
|
134
|
+
return activeChangesetId ? "staged" : "added";
|
|
135
|
+
}
|
|
136
|
+
async function findRelationshipsByEndpoints(model, source, target, predicate) {
|
|
137
|
+
const sourceIds = new Set(elementIdentifiers(model.getElementById(source) ?? {}, source)), targetIds = new Set(elementIdentifiers(model.getElementById(target) ?? {}, target));
|
|
138
|
+
return model.relationships.getAll().filter((rel) => sourceIds.has(rel.source) && targetIds.has(rel.target) && (!predicate || rel.predicate === predicate));
|
|
113
139
|
}
|
|
114
|
-
|
|
140
|
+
function noMatchingRelationshipHints(surface, source, inChangeset) {
|
|
141
|
+
return surface === "mcp" ? [
|
|
142
|
+
`Use "model_show" on ${source} to see its relationships`,
|
|
143
|
+
inChangeset ? 'Use "changeset_brief" to see what this changeset already stages' : 'Use "model_search" to check the source and target element IDs'
|
|
144
|
+
] : [
|
|
145
|
+
`Use "dr relationship list ${source}" to see the relationships recorded for ${source}`,
|
|
146
|
+
inChangeset ? 'Use "dr changeset staged" to see what the active changeset already stages' : 'Use "dr relationship prune --dry-run" to list rows whose endpoints no longer resolve'
|
|
147
|
+
];
|
|
148
|
+
}
|
|
149
|
+
async function deleteRelationshipHandler(model, source, target, predicate, preResolved, surface = "cli") {
|
|
150
|
+
const changesetManager = new StagingAreaManager(model.rootPath, model), changeset = await changesetManager.getActiveId() ? await activeStagedChangeset(changesetManager) : null;
|
|
151
|
+
if (changeset) {
|
|
152
|
+
const graph = await ChangesetGraph.build(model, changeset), matches = liveRelationshipsBetween(graph, source, target, predicate);
|
|
153
|
+
if (matches.length === 0)
|
|
154
|
+
throw new CLIError("No matching relationships found", ErrorCategory.USER, noMatchingRelationshipHints(surface, source, !0));
|
|
155
|
+
const staged = await stageRelationshipDeletes(changesetManager, graph, changeset, matches);
|
|
156
|
+
return { deletedCount: staged.length, staged };
|
|
157
|
+
}
|
|
115
158
|
let resolvedSourceLayerName = preResolved?.sourceLayerName;
|
|
116
|
-
|
|
117
|
-
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
159
|
+
resolvedSourceLayerName || (resolvedSourceLayerName = await findElementLayer(model, source));
|
|
118
160
|
let resolvedToDelete = preResolved?.toDelete;
|
|
119
|
-
if (resolvedToDelete || (resolvedToDelete = model
|
|
120
|
-
throw new CLIError("No matching relationships found", ErrorCategory.USER);
|
|
161
|
+
if (resolvedToDelete || (resolvedToDelete = await findRelationshipsByEndpoints(model, source, target, predicate)), resolvedToDelete.length === 0)
|
|
162
|
+
throw new CLIError("No matching relationships found", ErrorCategory.USER, noMatchingRelationshipHints(surface, source, !1));
|
|
121
163
|
const stagingManager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await stagingManager.getActiveId();
|
|
122
164
|
if (activeChangesetId)
|
|
123
165
|
for (const rel of resolvedToDelete) {
|
|
@@ -137,7 +179,9 @@ async function deleteRelationshipHandler(model, source, target, predicate, preRe
|
|
|
137
179
|
});
|
|
138
180
|
}
|
|
139
181
|
else {
|
|
140
|
-
|
|
182
|
+
for (const rel of resolvedToDelete)
|
|
183
|
+
model.relationships.delete(rel.source, rel.target, rel.predicate);
|
|
184
|
+
await model.saveRelationships(), await model.saveManifest();
|
|
141
185
|
try {
|
|
142
186
|
const orchestrator = new ModelReportOrchestrator(model, model.rootPath), affectedLayers = /* @__PURE__ */ new Set();
|
|
143
187
|
for (const rel of resolvedToDelete) {
|
|
@@ -161,15 +205,115 @@ async function deleteRelationshipHandler(model, source, target, predicate, preRe
|
|
|
161
205
|
}
|
|
162
206
|
return { deletedCount: resolvedToDelete.length };
|
|
163
207
|
}
|
|
164
|
-
function
|
|
165
|
-
|
|
208
|
+
async function pruneRelationshipsCommand(options) {
|
|
209
|
+
const format = options.format ?? "text";
|
|
210
|
+
if (format !== "text" && format !== "json")
|
|
211
|
+
throw new CLIError(`Invalid format: ${format}`, ErrorCategory.USER, [
|
|
212
|
+
"Use --format text or --format json"
|
|
213
|
+
]);
|
|
214
|
+
const jsonOutput = format === "json" || isJson(), layers = options.layers?.length ? options.layers : void 0;
|
|
215
|
+
if (layers) {
|
|
216
|
+
const invalid = layers.filter((l) => !isValidLayerName(l));
|
|
217
|
+
if (invalid.length > 0)
|
|
218
|
+
throw new CLIError(`Invalid layer name(s): ${invalid.join(", ")}`, ErrorCategory.USER, ['Use canonical layer names, e.g. "api", "data-model", "data-store"']);
|
|
219
|
+
}
|
|
220
|
+
const model = await Model.load(options.model || process.cwd()), elements = [];
|
|
221
|
+
for (const layerName of model.getLayerNames()) {
|
|
222
|
+
const layer = await model.getLayer(layerName);
|
|
223
|
+
layer && elements.push(...layer.listElements());
|
|
224
|
+
}
|
|
225
|
+
const known = collectKnownIdentifiers(elements), analysis = findDanglingRelationships(model.relationships.getAll(), known, { layers }), stagingManager = new StagingAreaManager(model.rootPath, model), activeChangeset = await stagingManager.getActive(), staging = !!activeChangeset && activeChangeset.status === "staged", result = {
|
|
226
|
+
scanned: analysis.scanned,
|
|
227
|
+
dangling: analysis.dangling.length,
|
|
228
|
+
removed: 0,
|
|
229
|
+
dryRun: !!options.dryRun,
|
|
230
|
+
staged: !1,
|
|
231
|
+
...staging ? { changeset: activeChangeset.name } : {},
|
|
232
|
+
...layers ? { layers } : {},
|
|
233
|
+
relationships: analysis.dangling.map(({ relationship: rel, unresolved }) => ({
|
|
234
|
+
source: rel.source,
|
|
235
|
+
predicate: rel.predicate,
|
|
236
|
+
target: rel.target,
|
|
237
|
+
layer: rel.layer,
|
|
238
|
+
...rel.targetLayer ? { targetLayer: rel.targetLayer } : {},
|
|
239
|
+
unresolved
|
|
240
|
+
}))
|
|
241
|
+
};
|
|
242
|
+
if (!options.dryRun && analysis.dangling.length > 0) {
|
|
243
|
+
if (staging) {
|
|
244
|
+
for (const { relationship: rel } of analysis.dangling)
|
|
245
|
+
await stagingManager.stage(activeChangeset.id, {
|
|
246
|
+
type: "relationship-delete",
|
|
247
|
+
elementId: `${rel.source}::${rel.predicate}::${rel.target}`,
|
|
248
|
+
layerName: rel.layer,
|
|
249
|
+
before: {
|
|
250
|
+
source: rel.source,
|
|
251
|
+
target: rel.target,
|
|
252
|
+
predicate: rel.predicate,
|
|
253
|
+
layer: rel.layer,
|
|
254
|
+
...rel.targetLayer ? { targetLayer: rel.targetLayer } : {},
|
|
255
|
+
...rel.properties ? { properties: rel.properties } : {}
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
result.staged = !0;
|
|
259
|
+
} else {
|
|
260
|
+
const danglingRows = new Set(analysis.dangling.map((d) => d.relationship));
|
|
261
|
+
model.relationships.retain((rel) => !danglingRows.has(rel)), await model.saveRelationships({ preserveHeader: !0 }), await model.saveManifest();
|
|
262
|
+
try {
|
|
263
|
+
const orchestrator = new ModelReportOrchestrator(model, model.rootPath), affectedLayers = /* @__PURE__ */ new Set();
|
|
264
|
+
for (const { relationship: rel } of analysis.dangling)
|
|
265
|
+
for (const name of [rel.layer, rel.targetLayer])
|
|
266
|
+
if (name && isValidLayerName(name))
|
|
267
|
+
for (const affected of orchestrator.computeAffectedLayers(name))
|
|
268
|
+
affectedLayers.add(affected);
|
|
269
|
+
await orchestrator.regenerate(affectedLayers);
|
|
270
|
+
} catch (error) {
|
|
271
|
+
emitLog(SeverityNumber.WARN, "Failed to regenerate layer reports after relationship prune", {
|
|
272
|
+
"relationship.pruned": analysis.dangling.length,
|
|
273
|
+
"error.message": getErrorMessage(error)
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
result.removed = analysis.dangling.length;
|
|
278
|
+
}
|
|
279
|
+
if (jsonOutput)
|
|
280
|
+
return console.log(JSON.stringify({ status: "ok", ...result }, null, 2)), result;
|
|
281
|
+
const scope = layers ? ` in layer(s) ${layers.join(", ")}` : "";
|
|
282
|
+
handleInfo(`Scanned ${result.scanned} relationship(s)${scope}: ${result.dangling} dangling`);
|
|
283
|
+
for (const row of result.relationships) {
|
|
284
|
+
const side = row.unresolved === "both" ? "source and target not found" : `${row.unresolved} not found`;
|
|
285
|
+
handleInfo(` - ${ansis.yellow(row.source)} --[${ansis.magenta(row.predicate)}]--> ${ansis.yellow(row.target)} ${ansis.dim(`(${side})`)}`);
|
|
286
|
+
}
|
|
287
|
+
return result.dangling === 0 ? handleSuccess("No dangling relationships found", {
|
|
288
|
+
scanned: result.scanned,
|
|
289
|
+
dangling: 0,
|
|
290
|
+
removed: 0
|
|
291
|
+
}) : result.dryRun ? handleSuccess(`Dry run: would remove ${result.dangling} dangling relationship(s)`, {
|
|
292
|
+
scanned: result.scanned,
|
|
293
|
+
dangling: result.dangling,
|
|
294
|
+
removed: 0,
|
|
295
|
+
dryRun: !0
|
|
296
|
+
}) : result.staged ? handleSuccess(`Staged removal of ${result.removed} dangling relationship(s) to ${ansis.bold(result.changeset)}`, {
|
|
297
|
+
scanned: result.scanned,
|
|
298
|
+
dangling: result.dangling,
|
|
299
|
+
removed: result.removed,
|
|
300
|
+
changesetStatus: "staged",
|
|
301
|
+
changeset: result.changeset
|
|
302
|
+
}) : handleSuccess(`Removed ${result.removed} dangling relationship(s)`, {
|
|
303
|
+
scanned: result.scanned,
|
|
304
|
+
dangling: result.dangling,
|
|
305
|
+
removed: result.removed
|
|
306
|
+
}), result;
|
|
307
|
+
}
|
|
308
|
+
function relationshipCommands(program, rootProgram) {
|
|
309
|
+
program.command("add <source> <target>").description("Add a relationship between elements (intra-layer or cross-layer)").option("--model <path>", "Path to model root (contains model/manifest.yaml)").requiredOption("--predicate <predicate>", "Relationship predicate (e.g., depends-on, realizes, exposes)").option("--properties <json>", "Relationship properties (JSON)").addHelpText("after", `
|
|
166
310
|
Examples:
|
|
167
311
|
$ dr relationship add motivation.goal.goal-a motivation.goal.goal-b --predicate aggregates
|
|
168
312
|
$ dr relationship add api.operation.create-order application.service.order-service --predicate exposes
|
|
169
313
|
$ dr relationship add business.businessprocess.checkout application.applicationprocess.checkout --predicate aggregates
|
|
170
314
|
$ dr relationship add element-1 element-2 --predicate realizes --properties '{"strength":"high"}'`).action(async (source, target, options) => {
|
|
171
315
|
try {
|
|
172
|
-
const model = await Model.load(), sourceLayerName = await findElementLayer(model, source);
|
|
316
|
+
const model = await Model.load(options.model), sourceLayerName = await findElementLayer(model, source);
|
|
173
317
|
if (!sourceLayerName)
|
|
174
318
|
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
175
319
|
const sourceLayer = await model.getLayer(sourceLayerName);
|
|
@@ -195,111 +339,171 @@ Examples:
|
|
|
195
339
|
} catch {
|
|
196
340
|
throw new CLIError("Invalid JSON in --properties", ErrorCategory.USER);
|
|
197
341
|
}
|
|
198
|
-
const activeChangesetId = await new StagingAreaManager(model.rootPath, model).getActiveId()
|
|
199
|
-
if (!await addRelationshipHandler(model, source, target, options.predicate, properties, {
|
|
342
|
+
const activeChangesetId = await new StagingAreaManager(model.rootPath, model).getActiveId(), outcome = await addRelationship(model, source, target, options.predicate, properties, {
|
|
200
343
|
source: { element: sourceElement, layerName: sourceLayerName },
|
|
201
344
|
target: { element: targetElement, layerName: targetLayerName }
|
|
202
|
-
})
|
|
345
|
+
});
|
|
346
|
+
if (outcome === "duplicate") {
|
|
347
|
+
handleSuccess(`Relationship ${source} --[${options.predicate}]--> ${target} already exists` + (activeChangesetId ? " (in the model or the active changeset); nothing staged" : ""), {
|
|
348
|
+
source,
|
|
349
|
+
target,
|
|
350
|
+
predicate: options.predicate,
|
|
351
|
+
layer: sourceLayerName,
|
|
352
|
+
duplicate: !0,
|
|
353
|
+
...activeChangesetId ? { changesetStatus: "unchanged" } : {}
|
|
354
|
+
}, { verbose: options.verbose });
|
|
203
355
|
return;
|
|
204
|
-
|
|
205
|
-
|
|
356
|
+
}
|
|
357
|
+
if (outcome === "restored") {
|
|
358
|
+
handleSuccess(`Restored relationship: ${ansis.bold(source)} ${options.predicate} ${ansis.bold(target)}` + ansis.dim(" [the active changeset's staged deletion of it was unstaged]"), {
|
|
359
|
+
source,
|
|
360
|
+
target,
|
|
361
|
+
predicate: options.predicate,
|
|
362
|
+
layer: sourceLayerName,
|
|
363
|
+
restored: !0,
|
|
364
|
+
changesetStatus: "unstaged"
|
|
365
|
+
}, { verbose: options.verbose });
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
let message = `Added relationship: ${ansis.bold(source)} ${options.predicate} ${ansis.bold(target)}`;
|
|
369
|
+
const details = {
|
|
370
|
+
source,
|
|
371
|
+
target,
|
|
372
|
+
predicate: options.predicate,
|
|
373
|
+
layer: sourceLayerName
|
|
374
|
+
};
|
|
375
|
+
constraints && (message += ansis.dim(` (${constraints.cardinality}, ${constraints.strength} strength)`), details.cardinality = constraints.cardinality, details.strength = constraints.strength), activeChangesetId && (message += ansis.dim(" [staged]"), details.changesetStatus = "staged"), handleSuccess(message, details, { verbose: options.verbose });
|
|
206
376
|
} catch (error) {
|
|
207
377
|
handleError(error);
|
|
208
378
|
}
|
|
209
|
-
}), program.command("delete <source> <target>").description("Delete a relationship").option("--predicate <predicate>", "Specific predicate to delete (optional, delete all if not specified)").option("--force", "Skip confirmation prompt").addHelpText("after", `
|
|
379
|
+
}), program.command("delete <source> <target>").description("Delete a relationship").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("--predicate <predicate>", "Specific predicate to delete (optional, delete all if not specified)").option("--force", "Skip confirmation prompt").addHelpText("after", `
|
|
210
380
|
Examples:
|
|
211
381
|
$ dr relationship delete element-1 element-2 --predicate depends-on
|
|
212
382
|
$ dr relationship delete element-1 element-2 --force`).action(async (source, target, options) => {
|
|
213
383
|
try {
|
|
214
|
-
const model = await Model.load(),
|
|
215
|
-
if (!sourceLayerName)
|
|
216
|
-
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
217
|
-
const toDelete = model.relationships.find(source, target, options.predicate);
|
|
384
|
+
const model = await Model.load(options.model), activeForDelete = await activeStagedChangeset(new StagingAreaManager(model.rootPath, model)), toDelete = activeForDelete ? liveRelationshipsBetween(await ChangesetGraph.build(model, activeForDelete), source, target, options.predicate) : await findRelationshipsByEndpoints(model, source, target, options.predicate);
|
|
218
385
|
if (toDelete.length === 0)
|
|
219
|
-
throw new CLIError("No matching relationships found", ErrorCategory.USER
|
|
220
|
-
|
|
386
|
+
throw new CLIError("No matching relationships found", ErrorCategory.USER, [
|
|
387
|
+
`Use "dr relationship list ${source}" to see the relationships recorded for ${source}`,
|
|
388
|
+
'Use "dr relationship prune --dry-run" to list rows whose endpoints no longer resolve'
|
|
389
|
+
]);
|
|
390
|
+
const sourceLayerName = await findElementLayer(model, source) ?? toDelete[0].layer, isInteractive = process.stdin.isTTY && process.stdout.isTTY;
|
|
221
391
|
if (!options.force && isInteractive) {
|
|
222
392
|
const { confirm } = await import("@clack/prompts");
|
|
223
393
|
if (!await confirm({
|
|
224
394
|
message: `Delete ${toDelete.length} relationship(s)? This cannot be undone.`,
|
|
225
395
|
initialValue: !1
|
|
226
396
|
})) {
|
|
227
|
-
|
|
397
|
+
handleSuccess("Deletion cancelled", {
|
|
398
|
+
source,
|
|
399
|
+
target,
|
|
400
|
+
status: "cancelled"
|
|
401
|
+
});
|
|
228
402
|
return;
|
|
229
403
|
}
|
|
230
404
|
}
|
|
231
405
|
const activeChangesetId = await new StagingAreaManager(model.rootPath, model).getActiveId(), result = await deleteRelationshipHandler(model, source, target, options.predicate, {
|
|
232
406
|
sourceLayerName,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
407
|
+
// In a changeset the handler re-reads the projected graph itself.
|
|
408
|
+
toDelete: activeForDelete ? void 0 : toDelete
|
|
409
|
+
}), stagedSuffix = activeChangesetId ? " [staged]" : "", deleteDetails = {
|
|
410
|
+
source,
|
|
411
|
+
target,
|
|
412
|
+
layer: sourceLayerName,
|
|
413
|
+
deletedCount: result.deletedCount,
|
|
414
|
+
...result.staged ? { relationships: result.staged } : {}
|
|
415
|
+
};
|
|
416
|
+
options.predicate && (deleteDetails.predicate = options.predicate), activeChangesetId && (deleteDetails.changesetStatus = "staged"), handleSuccess(`Deleted ${result.deletedCount} relationship(s) from ${ansis.bold(source)} to ${ansis.bold(target)}${stagedSuffix}`, deleteDetails, { verbose: options.verbose });
|
|
417
|
+
} catch (error) {
|
|
418
|
+
handleError(error);
|
|
419
|
+
}
|
|
420
|
+
}), program.command("prune").description("Remove relationship rows whose source or target no longer resolves to an element").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("--dry-run", "List the rows that would be removed without writing").option("--layers <layers...>", "Only scan rows whose source or target layer is one of these canonical layer names").option("--format <format>", "Output format: text, json", "text").addHelpText("after", `
|
|
421
|
+
A row is dangling when its source or target matches neither the UUID id nor the
|
|
422
|
+
dotted path of any current element. Kept rows keep their order and the file's
|
|
423
|
+
header comment is preserved. Inside an active changeset the removals are staged
|
|
424
|
+
as relationship deletions instead of being written to relationships.yaml.
|
|
425
|
+
|
|
426
|
+
Examples:
|
|
427
|
+
$ dr relationship prune --dry-run
|
|
428
|
+
$ dr relationship prune
|
|
429
|
+
$ dr relationship prune --layers api application --format json`).action(async (options) => {
|
|
430
|
+
try {
|
|
431
|
+
await pruneRelationshipsCommand({
|
|
432
|
+
model: options.model,
|
|
433
|
+
dryRun: !!options.dryRun,
|
|
434
|
+
layers: options.layers,
|
|
435
|
+
format: options.format
|
|
436
|
+
});
|
|
236
437
|
} catch (error) {
|
|
237
438
|
handleError(error);
|
|
238
439
|
}
|
|
239
|
-
}), program.command("list <id>").description("List relationships for an element").option("--direction <dir>", "Filter by direction (incoming/outgoing/all)", "all").option("--json", "Output as JSON").addHelpText("after", `
|
|
440
|
+
}), program.command("list <id>").description("List relationships for an element").option("--model <path>", "Path to model root (contains model/manifest.yaml)").option("--direction <dir>", "Filter by direction (incoming/outgoing/all)", "all").option("--json", "Output as JSON").addHelpText("after", `
|
|
240
441
|
Examples:
|
|
241
442
|
$ dr relationship list api-endpoint-create-customer
|
|
242
443
|
$ dr relationship list business-service-order --direction outgoing
|
|
243
444
|
$ dr relationship list element-1 --json`).action(async (id, options) => {
|
|
244
445
|
try {
|
|
245
|
-
const model = await Model.load();
|
|
446
|
+
const model = await Model.load(options.model);
|
|
246
447
|
if (!await findElementLayer(model, id))
|
|
247
448
|
throw new CLIError(`Element ${id} not found`, ErrorCategory.USER);
|
|
248
449
|
const { outgoing, incoming } = model.relationships.getForElement(id);
|
|
249
450
|
let relationships = [];
|
|
250
|
-
if ((options.direction === "outgoing" || options.direction === "all") && relationships.push(...outgoing), (options.direction === "incoming" || options.direction === "all") && relationships.push(...incoming), options.json) {
|
|
451
|
+
if ((options.direction === "outgoing" || options.direction === "all") && relationships.push(...outgoing), (options.direction === "incoming" || options.direction === "all") && relationships.push(...incoming), options.json ?? rootProgram?.opts().json) {
|
|
251
452
|
console.log(JSON.stringify(relationships, null, 2));
|
|
252
453
|
return;
|
|
253
454
|
}
|
|
254
455
|
if (relationships.length === 0) {
|
|
255
|
-
|
|
456
|
+
handleInfo(ansis.yellow(`No ${options.direction} relationships for ${id}`));
|
|
256
457
|
return;
|
|
257
458
|
}
|
|
258
|
-
|
|
459
|
+
handleInfo(""), handleInfo(ansis.bold(`${options.direction === "all" ? "" : options.direction + " "}relationships for ${ansis.cyan(id)}:`)), handleInfo(ansis.dim("\u2500".repeat(80)));
|
|
259
460
|
for (const rel of relationships) {
|
|
260
461
|
const isOutgoing = rel.source === id, direction = isOutgoing ? "\u2192" : "\u2190", otherElement = isOutgoing ? rel.target : rel.source, crossLayer = rel.targetLayer && rel.targetLayer !== rel.layer ? ansis.dim(` [${rel.layer} \u2192 ${rel.targetLayer}]`) : "";
|
|
261
|
-
if (
|
|
462
|
+
if (handleInfo(` ${direction} ${ansis.magenta(rel.predicate)}: ${ansis.yellow(otherElement)}${crossLayer}`), rel.properties) {
|
|
262
463
|
const propStr = Object.entries(rel.properties).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
263
|
-
|
|
464
|
+
handleInfo(` ${ansis.dim(propStr)}`);
|
|
264
465
|
}
|
|
265
466
|
}
|
|
266
|
-
|
|
467
|
+
handleInfo(ansis.dim("\u2500".repeat(80))), handleInfo(ansis.dim(`Total: ${relationships.length} relationship(s)`)), handleInfo("");
|
|
267
468
|
} catch (error) {
|
|
268
469
|
handleError(error);
|
|
269
470
|
}
|
|
270
|
-
}), program.command("show <source> <target>").description("Show relationship details").addHelpText("after", `
|
|
471
|
+
}), program.command("show <source> <target>").description("Show relationship details").option("--model <path>", "Path to model root (contains model/manifest.yaml)").addHelpText("after", `
|
|
271
472
|
Examples:
|
|
272
473
|
$ dr relationship show api-endpoint-create-customer business-service-customer-mgmt
|
|
273
|
-
$ dr relationship show application-component-api motivation-goal-sales-efficiency`).action(async (source, target) => {
|
|
474
|
+
$ dr relationship show application-component-api motivation-goal-sales-efficiency`).action(async (source, target, options) => {
|
|
274
475
|
try {
|
|
275
|
-
const model = await Model.load();
|
|
476
|
+
const model = await Model.load(options.model);
|
|
276
477
|
if (!await findElementLayer(model, source))
|
|
277
478
|
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
278
479
|
const relationships = model.relationships.find(source, target);
|
|
279
480
|
if (relationships.length === 0)
|
|
280
481
|
throw new CLIError(`No relationships from ${source} to ${target}`, ErrorCategory.USER);
|
|
281
|
-
|
|
482
|
+
handleInfo(""), handleInfo(ansis.bold(`Relationship${relationships.length > 1 ? "s" : ""} from ${ansis.cyan(source)} to ${ansis.yellow(target)}:`)), handleInfo(ansis.dim("\u2500".repeat(60)));
|
|
282
483
|
for (let i = 0; i < relationships.length; i++) {
|
|
283
484
|
const rel = relationships[i];
|
|
284
|
-
if (i > 0 &&
|
|
285
|
-
|
|
485
|
+
if (i > 0 && handleInfo(""), handleInfo(`Predicate: ${ansis.magenta(rel.predicate)}`), handleInfo(`Layer: ${ansis.cyan(rel.layer)}`), rel.targetLayer && rel.targetLayer !== rel.layer && handleInfo(`Target Layer: ${ansis.cyan(rel.targetLayer)}`), rel.properties && Object.keys(rel.properties).length > 0) {
|
|
486
|
+
handleInfo("Properties:");
|
|
286
487
|
for (const [key, value] of Object.entries(rel.properties)) {
|
|
287
488
|
const displayValue = typeof value == "string" ? value : JSON.stringify(value, null, 2);
|
|
288
|
-
|
|
489
|
+
handleInfo(` ${ansis.cyan(key)}: ${displayValue}`);
|
|
289
490
|
}
|
|
290
491
|
} else
|
|
291
|
-
|
|
492
|
+
handleInfo("Properties: none");
|
|
292
493
|
}
|
|
293
|
-
|
|
494
|
+
handleInfo("");
|
|
294
495
|
} catch (error) {
|
|
295
496
|
handleError(error);
|
|
296
497
|
}
|
|
297
498
|
});
|
|
298
499
|
}
|
|
299
500
|
export {
|
|
501
|
+
addRelationship,
|
|
300
502
|
addRelationshipHandler,
|
|
301
503
|
deleteRelationshipHandler,
|
|
504
|
+
findRelationshipsByEndpoints,
|
|
302
505
|
getRelationshipConstraints,
|
|
506
|
+
pruneRelationshipsCommand,
|
|
303
507
|
relationshipCommands,
|
|
304
508
|
validateRelationshipCombination
|
|
305
509
|
};
|