@documentation-robotics/cli 0.1.0 → 0.1.7
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/LICENSE +21 -0
- package/README.md +466 -693
- package/dist/analysis/data-model-analyzer.js +189 -0
- package/dist/analysis/data-model-analyzer.js.map +7 -0
- package/dist/analysis/index.js +3 -0
- package/dist/analysis/index.js.map +7 -0
- package/dist/analysis/relationship-classifier.js +181 -0
- package/dist/analysis/relationship-classifier.js.map +7 -0
- package/dist/analyzers/base-analyzer.js +1 -0
- package/dist/analyzers/base-analyzer.js.map +7 -0
- package/dist/analyzers/call-graph-utils.js +39 -0
- package/dist/analyzers/call-graph-utils.js.map +7 -0
- package/dist/analyzers/cbm-analyzer.js +1205 -0
- package/dist/analyzers/cbm-analyzer.js.map +7 -0
- package/dist/analyzers/heuristic-utils.js +55 -0
- package/dist/analyzers/heuristic-utils.js.map +7 -0
- package/dist/analyzers/mapping-loader.js +146 -0
- package/dist/analyzers/mapping-loader.js.map +7 -0
- package/dist/analyzers/registry.js +124 -0
- package/dist/analyzers/registry.js.map +7 -0
- package/dist/analyzers/session-state.js +176 -0
- package/dist/analyzers/session-state.js.map +7 -0
- package/dist/analyzers/stdio-client.js +208 -0
- package/dist/analyzers/stdio-client.js.map +7 -0
- package/dist/analyzers/types.js +15 -0
- package/dist/analyzers/types.js.map +7 -0
- package/dist/analyzers/verify-engine.js +209 -0
- package/dist/analyzers/verify-engine.js.map +7 -0
- package/dist/analyzers/verify-ignore.js +130 -0
- package/dist/analyzers/verify-ignore.js.map +7 -0
- package/dist/analyzers/version.js +8 -0
- package/dist/analyzers/version.js.map +7 -0
- package/dist/audit/ai/runner.js +41 -0
- package/dist/audit/ai/runner.js.map +7 -0
- package/dist/audit/differential-analyzer.js +183 -0
- package/dist/audit/differential-analyzer.js.map +7 -0
- package/dist/audit/index.js +32 -0
- package/dist/audit/index.js.map +7 -0
- package/dist/audit/nodes/ai/evaluator.js +49 -0
- package/dist/audit/nodes/ai/evaluator.js.map +7 -0
- package/dist/audit/nodes/ai/parser.js +55 -0
- package/dist/audit/nodes/ai/parser.js.map +7 -0
- package/dist/audit/nodes/ai/prompts.js +103 -0
- package/dist/audit/nodes/ai/prompts.js.map +7 -0
- package/dist/audit/nodes/analysis/node-completeness-checker.js +32 -0
- package/dist/audit/nodes/analysis/node-completeness-checker.js.map +7 -0
- package/dist/audit/nodes/analysis/node-definition-analyzer.js +47 -0
- package/dist/audit/nodes/analysis/node-definition-analyzer.js.map +7 -0
- package/dist/audit/nodes/analysis/node-overlap-detector.js +79 -0
- package/dist/audit/nodes/analysis/node-overlap-detector.js.map +7 -0
- package/dist/audit/nodes/model/orchestrator.js +82 -0
- package/dist/audit/nodes/model/orchestrator.js.map +7 -0
- package/dist/audit/nodes/spec/loader.js +116 -0
- package/dist/audit/nodes/spec/loader.js.map +7 -0
- package/dist/audit/nodes/spec/orchestrator.js +68 -0
- package/dist/audit/nodes/spec/orchestrator.js.map +7 -0
- package/dist/audit/nodes/types.js +1 -0
- package/dist/audit/nodes/types.js.map +7 -0
- package/dist/audit/pipeline/index.js +5 -0
- package/dist/audit/pipeline/index.js.map +7 -0
- package/dist/audit/pipeline/pipeline-orchestrator.js +218 -0
- package/dist/audit/pipeline/pipeline-orchestrator.js.map +7 -0
- package/dist/audit/relationships/ai/evaluator.js +235 -0
- package/dist/audit/relationships/ai/evaluator.js.map +7 -0
- package/dist/audit/relationships/ai/parser.js +197 -0
- package/dist/audit/relationships/ai/parser.js.map +7 -0
- package/dist/audit/relationships/ai/prompts.js +274 -0
- package/dist/audit/relationships/ai/prompts.js.map +7 -0
- package/dist/audit/relationships/analysis/balance-assessor.js +115 -0
- package/dist/audit/relationships/analysis/balance-assessor.js.map +7 -0
- package/dist/audit/relationships/analysis/coverage-analyzer.js +99 -0
- package/dist/audit/relationships/analysis/coverage-analyzer.js.map +7 -0
- package/dist/audit/relationships/analysis/duplicate-detector.js +95 -0
- package/dist/audit/relationships/analysis/duplicate-detector.js.map +7 -0
- package/dist/audit/relationships/analysis/gap-analyzer.js +99 -0
- package/dist/audit/relationships/analysis/gap-analyzer.js.map +7 -0
- package/dist/audit/relationships/analysis/layer-templates.js +294 -0
- package/dist/audit/relationships/analysis/layer-templates.js.map +7 -0
- package/dist/audit/relationships/graph/connectivity.js +129 -0
- package/dist/audit/relationships/graph/connectivity.js.map +7 -0
- package/dist/audit/relationships/graph/relationship-graph.js +179 -0
- package/dist/audit/relationships/graph/relationship-graph.js.map +7 -0
- package/dist/audit/relationships/model/balance-assessor.js +49 -0
- package/dist/audit/relationships/model/balance-assessor.js.map +7 -0
- package/dist/audit/relationships/model/coverage-analyzer.js +34 -0
- package/dist/audit/relationships/model/coverage-analyzer.js.map +7 -0
- package/dist/audit/relationships/model/duplicate-detector.js +68 -0
- package/dist/audit/relationships/model/duplicate-detector.js.map +7 -0
- package/dist/audit/relationships/model/gap-analyzer.js +41 -0
- package/dist/audit/relationships/model/gap-analyzer.js.map +7 -0
- package/dist/audit/relationships/model/orchestrator.js +126 -0
- package/dist/audit/relationships/model/orchestrator.js.map +7 -0
- package/dist/audit/relationships/spec/orchestrator.js +157 -0
- package/dist/audit/relationships/spec/orchestrator.js.map +7 -0
- package/dist/audit/reports/index.js +5 -0
- package/dist/audit/reports/index.js.map +7 -0
- package/dist/audit/reports/report-generator.js +118 -0
- package/dist/audit/reports/report-generator.js.map +7 -0
- package/dist/audit/snapshot-storage.js +163 -0
- package/dist/audit/snapshot-storage.js.map +7 -0
- package/dist/audit/types.js +21 -0
- package/dist/audit/types.js.map +7 -0
- package/dist/cli.js +223 -92
- package/dist/cli.js.map +3 -3
- package/dist/coding-agents/agents/claude-code.js +147 -0
- package/dist/coding-agents/agents/claude-code.js.map +7 -0
- package/dist/coding-agents/agents/index.js +5 -0
- package/dist/coding-agents/agents/index.js.map +7 -0
- package/dist/coding-agents/agents/types.js +1 -0
- package/dist/coding-agents/agents/types.js.map +7 -0
- package/dist/coding-agents/base-chat-client.js +45 -0
- package/dist/coding-agents/base-chat-client.js.map +7 -0
- package/dist/coding-agents/chat-utils.js +23 -0
- package/dist/coding-agents/chat-utils.js.map +7 -0
- package/dist/coding-agents/claude-code-client.js +246 -0
- package/dist/coding-agents/claude-code-client.js.map +7 -0
- package/dist/coding-agents/copilot-client.js +209 -0
- package/dist/coding-agents/copilot-client.js.map +7 -0
- package/dist/commands/add.js +95 -33
- package/dist/commands/add.js.map +2 -2
- package/dist/commands/analyzer.js +511 -0
- package/dist/commands/analyzer.js.map +7 -0
- package/dist/commands/audit-diff.js +49 -0
- package/dist/commands/audit-diff.js.map +7 -0
- package/dist/commands/audit-snapshots.js +62 -0
- package/dist/commands/audit-snapshots.js.map +7 -0
- package/dist/commands/audit.js +81 -0
- package/dist/commands/audit.js.map +7 -0
- package/dist/commands/catalog.js +248 -0
- package/dist/commands/catalog.js.map +7 -0
- package/dist/commands/changeset.js +577 -66
- package/dist/commands/changeset.js.map +2 -2
- package/dist/commands/chat.js +106 -83
- package/dist/commands/chat.js.map +2 -2
- package/dist/commands/claude.js +74 -0
- package/dist/commands/claude.js.map +7 -0
- package/dist/commands/conformance.js +71 -68
- package/dist/commands/conformance.js.map +2 -2
- package/dist/commands/copilot.js +75 -0
- package/dist/commands/copilot.js.map +7 -0
- package/dist/commands/delete.js +125 -11
- package/dist/commands/delete.js.map +3 -3
- package/dist/commands/discover-logic.js +44 -0
- package/dist/commands/discover-logic.js.map +7 -0
- package/dist/commands/docs.js +87 -0
- package/dist/commands/docs.js.map +7 -0
- package/dist/commands/element.js +14 -20
- package/dist/commands/element.js.map +2 -2
- package/dist/commands/export.js +13 -3
- package/dist/commands/export.js.map +2 -2
- package/dist/commands/import.js +51 -0
- package/dist/commands/import.js.map +7 -0
- package/dist/commands/info.js +30 -24
- package/dist/commands/info.js.map +2 -2
- package/dist/commands/init.js +27 -11
- package/dist/commands/init.js.map +2 -2
- package/dist/commands/list.js +63 -13
- package/dist/commands/list.js.map +3 -3
- package/dist/commands/relationship.js +225 -37
- package/dist/commands/relationship.js.map +2 -2
- package/dist/commands/report.js +54 -0
- package/dist/commands/report.js.map +7 -0
- package/dist/commands/reports.js +45 -0
- package/dist/commands/reports.js.map +7 -0
- package/dist/commands/schema.js +135 -0
- package/dist/commands/schema.js.map +7 -0
- package/dist/commands/search.js +40 -12
- package/dist/commands/search.js.map +2 -2
- package/dist/commands/show.js +58 -27
- package/dist/commands/show.js.map +2 -2
- package/dist/commands/stats.js +35 -0
- package/dist/commands/stats.js.map +7 -0
- package/dist/commands/trace.js +39 -16
- package/dist/commands/trace.js.map +2 -2
- package/dist/commands/update.js +141 -14
- package/dist/commands/update.js.map +2 -2
- package/dist/commands/upgrade.js +210 -46
- package/dist/commands/upgrade.js.map +3 -3
- package/dist/commands/validate.js +142 -23
- package/dist/commands/validate.js.map +3 -3
- package/dist/commands/version.js +8 -12
- package/dist/commands/version.js.map +2 -2
- package/dist/commands/visualize.js +162 -25
- package/dist/commands/visualize.js.map +2 -2
- package/dist/core/base-snapshot-manager.js +84 -0
- package/dist/core/base-snapshot-manager.js.map +7 -0
- package/dist/core/changeset-exporter.js +305 -0
- package/dist/core/changeset-exporter.js.map +7 -0
- package/dist/core/changeset-validator.js +41 -0
- package/dist/core/changeset-validator.js.map +7 -0
- package/dist/core/changeset.js +88 -173
- package/dist/core/changeset.js.map +2 -2
- package/dist/core/dependency-tracker.js +4 -2
- package/dist/core/dependency-tracker.js.map +2 -2
- package/dist/core/element.js +98 -27
- package/dist/core/element.js.map +2 -2
- package/dist/core/golden-copy-cache.js +290 -0
- package/dist/core/golden-copy-cache.js.map +7 -0
- package/dist/core/graph-model.js +266 -0
- package/dist/core/graph-model.js.map +7 -0
- package/dist/core/layer.js +159 -16
- package/dist/core/layer.js.map +2 -2
- package/dist/core/layers.js +32 -0
- package/dist/core/layers.js.map +7 -0
- package/dist/core/manifest.js +32 -11
- package/dist/core/manifest.js.map +2 -2
- package/dist/core/migration-registry.js +56 -1
- package/dist/core/migration-registry.js.map +2 -2
- package/dist/core/model.js +424 -217
- package/dist/core/model.js.map +3 -3
- package/dist/core/mutation-handler.js +179 -0
- package/dist/core/mutation-handler.js.map +7 -0
- package/dist/core/reference-registry.js +29 -21
- package/dist/core/reference-registry.js.map +2 -2
- package/dist/core/relationship-catalog.js +189 -0
- package/dist/core/relationship-catalog.js.map +7 -0
- package/dist/core/relationship-registry.js.map +2 -2
- package/dist/core/relationships.js.map +1 -1
- package/dist/core/report-data-model.js +285 -0
- package/dist/core/report-data-model.js.map +7 -0
- package/dist/core/spec-data-service.js +185 -0
- package/dist/core/spec-data-service.js.map +7 -0
- package/dist/core/spec-loader-types.js +1 -0
- package/dist/core/spec-loader-types.js.map +7 -0
- package/dist/core/spec-loader.js +234 -0
- package/dist/core/spec-loader.js.map +7 -0
- package/dist/core/staged-changeset-storage.js +282 -0
- package/dist/core/staged-changeset-storage.js.map +7 -0
- package/dist/core/staging-area.js +1002 -0
- package/dist/core/staging-area.js.map +7 -0
- package/dist/core/stats-collector.js +169 -0
- package/dist/core/stats-collector.js.map +7 -0
- package/dist/core/virtual-projection.js +443 -0
- package/dist/core/virtual-projection.js.map +7 -0
- package/dist/export/archimate-exporter.js +99 -60
- package/dist/export/archimate-exporter.js.map +2 -2
- package/dist/export/audit-formatters.js +479 -0
- package/dist/export/audit-formatters.js.map +7 -0
- package/dist/export/diff-formatters.js +99 -0
- package/dist/export/diff-formatters.js.map +7 -0
- package/dist/export/export-manager.js.map +2 -2
- package/dist/export/graphml-exporter.js +44 -27
- package/dist/export/graphml-exporter.js.map +2 -2
- package/dist/export/index.js +4 -0
- package/dist/export/index.js.map +2 -2
- package/dist/export/json-schema-exporter.js +55 -42
- package/dist/export/json-schema-exporter.js.map +2 -2
- package/dist/export/markdown-exporter.js +92 -70
- package/dist/export/markdown-exporter.js.map +2 -2
- package/dist/export/markdown-generator.js +248 -0
- package/dist/export/markdown-generator.js.map +7 -0
- package/dist/export/markdown-utils.js +30 -0
- package/dist/export/markdown-utils.js.map +7 -0
- package/dist/export/mermaid-markdown-exporter.js +37 -0
- package/dist/export/mermaid-markdown-exporter.js.map +7 -0
- package/dist/export/openapi-exporter.js +119 -71
- package/dist/export/openapi-exporter.js.map +2 -2
- package/dist/export/plantuml-exporter.js +104 -39
- package/dist/export/plantuml-exporter.js.map +2 -2
- package/dist/export/report-formatters.js +111 -0
- package/dist/export/report-formatters.js.map +7 -0
- package/dist/export/stats-formatters.js +98 -0
- package/dist/export/stats-formatters.js.map +7 -0
- package/dist/export/types.js +2 -14
- package/dist/export/types.js.map +2 -2
- package/dist/export/verify-formatters.js +153 -0
- package/dist/export/verify-formatters.js.map +7 -0
- package/dist/generated/compiled-validators.js +17 -0
- package/dist/generated/compiled-validators.js.map +7 -0
- package/dist/generated/index.js +31 -0
- package/dist/generated/index.js.map +7 -0
- package/dist/generated/layer-registry.js +190 -0
- package/dist/generated/layer-registry.js.map +7 -0
- package/dist/generated/layer-types.js +7 -0
- package/dist/generated/layer-types.js.map +7 -0
- package/dist/generated/node-types.js +1719 -0
- package/dist/generated/node-types.js.map +7 -0
- package/dist/generated/relationship-index.js +14552 -0
- package/dist/generated/relationship-index.js.map +7 -0
- package/dist/import/archimate-importer.js +166 -0
- package/dist/import/archimate-importer.js.map +7 -0
- package/dist/import/index.js +47 -0
- package/dist/import/index.js.map +7 -0
- package/dist/import/openapi-importer.js +143 -0
- package/dist/import/openapi-importer.js.map +7 -0
- package/dist/import/types.js +1 -0
- package/dist/import/types.js.map +7 -0
- package/dist/integrations/base-manager.js +311 -0
- package/dist/integrations/base-manager.js.map +7 -0
- package/dist/integrations/claude-manager.js +360 -0
- package/dist/integrations/claude-manager.js.map +7 -0
- package/dist/integrations/claude_code/agents/dr-advisor.md +253 -0
- package/dist/integrations/claude_code/agents/dr-architect.md +278 -0
- package/dist/integrations/claude_code/agents/dr-extractor.md +286 -0
- package/dist/integrations/claude_code/commands/dr-changeset.md +657 -0
- package/dist/integrations/claude_code/commands/dr-design.md +373 -0
- package/dist/integrations/claude_code/commands/dr-info.md +132 -0
- package/dist/integrations/claude_code/commands/dr-init.md +251 -0
- package/dist/integrations/claude_code/commands/dr-map.md +936 -0
- package/dist/integrations/claude_code/commands/dr-model.md +493 -0
- package/dist/integrations/claude_code/commands/dr-relate.md +814 -0
- package/dist/integrations/claude_code/commands/dr-sync.md +279 -0
- package/dist/integrations/claude_code/commands/dr-validate.md +654 -0
- package/dist/integrations/claude_code/commands/dr-verify.md +559 -0
- package/dist/integrations/claude_code/docs/END_TO_END_WALKTHROUGH.md +903 -0
- package/dist/integrations/claude_code/docs/QUICK_START.md +271 -0
- package/dist/integrations/claude_code/docs/README.md +347 -0
- package/dist/integrations/claude_code/skills/dr_01_motivation_layer/SKILL.md +550 -0
- package/dist/integrations/claude_code/skills/dr_02_business_layer/SKILL.md +620 -0
- package/dist/integrations/claude_code/skills/dr_03_security_layer/SKILL.md +642 -0
- package/dist/integrations/claude_code/skills/dr_04_application_layer/SKILL.md +911 -0
- package/dist/integrations/claude_code/skills/dr_05_technology_layer/SKILL.md +836 -0
- package/dist/integrations/claude_code/skills/dr_06_api_layer/SKILL.md +933 -0
- package/dist/integrations/claude_code/skills/dr_07_data_model_layer/SKILL.md +210 -0
- package/dist/integrations/claude_code/skills/dr_08_dataset_layer/SKILL.md +319 -0
- package/dist/integrations/claude_code/skills/dr_09_ux_layer/SKILL.md +319 -0
- package/dist/integrations/claude_code/skills/dr_10_navigation_layer/SKILL.md +318 -0
- package/dist/integrations/claude_code/skills/dr_11_apm_layer/SKILL.md +273 -0
- package/dist/integrations/claude_code/skills/dr_12_testing_layer/SKILL.md +273 -0
- package/dist/integrations/claude_code/skills/dr_changeset_reviewer/SKILL.md +187 -0
- package/dist/integrations/claude_code/skills/dr_codebase_memory/SKILL.md +590 -0
- package/dist/integrations/claude_code/skills/dr_engineering_guide/SKILL.md +295 -0
- package/dist/integrations/copilot-manager.js +328 -0
- package/dist/integrations/copilot-manager.js.map +7 -0
- package/dist/integrations/github_copilot/agents/dr-advisor.md +243 -0
- package/dist/integrations/github_copilot/agents/dr-architect.md +1567 -0
- package/dist/integrations/github_copilot/skills/dr_01_motivation_layer/SKILL.md +491 -0
- package/dist/integrations/github_copilot/skills/dr_02_business_layer/SKILL.md +539 -0
- package/dist/integrations/github_copilot/skills/dr_03_security_layer/SKILL.md +667 -0
- package/dist/integrations/github_copilot/skills/dr_04_application_layer/SKILL.md +670 -0
- package/dist/integrations/github_copilot/skills/dr_05_technology_layer/SKILL.md +660 -0
- package/dist/integrations/github_copilot/skills/dr_06_api_layer/SKILL.md +855 -0
- package/dist/integrations/github_copilot/skills/dr_07_data_model_layer/SKILL.md +171 -0
- package/dist/integrations/github_copilot/skills/dr_08_dataset_layer/SKILL.md +216 -0
- package/dist/integrations/github_copilot/skills/dr_09_ux_layer/SKILL.md +230 -0
- package/dist/integrations/github_copilot/skills/dr_10_navigation_layer/SKILL.md +228 -0
- package/dist/integrations/github_copilot/skills/dr_11_apm_layer/SKILL.md +234 -0
- package/dist/integrations/github_copilot/skills/dr_12_testing_layer/SKILL.md +230 -0
- package/dist/integrations/github_copilot/skills/dr_changeset_reviewer/SKILL.md +187 -0
- package/dist/integrations/hash-utils.js +51 -0
- package/dist/integrations/hash-utils.js.map +7 -0
- package/dist/integrations/types.js +16 -0
- package/dist/integrations/types.js.map +7 -0
- package/dist/reports/model-layer-report-generator.js +278 -0
- package/dist/reports/model-layer-report-generator.js.map +7 -0
- package/dist/reports/model-report-data.js +57 -0
- package/dist/reports/model-report-data.js.map +7 -0
- package/dist/reports/model-report-orchestrator.js +103 -0
- package/dist/reports/model-report-orchestrator.js.map +7 -0
- package/dist/schemas/bundled/analyzers/cbm.json +595 -0
- package/dist/schemas/bundled/analyzers/manifest.json +9 -0
- package/dist/schemas/bundled/api.json +3411 -0
- package/dist/schemas/bundled/apm.json +2371 -0
- package/dist/schemas/bundled/application.json +1253 -0
- package/dist/schemas/bundled/base.json +1622 -0
- package/dist/schemas/bundled/business.json +1279 -0
- package/dist/schemas/bundled/data-model.json +1298 -0
- package/dist/schemas/bundled/data-store.json +2025 -0
- package/dist/schemas/bundled/manifest.json +93 -0
- package/dist/schemas/bundled/motivation.json +1360 -0
- package/dist/schemas/bundled/navigation.json +1874 -0
- package/dist/schemas/bundled/security.json +3488 -0
- package/dist/schemas/bundled/technology.json +2067 -0
- package/dist/schemas/bundled/testing.json +3120 -0
- package/dist/schemas/bundled/ux.json +3592 -0
- package/dist/server/schemas.js +202 -0
- package/dist/server/schemas.js.map +7 -0
- package/dist/server/server.js +1336 -252
- package/dist/server/server.js.map +3 -3
- package/dist/server/telemetry-middleware.js +22 -15
- package/dist/server/telemetry-middleware.js.map +2 -2
- package/dist/server-entry.js +65 -0
- package/dist/server-entry.js.map +7 -0
- package/dist/telemetry/config.js +89 -0
- package/dist/telemetry/config.js.map +7 -0
- package/dist/telemetry/console-interceptor.js.map +1 -1
- package/dist/telemetry/detect.js +24 -0
- package/dist/telemetry/detect.js.map +7 -0
- package/dist/telemetry/fetch-otlp-exporter.js +112 -0
- package/dist/telemetry/fetch-otlp-exporter.js.map +7 -0
- package/dist/telemetry/index.js +153 -3
- package/dist/telemetry/index.js.map +2 -2
- package/dist/telemetry/resilient-exporter.js +22 -8
- package/dist/telemetry/resilient-exporter.js.map +2 -2
- package/dist/telemetry/resilient-log-exporter.js +17 -8
- package/dist/telemetry/resilient-log-exporter.js.map +2 -2
- package/dist/telemetry/test-instrumentation.js.map +2 -2
- package/dist/types/index.js +84 -0
- package/dist/types/index.js.map +3 -3
- package/dist/types/source-reference.js +1 -0
- package/dist/types/source-reference.js.map +7 -0
- package/dist/utils/chat-logger.js +292 -0
- package/dist/utils/chat-logger.js.map +7 -0
- package/dist/utils/claude-stream.js +8 -0
- package/dist/utils/claude-stream.js.map +7 -0
- package/dist/utils/date-utils.js +7 -0
- package/dist/utils/date-utils.js.map +7 -0
- package/dist/utils/element-utils.js.map +1 -1
- package/dist/utils/errors.js +88 -15
- package/dist/utils/errors.js.map +3 -3
- package/dist/utils/export-python-annotations.js +82 -0
- package/dist/utils/export-python-annotations.js.map +7 -0
- package/dist/utils/file-io.js +7 -2
- package/dist/utils/file-io.js.map +2 -2
- package/dist/utils/file-lock.js +156 -0
- package/dist/utils/file-lock.js.map +7 -0
- package/dist/utils/id-generator.js +18 -0
- package/dist/utils/id-generator.js.map +7 -0
- package/dist/utils/layer-name-formatter.js +16 -0
- package/dist/utils/layer-name-formatter.js.map +7 -0
- package/dist/utils/markdown-anchor.js +7 -0
- package/dist/utils/markdown-anchor.js.map +7 -0
- package/dist/utils/markdown-link.js +12 -0
- package/dist/utils/markdown-link.js.map +7 -0
- package/dist/utils/markdown-table.js +17 -0
- package/dist/utils/markdown-table.js.map +7 -0
- package/dist/utils/mermaid-utils.js +11 -0
- package/dist/utils/mermaid-utils.js.map +7 -0
- package/dist/utils/project-paths.js.map +2 -2
- package/dist/utils/source-reference.js +52 -0
- package/dist/utils/source-reference.js.map +7 -0
- package/dist/utils/spec-installer.js +40 -53
- package/dist/utils/spec-installer.js.map +2 -2
- package/dist/utils/spec-version.js +5 -1
- package/dist/utils/spec-version.js.map +2 -2
- package/dist/utils/string-utils.js +12 -0
- package/dist/utils/string-utils.js.map +7 -0
- package/dist/utils/table-formatting.js +19 -0
- package/dist/utils/table-formatting.js.map +7 -0
- package/dist/validators/index.js +4 -0
- package/dist/validators/index.js.map +2 -2
- package/dist/validators/naming-validator.js +20 -23
- package/dist/validators/naming-validator.js.map +2 -2
- package/dist/validators/reference-validator.js +23 -38
- package/dist/validators/reference-validator.js.map +2 -2
- package/dist/validators/relationship-schema-validator.js +243 -0
- package/dist/validators/relationship-schema-validator.js.map +7 -0
- package/dist/validators/schema-validator.js +168 -68
- package/dist/validators/schema-validator.js.map +2 -2
- package/dist/validators/semantic-validator.js +36 -60
- package/dist/validators/semantic-validator.js.map +2 -2
- package/dist/validators/types.js.map +2 -2
- package/dist/validators/validation-formatter.js +159 -0
- package/dist/validators/validation-formatter.js.map +7 -0
- package/dist/validators/validator.js +24 -38
- package/dist/validators/validator.js.map +2 -2
- package/dist/viewer/README.md +139 -0
- package/dist/viewer/assets/main-CY0Xufuj.css +1 -0
- package/dist/viewer/assets/main-DtgErnwF.js +81 -0
- package/dist/viewer/assets/vendor-CxKvDp2x.js +17 -0
- package/dist/viewer/favicon.svg +11 -0
- package/dist/viewer/fonts/inter/Inter-Black.woff2 +0 -0
- package/dist/viewer/fonts/inter/Inter-Bold.woff2 +0 -0
- package/dist/viewer/fonts/inter/Inter-ExtraBold.woff2 +0 -0
- package/dist/viewer/fonts/inter/Inter-Light.woff2 +0 -0
- package/dist/viewer/fonts/inter/Inter-Medium.woff2 +0 -0
- package/dist/viewer/fonts/inter/Inter-Regular.woff2 +0 -0
- package/dist/viewer/fonts/inter/Inter-SemiBold.woff2 +0 -0
- package/dist/viewer/fonts/jetbrains-mono/JetBrainsMono-Medium.woff2 +0 -0
- package/dist/viewer/fonts/jetbrains-mono/JetBrainsMono-Regular.woff2 +0 -0
- package/dist/viewer/fonts/jetbrains-mono/JetBrainsMono-SemiBold.woff2 +0 -0
- package/dist/viewer/index.html +15 -0
- package/dist/viewer/manifest.json +99 -0
- package/dist/viewer/version.json +1 -0
- package/package.json +42 -16
- package/PYTHON_CLI_PARITY.md +0 -265
- package/PYTHON_CLI_STRUCTURE_UPDATE.md +0 -246
- package/biome.json +0 -42
- package/bunfig.toml +0 -3
- package/dist/ai/claude-client.js +0 -71
- package/dist/ai/claude-client.js.map +0 -7
- package/dist/ai/context-provider.js +0 -129
- package/dist/ai/context-provider.js.map +0 -7
- package/dist/ai/tools.js +0 -231
- package/dist/ai/tools.js.map +0 -7
- package/dist/commands/migrate.js +0 -36
- package/dist/commands/migrate.js.map +0 -7
- package/dist/commands/project.js +0 -74
- package/dist/commands/project.js.map +0 -7
- package/dist/core/active-changeset.js +0 -52
- package/dist/core/active-changeset.js.map +0 -7
- package/dist/core/projection-engine.js +0 -288
- package/dist/core/projection-engine.js.map +0 -7
- package/dist/schemas/bundled/01-motivation-layer.schema.json +0 -942
- package/dist/schemas/bundled/02-business-layer.schema.json +0 -1293
- package/dist/schemas/bundled/03-security-layer.schema.json +0 -2177
- package/dist/schemas/bundled/04-application-layer.schema.json +0 -1328
- package/dist/schemas/bundled/05-technology-layer.schema.json +0 -1465
- package/dist/schemas/bundled/06-api-layer.schema.json +0 -1743
- package/dist/schemas/bundled/07-data-model-layer.schema.json +0 -1253
- package/dist/schemas/bundled/08-datastore-layer.schema.json +0 -892
- package/dist/schemas/bundled/09-ux-layer.schema.json +0 -1506
- package/dist/schemas/bundled/10-navigation-layer.schema.json +0 -843
- package/dist/schemas/bundled/11-apm-observability-layer.schema.json +0 -1430
- package/dist/schemas/bundled/12-testing-layer.schema.json +0 -1091
- package/dist/schemas/bundled/common/layer-extensions.schema.json +0 -266
- package/dist/schemas/bundled/common/predicates.schema.json +0 -493
- package/dist/schemas/bundled/common/relationships.schema.json +0 -791
- package/dist/schemas/bundled/common/source-references.schema.json +0 -71
- package/dist/schemas/bundled/link-registry.json +0 -1839
- package/dist/schemas/bundled/link-registry.schema.json +0 -339
- package/dist/schemas/bundled/relationship-catalog.json +0 -1302
- package/dist/schemas/bundled/relationship-type.schema.json +0 -221
- package/dist/utils/model-path.js +0 -22
- package/dist/utils/model-path.js.map +0 -7
- package/docs/TEST-INSTRUMENTATION.md +0 -405
- package/docs/telemetry.md +0 -427
- package/test-debug.js +0 -33
- package/test-special.mjs +0 -46
- package/test_runner.ts +0 -7
|
@@ -1,58 +1,240 @@
|
|
|
1
1
|
import ansis from "ansis";
|
|
2
2
|
import { Model } from "../core/model.js";
|
|
3
|
+
import { StagingAreaManager } from "../core/staging-area.js";
|
|
3
4
|
import { findElementLayer } from "../utils/element-utils.js";
|
|
5
|
+
import { isValidLayerName } from "../core/layers.js";
|
|
6
|
+
import { CLIError, ErrorCategory, handleError, getErrorMessage } from "../utils/errors.js";
|
|
7
|
+
import { getValidRelationships, getValidPredicatesForSource, getValidDestinationsForSourceAndPredicate } from "../generated/relationship-index.js";
|
|
8
|
+
import { normalizeNodeType } from "../generated/node-types.js";
|
|
9
|
+
import { ModelReportOrchestrator } from "../reports/model-report-orchestrator.js";
|
|
10
|
+
import { emitLog, SeverityNumber } from "../telemetry/index.js";
|
|
11
|
+
import { RelationshipCatalog } from "../core/relationship-catalog.js";
|
|
12
|
+
function constructSpecNodeId(element, elementId) {
|
|
13
|
+
const layerId = element.layer_id, type = element.type;
|
|
14
|
+
if (typeof layerId != "string" || !layerId)
|
|
15
|
+
throw new CLIError(`Invalid element ${elementId}: missing or invalid layer_id`, ErrorCategory.SYSTEM);
|
|
16
|
+
if (typeof type != "string" || !type)
|
|
17
|
+
throw new CLIError(`Invalid element ${elementId}: missing or invalid type`, ErrorCategory.SYSTEM);
|
|
18
|
+
const normalizedType = normalizeNodeType(layerId, type);
|
|
19
|
+
return `${layerId}.${normalizedType}`;
|
|
20
|
+
}
|
|
21
|
+
function validateRelationshipCombination(sourceSpecNodeId, predicate, destSpecNodeId) {
|
|
22
|
+
if (getValidRelationships(sourceSpecNodeId, predicate, destSpecNodeId).length > 0)
|
|
23
|
+
return { valid: !0 };
|
|
24
|
+
const suggestions = [], validPredicates = getValidPredicatesForSource(sourceSpecNodeId);
|
|
25
|
+
if (validPredicates.length > 0 ? suggestions.push(`Valid predicates for ${sourceSpecNodeId}: ${validPredicates.join(", ")}`) : suggestions.push(`No valid relationships defined for ${sourceSpecNodeId}`), predicate) {
|
|
26
|
+
const validDests = getValidDestinationsForSourceAndPredicate(sourceSpecNodeId, predicate);
|
|
27
|
+
validDests.length > 0 ? suggestions.push(`Valid destinations for --[${predicate}]-->: ${validDests.join(", ")}`) : suggestions.push(`No valid destinations for ${sourceSpecNodeId} --[${predicate}]-->`);
|
|
28
|
+
}
|
|
29
|
+
return { valid: !1, suggestions };
|
|
30
|
+
}
|
|
31
|
+
function getRelationshipConstraints(sourceSpecNodeId, predicate, destSpecNodeId) {
|
|
32
|
+
const rels = getValidRelationships(sourceSpecNodeId, predicate, destSpecNodeId);
|
|
33
|
+
if (rels.length === 0)
|
|
34
|
+
return null;
|
|
35
|
+
const rel = rels[0];
|
|
36
|
+
return {
|
|
37
|
+
cardinality: rel.cardinality,
|
|
38
|
+
strength: rel.strength
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async function addRelationshipHandler(model, source, target, predicate, properties, preResolved) {
|
|
42
|
+
let resolvedSourceLayerName = preResolved?.source?.layerName, resolvedSourceElement = preResolved?.source?.element, resolvedTargetLayerName = preResolved?.target?.layerName, resolvedTargetElement = preResolved?.target?.element;
|
|
43
|
+
if (!resolvedSourceLayerName && (resolvedSourceLayerName = await findElementLayer(model, source), !resolvedSourceLayerName))
|
|
44
|
+
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
45
|
+
if (!resolvedSourceElement) {
|
|
46
|
+
const sourceLayer = await model.getLayer(resolvedSourceLayerName);
|
|
47
|
+
if (!sourceLayer)
|
|
48
|
+
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
49
|
+
if (resolvedSourceElement = sourceLayer.getElement(source), !resolvedSourceElement)
|
|
50
|
+
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
51
|
+
}
|
|
52
|
+
if (!resolvedTargetLayerName && (resolvedTargetLayerName = await findElementLayer(model, target), !resolvedTargetLayerName))
|
|
53
|
+
throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);
|
|
54
|
+
if (!resolvedTargetElement) {
|
|
55
|
+
const targetLayer = await model.getLayer(resolvedTargetLayerName);
|
|
56
|
+
if (!targetLayer)
|
|
57
|
+
throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);
|
|
58
|
+
if (resolvedTargetElement = targetLayer.getElement(target), !resolvedTargetElement)
|
|
59
|
+
throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);
|
|
60
|
+
}
|
|
61
|
+
const sourceSpecNodeId = constructSpecNodeId(resolvedSourceElement, source), targetSpecNodeId = constructSpecNodeId(resolvedTargetElement, target), validation = validateRelationshipCombination(sourceSpecNodeId, predicate, targetSpecNodeId);
|
|
62
|
+
if (!validation.valid)
|
|
63
|
+
throw new CLIError(`Invalid relationship: ${source} --[${predicate}]--> ${target}`, ErrorCategory.USER, validation.suggestions);
|
|
64
|
+
{
|
|
65
|
+
const catalog = new RelationshipCatalog();
|
|
66
|
+
await catalog.load();
|
|
67
|
+
const relType = catalog.getTypeByPredicate(predicate);
|
|
68
|
+
if (relType && !relType.semantics.reflexivity && source === target)
|
|
69
|
+
throw new CLIError(`Invalid relationship: predicate "${predicate}" does not allow reflexive relationships (${source})`, ErrorCategory.USER);
|
|
70
|
+
}
|
|
71
|
+
if (model.relationships.find(source, target, predicate).length > 0)
|
|
72
|
+
return console.warn(ansis.yellow(`Warning: Relationship ${source} --[${predicate}]--> ${target} already exists. Skipping.`)), !1;
|
|
73
|
+
const stagingManager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await stagingManager.getActiveId(), relData = {
|
|
74
|
+
source,
|
|
75
|
+
target,
|
|
76
|
+
predicate,
|
|
77
|
+
layer: resolvedSourceLayerName,
|
|
78
|
+
...resolvedTargetLayerName !== resolvedSourceLayerName ? { targetLayer: resolvedTargetLayerName } : {},
|
|
79
|
+
category: "structural",
|
|
80
|
+
...properties ? { properties } : {}
|
|
81
|
+
};
|
|
82
|
+
if (activeChangesetId) {
|
|
83
|
+
const compositeKey = `${source}::${predicate}::${target}`;
|
|
84
|
+
await stagingManager.stage(activeChangesetId, {
|
|
85
|
+
type: "relationship-add",
|
|
86
|
+
elementId: compositeKey,
|
|
87
|
+
layerName: resolvedSourceLayerName,
|
|
88
|
+
after: relData
|
|
89
|
+
});
|
|
90
|
+
} else {
|
|
91
|
+
model.relationships.add(relData), await model.saveRelationships(), await model.saveManifest();
|
|
92
|
+
try {
|
|
93
|
+
const orchestrator = new ModelReportOrchestrator(model, model.rootPath), affectedLayers = /* @__PURE__ */ new Set();
|
|
94
|
+
if (isValidLayerName(resolvedSourceLayerName))
|
|
95
|
+
for (const layer of orchestrator.computeAffectedLayers(resolvedSourceLayerName))
|
|
96
|
+
affectedLayers.add(layer);
|
|
97
|
+
if (isValidLayerName(resolvedTargetLayerName))
|
|
98
|
+
for (const layer of orchestrator.computeAffectedLayers(resolvedTargetLayerName))
|
|
99
|
+
affectedLayers.add(layer);
|
|
100
|
+
await orchestrator.regenerate(affectedLayers);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
emitLog(SeverityNumber.WARN, "Failed to regenerate layer reports after relationship add", {
|
|
103
|
+
"relationship.predicate": predicate,
|
|
104
|
+
"relationship.sourceLayer": resolvedSourceLayerName,
|
|
105
|
+
"relationship.targetLayer": resolvedTargetLayerName,
|
|
106
|
+
"relationship.source": source,
|
|
107
|
+
"relationship.target": target,
|
|
108
|
+
"error.message": getErrorMessage(error)
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return !0;
|
|
113
|
+
}
|
|
114
|
+
async function deleteRelationshipHandler(model, source, target, predicate, preResolved) {
|
|
115
|
+
let resolvedSourceLayerName = preResolved?.sourceLayerName;
|
|
116
|
+
if (!resolvedSourceLayerName && (resolvedSourceLayerName = await findElementLayer(model, source), !resolvedSourceLayerName))
|
|
117
|
+
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
118
|
+
let resolvedToDelete = preResolved?.toDelete;
|
|
119
|
+
if (resolvedToDelete || (resolvedToDelete = model.relationships.find(source, target, predicate)), resolvedToDelete.length === 0)
|
|
120
|
+
throw new CLIError("No matching relationships found", ErrorCategory.USER);
|
|
121
|
+
const stagingManager = new StagingAreaManager(model.rootPath, model), activeChangesetId = await stagingManager.getActiveId();
|
|
122
|
+
if (activeChangesetId)
|
|
123
|
+
for (const rel of resolvedToDelete) {
|
|
124
|
+
const compositeKey = `${rel.source}::${rel.predicate}::${rel.target}`;
|
|
125
|
+
await stagingManager.stage(activeChangesetId, {
|
|
126
|
+
type: "relationship-delete",
|
|
127
|
+
elementId: compositeKey,
|
|
128
|
+
layerName: rel.layer,
|
|
129
|
+
before: {
|
|
130
|
+
source: rel.source,
|
|
131
|
+
target: rel.target,
|
|
132
|
+
predicate: rel.predicate,
|
|
133
|
+
layer: rel.layer,
|
|
134
|
+
...rel.targetLayer ? { targetLayer: rel.targetLayer } : {},
|
|
135
|
+
...rel.properties ? { properties: rel.properties } : {}
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
model.relationships.delete(source, target, predicate), await model.saveRelationships(), await model.saveManifest();
|
|
141
|
+
try {
|
|
142
|
+
const orchestrator = new ModelReportOrchestrator(model, model.rootPath), affectedLayers = /* @__PURE__ */ new Set();
|
|
143
|
+
for (const rel of resolvedToDelete) {
|
|
144
|
+
if (rel.layer && isValidLayerName(rel.layer))
|
|
145
|
+
for (const layer of orchestrator.computeAffectedLayers(rel.layer))
|
|
146
|
+
affectedLayers.add(layer);
|
|
147
|
+
if (rel.targetLayer && isValidLayerName(rel.targetLayer))
|
|
148
|
+
for (const layer of orchestrator.computeAffectedLayers(rel.targetLayer))
|
|
149
|
+
affectedLayers.add(layer);
|
|
150
|
+
}
|
|
151
|
+
await orchestrator.regenerate(affectedLayers);
|
|
152
|
+
} catch (error) {
|
|
153
|
+
emitLog(SeverityNumber.WARN, "Failed to regenerate layer reports after relationship delete", {
|
|
154
|
+
"relationship.predicate": predicate,
|
|
155
|
+
"relationship.source": source,
|
|
156
|
+
"relationship.target": target,
|
|
157
|
+
"relationship.deleteCount": resolvedToDelete.length,
|
|
158
|
+
"error.message": getErrorMessage(error)
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return { deletedCount: resolvedToDelete.length };
|
|
163
|
+
}
|
|
4
164
|
function relationshipCommands(program) {
|
|
5
|
-
program.command("add <source> <target>").description("Add a relationship between elements").requiredOption("--predicate <predicate>", "Relationship predicate (e.g., depends-on,
|
|
165
|
+
program.command("add <source> <target>").description("Add a relationship between elements (intra-layer or cross-layer)").requiredOption("--predicate <predicate>", "Relationship predicate (e.g., depends-on, realizes, exposes)").option("--properties <json>", "Relationship properties (JSON)").addHelpText("after", `
|
|
6
166
|
Examples:
|
|
7
|
-
$ dr relationship add
|
|
8
|
-
$ dr relationship add api-
|
|
9
|
-
$ dr relationship add
|
|
167
|
+
$ dr relationship add motivation.goal.goal-a motivation.goal.goal-b --predicate aggregates
|
|
168
|
+
$ dr relationship add api.operation.create-order application.service.order-service --predicate exposes
|
|
169
|
+
$ dr relationship add business.businessprocess.checkout application.applicationprocess.checkout --predicate aggregates
|
|
170
|
+
$ dr relationship add element-1 element-2 --predicate realizes --properties '{"strength":"high"}'`).action(async (source, target, options) => {
|
|
10
171
|
try {
|
|
11
172
|
const model = await Model.load(), sourceLayerName = await findElementLayer(model, source);
|
|
12
|
-
|
|
173
|
+
if (!sourceLayerName)
|
|
174
|
+
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
175
|
+
const sourceLayer = await model.getLayer(sourceLayerName);
|
|
176
|
+
if (!sourceLayer)
|
|
177
|
+
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
178
|
+
const sourceElement = sourceLayer.getElement(source);
|
|
179
|
+
if (!sourceElement)
|
|
180
|
+
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
13
181
|
const targetLayerName = await findElementLayer(model, target);
|
|
14
|
-
|
|
182
|
+
if (!targetLayerName)
|
|
183
|
+
throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);
|
|
184
|
+
const targetLayer = await model.getLayer(targetLayerName);
|
|
185
|
+
if (!targetLayer)
|
|
186
|
+
throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);
|
|
187
|
+
const targetElement = targetLayer.getElement(target);
|
|
188
|
+
if (!targetElement)
|
|
189
|
+
throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);
|
|
190
|
+
const sourceSpecNodeId = constructSpecNodeId(sourceElement, source), targetSpecNodeId = constructSpecNodeId(targetElement, target), constraints = getRelationshipConstraints(sourceSpecNodeId, options.predicate, targetSpecNodeId);
|
|
15
191
|
let properties;
|
|
16
192
|
if (options.properties)
|
|
17
193
|
try {
|
|
18
194
|
properties = JSON.parse(options.properties);
|
|
19
195
|
} catch {
|
|
20
|
-
|
|
196
|
+
throw new CLIError("Invalid JSON in --properties", ErrorCategory.USER);
|
|
21
197
|
}
|
|
22
|
-
model.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}), await model.saveRelationships(), await model.saveManifest(), console.log(ansis.green(`\u2713 Added relationship: ${ansis.bold(source)} ${options.predicate} ${ansis.bold(target)}`));
|
|
198
|
+
const activeChangesetId = await new StagingAreaManager(model.rootPath, model).getActiveId();
|
|
199
|
+
if (!await addRelationshipHandler(model, source, target, options.predicate, properties, {
|
|
200
|
+
source: { element: sourceElement, layerName: sourceLayerName },
|
|
201
|
+
target: { element: targetElement, layerName: targetLayerName }
|
|
202
|
+
}))
|
|
203
|
+
return;
|
|
204
|
+
let message = `\u2713 Added relationship: ${ansis.bold(source)} ${options.predicate} ${ansis.bold(target)}`;
|
|
205
|
+
constraints && (message += ansis.dim(` (${constraints.cardinality}, ${constraints.strength} strength)`)), activeChangesetId && (message += ansis.dim(" [staged]")), console.log(ansis.green(message));
|
|
31
206
|
} catch (error) {
|
|
32
|
-
|
|
33
|
-
console.error(ansis.red(`Error: ${message}`)), process.exit(1);
|
|
207
|
+
handleError(error);
|
|
34
208
|
}
|
|
35
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", `
|
|
36
210
|
Examples:
|
|
37
211
|
$ dr relationship delete element-1 element-2 --predicate depends-on
|
|
38
212
|
$ dr relationship delete element-1 element-2 --force`).action(async (source, target, options) => {
|
|
39
213
|
try {
|
|
40
|
-
const model = await Model.load();
|
|
41
|
-
|
|
214
|
+
const model = await Model.load(), sourceLayerName = await findElementLayer(model, source);
|
|
215
|
+
if (!sourceLayerName)
|
|
216
|
+
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
42
217
|
const toDelete = model.relationships.find(source, target, options.predicate);
|
|
43
|
-
toDelete.length === 0
|
|
218
|
+
if (toDelete.length === 0)
|
|
219
|
+
throw new CLIError("No matching relationships found", ErrorCategory.USER);
|
|
44
220
|
const isInteractive = process.stdin.isTTY && process.stdout.isTTY;
|
|
45
221
|
if (!options.force && isInteractive) {
|
|
46
222
|
const { confirm } = await import("@clack/prompts");
|
|
47
|
-
await confirm({
|
|
223
|
+
if (!await confirm({
|
|
48
224
|
message: `Delete ${toDelete.length} relationship(s)? This cannot be undone.`,
|
|
49
225
|
initialValue: !1
|
|
50
|
-
})
|
|
226
|
+
})) {
|
|
227
|
+
console.log(ansis.dim("Cancelled"));
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
51
230
|
}
|
|
52
|
-
|
|
231
|
+
const activeChangesetId = await new StagingAreaManager(model.rootPath, model).getActiveId(), result = await deleteRelationshipHandler(model, source, target, options.predicate, {
|
|
232
|
+
sourceLayerName,
|
|
233
|
+
toDelete
|
|
234
|
+
}), stagedSuffix = activeChangesetId ? " [staged]" : "";
|
|
235
|
+
console.log(ansis.green(`\u2713 Deleted ${result.deletedCount} relationship(s) from ${ansis.bold(source)} to ${ansis.bold(target)}${stagedSuffix}`));
|
|
53
236
|
} catch (error) {
|
|
54
|
-
|
|
55
|
-
console.error(ansis.red(`Error: ${message}`)), process.exit(1);
|
|
237
|
+
handleError(error);
|
|
56
238
|
}
|
|
57
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", `
|
|
58
240
|
Examples:
|
|
@@ -61,7 +243,8 @@ Examples:
|
|
|
61
243
|
$ dr relationship list element-1 --json`).action(async (id, options) => {
|
|
62
244
|
try {
|
|
63
245
|
const model = await Model.load();
|
|
64
|
-
await findElementLayer(model, id)
|
|
246
|
+
if (!await findElementLayer(model, id))
|
|
247
|
+
throw new CLIError(`Element ${id} not found`, ErrorCategory.USER);
|
|
65
248
|
const { outgoing, incoming } = model.relationships.getForElement(id);
|
|
66
249
|
let relationships = [];
|
|
67
250
|
if ((options.direction === "outgoing" || options.direction === "all") && relationships.push(...outgoing), (options.direction === "incoming" || options.direction === "all") && relationships.push(...incoming), options.json) {
|
|
@@ -74,16 +257,15 @@ Examples:
|
|
|
74
257
|
}
|
|
75
258
|
console.log(""), console.log(ansis.bold(`${options.direction === "all" ? "" : options.direction + " "}relationships for ${ansis.cyan(id)}:`)), console.log(ansis.dim("\u2500".repeat(80)));
|
|
76
259
|
for (const rel of relationships) {
|
|
77
|
-
const isOutgoing = rel.source === id, direction = isOutgoing ? "\u2192" : "\u2190", otherElement = isOutgoing ? rel.target : rel.source;
|
|
78
|
-
if (console.log(` ${direction} ${ansis.magenta(rel.predicate)}: ${ansis.yellow(otherElement)}`), rel.properties) {
|
|
260
|
+
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 (console.log(` ${direction} ${ansis.magenta(rel.predicate)}: ${ansis.yellow(otherElement)}${crossLayer}`), rel.properties) {
|
|
79
262
|
const propStr = Object.entries(rel.properties).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
80
263
|
console.log(` ${ansis.dim(propStr)}`);
|
|
81
264
|
}
|
|
82
265
|
}
|
|
83
266
|
console.log(ansis.dim("\u2500".repeat(80))), console.log(ansis.dim(`Total: ${relationships.length} relationship(s)`)), console.log("");
|
|
84
267
|
} catch (error) {
|
|
85
|
-
|
|
86
|
-
console.error(ansis.red(`Error: ${message}`)), process.exit(1);
|
|
268
|
+
handleError(error);
|
|
87
269
|
}
|
|
88
270
|
}), program.command("show <source> <target>").description("Show relationship details").addHelpText("after", `
|
|
89
271
|
Examples:
|
|
@@ -91,12 +273,15 @@ Examples:
|
|
|
91
273
|
$ dr relationship show application-component-api motivation-goal-sales-efficiency`).action(async (source, target) => {
|
|
92
274
|
try {
|
|
93
275
|
const model = await Model.load();
|
|
94
|
-
await findElementLayer(model, source)
|
|
276
|
+
if (!await findElementLayer(model, source))
|
|
277
|
+
throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);
|
|
95
278
|
const relationships = model.relationships.find(source, target);
|
|
96
|
-
relationships.length === 0
|
|
279
|
+
if (relationships.length === 0)
|
|
280
|
+
throw new CLIError(`No relationships from ${source} to ${target}`, ErrorCategory.USER);
|
|
281
|
+
console.log(""), console.log(ansis.bold(`Relationship${relationships.length > 1 ? "s" : ""} from ${ansis.cyan(source)} to ${ansis.yellow(target)}:`)), console.log(ansis.dim("\u2500".repeat(60)));
|
|
97
282
|
for (let i = 0; i < relationships.length; i++) {
|
|
98
283
|
const rel = relationships[i];
|
|
99
|
-
if (i > 0 && console.log(""), console.log(`Predicate: ${ansis.magenta(rel.predicate)}`), rel.properties && Object.keys(rel.properties).length > 0) {
|
|
284
|
+
if (i > 0 && console.log(""), console.log(`Predicate: ${ansis.magenta(rel.predicate)}`), console.log(`Layer: ${ansis.cyan(rel.layer)}`), rel.targetLayer && rel.targetLayer !== rel.layer && console.log(`Target Layer: ${ansis.cyan(rel.targetLayer)}`), rel.properties && Object.keys(rel.properties).length > 0) {
|
|
100
285
|
console.log("Properties:");
|
|
101
286
|
for (const [key, value] of Object.entries(rel.properties)) {
|
|
102
287
|
const displayValue = typeof value == "string" ? value : JSON.stringify(value, null, 2);
|
|
@@ -107,12 +292,15 @@ Examples:
|
|
|
107
292
|
}
|
|
108
293
|
console.log("");
|
|
109
294
|
} catch (error) {
|
|
110
|
-
|
|
111
|
-
console.error(ansis.red(`Error: ${message}`)), process.exit(1);
|
|
295
|
+
handleError(error);
|
|
112
296
|
}
|
|
113
297
|
});
|
|
114
298
|
}
|
|
115
299
|
export {
|
|
116
|
-
|
|
300
|
+
addRelationshipHandler,
|
|
301
|
+
deleteRelationshipHandler,
|
|
302
|
+
getRelationshipConstraints,
|
|
303
|
+
relationshipCommands,
|
|
304
|
+
validateRelationshipCombination
|
|
117
305
|
};
|
|
118
306
|
//# sourceMappingURL=relationship.js.map
|
|
@@ -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 relationships\n */\n\nimport { Command } from 'commander';\nimport ansis from 'ansis';\nimport { Model } from '../core/model.js';\nimport { findElementLayer } from '../utils/element-utils.js';\n\nexport function relationshipCommands(program: Command): void {\n program\n .command('add <source> <target>')\n .description('Add a relationship between elements')\n .requiredOption('--predicate <predicate>', 'Relationship predicate (e.g., depends-on, implements)')\n .option('--properties <json>', 'Relationship properties (JSON)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ dr relationship add business-service-a business-service-b --predicate depends-on\n $ dr relationship add api-endpoint-1 api-endpoint-2 --predicate \"service-of\"\n $ dr relationship add element-1 element-2 --predicate implements --properties '{\"method\":\"REST\"}'`\n )\n .action(async (source, target, options) => {\n try {\n // Load model\n const model = await Model.load();\n\n // Find source element\n const sourceLayerName = await findElementLayer(model, source);\n if (!sourceLayerName) {\n console.error(ansis.red(`Error: Source element ${source} not found`));\n process.exit(1);\n }\n\n // Find target element\n const targetLayerName = await findElementLayer(model, target);\n if (!targetLayerName) {\n console.error(ansis.red(`Error: Target element ${target} not found`));\n process.exit(1);\n }\n\n // Relationships are intra-layer only\n if (sourceLayerName !== targetLayerName) {\n console.error(\n ansis.red(\n 'Error: cannot add cross-layer relationship. Relationships must be within the same layer.'\n )\n );\n process.exit(1);\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 console.error(ansis.red('Error: Invalid JSON in --properties'));\n process.exit(1);\n }\n }\n\n // Add relationship to centralized relationships.yaml\n model.relationships.add({\n source,\n target,\n predicate: options.predicate,\n layer: sourceLayerName,\n category: 'structural', // Default category\n properties,\n });\n\n // Save relationships\n await model.saveRelationships();\n await model.saveManifest();\n\n console.log(\n ansis.green(\n `\u2713 Added relationship: ${ansis.bold(source)} ${options.predicate} ${ansis.bold(target)}`\n )\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(ansis.red(`Error: ${message}`));\n process.exit(1);\n }\n });\n\n program\n .command('delete <source> <target>')\n .description('Delete a relationship')\n .option('--predicate <predicate>', 'Specific predicate to delete (optional, delete all if not specified)')\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();\n\n // Find source element\n const sourceLayerName = await findElementLayer(model, source);\n if (!sourceLayerName) {\n console.error(ansis.red(`Error: Source element ${source} not found`));\n process.exit(1);\n }\n\n // Find relationships to delete\n const toDelete = model.relationships.find(source, target, options.predicate);\n\n if (toDelete.length === 0) {\n console.error(ansis.red('Error: No matching relationships found'));\n process.exit(1);\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 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 console.log(ansis.dim('Cancelled'));\n process.exit(0);\n }\n }\n\n // Delete relationships\n model.relationships.delete(source, target, options.predicate);\n\n // Save\n await model.saveRelationships();\n await model.saveManifest();\n\n console.log(\n ansis.green(\n `\u2713 Deleted ${toDelete.length} relationship(s) from ${ansis.bold(source)} to ${ansis.bold(target)}`\n )\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(ansis.red(`Error: ${message}`));\n process.exit(1);\n }\n });\n\n program\n .command('list <id>')\n .description('List relationships for an element')\n .option('--direction <dir>', 'Filter by direction (incoming/outgoing/all)', 'all')\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();\n const layerName = await findElementLayer(model, id);\n\n if (!layerName) {\n console.error(ansis.red(`Error: Element ${id} not found`));\n process.exit(1);\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 if (options.json) {\n console.log(JSON.stringify(relationships, null, 2));\n return;\n }\n\n if (relationships.length === 0) {\n console.log(ansis.yellow(`No ${options.direction} relationships for ${id}`));\n return;\n }\n\n console.log('');\n console.log(\n ansis.bold(\n `${options.direction === 'all' ? '' : options.direction + ' '}relationships for ${ansis.cyan(id)}:`\n )\n );\n console.log(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\n console.log(\n ` ${direction} ${ansis.magenta(rel.predicate)}: ${ansis.yellow(otherElement)}`\n );\n\n if (rel.properties) {\n const propStr = Object.entries(rel.properties)\n .map(([k, v]) => `${k}=${v}`)\n .join(', ');\n console.log(` ${ansis.dim(propStr)}`);\n }\n }\n\n console.log(ansis.dim('\u2500'.repeat(80)));\n console.log(ansis.dim(`Total: ${relationships.length} relationship(s)`));\n console.log('');\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(ansis.red(`Error: ${message}`));\n process.exit(1);\n }\n });\n\n program\n .command('show <source> <target>')\n .description('Show relationship details')\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) => {\n try {\n // Load model\n const model = await Model.load();\n const sourceLayerName = await findElementLayer(model, source);\n\n if (!sourceLayerName) {\n console.error(ansis.red(`Error: Source element ${source} not found`));\n process.exit(1);\n }\n\n // Find relationships from centralized store\n const relationships = model.relationships.find(source, target);\n\n if (relationships.length === 0) {\n console.error(\n ansis.red(`Error: No relationships from ${source} to ${target}`)\n );\n process.exit(1);\n }\n\n console.log('');\n console.log(\n ansis.bold(\n `Relationship${relationships.length > 1 ? 's' : ''} from ${ansis.cyan(source)} to ${ansis.yellow(target)}:`\n )\n );\n console.log(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 console.log('');\n }\n\n console.log(`Predicate: ${ansis.magenta(rel.predicate)}`);\n\n if (rel.properties && Object.keys(rel.properties).length > 0) {\n console.log('Properties:');\n for (const [key, value] of Object.entries(rel.properties)) {\n const displayValue =\n typeof value === 'string' ? value : JSON.stringify(value, null, 2);\n console.log(` ${ansis.cyan(key)}: ${displayValue}`);\n }\n } else {\n console.log('Properties: none');\n }\n }\n\n console.log('');\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(ansis.red(`Error: ${message}`));\n process.exit(1);\n }\n });\n}\n"],
|
|
5
|
-
"mappings": "AAKA,OAAO,WAAW;AAClB,SAAS,aAAa;AACtB,SAAS,wBAAwB;
|
|
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 { CLIError, ErrorCategory, handleError, getErrorMessage } 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)\n .length > 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(`Source element ${source} not found`, ErrorCategory.USER);\n }\n }\n\n if (!resolvedSourceElement) {\n const sourceLayer = await model.getLayer(resolvedSourceLayerName);\n if (!sourceLayer) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n resolvedSourceElement = sourceLayer.getElement(source);\n if (!resolvedSourceElement) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n }\n\n if (!resolvedTargetLayerName) {\n resolvedTargetLayerName = await findElementLayer(model, target);\n if (!resolvedTargetLayerName) {\n throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);\n }\n }\n\n if (!resolvedTargetElement) {\n const targetLayer = await model.getLayer(resolvedTargetLayerName);\n if (!targetLayer) {\n throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);\n }\n resolvedTargetElement = targetLayer.getElement(target);\n if (!resolvedTargetElement) {\n throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);\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 console.warn(\n ansis.yellow(`Warning: Relationship ${source} --[${predicate}]--> ${target} already exists. Skipping.`)\n );\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 ? { targetLayer: resolvedTargetLayerName } : {}),\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(resolvedSourceLayerName)) {\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(resolvedTargetLayerName)) {\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(`Source element ${source} not found`, ErrorCategory.USER);\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(rel.targetLayer)) {\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): void {\n program\n .command(\"add <source> <target>\")\n .description(\"Add a relationship between elements (intra-layer or cross-layer)\")\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();\n\n // Find source element for constraints info\n const sourceLayerName = await findElementLayer(model, source);\n if (!sourceLayerName) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n const sourceLayer = await model.getLayer(sourceLayerName);\n if (!sourceLayer) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n const sourceElement = sourceLayer.getElement(source);\n if (!sourceElement) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\n }\n\n // Find target element for constraints info\n const targetLayerName = await findElementLayer(model, target);\n if (!targetLayerName) {\n throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);\n }\n const targetLayer = await model.getLayer(targetLayerName);\n if (!targetLayer) {\n throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);\n }\n const targetElement = targetLayer.getElement(target);\n if (!targetElement) {\n throw new CLIError(`Target element ${target} not found`, ErrorCategory.USER);\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(\"Invalid JSON in --properties\", ErrorCategory.USER);\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) return; // duplicate \u2014 warning already printed\n\n // Show cardinality and strength in output\n let message = `\u2713 Added relationship: ${ansis.bold(source)} ${options.predicate} ${ansis.bold(target)}`;\n if (constraints) {\n message += ansis.dim(\n ` (${constraints.cardinality}, ${constraints.strength} strength)`\n );\n }\n if (activeChangesetId) {\n message += ansis.dim(` [staged]`);\n }\n\n console.log(ansis.green(message));\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"delete <source> <target>\")\n .description(\"Delete a relationship\")\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();\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(`Source element ${source} not found`, ErrorCategory.USER);\n }\n\n // Find relationships to delete (to show confirmation count)\n const toDelete = model.relationships.find(source, target, options.predicate);\n\n if (toDelete.length === 0) {\n throw new CLIError(\"No matching relationships found\", ErrorCategory.USER);\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 console.log(ansis.dim(\"Cancelled\"));\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 console.log(\n ansis.green(\n `\u2713 Deleted ${result.deletedCount} relationship(s) from ${ansis.bold(source)} to ${ansis.bold(target)}${stagedSuffix}`\n )\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(\"--direction <dir>\", \"Filter by direction (incoming/outgoing/all)\", \"all\")\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();\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 if (options.json) {\n console.log(JSON.stringify(relationships, null, 2));\n return;\n }\n\n if (relationships.length === 0) {\n console.log(ansis.yellow(`No ${options.direction} relationships for ${id}`));\n return;\n }\n\n console.log(\"\");\n console.log(\n ansis.bold(\n `${options.direction === \"all\" ? \"\" : options.direction + \" \"}relationships for ${ansis.cyan(id)}:`\n )\n );\n console.log(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 = rel.targetLayer && rel.targetLayer !== rel.layer\n ? ansis.dim(` [${rel.layer} \u2192 ${rel.targetLayer}]`)\n : \"\";\n\n console.log(\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 console.log(` ${ansis.dim(propStr)}`);\n }\n }\n\n console.log(ansis.dim(\"\u2500\".repeat(80)));\n console.log(ansis.dim(`Total: ${relationships.length} relationship(s)`));\n console.log(\"\");\n } catch (error) {\n handleError(error);\n }\n });\n\n program\n .command(\"show <source> <target>\")\n .description(\"Show relationship details\")\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) => {\n try {\n // Load model\n const model = await Model.load();\n const sourceLayerName = await findElementLayer(model, source);\n\n if (!sourceLayerName) {\n throw new CLIError(`Source element ${source} not found`, ErrorCategory.USER);\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(`No relationships from ${source} to ${target}`, ErrorCategory.USER);\n }\n\n console.log(\"\");\n console.log(\n ansis.bold(\n `Relationship${relationships.length > 1 ? \"s\" : \"\"} from ${ansis.cyan(source)} to ${ansis.yellow(target)}:`\n )\n );\n console.log(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 console.log(\"\");\n }\n\n console.log(`Predicate: ${ansis.magenta(rel.predicate)}`);\n console.log(`Layer: ${ansis.cyan(rel.layer)}`);\n if (rel.targetLayer && rel.targetLayer !== rel.layer) {\n console.log(`Target Layer: ${ansis.cyan(rel.targetLayer)}`);\n }\n\n if (rel.properties && Object.keys(rel.properties).length > 0) {\n console.log(\"Properties:\");\n for (const [key, value] of Object.entries(rel.properties)) {\n const displayValue =\n typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n console.log(` ${ansis.cyan(key)}: ${displayValue}`);\n }\n } else {\n console.log(\"Properties: none\");\n }\n }\n\n console.log(\"\");\n } catch (error) {\n handleError(error);\n }\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import ansis from "ansis";
|
|
2
|
+
import { writeFile, ensureDir } from "../utils/file-io.js";
|
|
3
|
+
import { Model } from "../core/model.js";
|
|
4
|
+
import { ReportDataModel } from "../core/report-data-model.js";
|
|
5
|
+
import { formatReport } from "../export/report-formatters.js";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { getErrorMessage } from "../utils/errors.js";
|
|
8
|
+
async function reportCommand(options) {
|
|
9
|
+
try {
|
|
10
|
+
const model = await Model.load(options.model), report = await new ReportDataModel(model).collect();
|
|
11
|
+
let format = options.format || "text";
|
|
12
|
+
if (options.output) {
|
|
13
|
+
const ext = path.extname(options.output).toLowerCase();
|
|
14
|
+
ext === ".json" ? format = "json" : ext === ".md" && (format = "markdown");
|
|
15
|
+
}
|
|
16
|
+
let includeDataModel = options.includeDataModel !== !1, includeQuality = options.includeQuality !== !1;
|
|
17
|
+
switch (options.type) {
|
|
18
|
+
case "statistics":
|
|
19
|
+
includeDataModel = !1, includeQuality = !0;
|
|
20
|
+
break;
|
|
21
|
+
case "relationships":
|
|
22
|
+
includeDataModel = !1, includeQuality = !1;
|
|
23
|
+
break;
|
|
24
|
+
case "data-model":
|
|
25
|
+
includeDataModel = !0, includeQuality = !1;
|
|
26
|
+
break;
|
|
27
|
+
case "quality":
|
|
28
|
+
includeDataModel = !1, includeQuality = !0;
|
|
29
|
+
break;
|
|
30
|
+
case "comprehensive":
|
|
31
|
+
default:
|
|
32
|
+
includeDataModel = !0, includeQuality = !0;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
const output = formatReport(report, {
|
|
36
|
+
format,
|
|
37
|
+
verbose: options.verbose,
|
|
38
|
+
includeDataModel,
|
|
39
|
+
includeQuality
|
|
40
|
+
});
|
|
41
|
+
if (options.output) {
|
|
42
|
+
const outputPath = path.resolve(process.cwd(), options.output), outputDir = path.dirname(outputPath);
|
|
43
|
+
await ensureDir(outputDir), await writeFile(outputPath, output), console.log(ansis.green(`\u2713 Report written to ${options.output}`));
|
|
44
|
+
} else
|
|
45
|
+
console.log(output);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
const message = getErrorMessage(error);
|
|
48
|
+
console.error(ansis.red(`Error: ${message}`)), process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
reportCommand
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/commands/report.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Generate comprehensive architecture reports\n */\n\nimport ansis from \"ansis\";\nimport { writeFile, ensureDir } from \"../utils/file-io.js\";\nimport { Model } from \"../core/model.js\";\nimport { ReportDataModel } from \"../core/report-data-model.js\";\nimport { formatReport, ReportFormat } from \"../export/report-formatters.js\";\nimport path from \"path\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\nexport interface ReportOptions {\n type?: \"comprehensive\" | \"statistics\" | \"relationships\" | \"data-model\" | \"quality\";\n format?: ReportFormat;\n output?: string;\n verbose?: boolean;\n model?: string;\n debug?: boolean;\n includeDataModel?: boolean;\n includeQuality?: boolean;\n}\n\n/**\n * Run the report command\n */\nexport async function reportCommand(options: ReportOptions): Promise<void> {\n try {\n // Load model\n const model = await Model.load(options.model);\n\n // Create report data model\n const reportModel = new ReportDataModel(model);\n const report = await reportModel.collect();\n\n // Determine output format\n let format: ReportFormat = options.format || \"text\";\n\n // Auto-detect format from output file extension\n if (options.output) {\n const ext = path.extname(options.output).toLowerCase();\n if (ext === \".json\") {\n format = \"json\";\n } else if (ext === \".md\") {\n format = \"markdown\";\n }\n }\n\n // Determine what to include based on report type\n let includeDataModel = options.includeDataModel !== false;\n let includeQuality = options.includeQuality !== false;\n\n switch (options.type) {\n case \"statistics\":\n includeDataModel = false;\n includeQuality = true;\n break;\n case \"relationships\":\n includeDataModel = false;\n includeQuality = false;\n break;\n case \"data-model\":\n includeDataModel = true;\n includeQuality = false;\n break;\n case \"quality\":\n includeDataModel = false;\n includeQuality = true;\n break;\n case \"comprehensive\":\n default:\n includeDataModel = true;\n includeQuality = true;\n break;\n }\n\n // Format output\n const output = formatReport(report, {\n format,\n verbose: options.verbose,\n includeDataModel,\n includeQuality,\n });\n\n // Write to file or stdout\n if (options.output) {\n const outputPath = path.resolve(process.cwd(), options.output);\n const outputDir = path.dirname(outputPath);\n\n // Ensure output directory exists\n await ensureDir(outputDir);\n\n // Write file\n await writeFile(outputPath, output);\n\n console.log(ansis.green(`\u2713 Report written to ${options.output}`));\n } else {\n // Print to stdout\n console.log(output);\n }\n } catch (error) {\n const message = getErrorMessage(error);\n console.error(ansis.red(`Error: ${message}`));\n process.exit(1);\n }\n}\n"],
|
|
5
|
+
"mappings": "AAIA,OAAO,WAAW;AAClB,SAAS,WAAW,iBAAiB;AACrC,SAAS,aAAa;AACtB,SAAS,uBAAuB;AAChC,SAAS,oBAAkC;AAC3C,OAAO,UAAU;AACjB,SAAS,uBAAuB;AAgBhC,eAAsB,cAAc,SAAsB;AACxD,MAAI;AAEF,UAAM,QAAQ,MAAM,MAAM,KAAK,QAAQ,KAAK,GAItC,SAAS,MADK,IAAI,gBAAgB,KAAK,EACZ,QAAO;AAGxC,QAAI,SAAuB,QAAQ,UAAU;AAG7C,QAAI,QAAQ,QAAQ;AAClB,YAAM,MAAM,KAAK,QAAQ,QAAQ,MAAM,EAAE,YAAW;AACpD,MAAI,QAAQ,UACV,SAAS,SACA,QAAQ,UACjB,SAAS;IAEb;AAGA,QAAI,mBAAmB,QAAQ,qBAAqB,IAChD,iBAAiB,QAAQ,mBAAmB;AAEhD,YAAQ,QAAQ,MAAM;MACpB,KAAK;AACH,2BAAmB,IACnB,iBAAiB;AACjB;MACF,KAAK;AACH,2BAAmB,IACnB,iBAAiB;AACjB;MACF,KAAK;AACH,2BAAmB,IACnB,iBAAiB;AACjB;MACF,KAAK;AACH,2BAAmB,IACnB,iBAAiB;AACjB;MACF,KAAK;MACL;AACE,2BAAmB,IACnB,iBAAiB;AACjB;IACJ;AAGA,UAAM,SAAS,aAAa,QAAQ;MAClC;MACA,SAAS,QAAQ;MACjB;MACA;KACD;AAGD,QAAI,QAAQ,QAAQ;AAClB,YAAM,aAAa,KAAK,QAAQ,QAAQ,IAAG,GAAI,QAAQ,MAAM,GACvD,YAAY,KAAK,QAAQ,UAAU;AAGzC,YAAM,UAAU,SAAS,GAGzB,MAAM,UAAU,YAAY,MAAM,GAElC,QAAQ,IAAI,MAAM,MAAM,4BAAuB,QAAQ,MAAM,EAAE,CAAC;IAClE;AAEE,cAAQ,IAAI,MAAM;EAEtB,SAAS,OAAO;AACd,UAAM,UAAU,gBAAgB,KAAK;AACrC,YAAQ,MAAM,MAAM,IAAI,UAAU,OAAO,EAAE,CAAC,GAC5C,QAAQ,KAAK,CAAC;EAChB;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import ansis from "ansis";
|
|
2
|
+
import * as fs from "fs/promises";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import { Model } from "../core/model.js";
|
|
5
|
+
import { ModelReportOrchestrator } from "../reports/model-report-orchestrator.js";
|
|
6
|
+
import { findProjectRoot } from "../utils/project-paths.js";
|
|
7
|
+
import { getErrorMessage } from "../utils/errors.js";
|
|
8
|
+
function reportsCommands(parent) {
|
|
9
|
+
parent.command("regenerate").description("Delete existing layer reports and regenerate all 12 markdown reports").addHelpText("after", `
|
|
10
|
+
Examples:
|
|
11
|
+
$ dr reports regenerate # Delete existing reports and regenerate all 12 layer reports`).action(async () => {
|
|
12
|
+
await reportsRegenerateCommand();
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
async function reportsRegenerateCommand() {
|
|
16
|
+
try {
|
|
17
|
+
const projectRoot = await findProjectRoot();
|
|
18
|
+
projectRoot || (console.error(ansis.red("Error: No DR project found")), console.error(ansis.dim('Run "dr init" to create a new project')), process.exit(1)), await regenerateLayerReports(projectRoot);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error(ansis.red(`Error: ${getErrorMessage(error)}`)), process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function regenerateLayerReports(projectRoot) {
|
|
24
|
+
const reportDir = path.join(projectRoot, "documentation-robotics", "reports");
|
|
25
|
+
console.log(ansis.dim("Removing existing reports...")), await fs.rm(reportDir, { recursive: !0, force: !0 }), console.log(ansis.dim("Loading model..."));
|
|
26
|
+
const model = await Model.load(projectRoot), orchestrator = new ModelReportOrchestrator(model, projectRoot);
|
|
27
|
+
console.log(ansis.dim("Generating 12 layer reports...")), await orchestrator.regenerateAll(), console.log(ansis.green("\u2713 All 12 layer reports regenerated")), console.log(ansis.dim(" Reports written to: documentation-robotics/reports/"));
|
|
28
|
+
}
|
|
29
|
+
async function hasLayerReports(projectRoot) {
|
|
30
|
+
const reportDir = path.join(projectRoot, "documentation-robotics", "reports");
|
|
31
|
+
try {
|
|
32
|
+
return (await fs.readdir(reportDir)).some((f) => f.endsWith(".md"));
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (error.code === "ENOENT")
|
|
35
|
+
return !1;
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
hasLayerReports,
|
|
41
|
+
regenerateLayerReports,
|
|
42
|
+
reportsCommands,
|
|
43
|
+
reportsRegenerateCommand
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=reports.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 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 12 markdown reports\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ dr reports regenerate # Delete existing reports and regenerate all 12 layer reports`\n )\n .action(async () => {\n await reportsRegenerateCommand();\n });\n}\n\n/**\n * Delete existing layer reports and regenerate all 12 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 12 layer reports.\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 console.log(ansis.dim(\"Removing existing reports...\"));\n await fs.rm(reportDir, { recursive: true, force: true });\n\n // Load model and regenerate all reports\n console.log(ansis.dim(\"Loading model...\"));\n const model = await Model.load(projectRoot);\n\n const orchestrator = new ModelReportOrchestrator(model, projectRoot);\n console.log(ansis.dim(\"Generating 12 layer reports...\"));\n await orchestrator.regenerateAll();\n\n console.log(ansis.green(\"\u2713 All 12 layer reports regenerated\"));\n console.log(ansis.dim(\" Reports written to: documentation-robotics/reports/\"));\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;AAMA,eAAsB,uBAAuB,aAAmB;AAC9D,QAAM,YAAY,KAAK,KAAK,aAAa,0BAA0B,SAAS;AAK5E,UAAQ,IAAI,MAAM,IAAI,8BAA8B,CAAC,GACrD,MAAM,GAAG,GAAG,WAAW,EAAE,WAAW,IAAM,OAAO,GAAI,CAAE,GAGvD,QAAQ,IAAI,MAAM,IAAI,kBAAkB,CAAC;AACzC,QAAM,QAAQ,MAAM,MAAM,KAAK,WAAW,GAEpC,eAAe,IAAI,wBAAwB,OAAO,WAAW;AACnE,UAAQ,IAAI,MAAM,IAAI,gCAAgC,CAAC,GACvD,MAAM,aAAa,cAAa,GAEhC,QAAQ,IAAI,MAAM,MAAM,yCAAoC,CAAC,GAC7D,QAAQ,IAAI,MAAM,IAAI,uDAAuD,CAAC;AAChF;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
|
+
"names": []
|
|
7
|
+
}
|