@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
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import * as yaml from "yaml";
|
|
4
|
+
import { CoverageAnalyzer } from "../analysis/coverage-analyzer.js";
|
|
5
|
+
import { DuplicateDetector } from "../analysis/duplicate-detector.js";
|
|
6
|
+
import { GapAnalyzer } from "../analysis/gap-analyzer.js";
|
|
7
|
+
import { BalanceAssessor } from "../analysis/balance-assessor.js";
|
|
8
|
+
import { ConnectivityAnalyzer } from "../graph/connectivity.js";
|
|
9
|
+
import { RelationshipCatalog } from "../../../core/relationship-catalog.js";
|
|
10
|
+
import { RelationshipGraph } from "../graph/relationship-graph.js";
|
|
11
|
+
import { getLayerById, getAllLayers } from "../../../generated/layer-registry.js";
|
|
12
|
+
import { getErrorMessage } from "../../../utils/errors.js";
|
|
13
|
+
class AuditOrchestrator {
|
|
14
|
+
catalog;
|
|
15
|
+
graph;
|
|
16
|
+
coverageAnalyzer;
|
|
17
|
+
duplicateDetector;
|
|
18
|
+
gapAnalyzer;
|
|
19
|
+
balanceAssessor;
|
|
20
|
+
connectivityAnalyzer;
|
|
21
|
+
initialized = !1;
|
|
22
|
+
constructor() {
|
|
23
|
+
this.catalog = new RelationshipCatalog(), this.graph = new RelationshipGraph(), this.coverageAnalyzer = new CoverageAnalyzer(this.catalog), this.duplicateDetector = new DuplicateDetector(this.catalog), this.gapAnalyzer = new GapAnalyzer(), this.balanceAssessor = new BalanceAssessor(), this.connectivityAnalyzer = new ConnectivityAnalyzer(this.graph, this.catalog);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Initialize the orchestrator (must be called before running audit)
|
|
27
|
+
*/
|
|
28
|
+
async initialize() {
|
|
29
|
+
this.initialized || (await this.catalog.load(), this.initialized = !0);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get predicates applicable to a specific layer
|
|
33
|
+
* Useful for AI evaluation to provide available relationship types
|
|
34
|
+
*/
|
|
35
|
+
getPredicatesForLayer(layer) {
|
|
36
|
+
return this.catalog.getTypesForLayer(layer).map((t) => t.predicate);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Run coverage analysis
|
|
40
|
+
*/
|
|
41
|
+
async runCoverageAnalysis(options) {
|
|
42
|
+
if (this.log(options, "Running coverage analysis..."), options.layer) {
|
|
43
|
+
const layer = getLayerById(options.layer);
|
|
44
|
+
if (!layer) {
|
|
45
|
+
const validLayerNames = getAllLayers().map((l) => l.id).join(", ");
|
|
46
|
+
throw new Error(`Layer not found: '${options.layer}'. Valid layers: ${validLayerNames}`);
|
|
47
|
+
}
|
|
48
|
+
return [await this.coverageAnalyzer.analyzeLayer(layer)];
|
|
49
|
+
}
|
|
50
|
+
return (await this.coverageAnalyzer.analyzeAll()).results;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Run duplicate detection
|
|
54
|
+
*/
|
|
55
|
+
async runDuplicateDetection(options) {
|
|
56
|
+
if (this.log(options, "Running duplicate detection..."), options.layer) {
|
|
57
|
+
const layer = getLayerById(options.layer);
|
|
58
|
+
if (!layer)
|
|
59
|
+
throw new Error(`Layer not found: ${options.layer}`);
|
|
60
|
+
return this.duplicateDetector.detectDuplicatesByLayer(layer.id);
|
|
61
|
+
}
|
|
62
|
+
return this.duplicateDetector.detectDuplicates();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Run gap analysis
|
|
66
|
+
*/
|
|
67
|
+
async runGapAnalysis(options) {
|
|
68
|
+
if (this.log(options, "Running gap analysis..."), options.layer) {
|
|
69
|
+
const layer = getLayerById(options.layer);
|
|
70
|
+
if (!layer)
|
|
71
|
+
throw new Error(`Layer not found: ${options.layer}`);
|
|
72
|
+
return this.gapAnalyzer.analyzeLayer(layer);
|
|
73
|
+
}
|
|
74
|
+
return this.gapAnalyzer.analyzeAll();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Run balance assessment
|
|
78
|
+
*/
|
|
79
|
+
async runBalanceAssessment(options) {
|
|
80
|
+
if (this.log(options, "Running balance assessment..."), options.layer) {
|
|
81
|
+
const layer = getLayerById(options.layer);
|
|
82
|
+
if (!layer)
|
|
83
|
+
throw new Error(`Layer not found: ${options.layer}`);
|
|
84
|
+
return this.balanceAssessor.assessLayer(layer);
|
|
85
|
+
}
|
|
86
|
+
return this.balanceAssessor.assessAll();
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Run connectivity analysis
|
|
90
|
+
*/
|
|
91
|
+
async runConnectivityAnalysis(options) {
|
|
92
|
+
this.log(options, "Running connectivity analysis...");
|
|
93
|
+
const layerId = options.layer ? getLayerById(options.layer)?.id : void 0;
|
|
94
|
+
await this.graph.build(layerId);
|
|
95
|
+
const components = this.connectivityAnalyzer.findConnectedComponents(), degrees = this.connectivityAnalyzer.calculateDegreeDistribution(), transitiveChains = await this.connectivityAnalyzer.findTransitiveChains(), rawStats = this.connectivityAnalyzer.getConnectivityStats(), stats = {
|
|
96
|
+
totalNodes: rawStats.nodeCount,
|
|
97
|
+
totalEdges: rawStats.edgeCount,
|
|
98
|
+
connectedComponents: rawStats.componentCount,
|
|
99
|
+
largestComponentSize: rawStats.largestComponentSize,
|
|
100
|
+
isolatedNodes: rawStats.isolatedNodeCount,
|
|
101
|
+
averageDegree: rawStats.averageDegree,
|
|
102
|
+
transitiveChainCount: transitiveChains.length
|
|
103
|
+
};
|
|
104
|
+
return { components, degrees, transitiveChains, stats };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Load model metadata from manifest
|
|
108
|
+
*/
|
|
109
|
+
async loadModelMetadata(options) {
|
|
110
|
+
this.log(options, "Loading model metadata...");
|
|
111
|
+
const projectRoot = options.projectRoot || process.cwd(), defaultMetadata = {
|
|
112
|
+
name: "Documentation Robotics Model",
|
|
113
|
+
version: "1.0.0"
|
|
114
|
+
};
|
|
115
|
+
try {
|
|
116
|
+
const manifestPath = join(projectRoot, "documentation-robotics", "model", "manifest.yaml"), manifestContent = await readFile(manifestPath, "utf-8");
|
|
117
|
+
let manifest;
|
|
118
|
+
try {
|
|
119
|
+
manifest = yaml.parse(manifestContent);
|
|
120
|
+
} catch (parseError) {
|
|
121
|
+
const parseErrorMsg = getErrorMessage(parseError);
|
|
122
|
+
return console.warn(`\u26A0\uFE0F Warning: Manifest file is corrupted or has invalid YAML syntax (${parseErrorMsg}). Using default model metadata.`), defaultMetadata;
|
|
123
|
+
}
|
|
124
|
+
const name = manifest.name || manifest.project?.name, version = manifest.project?.version || manifest.version;
|
|
125
|
+
return !name || typeof name != "string" ? (console.warn("\u26A0\uFE0F Warning: Manifest missing required field 'name'. Using default model metadata."), defaultMetadata) : !version || typeof version != "string" ? (console.warn("\u26A0\uFE0F Warning: Manifest missing required field 'version'. Using default model metadata."), defaultMetadata) : { name, version };
|
|
126
|
+
} catch (error) {
|
|
127
|
+
const errorMsg = getErrorMessage(error);
|
|
128
|
+
return errorMsg.includes("ENOENT") || errorMsg.includes("no such file") ? this.log(options, "Using default model metadata (manifest not found)") : console.warn(`\u26A0\uFE0F Warning: Cannot read manifest file (${errorMsg}). Using default model metadata.`), defaultMetadata;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Run complete audit and build report
|
|
133
|
+
*/
|
|
134
|
+
async runAudit(options = {}) {
|
|
135
|
+
await this.initialize();
|
|
136
|
+
const coverage = await this.runCoverageAnalysis(options), duplicates = await this.runDuplicateDetection(options), gaps = await this.runGapAnalysis(options), balance = await this.runBalanceAssessment(options), connectivity = await this.runConnectivityAnalysis(options), modelMetadata = await this.loadModelMetadata(options);
|
|
137
|
+
return this.log(options, "Generating audit report..."), {
|
|
138
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
139
|
+
model: modelMetadata,
|
|
140
|
+
coverage,
|
|
141
|
+
duplicates,
|
|
142
|
+
gaps,
|
|
143
|
+
balance,
|
|
144
|
+
connectivity
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Log helper that respects verbose/debug flags
|
|
149
|
+
*/
|
|
150
|
+
log(options, message) {
|
|
151
|
+
(options.verbose || options.debug) && console.error(message);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export {
|
|
155
|
+
AuditOrchestrator
|
|
156
|
+
};
|
|
157
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/audit/relationships/spec/orchestrator.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Audit Orchestrator - Centralized audit execution logic\n *\n * This class eliminates code duplication between cli/src/commands/audit.ts\n * and cli/scripts/relationship-audit.ts by extracting shared audit orchestration.\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport * as yaml from \"yaml\";\nimport { CoverageAnalyzer } from \"../analysis/coverage-analyzer.js\";\nimport { DuplicateDetector } from \"../analysis/duplicate-detector.js\";\nimport { GapAnalyzer } from \"../analysis/gap-analyzer.js\";\nimport { BalanceAssessor } from \"../analysis/balance-assessor.js\";\nimport { ConnectivityAnalyzer } from \"../graph/connectivity.js\";\nimport { RelationshipCatalog } from \"../../../core/relationship-catalog.js\";\nimport { RelationshipGraph } from \"../graph/relationship-graph.js\";\nimport { getLayerById, getAllLayers } from \"../../../generated/layer-registry.js\";\nimport type {\n AuditReport,\n ConnectivityStats,\n CoverageMetrics,\n DuplicateCandidate,\n GapCandidate,\n BalanceAssessment,\n} from \"../../types.js\";\nimport { getErrorMessage } from \"../../../utils/errors.js\";\n\nexport interface AuditOptions {\n layer?: string;\n verbose?: boolean;\n debug?: boolean;\n projectRoot?: string;\n}\n\nexport interface AuditComponents {\n coverage: CoverageMetrics[];\n duplicates: DuplicateCandidate[];\n gaps: GapCandidate[];\n balance: BalanceAssessment[];\n connectivity: {\n components: ReturnType<ConnectivityAnalyzer[\"findConnectedComponents\"]>;\n degrees: ReturnType<ConnectivityAnalyzer[\"calculateDegreeDistribution\"]>;\n transitiveChains: Awaited<\n ReturnType<ConnectivityAnalyzer[\"findTransitiveChains\"]>\n >;\n stats: ConnectivityStats;\n };\n}\n\n/**\n * Orchestrates the full audit pipeline\n */\nexport class AuditOrchestrator {\n private catalog: RelationshipCatalog;\n private graph: RelationshipGraph;\n private coverageAnalyzer: CoverageAnalyzer;\n private duplicateDetector: DuplicateDetector;\n private gapAnalyzer: GapAnalyzer;\n private balanceAssessor: BalanceAssessor;\n private connectivityAnalyzer: ConnectivityAnalyzer;\n private initialized = false;\n\n constructor() {\n this.catalog = new RelationshipCatalog();\n this.graph = new RelationshipGraph();\n\n this.coverageAnalyzer = new CoverageAnalyzer(this.catalog);\n this.duplicateDetector = new DuplicateDetector(this.catalog);\n this.gapAnalyzer = new GapAnalyzer();\n this.balanceAssessor = new BalanceAssessor();\n this.connectivityAnalyzer = new ConnectivityAnalyzer(this.graph, this.catalog);\n }\n\n /**\n * Initialize the orchestrator (must be called before running audit)\n */\n async initialize(): Promise<void> {\n if (!this.initialized) {\n await this.catalog.load();\n this.initialized = true;\n }\n }\n\n /**\n * Get predicates applicable to a specific layer\n * Useful for AI evaluation to provide available relationship types\n */\n getPredicatesForLayer(layer: string): string[] {\n const relationshipTypes = this.catalog.getTypesForLayer(layer);\n return relationshipTypes.map((t) => t.predicate);\n }\n\n /**\n * Run coverage analysis\n */\n async runCoverageAnalysis(options: AuditOptions): Promise<CoverageMetrics[]> {\n this.log(options, \"Running coverage analysis...\");\n\n if (options.layer) {\n const layer = getLayerById(options.layer);\n if (!layer) {\n const allLayers = getAllLayers();\n const validLayerNames = allLayers.map((l) => l.id).join(\", \");\n throw new Error(\n `Layer not found: '${options.layer}'. Valid layers: ${validLayerNames}`\n );\n }\n const metrics = await this.coverageAnalyzer.analyzeLayer(layer);\n return [metrics];\n }\n const result = await this.coverageAnalyzer.analyzeAll();\n return result.results;\n }\n\n /**\n * Run duplicate detection\n */\n async runDuplicateDetection(\n options: AuditOptions\n ): Promise<DuplicateCandidate[]> {\n this.log(options, \"Running duplicate detection...\");\n\n if (options.layer) {\n const layer = getLayerById(options.layer);\n if (!layer) {\n throw new Error(`Layer not found: ${options.layer}`);\n }\n return this.duplicateDetector.detectDuplicatesByLayer(layer.id);\n }\n return this.duplicateDetector.detectDuplicates();\n }\n\n /**\n * Run gap analysis\n */\n async runGapAnalysis(options: AuditOptions): Promise<GapCandidate[]> {\n this.log(options, \"Running gap analysis...\");\n\n if (options.layer) {\n const layer = getLayerById(options.layer);\n if (!layer) {\n throw new Error(`Layer not found: ${options.layer}`);\n }\n return this.gapAnalyzer.analyzeLayer(layer);\n }\n return this.gapAnalyzer.analyzeAll();\n }\n\n /**\n * Run balance assessment\n */\n async runBalanceAssessment(options: AuditOptions): Promise<BalanceAssessment[]> {\n this.log(options, \"Running balance assessment...\");\n\n if (options.layer) {\n const layer = getLayerById(options.layer);\n if (!layer) {\n throw new Error(`Layer not found: ${options.layer}`);\n }\n return this.balanceAssessor.assessLayer(layer);\n }\n return this.balanceAssessor.assessAll();\n }\n\n /**\n * Run connectivity analysis\n */\n async runConnectivityAnalysis(options: AuditOptions): Promise<{\n components: ReturnType<ConnectivityAnalyzer[\"findConnectedComponents\"]>;\n degrees: ReturnType<ConnectivityAnalyzer[\"calculateDegreeDistribution\"]>;\n transitiveChains: Awaited<\n ReturnType<ConnectivityAnalyzer[\"findTransitiveChains\"]>\n >;\n stats: ConnectivityStats;\n }> {\n this.log(options, \"Running connectivity analysis...\");\n\n // Build the graph first if analyzing a specific layer or all relationships\n const layerId = options.layer ? getLayerById(options.layer)?.id : undefined;\n await this.graph.build(layerId);\n\n const components = this.connectivityAnalyzer.findConnectedComponents();\n const degrees = this.connectivityAnalyzer.calculateDegreeDistribution();\n const transitiveChains =\n await this.connectivityAnalyzer.findTransitiveChains();\n const rawStats = this.connectivityAnalyzer.getConnectivityStats();\n\n // Convert connectivity stats to match AuditReport format\n const stats: ConnectivityStats = {\n totalNodes: rawStats.nodeCount,\n totalEdges: rawStats.edgeCount,\n connectedComponents: rawStats.componentCount,\n largestComponentSize: rawStats.largestComponentSize,\n isolatedNodes: rawStats.isolatedNodeCount,\n averageDegree: rawStats.averageDegree,\n transitiveChainCount: transitiveChains.length,\n };\n\n return { components, degrees, transitiveChains, stats };\n }\n\n /**\n * Load model metadata from manifest\n */\n async loadModelMetadata(options: AuditOptions): Promise<{\n name: string;\n version: string;\n }> {\n this.log(options, \"Loading model metadata...\");\n\n const projectRoot = options.projectRoot || process.cwd();\n const defaultMetadata = {\n name: \"Documentation Robotics Model\",\n version: \"1.0.0\",\n };\n\n try {\n const manifestPath = join(\n projectRoot,\n \"documentation-robotics\",\n \"model\",\n \"manifest.yaml\"\n );\n const manifestContent = await readFile(manifestPath, \"utf-8\");\n let manifest: { name?: string; version?: string; project?: { name?: string; version?: string } };\n\n try {\n manifest = yaml.parse(manifestContent) as typeof manifest;\n } catch (parseError: unknown) {\n // YAML parsing failed - file is corrupt\n const parseErrorMsg = getErrorMessage(parseError);\n console.warn(\n `\u26A0\uFE0F Warning: Manifest file is corrupted or has invalid YAML syntax (${parseErrorMsg}). Using default model metadata.`\n );\n return defaultMetadata;\n }\n\n // Name may be at top level or nested under project.name (CLI-generated manifests)\n const name = manifest.name || manifest.project?.name;\n // Version may be at top level or nested under project.version; top-level version is\n // the manifest schema version, so prefer project.version when available\n const version = manifest.project?.version || manifest.version;\n\n if (!name || typeof name !== \"string\") {\n console.warn(\n `\u26A0\uFE0F Warning: Manifest missing required field 'name'. Using default model metadata.`\n );\n return defaultMetadata;\n }\n if (!version || typeof version !== \"string\") {\n console.warn(\n `\u26A0\uFE0F Warning: Manifest missing required field 'version'. Using default model metadata.`\n );\n return defaultMetadata;\n }\n\n return { name, version };\n } catch (error: unknown) {\n // Distinguish between file not found vs read error\n const errorMsg = getErrorMessage(error);\n if (errorMsg.includes(\"ENOENT\") || errorMsg.includes(\"no such file\")) {\n // File not found - expected in tests, use defaults silently\n this.log(\n options,\n \"Using default model metadata (manifest not found)\"\n );\n } else {\n // File exists but cannot be read (permissions, disk error, etc)\n console.warn(\n `\u26A0\uFE0F Warning: Cannot read manifest file (${errorMsg}). Using default model metadata.`\n );\n }\n return defaultMetadata;\n }\n }\n\n /**\n * Run complete audit and build report\n */\n async runAudit(options: AuditOptions = {}): Promise<AuditReport> {\n // Ensure catalog is loaded before running analysis\n await this.initialize();\n\n const coverage = await this.runCoverageAnalysis(options);\n const duplicates = await this.runDuplicateDetection(options);\n const gaps = await this.runGapAnalysis(options);\n const balance = await this.runBalanceAssessment(options);\n const connectivity = await this.runConnectivityAnalysis(options);\n const modelMetadata = await this.loadModelMetadata(options);\n\n this.log(options, \"Generating audit report...\");\n\n return {\n timestamp: new Date().toISOString(),\n model: modelMetadata,\n coverage,\n duplicates,\n gaps,\n balance,\n connectivity,\n };\n }\n\n /**\n * Log helper that respects verbose/debug flags\n */\n private log(options: AuditOptions, message: string): void {\n if (options.verbose || options.debug) {\n console.error(message);\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "AAOA,SAAS,gBAAgB;AACzB,SAAS,YAAY;AACrB,YAAY,UAAU;AACtB,SAAS,wBAAwB;AACjC,SAAS,yBAAyB;AAClC,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC,SAAS,4BAA4B;AACrC,SAAS,2BAA2B;AACpC,SAAS,yBAAyB;AAClC,SAAS,cAAc,oBAAoB;AAS3C,SAAS,uBAAuB;AA2B1B,MAAO,kBAAiB;EACpB;EACA;EACA;EACA;EACA;EACA;EACA;EACA,cAAc;EAEtB,cAAA;AACE,SAAK,UAAU,IAAI,oBAAmB,GACtC,KAAK,QAAQ,IAAI,kBAAiB,GAElC,KAAK,mBAAmB,IAAI,iBAAiB,KAAK,OAAO,GACzD,KAAK,oBAAoB,IAAI,kBAAkB,KAAK,OAAO,GAC3D,KAAK,cAAc,IAAI,YAAW,GAClC,KAAK,kBAAkB,IAAI,gBAAe,GAC1C,KAAK,uBAAuB,IAAI,qBAAqB,KAAK,OAAO,KAAK,OAAO;EAC/E;;;;EAKA,MAAM,aAAU;AACd,IAAK,KAAK,gBACR,MAAM,KAAK,QAAQ,KAAI,GACvB,KAAK,cAAc;EAEvB;;;;;EAMA,sBAAsB,OAAa;AAEjC,WAD0B,KAAK,QAAQ,iBAAiB,KAAK,EACpC,IAAI,CAAC,MAAM,EAAE,SAAS;EACjD;;;;EAKA,MAAM,oBAAoB,SAAqB;AAG7C,QAFA,KAAK,IAAI,SAAS,8BAA8B,GAE5C,QAAQ,OAAO;AACjB,YAAM,QAAQ,aAAa,QAAQ,KAAK;AACxC,UAAI,CAAC,OAAO;AAEV,cAAM,kBADY,aAAY,EACI,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,IAAI;AAC5D,cAAM,IAAI,MACR,qBAAqB,QAAQ,KAAK,oBAAoB,eAAe,EAAE;MAE3E;AAEA,aAAO,CADS,MAAM,KAAK,iBAAiB,aAAa,KAAK,CAC/C;IACjB;AAEA,YADe,MAAM,KAAK,iBAAiB,WAAU,GACvC;EAChB;;;;EAKA,MAAM,sBACJ,SAAqB;AAIrB,QAFA,KAAK,IAAI,SAAS,gCAAgC,GAE9C,QAAQ,OAAO;AACjB,YAAM,QAAQ,aAAa,QAAQ,KAAK;AACxC,UAAI,CAAC;AACH,cAAM,IAAI,MAAM,oBAAoB,QAAQ,KAAK,EAAE;AAErD,aAAO,KAAK,kBAAkB,wBAAwB,MAAM,EAAE;IAChE;AACA,WAAO,KAAK,kBAAkB,iBAAgB;EAChD;;;;EAKA,MAAM,eAAe,SAAqB;AAGxC,QAFA,KAAK,IAAI,SAAS,yBAAyB,GAEvC,QAAQ,OAAO;AACjB,YAAM,QAAQ,aAAa,QAAQ,KAAK;AACxC,UAAI,CAAC;AACH,cAAM,IAAI,MAAM,oBAAoB,QAAQ,KAAK,EAAE;AAErD,aAAO,KAAK,YAAY,aAAa,KAAK;IAC5C;AACA,WAAO,KAAK,YAAY,WAAU;EACpC;;;;EAKA,MAAM,qBAAqB,SAAqB;AAG9C,QAFA,KAAK,IAAI,SAAS,+BAA+B,GAE7C,QAAQ,OAAO;AACjB,YAAM,QAAQ,aAAa,QAAQ,KAAK;AACxC,UAAI,CAAC;AACH,cAAM,IAAI,MAAM,oBAAoB,QAAQ,KAAK,EAAE;AAErD,aAAO,KAAK,gBAAgB,YAAY,KAAK;IAC/C;AACA,WAAO,KAAK,gBAAgB,UAAS;EACvC;;;;EAKA,MAAM,wBAAwB,SAAqB;AAQjD,SAAK,IAAI,SAAS,kCAAkC;AAGpD,UAAM,UAAU,QAAQ,QAAQ,aAAa,QAAQ,KAAK,GAAG,KAAK;AAClE,UAAM,KAAK,MAAM,MAAM,OAAO;AAE9B,UAAM,aAAa,KAAK,qBAAqB,wBAAuB,GAC9D,UAAU,KAAK,qBAAqB,4BAA2B,GAC/D,mBACJ,MAAM,KAAK,qBAAqB,qBAAoB,GAChD,WAAW,KAAK,qBAAqB,qBAAoB,GAGzD,QAA2B;MAC/B,YAAY,SAAS;MACrB,YAAY,SAAS;MACrB,qBAAqB,SAAS;MAC9B,sBAAsB,SAAS;MAC/B,eAAe,SAAS;MACxB,eAAe,SAAS;MACxB,sBAAsB,iBAAiB;;AAGzC,WAAO,EAAE,YAAY,SAAS,kBAAkB,MAAK;EACvD;;;;EAKA,MAAM,kBAAkB,SAAqB;AAI3C,SAAK,IAAI,SAAS,2BAA2B;AAE7C,UAAM,cAAc,QAAQ,eAAe,QAAQ,IAAG,GAChD,kBAAkB;MACtB,MAAM;MACN,SAAS;;AAGX,QAAI;AACF,YAAM,eAAe,KACnB,aACA,0BACA,SACA,eAAe,GAEX,kBAAkB,MAAM,SAAS,cAAc,OAAO;AAC5D,UAAI;AAEJ,UAAI;AACF,mBAAW,KAAK,MAAM,eAAe;MACvC,SAAS,YAAqB;AAE5B,cAAM,gBAAgB,gBAAgB,UAAU;AAChD,uBAAQ,KACN,iFAAuE,aAAa,kCAAkC,GAEjH;MACT;AAGA,YAAM,OAAO,SAAS,QAAQ,SAAS,SAAS,MAG1C,UAAU,SAAS,SAAS,WAAW,SAAS;AAEtD,aAAI,CAAC,QAAQ,OAAO,QAAS,YAC3B,QAAQ,KACN,8FAAoF,GAE/E,mBAEL,CAAC,WAAW,OAAO,WAAY,YACjC,QAAQ,KACN,iGAAuF,GAElF,mBAGF,EAAE,MAAM,QAAO;IACxB,SAAS,OAAgB;AAEvB,YAAM,WAAW,gBAAgB,KAAK;AACtC,aAAI,SAAS,SAAS,QAAQ,KAAK,SAAS,SAAS,cAAc,IAEjE,KAAK,IACH,SACA,mDAAmD,IAIrD,QAAQ,KACN,qDAA2C,QAAQ,kCAAkC,GAGlF;IACT;EACF;;;;EAKA,MAAM,SAAS,UAAwB,CAAA,GAAE;AAEvC,UAAM,KAAK,WAAU;AAErB,UAAM,WAAW,MAAM,KAAK,oBAAoB,OAAO,GACjD,aAAa,MAAM,KAAK,sBAAsB,OAAO,GACrD,OAAO,MAAM,KAAK,eAAe,OAAO,GACxC,UAAU,MAAM,KAAK,qBAAqB,OAAO,GACjD,eAAe,MAAM,KAAK,wBAAwB,OAAO,GACzD,gBAAgB,MAAM,KAAK,kBAAkB,OAAO;AAE1D,gBAAK,IAAI,SAAS,4BAA4B,GAEvC;MACL,YAAW,oBAAI,KAAI,GAAG,YAAW;MACjC,OAAO;MACP;MACA;MACA;MACA;MACA;;EAEJ;;;;EAKQ,IAAI,SAAuB,SAAe;AAChD,KAAI,QAAQ,WAAW,QAAQ,UAC7B,QAAQ,MAAM,OAAO;EAEzB;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
2
|
+
import path from "path";
|
|
3
|
+
class ReportGenerator {
|
|
4
|
+
/**
|
|
5
|
+
* Generate a complete audit report
|
|
6
|
+
*/
|
|
7
|
+
async generateReport(result, options) {
|
|
8
|
+
try {
|
|
9
|
+
await fs.mkdir(options.outputDir, { recursive: !0 });
|
|
10
|
+
} catch (error) {
|
|
11
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
12
|
+
throw new Error(`Failed to create output directory for ${options.format} report at ${options.outputDir}: ${errorMsg}`);
|
|
13
|
+
}
|
|
14
|
+
const totalNodeTypes = result.coverage.reduce((sum, c) => sum + c.nodeTypeCount, 0), totalRelationships = result.coverage.reduce((sum, c) => sum + c.relationshipCount, 0), metadata = {
|
|
15
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16
|
+
phase: options.phase,
|
|
17
|
+
layer: options.layer,
|
|
18
|
+
totalNodeTypes,
|
|
19
|
+
totalRelationships
|
|
20
|
+
};
|
|
21
|
+
let reportContent, filename;
|
|
22
|
+
switch (options.format) {
|
|
23
|
+
case "json":
|
|
24
|
+
reportContent = this.generateJsonReport(result, metadata), filename = `audit-${options.phase}.json`;
|
|
25
|
+
break;
|
|
26
|
+
case "markdown":
|
|
27
|
+
reportContent = this.generateMarkdownReport(result, metadata, options.verbose), filename = `audit-${options.phase}.md`;
|
|
28
|
+
break;
|
|
29
|
+
case "text":
|
|
30
|
+
default:
|
|
31
|
+
reportContent = this.generateTextReport(result, metadata, options.verbose), filename = `audit-${options.phase}.txt`;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
const outputPath = path.join(options.outputDir, filename);
|
|
35
|
+
try {
|
|
36
|
+
await fs.writeFile(outputPath, reportContent, "utf-8");
|
|
37
|
+
} catch (error) {
|
|
38
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
39
|
+
throw new Error(`Failed to write ${options.format} report to ${outputPath}: ${errorMsg}`);
|
|
40
|
+
}
|
|
41
|
+
return outputPath;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Generate JSON format report
|
|
45
|
+
*/
|
|
46
|
+
generateJsonReport(result, metadata) {
|
|
47
|
+
return JSON.stringify({
|
|
48
|
+
metadata,
|
|
49
|
+
...result
|
|
50
|
+
}, null, 2);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Generate Markdown format report
|
|
54
|
+
*/
|
|
55
|
+
generateMarkdownReport(result, metadata, verbose = !1) {
|
|
56
|
+
const lines = [];
|
|
57
|
+
if (lines.push(`# Relationship Audit Report - ${metadata.phase.toUpperCase()}`), lines.push(""), lines.push(`**Timestamp**: ${metadata.timestamp}`), metadata.layer && lines.push(`**Layer**: ${metadata.layer}`), lines.push(`**Total Node Types**: ${metadata.totalNodeTypes}`), lines.push(`**Total Relationships**: ${metadata.totalRelationships}`), lines.push(""), result.coverage && result.coverage.length > 0 && (lines.push("## Coverage Metrics"), lines.push(""), result.coverage.forEach((coverage) => {
|
|
58
|
+
lines.push(`### Layer: ${coverage.layer}`), lines.push(`- **Isolation Rate**: ${coverage.isolationPercentage.toFixed(1)}%`), lines.push(`- **Density**: ${coverage.relationshipsPerNodeType.toFixed(2)} relationships/node type`), lines.push(`- **Predicate Utilization**: ${coverage.utilizationPercentage.toFixed(1)}%`), lines.push(""), verbose && coverage.isolatedNodeTypes.length > 0 && (lines.push("#### Isolated Node Types"), coverage.isolatedNodeTypes.forEach((nodeType) => {
|
|
59
|
+
lines.push(`- ${nodeType}`);
|
|
60
|
+
}), lines.push(""));
|
|
61
|
+
})), result.gaps && result.gaps.length > 0) {
|
|
62
|
+
lines.push("## Gap Analysis"), lines.push(""), lines.push(`Total Gaps Found: ${result.gaps.length}`), lines.push("");
|
|
63
|
+
const highPriorityGaps = result.gaps.filter((g) => g.priority === "high");
|
|
64
|
+
if (highPriorityGaps.length > 0 && (lines.push("### High Priority Gaps"), highPriorityGaps.forEach((gap) => {
|
|
65
|
+
lines.push(`- **${gap.sourceNodeType}** \u2192 **${gap.destinationNodeType}**: ${gap.suggestedPredicate} - ${gap.reason}`);
|
|
66
|
+
}), lines.push("")), verbose) {
|
|
67
|
+
const mediumPriorityGaps = result.gaps.filter((g) => g.priority === "medium");
|
|
68
|
+
mediumPriorityGaps.length > 0 && (lines.push("### Medium Priority Gaps"), mediumPriorityGaps.forEach((gap) => {
|
|
69
|
+
lines.push(`- **${gap.sourceNodeType}** \u2192 **${gap.destinationNodeType}**: ${gap.suggestedPredicate} - ${gap.reason}`);
|
|
70
|
+
}), lines.push(""));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (result.duplicates && result.duplicates.length > 0 && (lines.push("## Duplicate Candidates"), lines.push(""), lines.push(`Total Duplicates Found: ${result.duplicates.length}`), lines.push(""), result.duplicates.slice(0, verbose ? void 0 : 10).forEach((dup) => {
|
|
74
|
+
lines.push(`- ${dup.relationships[0]} \u2194 ${dup.relationships[1]}`), lines.push(` - Predicates: ${dup.predicates[0]} / ${dup.predicates[1]}`), lines.push(` - Reason: ${dup.reason}`), lines.push(` - Confidence: ${dup.confidence}`);
|
|
75
|
+
}), lines.push("")), result.balance && result.balance.length > 0) {
|
|
76
|
+
lines.push("## Balance Analysis"), lines.push("");
|
|
77
|
+
const summary = this.summarizeBalance(result.balance);
|
|
78
|
+
lines.push(`- **Structural Node Types**: ${summary.structural}`), lines.push(`- **Behavioral Node Types**: ${summary.behavioral}`), lines.push(`- **Under-connected**: ${summary.under}`), lines.push(`- **Well-balanced**: ${summary.balanced}`), lines.push(`- **Over-connected**: ${summary.over}`), lines.push("");
|
|
79
|
+
}
|
|
80
|
+
return result.connectivity && (lines.push("## Connectivity"), lines.push(""), lines.push(`- **Connected Components**: ${result.connectivity.stats.connectedComponents}`), lines.push(`- **Largest Component**: ${result.connectivity.stats.largestComponentSize} nodes`), lines.push(`- **Isolated Nodes**: ${result.connectivity.stats.isolatedNodes}`), lines.push(`- **Average Degree**: ${result.connectivity.stats.averageDegree.toFixed(2)}`), lines.push("")), lines.join(`
|
|
81
|
+
`);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Summarize balance assessments
|
|
85
|
+
*/
|
|
86
|
+
summarizeBalance(balance) {
|
|
87
|
+
return {
|
|
88
|
+
structural: balance.filter((b) => b.category === "structural").length,
|
|
89
|
+
behavioral: balance.filter((b) => b.category === "behavioral").length,
|
|
90
|
+
under: balance.filter((b) => b.status === "under").length,
|
|
91
|
+
balanced: balance.filter((b) => b.status === "balanced").length,
|
|
92
|
+
over: balance.filter((b) => b.status === "over").length
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Generate Text format report
|
|
97
|
+
*/
|
|
98
|
+
generateTextReport(result, metadata, verbose = !1) {
|
|
99
|
+
const lines = [];
|
|
100
|
+
if (lines.push("=".repeat(80)), lines.push(`RELATIONSHIP AUDIT REPORT - ${metadata.phase.toUpperCase()}`), lines.push("=".repeat(80)), lines.push(""), lines.push(`Timestamp: ${metadata.timestamp}`), metadata.layer && lines.push(`Layer: ${metadata.layer}`), lines.push(`Total Node Types: ${metadata.totalNodeTypes}`), lines.push(`Total Relationships: ${metadata.totalRelationships}`), lines.push(""), result.coverage && result.coverage.length > 0 && (lines.push("-".repeat(80)), lines.push("COVERAGE METRICS"), lines.push("-".repeat(80)), result.coverage.forEach((coverage) => {
|
|
101
|
+
lines.push(`Layer: ${coverage.layer}`), lines.push(` Isolation Rate: ${coverage.isolationPercentage.toFixed(1)}%`), lines.push(` Density: ${coverage.relationshipsPerNodeType.toFixed(2)} relationships/node type`), lines.push(` Predicate Utilization: ${coverage.utilizationPercentage.toFixed(1)}%`), lines.push("");
|
|
102
|
+
})), result.gaps && result.gaps.length > 0) {
|
|
103
|
+
lines.push("-".repeat(80)), lines.push("GAP ANALYSIS"), lines.push("-".repeat(80)), lines.push(`Total Gaps: ${result.gaps.length}`), lines.push("");
|
|
104
|
+
const highPriorityGaps = result.gaps.filter((g) => g.priority === "high");
|
|
105
|
+
highPriorityGaps.length > 0 && (lines.push("High Priority Gaps:"), highPriorityGaps.forEach((gap, i) => {
|
|
106
|
+
lines.push(` ${i + 1}. ${gap.sourceNodeType} \u2192 ${gap.destinationNodeType}`), lines.push(` ${gap.suggestedPredicate}: ${gap.reason}`);
|
|
107
|
+
}), lines.push(""));
|
|
108
|
+
}
|
|
109
|
+
return result.duplicates && result.duplicates.length > 0 && (lines.push("-".repeat(80)), lines.push("DUPLICATE CANDIDATES"), lines.push("-".repeat(80)), lines.push(`Total Duplicates: ${result.duplicates.length}`), lines.push(""), result.duplicates.slice(0, verbose ? void 0 : 10).forEach((dup, i) => {
|
|
110
|
+
lines.push(` ${i + 1}. ${dup.relationships[0]} \u2194 ${dup.relationships[1]}`), lines.push(` Predicates: ${dup.predicates[0]} / ${dup.predicates[1]}`), lines.push(` ${dup.reason} (${dup.confidence})`);
|
|
111
|
+
}), lines.push("")), result.connectivity && (lines.push("-".repeat(80)), lines.push("CONNECTIVITY"), lines.push("-".repeat(80)), lines.push(`Connected Components: ${result.connectivity.stats.connectedComponents}`), lines.push(`Largest Component: ${result.connectivity.stats.largestComponentSize} nodes`), lines.push(`Isolated Nodes: ${result.connectivity.stats.isolatedNodes}`), lines.push(`Average Degree: ${result.connectivity.stats.averageDegree.toFixed(2)}`), lines.push("")), lines.push("=".repeat(80)), lines.join(`
|
|
112
|
+
`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export {
|
|
116
|
+
ReportGenerator
|
|
117
|
+
};
|
|
118
|
+
//# sourceMappingURL=report-generator.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/audit/reports/report-generator.ts"],
|
|
4
|
+
"sourcesContent": ["import fs from \"fs/promises\";\nimport path from \"path\";\nimport type { AuditReport, GapCandidate, DuplicateCandidate, BalanceAssessment } from \"../types.js\";\n\nexport interface ReportOptions {\n /**\n * Phase of the audit pipeline - before or after AI evaluation\n */\n phase: \"before\" | \"after\";\n\n /**\n * Output directory for the report\n */\n outputDir: string;\n\n /**\n * Report format\n */\n format: \"text\" | \"json\" | \"markdown\";\n\n /**\n * Layer name (if audit is layer-specific)\n */\n layer?: string;\n\n /**\n * Whether to include verbose details\n */\n verbose?: boolean;\n}\n\nexport interface ReportMetadata {\n timestamp: string;\n phase: \"before\" | \"after\";\n layer?: string;\n totalNodeTypes: number;\n totalRelationships: number;\n}\n\n/**\n * Generates audit reports with support for before/after phases\n */\nexport class ReportGenerator {\n /**\n * Generate a complete audit report\n */\n async generateReport(\n result: AuditReport,\n options: ReportOptions\n ): Promise<string> {\n // Ensure output directory exists\n try {\n await fs.mkdir(options.outputDir, { recursive: true });\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to create output directory for ${options.format} report at ${options.outputDir}: ${errorMsg}`\n );\n }\n\n // Calculate totals from all layers\n const totalNodeTypes = result.coverage.reduce((sum, c) => sum + c.nodeTypeCount, 0);\n const totalRelationships = result.coverage.reduce((sum, c) => sum + c.relationshipCount, 0);\n\n const metadata: ReportMetadata = {\n timestamp: new Date().toISOString(),\n phase: options.phase,\n layer: options.layer,\n totalNodeTypes,\n totalRelationships,\n };\n\n // Generate report based on format\n let reportContent: string;\n let filename: string;\n\n switch (options.format) {\n case \"json\":\n reportContent = this.generateJsonReport(result, metadata);\n filename = `audit-${options.phase}.json`;\n break;\n case \"markdown\":\n reportContent = this.generateMarkdownReport(result, metadata, options.verbose);\n filename = `audit-${options.phase}.md`;\n break;\n case \"text\":\n default:\n reportContent = this.generateTextReport(result, metadata, options.verbose);\n filename = `audit-${options.phase}.txt`;\n break;\n }\n\n const outputPath = path.join(options.outputDir, filename);\n try {\n await fs.writeFile(outputPath, reportContent, \"utf-8\");\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to write ${options.format} report to ${outputPath}: ${errorMsg}`\n );\n }\n\n return outputPath;\n }\n\n /**\n * Generate JSON format report\n */\n private generateJsonReport(\n result: AuditReport,\n metadata: ReportMetadata\n ): string {\n return JSON.stringify(\n {\n metadata,\n ...result,\n },\n null,\n 2\n );\n }\n\n /**\n * Generate Markdown format report\n */\n private generateMarkdownReport(\n result: AuditReport,\n metadata: ReportMetadata,\n verbose = false\n ): string {\n const lines: string[] = [];\n\n // Header\n lines.push(`# Relationship Audit Report - ${metadata.phase.toUpperCase()}`);\n lines.push(\"\");\n lines.push(`**Timestamp**: ${metadata.timestamp}`);\n if (metadata.layer) {\n lines.push(`**Layer**: ${metadata.layer}`);\n }\n lines.push(`**Total Node Types**: ${metadata.totalNodeTypes}`);\n lines.push(`**Total Relationships**: ${metadata.totalRelationships}`);\n lines.push(\"\");\n\n // Coverage Section\n if (result.coverage && result.coverage.length > 0) {\n lines.push(\"## Coverage Metrics\");\n lines.push(\"\");\n\n result.coverage.forEach((coverage) => {\n lines.push(`### Layer: ${coverage.layer}`);\n lines.push(`- **Isolation Rate**: ${coverage.isolationPercentage.toFixed(1)}%`);\n lines.push(`- **Density**: ${coverage.relationshipsPerNodeType.toFixed(2)} relationships/node type`);\n lines.push(`- **Predicate Utilization**: ${coverage.utilizationPercentage.toFixed(1)}%`);\n lines.push(\"\");\n\n if (verbose && coverage.isolatedNodeTypes.length > 0) {\n lines.push(\"#### Isolated Node Types\");\n coverage.isolatedNodeTypes.forEach((nodeType: string) => {\n lines.push(`- ${nodeType}`);\n });\n lines.push(\"\");\n }\n });\n }\n\n // Gap Analysis Section\n if (result.gaps && result.gaps.length > 0) {\n lines.push(\"## Gap Analysis\");\n lines.push(\"\");\n lines.push(`Total Gaps Found: ${result.gaps.length}`);\n lines.push(\"\");\n\n const highPriorityGaps = result.gaps.filter((g: GapCandidate) => g.priority === \"high\");\n if (highPriorityGaps.length > 0) {\n lines.push(\"### High Priority Gaps\");\n highPriorityGaps.forEach((gap: GapCandidate) => {\n lines.push(`- **${gap.sourceNodeType}** \u2192 **${gap.destinationNodeType}**: ${gap.suggestedPredicate} - ${gap.reason}`);\n });\n lines.push(\"\");\n }\n\n if (verbose) {\n const mediumPriorityGaps = result.gaps.filter((g: GapCandidate) => g.priority === \"medium\");\n if (mediumPriorityGaps.length > 0) {\n lines.push(\"### Medium Priority Gaps\");\n mediumPriorityGaps.forEach((gap: GapCandidate) => {\n lines.push(`- **${gap.sourceNodeType}** \u2192 **${gap.destinationNodeType}**: ${gap.suggestedPredicate} - ${gap.reason}`);\n });\n lines.push(\"\");\n }\n }\n }\n\n // Duplicates Section\n if (result.duplicates && result.duplicates.length > 0) {\n lines.push(\"## Duplicate Candidates\");\n lines.push(\"\");\n lines.push(`Total Duplicates Found: ${result.duplicates.length}`);\n lines.push(\"\");\n\n result.duplicates.slice(0, verbose ? undefined : 10).forEach((dup: DuplicateCandidate) => {\n lines.push(`- ${dup.relationships[0]} \u2194 ${dup.relationships[1]}`);\n lines.push(` - Predicates: ${dup.predicates[0]} / ${dup.predicates[1]}`);\n lines.push(` - Reason: ${dup.reason}`);\n lines.push(` - Confidence: ${dup.confidence}`);\n });\n lines.push(\"\");\n }\n\n // Balance Section\n if (result.balance && result.balance.length > 0) {\n lines.push(\"## Balance Analysis\");\n lines.push(\"\");\n\n const summary = this.summarizeBalance(result.balance as BalanceAssessment[]);\n lines.push(`- **Structural Node Types**: ${summary.structural}`);\n lines.push(`- **Behavioral Node Types**: ${summary.behavioral}`);\n lines.push(`- **Under-connected**: ${summary.under}`);\n lines.push(`- **Well-balanced**: ${summary.balanced}`);\n lines.push(`- **Over-connected**: ${summary.over}`);\n lines.push(\"\");\n }\n\n // Connectivity Section\n if (result.connectivity) {\n lines.push(\"## Connectivity\");\n lines.push(\"\");\n lines.push(`- **Connected Components**: ${result.connectivity.stats.connectedComponents}`);\n lines.push(`- **Largest Component**: ${result.connectivity.stats.largestComponentSize} nodes`);\n lines.push(`- **Isolated Nodes**: ${result.connectivity.stats.isolatedNodes}`);\n lines.push(`- **Average Degree**: ${result.connectivity.stats.averageDegree.toFixed(2)}`);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n }\n\n /**\n * Summarize balance assessments\n */\n private summarizeBalance(balance: BalanceAssessment[]): {\n structural: number;\n behavioral: number;\n under: number;\n balanced: number;\n over: number;\n } {\n return {\n structural: balance.filter((b) => b.category === \"structural\").length,\n behavioral: balance.filter((b) => b.category === \"behavioral\").length,\n under: balance.filter((b) => b.status === \"under\").length,\n balanced: balance.filter((b) => b.status === \"balanced\").length,\n over: balance.filter((b) => b.status === \"over\").length,\n };\n }\n\n /**\n * Generate Text format report\n */\n private generateTextReport(\n result: AuditReport,\n metadata: ReportMetadata,\n verbose = false\n ): string {\n const lines: string[] = [];\n\n // Header\n lines.push(\"=\".repeat(80));\n lines.push(`RELATIONSHIP AUDIT REPORT - ${metadata.phase.toUpperCase()}`);\n lines.push(\"=\".repeat(80));\n lines.push(\"\");\n lines.push(`Timestamp: ${metadata.timestamp}`);\n if (metadata.layer) {\n lines.push(`Layer: ${metadata.layer}`);\n }\n lines.push(`Total Node Types: ${metadata.totalNodeTypes}`);\n lines.push(`Total Relationships: ${metadata.totalRelationships}`);\n lines.push(\"\");\n\n // Coverage Section\n if (result.coverage && result.coverage.length > 0) {\n lines.push(\"-\".repeat(80));\n lines.push(\"COVERAGE METRICS\");\n lines.push(\"-\".repeat(80));\n\n result.coverage.forEach((coverage) => {\n lines.push(`Layer: ${coverage.layer}`);\n lines.push(` Isolation Rate: ${coverage.isolationPercentage.toFixed(1)}%`);\n lines.push(` Density: ${coverage.relationshipsPerNodeType.toFixed(2)} relationships/node type`);\n lines.push(` Predicate Utilization: ${coverage.utilizationPercentage.toFixed(1)}%`);\n lines.push(\"\");\n });\n }\n\n // Gap Analysis Section\n if (result.gaps && result.gaps.length > 0) {\n lines.push(\"-\".repeat(80));\n lines.push(\"GAP ANALYSIS\");\n lines.push(\"-\".repeat(80));\n lines.push(`Total Gaps: ${result.gaps.length}`);\n lines.push(\"\");\n\n const highPriorityGaps = result.gaps.filter((g: GapCandidate) => g.priority === \"high\");\n if (highPriorityGaps.length > 0) {\n lines.push(\"High Priority Gaps:\");\n highPriorityGaps.forEach((gap: GapCandidate, i: number) => {\n lines.push(` ${i + 1}. ${gap.sourceNodeType} \u2192 ${gap.destinationNodeType}`);\n lines.push(` ${gap.suggestedPredicate}: ${gap.reason}`);\n });\n lines.push(\"\");\n }\n }\n\n // Duplicates Section\n if (result.duplicates && result.duplicates.length > 0) {\n lines.push(\"-\".repeat(80));\n lines.push(\"DUPLICATE CANDIDATES\");\n lines.push(\"-\".repeat(80));\n lines.push(`Total Duplicates: ${result.duplicates.length}`);\n lines.push(\"\");\n\n result.duplicates.slice(0, verbose ? undefined : 10).forEach((dup: DuplicateCandidate, i: number) => {\n lines.push(` ${i + 1}. ${dup.relationships[0]} \u2194 ${dup.relationships[1]}`);\n lines.push(` Predicates: ${dup.predicates[0]} / ${dup.predicates[1]}`);\n lines.push(` ${dup.reason} (${dup.confidence})`);\n });\n lines.push(\"\");\n }\n\n // Connectivity Section\n if (result.connectivity) {\n lines.push(\"-\".repeat(80));\n lines.push(\"CONNECTIVITY\");\n lines.push(\"-\".repeat(80));\n lines.push(`Connected Components: ${result.connectivity.stats.connectedComponents}`);\n lines.push(`Largest Component: ${result.connectivity.stats.largestComponentSize} nodes`);\n lines.push(`Isolated Nodes: ${result.connectivity.stats.isolatedNodes}`);\n lines.push(`Average Degree: ${result.connectivity.stats.averageDegree.toFixed(2)}`);\n lines.push(\"\");\n }\n\n lines.push(\"=\".repeat(80));\n\n return lines.join(\"\\n\");\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AAyCX,MAAO,gBAAe;;;;EAI1B,MAAM,eACJ,QACA,SAAsB;AAGtB,QAAI;AACF,YAAM,GAAG,MAAM,QAAQ,WAAW,EAAE,WAAW,GAAI,CAAE;IACvD,SAAS,OAAO;AACd,YAAM,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACtE,YAAM,IAAI,MACR,yCAAyC,QAAQ,MAAM,cAAc,QAAQ,SAAS,KAAK,QAAQ,EAAE;IAEzG;AAGA,UAAM,iBAAiB,OAAO,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,eAAe,CAAC,GAC5E,qBAAqB,OAAO,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,mBAAmB,CAAC,GAEpF,WAA2B;MAC/B,YAAW,oBAAI,KAAI,GAAG,YAAW;MACjC,OAAO,QAAQ;MACf,OAAO,QAAQ;MACf;MACA;;AAIF,QAAI,eACA;AAEJ,YAAQ,QAAQ,QAAQ;MACtB,KAAK;AACH,wBAAgB,KAAK,mBAAmB,QAAQ,QAAQ,GACxD,WAAW,SAAS,QAAQ,KAAK;AACjC;MACF,KAAK;AACH,wBAAgB,KAAK,uBAAuB,QAAQ,UAAU,QAAQ,OAAO,GAC7E,WAAW,SAAS,QAAQ,KAAK;AACjC;MACF,KAAK;MACL;AACE,wBAAgB,KAAK,mBAAmB,QAAQ,UAAU,QAAQ,OAAO,GACzE,WAAW,SAAS,QAAQ,KAAK;AACjC;IACJ;AAEA,UAAM,aAAa,KAAK,KAAK,QAAQ,WAAW,QAAQ;AACxD,QAAI;AACF,YAAM,GAAG,UAAU,YAAY,eAAe,OAAO;IACvD,SAAS,OAAO;AACd,YAAM,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACtE,YAAM,IAAI,MACR,mBAAmB,QAAQ,MAAM,cAAc,UAAU,KAAK,QAAQ,EAAE;IAE5E;AAEA,WAAO;EACT;;;;EAKQ,mBACN,QACA,UAAwB;AAExB,WAAO,KAAK,UACV;MACE;MACA,GAAG;OAEL,MACA,CAAC;EAEL;;;;EAKQ,uBACN,QACA,UACA,UAAU,IAAK;AAEf,UAAM,QAAkB,CAAA;AAoCxB,QAjCA,MAAM,KAAK,iCAAiC,SAAS,MAAM,YAAW,CAAE,EAAE,GAC1E,MAAM,KAAK,EAAE,GACb,MAAM,KAAK,kBAAkB,SAAS,SAAS,EAAE,GAC7C,SAAS,SACX,MAAM,KAAK,cAAc,SAAS,KAAK,EAAE,GAE3C,MAAM,KAAK,yBAAyB,SAAS,cAAc,EAAE,GAC7D,MAAM,KAAK,4BAA4B,SAAS,kBAAkB,EAAE,GACpE,MAAM,KAAK,EAAE,GAGT,OAAO,YAAY,OAAO,SAAS,SAAS,MAC9C,MAAM,KAAK,qBAAqB,GAChC,MAAM,KAAK,EAAE,GAEb,OAAO,SAAS,QAAQ,CAAC,aAAY;AACnC,YAAM,KAAK,cAAc,SAAS,KAAK,EAAE,GACzC,MAAM,KAAK,yBAAyB,SAAS,oBAAoB,QAAQ,CAAC,CAAC,GAAG,GAC9E,MAAM,KAAK,kBAAkB,SAAS,yBAAyB,QAAQ,CAAC,CAAC,0BAA0B,GACnG,MAAM,KAAK,gCAAgC,SAAS,sBAAsB,QAAQ,CAAC,CAAC,GAAG,GACvF,MAAM,KAAK,EAAE,GAET,WAAW,SAAS,kBAAkB,SAAS,MACjD,MAAM,KAAK,0BAA0B,GACrC,SAAS,kBAAkB,QAAQ,CAAC,aAAoB;AACtD,cAAM,KAAK,KAAK,QAAQ,EAAE;MAC5B,CAAC,GACD,MAAM,KAAK,EAAE;IAEjB,CAAC,IAIC,OAAO,QAAQ,OAAO,KAAK,SAAS,GAAG;AACzC,YAAM,KAAK,iBAAiB,GAC5B,MAAM,KAAK,EAAE,GACb,MAAM,KAAK,qBAAqB,OAAO,KAAK,MAAM,EAAE,GACpD,MAAM,KAAK,EAAE;AAEb,YAAM,mBAAmB,OAAO,KAAK,OAAO,CAAC,MAAoB,EAAE,aAAa,MAAM;AAStF,UARI,iBAAiB,SAAS,MAC5B,MAAM,KAAK,wBAAwB,GACnC,iBAAiB,QAAQ,CAAC,QAAqB;AAC7C,cAAM,KAAK,OAAO,IAAI,cAAc,eAAU,IAAI,mBAAmB,OAAO,IAAI,kBAAkB,MAAM,IAAI,MAAM,EAAE;MACtH,CAAC,GACD,MAAM,KAAK,EAAE,IAGX,SAAS;AACX,cAAM,qBAAqB,OAAO,KAAK,OAAO,CAAC,MAAoB,EAAE,aAAa,QAAQ;AAC1F,QAAI,mBAAmB,SAAS,MAC9B,MAAM,KAAK,0BAA0B,GACrC,mBAAmB,QAAQ,CAAC,QAAqB;AAC/C,gBAAM,KAAK,OAAO,IAAI,cAAc,eAAU,IAAI,mBAAmB,OAAO,IAAI,kBAAkB,MAAM,IAAI,MAAM,EAAE;QACtH,CAAC,GACD,MAAM,KAAK,EAAE;MAEjB;IACF;AAmBA,QAhBI,OAAO,cAAc,OAAO,WAAW,SAAS,MAClD,MAAM,KAAK,yBAAyB,GACpC,MAAM,KAAK,EAAE,GACb,MAAM,KAAK,2BAA2B,OAAO,WAAW,MAAM,EAAE,GAChE,MAAM,KAAK,EAAE,GAEb,OAAO,WAAW,MAAM,GAAG,UAAU,SAAY,EAAE,EAAE,QAAQ,CAAC,QAA2B;AACvF,YAAM,KAAK,KAAK,IAAI,cAAc,CAAC,CAAC,WAAM,IAAI,cAAc,CAAC,CAAC,EAAE,GAChE,MAAM,KAAK,mBAAmB,IAAI,WAAW,CAAC,CAAC,MAAM,IAAI,WAAW,CAAC,CAAC,EAAE,GACxE,MAAM,KAAK,eAAe,IAAI,MAAM,EAAE,GACtC,MAAM,KAAK,mBAAmB,IAAI,UAAU,EAAE;IAChD,CAAC,GACD,MAAM,KAAK,EAAE,IAIX,OAAO,WAAW,OAAO,QAAQ,SAAS,GAAG;AAC/C,YAAM,KAAK,qBAAqB,GAChC,MAAM,KAAK,EAAE;AAEb,YAAM,UAAU,KAAK,iBAAiB,OAAO,OAA8B;AAC3E,YAAM,KAAK,gCAAgC,QAAQ,UAAU,EAAE,GAC/D,MAAM,KAAK,gCAAgC,QAAQ,UAAU,EAAE,GAC/D,MAAM,KAAK,0BAA0B,QAAQ,KAAK,EAAE,GACpD,MAAM,KAAK,wBAAwB,QAAQ,QAAQ,EAAE,GACrD,MAAM,KAAK,yBAAyB,QAAQ,IAAI,EAAE,GAClD,MAAM,KAAK,EAAE;IACf;AAGA,WAAI,OAAO,iBACT,MAAM,KAAK,iBAAiB,GAC5B,MAAM,KAAK,EAAE,GACb,MAAM,KAAK,+BAA+B,OAAO,aAAa,MAAM,mBAAmB,EAAE,GACzF,MAAM,KAAK,4BAA4B,OAAO,aAAa,MAAM,oBAAoB,QAAQ,GAC7F,MAAM,KAAK,yBAAyB,OAAO,aAAa,MAAM,aAAa,EAAE,GAC7E,MAAM,KAAK,yBAAyB,OAAO,aAAa,MAAM,cAAc,QAAQ,CAAC,CAAC,EAAE,GACxF,MAAM,KAAK,EAAE,IAGR,MAAM,KAAK;CAAI;EACxB;;;;EAKQ,iBAAiB,SAA4B;AAOnD,WAAO;MACL,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,aAAa,YAAY,EAAE;MAC/D,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,aAAa,YAAY,EAAE;MAC/D,OAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,EAAE;MACnD,UAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EAAE;MACzD,MAAM,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;;EAErD;;;;EAKQ,mBACN,QACA,UACA,UAAU,IAAK;AAEf,UAAM,QAAkB,CAAA;AA+BxB,QA5BA,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,+BAA+B,SAAS,MAAM,YAAW,CAAE,EAAE,GACxE,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,EAAE,GACb,MAAM,KAAK,cAAc,SAAS,SAAS,EAAE,GACzC,SAAS,SACX,MAAM,KAAK,UAAU,SAAS,KAAK,EAAE,GAEvC,MAAM,KAAK,qBAAqB,SAAS,cAAc,EAAE,GACzD,MAAM,KAAK,wBAAwB,SAAS,kBAAkB,EAAE,GAChE,MAAM,KAAK,EAAE,GAGT,OAAO,YAAY,OAAO,SAAS,SAAS,MAC9C,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,kBAAkB,GAC7B,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GAEzB,OAAO,SAAS,QAAQ,CAAC,aAAY;AACnC,YAAM,KAAK,UAAU,SAAS,KAAK,EAAE,GACrC,MAAM,KAAK,qBAAqB,SAAS,oBAAoB,QAAQ,CAAC,CAAC,GAAG,GAC1E,MAAM,KAAK,cAAc,SAAS,yBAAyB,QAAQ,CAAC,CAAC,0BAA0B,GAC/F,MAAM,KAAK,4BAA4B,SAAS,sBAAsB,QAAQ,CAAC,CAAC,GAAG,GACnF,MAAM,KAAK,EAAE;IACf,CAAC,IAIC,OAAO,QAAQ,OAAO,KAAK,SAAS,GAAG;AACzC,YAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,cAAc,GACzB,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,eAAe,OAAO,KAAK,MAAM,EAAE,GAC9C,MAAM,KAAK,EAAE;AAEb,YAAM,mBAAmB,OAAO,KAAK,OAAO,CAAC,MAAoB,EAAE,aAAa,MAAM;AACtF,MAAI,iBAAiB,SAAS,MAC5B,MAAM,KAAK,qBAAqB,GAChC,iBAAiB,QAAQ,CAAC,KAAmB,MAAa;AACxD,cAAM,KAAK,KAAK,IAAI,CAAC,KAAK,IAAI,cAAc,WAAM,IAAI,mBAAmB,EAAE,GAC3E,MAAM,KAAK,QAAQ,IAAI,kBAAkB,KAAK,IAAI,MAAM,EAAE;MAC5D,CAAC,GACD,MAAM,KAAK,EAAE;IAEjB;AAGA,WAAI,OAAO,cAAc,OAAO,WAAW,SAAS,MAClD,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,sBAAsB,GACjC,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,qBAAqB,OAAO,WAAW,MAAM,EAAE,GAC1D,MAAM,KAAK,EAAE,GAEb,OAAO,WAAW,MAAM,GAAG,UAAU,SAAY,EAAE,EAAE,QAAQ,CAAC,KAAyB,MAAa;AAClG,YAAM,KAAK,KAAK,IAAI,CAAC,KAAK,IAAI,cAAc,CAAC,CAAC,WAAM,IAAI,cAAc,CAAC,CAAC,EAAE,GAC1E,MAAM,KAAK,oBAAoB,IAAI,WAAW,CAAC,CAAC,MAAM,IAAI,WAAW,CAAC,CAAC,EAAE,GACzE,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,UAAU,GAAG;IACrD,CAAC,GACD,MAAM,KAAK,EAAE,IAIX,OAAO,iBACT,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,cAAc,GACzB,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GACzB,MAAM,KAAK,yBAAyB,OAAO,aAAa,MAAM,mBAAmB,EAAE,GACnF,MAAM,KAAK,sBAAsB,OAAO,aAAa,MAAM,oBAAoB,QAAQ,GACvF,MAAM,KAAK,mBAAmB,OAAO,aAAa,MAAM,aAAa,EAAE,GACvE,MAAM,KAAK,mBAAmB,OAAO,aAAa,MAAM,cAAc,QAAQ,CAAC,CAAC,EAAE,GAClF,MAAM,KAAK,EAAE,IAGf,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,GAElB,MAAM,KAAK;CAAI;EACxB;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
class SnapshotStorage {
|
|
4
|
+
storageDir;
|
|
5
|
+
maxSnapshots;
|
|
6
|
+
constructor(config = {}) {
|
|
7
|
+
this.storageDir = config.storageDir || path.join(process.cwd(), ".dr", "audit-snapshots"), this.maxSnapshots = config.maxSnapshots || 0;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Initialize storage directory
|
|
11
|
+
*/
|
|
12
|
+
async ensureStorageDir() {
|
|
13
|
+
await fs.mkdir(this.storageDir, { recursive: !0 });
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Generate snapshot ID from timestamp
|
|
17
|
+
*/
|
|
18
|
+
generateSnapshotId(timestamp) {
|
|
19
|
+
return new Date(timestamp).toISOString().replace(/[-:]/g, "").replace(/\..+/, "").replace("T", "-");
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get snapshot file path
|
|
23
|
+
*/
|
|
24
|
+
getSnapshotPath(id) {
|
|
25
|
+
return path.join(this.storageDir, `${id}.json`);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get metadata file path
|
|
29
|
+
*/
|
|
30
|
+
getMetadataPath(id) {
|
|
31
|
+
return path.join(this.storageDir, `${id}.meta.json`);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Save an audit report as a snapshot
|
|
35
|
+
*/
|
|
36
|
+
async save(report) {
|
|
37
|
+
await this.ensureStorageDir();
|
|
38
|
+
const id = this.generateSnapshotId(report.timestamp), snapshotPath = this.getSnapshotPath(id), metadataPath = this.getMetadataPath(id), layers = report.coverage.map((c) => c.layer), metadata = {
|
|
39
|
+
id,
|
|
40
|
+
timestamp: report.timestamp,
|
|
41
|
+
modelName: report.model.name,
|
|
42
|
+
modelVersion: report.model.version,
|
|
43
|
+
layers,
|
|
44
|
+
snapshotPath
|
|
45
|
+
};
|
|
46
|
+
try {
|
|
47
|
+
await fs.writeFile(snapshotPath, JSON.stringify(report, null, 2), "utf-8");
|
|
48
|
+
} catch (error) {
|
|
49
|
+
throw new Error(`Failed to write snapshot file ${snapshotPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2), "utf-8");
|
|
53
|
+
} catch (error) {
|
|
54
|
+
try {
|
|
55
|
+
await fs.unlink(snapshotPath);
|
|
56
|
+
} catch {
|
|
57
|
+
}
|
|
58
|
+
throw new Error(`Failed to write snapshot metadata ${metadataPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
59
|
+
}
|
|
60
|
+
return this.maxSnapshots > 0 && await this.cleanupOldSnapshots(), metadata;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Load a snapshot by ID or timestamp
|
|
64
|
+
*/
|
|
65
|
+
async load(idOrTimestamp) {
|
|
66
|
+
await this.ensureStorageDir();
|
|
67
|
+
let id;
|
|
68
|
+
/^\d{8}-\d{6}$/.test(idOrTimestamp) ? id = idOrTimestamp : id = this.generateSnapshotId(idOrTimestamp);
|
|
69
|
+
const snapshotPath = this.getSnapshotPath(id);
|
|
70
|
+
try {
|
|
71
|
+
const content = await fs.readFile(snapshotPath, "utf-8");
|
|
72
|
+
return JSON.parse(content);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw error.code === "ENOENT" ? new Error(`Snapshot not found: ${id}. Use 'dr audit snapshots' to list available snapshots.`) : new Error(`Failed to parse snapshot ${id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* List all available snapshots
|
|
79
|
+
*/
|
|
80
|
+
async list() {
|
|
81
|
+
await this.ensureStorageDir();
|
|
82
|
+
try {
|
|
83
|
+
const metadataFiles = (await fs.readdir(this.storageDir)).filter((f) => f.endsWith(".meta.json")), snapshots = [];
|
|
84
|
+
for (const file of metadataFiles) {
|
|
85
|
+
const content = await fs.readFile(path.join(this.storageDir, file), "utf-8");
|
|
86
|
+
snapshots.push(JSON.parse(content));
|
|
87
|
+
}
|
|
88
|
+
return snapshots.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (error.code === "ENOENT")
|
|
91
|
+
return [];
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Delete a snapshot
|
|
97
|
+
*
|
|
98
|
+
* Deletes both snapshot and metadata files sequentially with rollback on failure
|
|
99
|
+
* to prevent partial deletion state.
|
|
100
|
+
*/
|
|
101
|
+
async delete(idOrTimestamp) {
|
|
102
|
+
await this.ensureStorageDir();
|
|
103
|
+
let id;
|
|
104
|
+
/^\d{8}-\d{6}$/.test(idOrTimestamp) ? id = idOrTimestamp : id = this.generateSnapshotId(idOrTimestamp);
|
|
105
|
+
const snapshotPath = this.getSnapshotPath(id), metadataPath = this.getMetadataPath(id);
|
|
106
|
+
try {
|
|
107
|
+
await fs.unlink(snapshotPath);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (error.code !== "ENOENT")
|
|
110
|
+
throw new Error(`Failed to delete snapshot ${id}: ${error.message}`);
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
await fs.unlink(metadataPath);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
if (error.code !== "ENOENT")
|
|
116
|
+
throw new Error(`Failed to delete snapshot metadata ${id}: ${error.message}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get the most recent snapshot
|
|
121
|
+
*/
|
|
122
|
+
async getLatest() {
|
|
123
|
+
const snapshots = await this.list();
|
|
124
|
+
return snapshots.length === 0 ? null : this.load(snapshots[0].id);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get the two most recent snapshots for comparison.
|
|
128
|
+
* Returns a tuple of [before, after] where 'before' is the older snapshot
|
|
129
|
+
* and 'after' is the more recent snapshot (for differential analysis).
|
|
130
|
+
* @returns [before, after] tuple where both are sorted chronologically, or [null, null] if fewer than 2 snapshots exist
|
|
131
|
+
*/
|
|
132
|
+
async getLatestPair() {
|
|
133
|
+
const snapshots = await this.list();
|
|
134
|
+
if (snapshots.length < 2)
|
|
135
|
+
return [null, null];
|
|
136
|
+
const [after, before] = await Promise.all([
|
|
137
|
+
this.load(snapshots[0].id),
|
|
138
|
+
this.load(snapshots[1].id)
|
|
139
|
+
]);
|
|
140
|
+
return [before, after];
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Clean up old snapshots beyond the retention limit
|
|
144
|
+
*/
|
|
145
|
+
async cleanupOldSnapshots() {
|
|
146
|
+
const snapshots = await this.list();
|
|
147
|
+
if (snapshots.length <= this.maxSnapshots)
|
|
148
|
+
return;
|
|
149
|
+
const toDelete = snapshots.slice(this.maxSnapshots);
|
|
150
|
+
await Promise.all(toDelete.map((s) => this.delete(s.id)));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Clear all snapshots
|
|
154
|
+
*/
|
|
155
|
+
async clear() {
|
|
156
|
+
const snapshots = await this.list();
|
|
157
|
+
await Promise.all(snapshots.map((s) => this.delete(s.id)));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
export {
|
|
161
|
+
SnapshotStorage
|
|
162
|
+
};
|
|
163
|
+
//# sourceMappingURL=snapshot-storage.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/audit/snapshot-storage.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Audit snapshot storage and management\n *\n * Provides persistence for audit reports to enable temporal analysis\n * and before/after differential comparison.\n */\n\nimport { promises as fs } from \"fs\";\nimport * as path from \"path\";\nimport type { AuditReport } from \"./types.js\";\n\n/**\n * Metadata for a stored audit snapshot\n */\nexport interface SnapshotMetadata {\n id: string; // Unique identifier (timestamp-based)\n timestamp: string; // ISO 8601 timestamp\n modelName: string;\n modelVersion: string;\n layers: string[]; // Layers included in this snapshot\n snapshotPath: string; // Path to snapshot file\n}\n\n/**\n * Snapshot storage configuration\n */\nexport interface SnapshotStorageConfig {\n storageDir?: string; // Override default storage directory\n maxSnapshots?: number; // Maximum snapshots to retain (0 = unlimited)\n}\n\n/**\n * Manager for audit snapshot persistence\n */\nexport class SnapshotStorage {\n private readonly storageDir: string;\n private readonly maxSnapshots: number;\n\n constructor(config: SnapshotStorageConfig = {}) {\n this.storageDir =\n config.storageDir || path.join(process.cwd(), \".dr\", \"audit-snapshots\");\n this.maxSnapshots = config.maxSnapshots || 0; // Unlimited by default\n }\n\n /**\n * Initialize storage directory\n */\n private async ensureStorageDir(): Promise<void> {\n await fs.mkdir(this.storageDir, { recursive: true });\n }\n\n /**\n * Generate snapshot ID from timestamp\n */\n private generateSnapshotId(timestamp: string): string {\n // Format: YYYYMMDD-HHmmss\n const date = new Date(timestamp);\n const formatted = date\n .toISOString()\n .replace(/[-:]/g, \"\")\n .replace(/\\..+/, \"\")\n .replace(\"T\", \"-\");\n return formatted;\n }\n\n /**\n * Get snapshot file path\n */\n private getSnapshotPath(id: string): string {\n return path.join(this.storageDir, `${id}.json`);\n }\n\n /**\n * Get metadata file path\n */\n private getMetadataPath(id: string): string {\n return path.join(this.storageDir, `${id}.meta.json`);\n }\n\n /**\n * Save an audit report as a snapshot\n */\n async save(report: AuditReport): Promise<SnapshotMetadata> {\n await this.ensureStorageDir();\n\n const id = this.generateSnapshotId(report.timestamp);\n const snapshotPath = this.getSnapshotPath(id);\n const metadataPath = this.getMetadataPath(id);\n\n // Extract layers from coverage data\n const layers = report.coverage.map((c) => c.layer);\n\n const metadata: SnapshotMetadata = {\n id,\n timestamp: report.timestamp,\n modelName: report.model.name,\n modelVersion: report.model.version,\n layers,\n snapshotPath,\n };\n\n // Write snapshot data\n try {\n await fs.writeFile(snapshotPath, JSON.stringify(report, null, 2), \"utf-8\");\n } catch (error) {\n throw new Error(\n `Failed to write snapshot file ${snapshotPath}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n // Write metadata\n try {\n await fs.writeFile(\n metadataPath,\n JSON.stringify(metadata, null, 2),\n \"utf-8\",\n );\n } catch (error) {\n // If metadata write fails, clean up orphaned snapshot file\n try {\n await fs.unlink(snapshotPath);\n } catch (unlinkError) {\n // Ignore cleanup errors\n }\n throw new Error(\n `Failed to write snapshot metadata ${metadataPath}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n\n // Cleanup old snapshots if limit exceeded\n if (this.maxSnapshots > 0) {\n await this.cleanupOldSnapshots();\n }\n\n return metadata;\n }\n\n /**\n * Load a snapshot by ID or timestamp\n */\n async load(idOrTimestamp: string): Promise<AuditReport> {\n await this.ensureStorageDir();\n\n let id: string;\n\n // Check if input is already a snapshot ID\n if (/^\\d{8}-\\d{6}$/.test(idOrTimestamp)) {\n id = idOrTimestamp;\n } else {\n // Assume it's a timestamp, convert to ID\n id = this.generateSnapshotId(idOrTimestamp);\n }\n\n const snapshotPath = this.getSnapshotPath(id);\n\n try {\n const content = await fs.readFile(snapshotPath, \"utf-8\");\n return JSON.parse(content) as AuditReport;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new Error(\n `Snapshot not found: ${id}. Use 'dr audit snapshots' to list available snapshots.`,\n );\n }\n // Include snapshot ID in parse error context\n throw new Error(\n `Failed to parse snapshot ${id}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * List all available snapshots\n */\n async list(): Promise<SnapshotMetadata[]> {\n await this.ensureStorageDir();\n\n try {\n const files = await fs.readdir(this.storageDir);\n const metadataFiles = files.filter((f) => f.endsWith(\".meta.json\"));\n\n const snapshots: SnapshotMetadata[] = [];\n for (const file of metadataFiles) {\n const content = await fs.readFile(\n path.join(this.storageDir, file),\n \"utf-8\",\n );\n snapshots.push(JSON.parse(content) as SnapshotMetadata);\n }\n\n // Sort by timestamp (newest first)\n return snapshots.sort(\n (a, b) =>\n new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(),\n );\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return []; // Directory doesn't exist yet\n }\n throw error;\n }\n }\n\n /**\n * Delete a snapshot\n *\n * Deletes both snapshot and metadata files sequentially with rollback on failure\n * to prevent partial deletion state.\n */\n async delete(idOrTimestamp: string): Promise<void> {\n await this.ensureStorageDir();\n\n let id: string;\n if (/^\\d{8}-\\d{6}$/.test(idOrTimestamp)) {\n id = idOrTimestamp;\n } else {\n id = this.generateSnapshotId(idOrTimestamp);\n }\n\n const snapshotPath = this.getSnapshotPath(id);\n const metadataPath = this.getMetadataPath(id);\n\n // Delete snapshot file first\n try {\n await fs.unlink(snapshotPath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw new Error(`Failed to delete snapshot ${id}: ${(error as NodeJS.ErrnoException).message}`);\n }\n // File doesn't exist, continue to metadata\n }\n\n // Delete metadata file\n try {\n await fs.unlink(metadataPath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw new Error(\n `Failed to delete snapshot metadata ${id}: ${(error as NodeJS.ErrnoException).message}`\n );\n }\n // File doesn't exist, both are gone\n }\n }\n\n /**\n * Get the most recent snapshot\n */\n async getLatest(): Promise<AuditReport | null> {\n const snapshots = await this.list();\n if (snapshots.length === 0) {\n return null;\n }\n return this.load(snapshots[0].id);\n }\n\n /**\n * Get the two most recent snapshots for comparison.\n * Returns a tuple of [before, after] where 'before' is the older snapshot\n * and 'after' is the more recent snapshot (for differential analysis).\n * @returns [before, after] tuple where both are sorted chronologically, or [null, null] if fewer than 2 snapshots exist\n */\n async getLatestPair(): Promise<\n [AuditReport, AuditReport] | [null, null]\n > {\n const snapshots = await this.list();\n if (snapshots.length < 2) {\n return [null, null];\n }\n\n const [after, before] = await Promise.all([\n this.load(snapshots[0].id),\n this.load(snapshots[1].id),\n ]);\n\n return [before, after];\n }\n\n /**\n * Clean up old snapshots beyond the retention limit\n */\n private async cleanupOldSnapshots(): Promise<void> {\n const snapshots = await this.list();\n\n if (snapshots.length <= this.maxSnapshots) {\n return;\n }\n\n const toDelete = snapshots.slice(this.maxSnapshots);\n await Promise.all(toDelete.map((s) => this.delete(s.id)));\n }\n\n /**\n * Clear all snapshots\n */\n async clear(): Promise<void> {\n const snapshots = await this.list();\n await Promise.all(snapshots.map((s) => this.delete(s.id)));\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
function createPercentage(value) {
|
|
2
|
+
if (value < 0 || value > 100 || !Number.isFinite(value))
|
|
3
|
+
throw new Error(`Invalid percentage: ${value}. Must be a number between 0 and 100.`);
|
|
4
|
+
return value;
|
|
5
|
+
}
|
|
6
|
+
function gapImpactScore(priority) {
|
|
7
|
+
return { high: 85, medium: 55, low: 25 }[priority];
|
|
8
|
+
}
|
|
9
|
+
function duplicateImpactScore(confidence) {
|
|
10
|
+
return { high: 75, medium: 45, low: 20 }[confidence];
|
|
11
|
+
}
|
|
12
|
+
function recommendationImpactScore(priority) {
|
|
13
|
+
return gapImpactScore(priority);
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
createPercentage,
|
|
17
|
+
duplicateImpactScore,
|
|
18
|
+
gapImpactScore,
|
|
19
|
+
recommendationImpactScore
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/audit/types.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Type definitions for relationship audit system\n */\n\n/**\n * Percentage value constrained to 0-100 range\n * Use createPercentage() to construct safely\n */\nexport type Percentage = number & { readonly __brand: \"Percentage\" };\n\n/**\n * Create a validated percentage value (0-100)\n * @throws Error if value is not in valid range\n */\nexport function createPercentage(value: number): Percentage {\n if (value < 0 || value > 100 || !Number.isFinite(value)) {\n throw new Error(`Invalid percentage: ${value}. Must be a number between 0 and 100.`);\n }\n return value as Percentage;\n}\n\n/**\n * Coverage metrics for a layer\n */\nexport interface CoverageMetrics {\n readonly layer: string;\n readonly nodeTypeCount: number;\n /** Intra-layer relationship instances (both endpoints in this layer) */\n readonly relationshipCount: number;\n /** Outgoing cross-layer relationship instances (source in this layer, target in another) */\n readonly interLayerRelationshipCount: number;\n\n // Node isolation\n readonly isolatedNodeTypes: readonly string[]; // Zero relationships\n /** Percentage of node types with zero relationships (0-100) */\n readonly isolationPercentage: Percentage;\n\n // Predicate utilization\n readonly availablePredicates: readonly string[]; // Predicates applicable to this layer\n readonly usedPredicates: readonly string[]; // Actually used\n /** Percentage of available predicates actually used (0-100) */\n readonly utilizationPercentage: Percentage;\n\n // Density\n readonly relationshipsPerNodeType: number;\n\n // Standard alignment (for ArchiMate layers)\n readonly standardAlignment?: {\n readonly standard: string;\n readonly expectedRelationships: number;\n readonly missingFromStandard: readonly string[];\n };\n}\n\n/**\n * Semantic duplicate candidate\n */\nexport interface DuplicateCandidate {\n readonly relationships: readonly [string, string]; // IDs of duplicate pair\n readonly predicates: readonly [string, string]; // Predicate names\n readonly sourceNodeType: string;\n readonly destinationNodeType: string;\n readonly reason: string; // Explanation of semantic overlap\n readonly confidence: \"high\" | \"medium\" | \"low\";\n /** How necessary it is to clean up this duplicate (0\u2013100, higher = more urgent) */\n readonly impactScore: number;\n /** 100 - impactScore; aligns with NodeAIEvaluation.alignmentScore semantics (lower = more action needed) */\n readonly alignmentScore: number;\n}\n\n/**\n * Missing relationship gap candidate\n */\nexport interface GapCandidate {\n readonly sourceNodeType: string;\n readonly destinationNodeType: string;\n readonly suggestedPredicate: string;\n readonly reason: string;\n readonly priority: \"high\" | \"medium\" | \"low\";\n readonly standardReference?: string; // e.g., \"ArchiMate 3.2 \u00A75.2\"\n /** How necessary this gap is to fill (0\u2013100, higher = more urgent) */\n readonly impactScore: number;\n /** 100 - impactScore; aligns with NodeAIEvaluation.alignmentScore semantics (lower = more action needed) */\n readonly alignmentScore: number;\n}\n\n/**\n * Balance assessment for node type relationship density\n */\nexport interface BalanceAssessment {\n readonly nodeType: string;\n readonly layer: string;\n readonly category: \"structural\" | \"behavioral\" | \"enumeration\" | \"reference\";\n readonly currentCount: number;\n readonly targetRange: readonly [number, number];\n readonly status: \"under\" | \"balanced\" | \"over\";\n readonly recommendation?: string;\n}\n\n/**\n * Connected component in relationship graph\n */\nexport interface ConnectedComponent {\n readonly nodes: readonly string[];\n}\n\n/**\n * Node degree information\n */\nexport interface NodeDegree {\n readonly nodeType: string;\n readonly inDegree: number;\n readonly outDegree: number;\n readonly totalDegree: number;\n}\n\n/**\n * Transitive relationship chain\n */\nexport interface TransitiveChain {\n readonly predicate: string;\n readonly chain: readonly string[]; // Node types in chain\n}\n\n/**\n * Connectivity statistics summary\n */\nexport interface ConnectivityStats {\n readonly totalNodes: number;\n readonly totalEdges: number;\n readonly connectedComponents: number;\n readonly largestComponentSize: number;\n readonly isolatedNodes: number;\n readonly averageDegree: number;\n readonly transitiveChainCount: number;\n}\n\n/**\n * Comprehensive audit report combining all analysis results\n */\nexport interface AuditReport {\n readonly timestamp: string;\n readonly model: {\n readonly name: string;\n readonly version: string;\n };\n readonly coverage: readonly CoverageMetrics[];\n readonly duplicates: readonly DuplicateCandidate[];\n readonly gaps: readonly GapCandidate[];\n readonly balance: readonly BalanceAssessment[];\n readonly connectivity: {\n readonly components: readonly ConnectedComponent[];\n readonly degrees: readonly NodeDegree[];\n readonly transitiveChains: readonly TransitiveChain[];\n readonly stats: ConnectivityStats;\n };\n}\n\n/**\n * Summary report comparing before/after audit states\n */\nexport interface SummaryReport {\n readonly timestamp: string;\n readonly coverageChanges: readonly {\n readonly layer: string;\n readonly before: { readonly isolation: number; readonly density: number };\n readonly after: { readonly isolation: number; readonly density: number };\n readonly delta: { readonly isolation: number; readonly density: number };\n }[];\n readonly relationshipsAdded: number;\n readonly gapsResolved: number;\n readonly remainingGaps: number;\n readonly duplicatesResolved: number;\n readonly balanceImprovements: readonly string[];\n}\n\n/**\n * Layer-specific aggregated data\n */\nexport interface LayerData {\n readonly layer: string;\n readonly coverage: CoverageMetrics;\n readonly duplicates: readonly DuplicateCandidate[];\n readonly gaps: readonly GapCandidate[];\n readonly balance: readonly BalanceAssessment[];\n}\n\n// ---------------------------------------------------------------------------\n// Score helpers \u2014 shared by all gap/duplicate analyzers\n// ---------------------------------------------------------------------------\n\n/**\n * Impact score for a gap (missing relationship).\n * Higher = more urgently needed. Maps directly to priority.\n */\nexport function gapImpactScore(priority: \"high\" | \"medium\" | \"low\"): number {\n const scores: Record<\"high\" | \"medium\" | \"low\", number> = { high: 85, medium: 55, low: 25 };\n return scores[priority];\n}\n\n/**\n * Impact score for a duplicate candidate.\n * Higher = more confident it should be removed. Maps directly to confidence.\n */\nexport function duplicateImpactScore(confidence: \"high\" | \"medium\" | \"low\"): number {\n const scores: Record<\"high\" | \"medium\" | \"low\", number> = { high: 75, medium: 45, low: 20 };\n return scores[confidence];\n}\n\n/**\n * Impact score for an AI relationship recommendation.\n * Same scale as gap scores \u2014 recommendations describe missing relationships.\n */\nexport function recommendationImpactScore(priority: \"high\" | \"medium\" | \"low\"): number {\n return gapImpactScore(priority);\n}\n"],
|
|
5
|
+
"mappings": "AAcM,SAAU,iBAAiB,OAAa;AAC5C,MAAI,QAAQ,KAAK,QAAQ,OAAO,CAAC,OAAO,SAAS,KAAK;AACpD,UAAM,IAAI,MAAM,uBAAuB,KAAK,uCAAuC;AAErF,SAAO;AACT;AAgLM,SAAU,eAAe,UAAmC;AAEhE,SAD0D,EAAE,MAAM,IAAI,QAAQ,IAAI,KAAK,GAAE,EAC3E,QAAQ;AACxB;AAMM,SAAU,qBAAqB,YAAqC;AAExE,SAD0D,EAAE,MAAM,IAAI,QAAQ,IAAI,KAAK,GAAE,EAC3E,UAAU;AAC1B;AAMM,SAAU,0BAA0B,UAAmC;AAC3E,SAAO,eAAe,QAAQ;AAChC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|