@documentation-robotics/cli 0.1.0 → 0.1.5
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 +206 -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 +155 -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 +37 -13
- 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,183 @@
|
|
|
1
|
+
class DifferentialAnalyzer {
|
|
2
|
+
/**
|
|
3
|
+
* Compare two audit reports
|
|
4
|
+
*/
|
|
5
|
+
analyze(before, after) {
|
|
6
|
+
const { comparison: coverageComparison, skipped: skippedLayers } = this.analyzeCoverage(before.coverage, after.coverage), gapChanges = this.analyzeGaps(before.gaps, after.gaps), duplicateChanges = this.analyzeDuplicates(before.duplicates, after.duplicates), balanceChanges = this.analyzeBalance(before.balance, after.balance), connectivityChanges = this.analyzeConnectivity(before.connectivity, after.connectivity);
|
|
7
|
+
return {
|
|
8
|
+
summary: this.generateSummary(after.timestamp, coverageComparison, gapChanges, duplicateChanges, balanceChanges),
|
|
9
|
+
detailed: {
|
|
10
|
+
coverageByLayer: coverageComparison,
|
|
11
|
+
gapChanges,
|
|
12
|
+
duplicateChanges,
|
|
13
|
+
balanceChanges,
|
|
14
|
+
connectivityChanges,
|
|
15
|
+
skippedLayers
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Analyze coverage changes across layers
|
|
21
|
+
*/
|
|
22
|
+
analyzeCoverage(before, after) {
|
|
23
|
+
const comparison = /* @__PURE__ */ new Map(), skipped = [], beforeMap = new Map(before.map((c) => [c.layer, c])), afterMap = new Map(after.map((c) => [c.layer, c]));
|
|
24
|
+
for (const beforeCoverage of before)
|
|
25
|
+
afterMap.has(beforeCoverage.layer) || skipped.push({
|
|
26
|
+
layer: beforeCoverage.layer,
|
|
27
|
+
reason: "only-in-before",
|
|
28
|
+
coverage: beforeCoverage
|
|
29
|
+
});
|
|
30
|
+
for (const afterCoverage of after) {
|
|
31
|
+
const beforeCoverage = beforeMap.get(afterCoverage.layer);
|
|
32
|
+
if (!beforeCoverage) {
|
|
33
|
+
skipped.push({
|
|
34
|
+
layer: afterCoverage.layer,
|
|
35
|
+
reason: "only-in-after",
|
|
36
|
+
coverage: afterCoverage
|
|
37
|
+
});
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const deltas = {
|
|
41
|
+
isolationChange: afterCoverage.isolationPercentage - beforeCoverage.isolationPercentage,
|
|
42
|
+
densityChange: afterCoverage.relationshipsPerNodeType - beforeCoverage.relationshipsPerNodeType,
|
|
43
|
+
utilizationChange: afterCoverage.utilizationPercentage - beforeCoverage.utilizationPercentage,
|
|
44
|
+
nodeTypeCountChange: afterCoverage.nodeTypeCount - beforeCoverage.nodeTypeCount,
|
|
45
|
+
relationshipCountChange: afterCoverage.relationshipCount - beforeCoverage.relationshipCount
|
|
46
|
+
}, improvements = [], regressions = [];
|
|
47
|
+
deltas.isolationChange < -5 ? improvements.push(`Isolation reduced by ${Math.abs(deltas.isolationChange).toFixed(1)}%`) : deltas.isolationChange > 5 && regressions.push(`Isolation increased by ${deltas.isolationChange.toFixed(1)}%`), deltas.densityChange > 0.5 ? improvements.push(`Density increased by ${deltas.densityChange.toFixed(2)}`) : deltas.densityChange < -0.5 && regressions.push(`Density decreased by ${Math.abs(deltas.densityChange).toFixed(2)}`), deltas.utilizationChange > 5 ? improvements.push(`Predicate utilization increased by ${deltas.utilizationChange.toFixed(1)}%`) : deltas.utilizationChange < -5 && regressions.push(`Predicate utilization decreased by ${Math.abs(deltas.utilizationChange).toFixed(1)}%`), comparison.set(afterCoverage.layer, {
|
|
48
|
+
layer: afterCoverage.layer,
|
|
49
|
+
before: beforeCoverage,
|
|
50
|
+
after: afterCoverage,
|
|
51
|
+
deltas,
|
|
52
|
+
improvements,
|
|
53
|
+
regressions
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return { comparison, skipped };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Analyze gap changes
|
|
60
|
+
*/
|
|
61
|
+
analyzeGaps(before, after) {
|
|
62
|
+
const beforeSigs = new Set(before.map((g) => this.gapSignature(g))), afterSigs = new Set(after.map((g) => this.gapSignature(g))), resolved = before.filter((g) => !afterSigs.has(this.gapSignature(g))), newGaps = after.filter((g) => !beforeSigs.has(this.gapSignature(g))), persistent = after.filter((g) => beforeSigs.has(this.gapSignature(g))), resolutionRate = before.length > 0 ? resolved.length / before.length * 100 : 0;
|
|
63
|
+
return {
|
|
64
|
+
before,
|
|
65
|
+
after,
|
|
66
|
+
resolved,
|
|
67
|
+
newGaps,
|
|
68
|
+
persistent,
|
|
69
|
+
resolutionRate
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Generate gap signature for comparison
|
|
74
|
+
*/
|
|
75
|
+
gapSignature(gap) {
|
|
76
|
+
return `${gap.sourceNodeType}:${gap.destinationNodeType}:${gap.suggestedPredicate}`;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Analyze duplicate changes
|
|
80
|
+
*/
|
|
81
|
+
analyzeDuplicates(before, after) {
|
|
82
|
+
const beforeSigs = new Set(before.map((d) => this.duplicateSignature(d))), afterSigs = new Set(after.map((d) => this.duplicateSignature(d))), resolved = before.filter((d) => !afterSigs.has(this.duplicateSignature(d))), newDuplicates = after.filter((d) => !beforeSigs.has(this.duplicateSignature(d))), persistent = after.filter((d) => beforeSigs.has(this.duplicateSignature(d))), eliminationRate = before.length > 0 ? resolved.length / before.length * 100 : 0;
|
|
83
|
+
return {
|
|
84
|
+
before,
|
|
85
|
+
after,
|
|
86
|
+
resolved,
|
|
87
|
+
newDuplicates,
|
|
88
|
+
persistent,
|
|
89
|
+
eliminationRate
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Generate duplicate signature for comparison
|
|
94
|
+
*/
|
|
95
|
+
duplicateSignature(dup) {
|
|
96
|
+
const sorted = [...dup.relationships].sort();
|
|
97
|
+
return `${sorted[0]}:${sorted[1]}`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Analyze balance changes
|
|
101
|
+
*/
|
|
102
|
+
analyzeBalance(before, after) {
|
|
103
|
+
const beforeMap = new Map(before.map((b) => [b.nodeType, b])), improvements = [], regressions = [], newlyBalanced = [];
|
|
104
|
+
for (const afterAssessment of after) {
|
|
105
|
+
const beforeAssessment = beforeMap.get(afterAssessment.nodeType);
|
|
106
|
+
if (!beforeAssessment)
|
|
107
|
+
continue;
|
|
108
|
+
const beforeDistance = this.distanceFromBalance(beforeAssessment), afterDistance = this.distanceFromBalance(afterAssessment);
|
|
109
|
+
afterDistance < beforeDistance ? improvements.push(afterAssessment) : afterDistance > beforeDistance && regressions.push(afterAssessment), beforeAssessment.status !== "balanced" && afterAssessment.status === "balanced" && newlyBalanced.push(afterAssessment);
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
before,
|
|
113
|
+
after,
|
|
114
|
+
improvements,
|
|
115
|
+
regressions,
|
|
116
|
+
newlyBalanced
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Calculate distance from balanced state
|
|
121
|
+
*/
|
|
122
|
+
distanceFromBalance(assessment) {
|
|
123
|
+
const [min, max] = assessment.targetRange, target = (min + max) / 2;
|
|
124
|
+
return Math.abs(assessment.currentCount - target);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Analyze connectivity changes
|
|
128
|
+
*/
|
|
129
|
+
analyzeConnectivity(before, after) {
|
|
130
|
+
const beforeStats = {
|
|
131
|
+
componentCount: before.components.length,
|
|
132
|
+
isolatedNodes: before.stats.isolatedNodes,
|
|
133
|
+
averageDegree: before.stats.averageDegree
|
|
134
|
+
}, afterStats = {
|
|
135
|
+
componentCount: after.components.length,
|
|
136
|
+
isolatedNodes: after.stats.isolatedNodes,
|
|
137
|
+
averageDegree: after.stats.averageDegree
|
|
138
|
+
};
|
|
139
|
+
return {
|
|
140
|
+
before: beforeStats,
|
|
141
|
+
after: afterStats,
|
|
142
|
+
deltas: {
|
|
143
|
+
componentChange: afterStats.componentCount - beforeStats.componentCount,
|
|
144
|
+
isolationChange: afterStats.isolatedNodes - beforeStats.isolatedNodes,
|
|
145
|
+
degreeChange: afterStats.averageDegree - beforeStats.averageDegree
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Generate summary report
|
|
151
|
+
*/
|
|
152
|
+
generateSummary(timestamp, coverageComparison, gapChanges, duplicateChanges, balanceChanges) {
|
|
153
|
+
const coverageChanges = Array.from(coverageComparison.values()).map((comp) => ({
|
|
154
|
+
layer: comp.layer,
|
|
155
|
+
before: {
|
|
156
|
+
isolation: comp.before.isolationPercentage,
|
|
157
|
+
density: comp.before.relationshipsPerNodeType
|
|
158
|
+
},
|
|
159
|
+
after: {
|
|
160
|
+
isolation: comp.after.isolationPercentage,
|
|
161
|
+
density: comp.after.relationshipsPerNodeType
|
|
162
|
+
},
|
|
163
|
+
delta: {
|
|
164
|
+
isolation: comp.deltas.isolationChange,
|
|
165
|
+
density: comp.deltas.densityChange
|
|
166
|
+
}
|
|
167
|
+
})), relationshipsAdded = Array.from(coverageComparison.values()).reduce((sum, comp) => sum + comp.deltas.relationshipCountChange, 0), balanceImprovements = balanceChanges.newlyBalanced.map((b) => `${b.nodeType} achieved balanced density (${b.currentCount} relationships)`);
|
|
168
|
+
return {
|
|
169
|
+
timestamp,
|
|
170
|
+
coverageChanges,
|
|
171
|
+
relationshipsAdded: Math.max(0, relationshipsAdded),
|
|
172
|
+
// Only count additions
|
|
173
|
+
gapsResolved: gapChanges.resolved.length,
|
|
174
|
+
remainingGaps: gapChanges.after.length,
|
|
175
|
+
duplicatesResolved: duplicateChanges.resolved.length,
|
|
176
|
+
balanceImprovements
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
export {
|
|
181
|
+
DifferentialAnalyzer
|
|
182
|
+
};
|
|
183
|
+
//# sourceMappingURL=differential-analyzer.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/audit/differential-analyzer.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Differential analysis for before/after audit comparison\n *\n * Analyzes changes between two audit snapshots to identify\n * improvements, regressions, and trends in relationship quality.\n */\n\nimport {\n AuditReport,\n SummaryReport,\n CoverageMetrics,\n GapCandidate,\n DuplicateCandidate,\n BalanceAssessment,\n} from \"./types.js\";\n\n/**\n * Detailed differential analysis result\n */\nexport interface DifferentialAnalysis {\n summary: SummaryReport;\n detailed: {\n coverageByLayer: Map<string, CoverageComparison>;\n gapChanges: GapChanges;\n duplicateChanges: DuplicateChanges;\n balanceChanges: BalanceChanges;\n connectivityChanges: ConnectivityComparison;\n skippedLayers: SkippedLayer[]; // Layers that couldn't be compared\n };\n}\n\n/**\n * Information about a layer that was skipped during comparison\n */\nexport interface SkippedLayer {\n layer: string;\n reason: \"only-in-before\" | \"only-in-after\";\n coverage?: CoverageMetrics; // Coverage metrics if available\n}\n\n/**\n * Coverage comparison for a single layer\n */\nexport interface CoverageComparison {\n layer: string;\n before: CoverageMetrics;\n after: CoverageMetrics;\n deltas: {\n isolationChange: number; // Negative = improvement\n densityChange: number; // Positive = improvement\n utilizationChange: number; // Positive = improvement\n nodeTypeCountChange: number;\n relationshipCountChange: number;\n };\n improvements: string[];\n regressions: string[];\n}\n\n/**\n * Gap analysis changes\n */\nexport interface GapChanges {\n before: GapCandidate[];\n after: GapCandidate[];\n resolved: GapCandidate[]; // Gaps that disappeared\n newGaps: GapCandidate[]; // New gaps introduced\n persistent: GapCandidate[]; // Gaps still present\n /** Percentage of gaps resolved (0-100) */\n resolutionRate: number;\n}\n\n/**\n * Duplicate analysis changes\n */\nexport interface DuplicateChanges {\n before: DuplicateCandidate[];\n after: DuplicateCandidate[];\n resolved: DuplicateCandidate[]; // Duplicates eliminated\n newDuplicates: DuplicateCandidate[]; // New duplicates introduced\n persistent: DuplicateCandidate[]; // Still duplicated\n /** Percentage of duplicates eliminated (0-100) */\n eliminationRate: number;\n}\n\n/**\n * Balance assessment changes\n */\nexport interface BalanceChanges {\n before: BalanceAssessment[];\n after: BalanceAssessment[];\n improvements: BalanceAssessment[]; // Moved toward balanced\n regressions: BalanceAssessment[]; // Moved away from balanced\n newlyBalanced: BalanceAssessment[]; // Achieved balanced status\n}\n\n/**\n * Connectivity comparison\n */\nexport interface ConnectivityComparison {\n before: {\n componentCount: number;\n isolatedNodes: number;\n averageDegree: number;\n };\n after: {\n componentCount: number;\n isolatedNodes: number;\n averageDegree: number;\n };\n deltas: {\n componentChange: number; // Negative = more connected\n isolationChange: number; // Negative = improvement\n degreeChange: number; // Positive = more connected\n };\n}\n\n/**\n * Analyzer for comparing audit snapshots\n */\nexport class DifferentialAnalyzer {\n /**\n * Compare two audit reports\n */\n analyze(before: AuditReport, after: AuditReport): DifferentialAnalysis {\n const { comparison: coverageComparison, skipped: skippedLayers } =\n this.analyzeCoverage(before.coverage as CoverageMetrics[], after.coverage as CoverageMetrics[]);\n const gapChanges = this.analyzeGaps(before.gaps as GapCandidate[], after.gaps as GapCandidate[]);\n const duplicateChanges = this.analyzeDuplicates(\n before.duplicates as DuplicateCandidate[],\n after.duplicates as DuplicateCandidate[],\n );\n const balanceChanges = this.analyzeBalance(before.balance as BalanceAssessment[], after.balance as BalanceAssessment[]);\n const connectivityChanges = this.analyzeConnectivity(\n before.connectivity,\n after.connectivity,\n );\n\n const summary = this.generateSummary(\n after.timestamp,\n coverageComparison,\n gapChanges,\n duplicateChanges,\n balanceChanges,\n );\n\n return {\n summary,\n detailed: {\n coverageByLayer: coverageComparison,\n gapChanges,\n duplicateChanges,\n balanceChanges,\n connectivityChanges,\n skippedLayers,\n },\n };\n }\n\n /**\n * Analyze coverage changes across layers\n */\n private analyzeCoverage(\n before: CoverageMetrics[],\n after: CoverageMetrics[],\n ): {\n comparison: Map<string, CoverageComparison>;\n skipped: SkippedLayer[];\n } {\n const comparison = new Map<string, CoverageComparison>();\n const skipped: SkippedLayer[] = [];\n\n // Create lookup maps for before and after states\n const beforeMap = new Map(before.map((c) => [c.layer, c]));\n const afterMap = new Map(after.map((c) => [c.layer, c]));\n\n // Check for layers only in \"before\"\n for (const beforeCoverage of before) {\n if (!afterMap.has(beforeCoverage.layer)) {\n skipped.push({\n layer: beforeCoverage.layer,\n reason: \"only-in-before\",\n coverage: beforeCoverage,\n });\n }\n }\n\n for (const afterCoverage of after) {\n const beforeCoverage = beforeMap.get(afterCoverage.layer);\n if (!beforeCoverage) {\n // New layer in after state - track as skipped\n skipped.push({\n layer: afterCoverage.layer,\n reason: \"only-in-after\",\n coverage: afterCoverage,\n });\n continue;\n }\n\n const deltas = {\n isolationChange:\n afterCoverage.isolationPercentage -\n beforeCoverage.isolationPercentage,\n densityChange:\n afterCoverage.relationshipsPerNodeType -\n beforeCoverage.relationshipsPerNodeType,\n utilizationChange:\n afterCoverage.utilizationPercentage -\n beforeCoverage.utilizationPercentage,\n nodeTypeCountChange:\n afterCoverage.nodeTypeCount - beforeCoverage.nodeTypeCount,\n relationshipCountChange:\n afterCoverage.relationshipCount - beforeCoverage.relationshipCount,\n };\n\n const improvements: string[] = [];\n const regressions: string[] = [];\n\n // Analyze changes\n if (deltas.isolationChange < -5) {\n improvements.push(\n `Isolation reduced by ${Math.abs(deltas.isolationChange).toFixed(1)}%`,\n );\n } else if (deltas.isolationChange > 5) {\n regressions.push(\n `Isolation increased by ${deltas.isolationChange.toFixed(1)}%`,\n );\n }\n\n if (deltas.densityChange > 0.5) {\n improvements.push(\n `Density increased by ${deltas.densityChange.toFixed(2)}`,\n );\n } else if (deltas.densityChange < -0.5) {\n regressions.push(\n `Density decreased by ${Math.abs(deltas.densityChange).toFixed(2)}`,\n );\n }\n\n if (deltas.utilizationChange > 5) {\n improvements.push(\n `Predicate utilization increased by ${deltas.utilizationChange.toFixed(1)}%`,\n );\n } else if (deltas.utilizationChange < -5) {\n regressions.push(\n `Predicate utilization decreased by ${Math.abs(deltas.utilizationChange).toFixed(1)}%`,\n );\n }\n\n comparison.set(afterCoverage.layer, {\n layer: afterCoverage.layer,\n before: beforeCoverage,\n after: afterCoverage,\n deltas,\n improvements,\n regressions,\n });\n }\n\n return { comparison, skipped };\n }\n\n /**\n * Analyze gap changes\n */\n private analyzeGaps(\n before: GapCandidate[],\n after: GapCandidate[],\n ): GapChanges {\n // Create gap signatures for comparison\n const beforeSigs = new Set(\n before.map((g) => this.gapSignature(g)),\n );\n const afterSigs = new Set(after.map((g) => this.gapSignature(g)));\n\n const resolved = before.filter(\n (g) => !afterSigs.has(this.gapSignature(g)),\n );\n const newGaps = after.filter(\n (g) => !beforeSigs.has(this.gapSignature(g)),\n );\n const persistent = after.filter((g) =>\n beforeSigs.has(this.gapSignature(g)),\n );\n\n const resolutionRate =\n before.length > 0 ? (resolved.length / before.length) * 100 : 0;\n\n return {\n before,\n after,\n resolved,\n newGaps,\n persistent,\n resolutionRate,\n };\n }\n\n /**\n * Generate gap signature for comparison\n */\n private gapSignature(gap: GapCandidate): string {\n return `${gap.sourceNodeType}:${gap.destinationNodeType}:${gap.suggestedPredicate}`;\n }\n\n /**\n * Analyze duplicate changes\n */\n private analyzeDuplicates(\n before: DuplicateCandidate[],\n after: DuplicateCandidate[],\n ): DuplicateChanges {\n const beforeSigs = new Set(\n before.map((d) => this.duplicateSignature(d)),\n );\n const afterSigs = new Set(\n after.map((d) => this.duplicateSignature(d)),\n );\n\n const resolved = before.filter(\n (d) => !afterSigs.has(this.duplicateSignature(d)),\n );\n const newDuplicates = after.filter(\n (d) => !beforeSigs.has(this.duplicateSignature(d)),\n );\n const persistent = after.filter((d) =>\n beforeSigs.has(this.duplicateSignature(d)),\n );\n\n const eliminationRate =\n before.length > 0 ? (resolved.length / before.length) * 100 : 0;\n\n return {\n before,\n after,\n resolved,\n newDuplicates,\n persistent,\n eliminationRate,\n };\n }\n\n /**\n * Generate duplicate signature for comparison\n */\n private duplicateSignature(dup: DuplicateCandidate): string {\n // Sort relationship IDs for consistent comparison\n const sorted = [...dup.relationships].sort();\n return `${sorted[0]}:${sorted[1]}`;\n }\n\n /**\n * Analyze balance changes\n */\n private analyzeBalance(\n before: BalanceAssessment[],\n after: BalanceAssessment[],\n ): BalanceChanges {\n const beforeMap = new Map(before.map((b) => [b.nodeType, b]));\n\n const improvements: BalanceAssessment[] = [];\n const regressions: BalanceAssessment[] = [];\n const newlyBalanced: BalanceAssessment[] = [];\n\n for (const afterAssessment of after) {\n const beforeAssessment = beforeMap.get(afterAssessment.nodeType);\n if (!beforeAssessment) {\n continue;\n }\n\n // Check if moved toward balanced\n const beforeDistance = this.distanceFromBalance(beforeAssessment);\n const afterDistance = this.distanceFromBalance(afterAssessment);\n\n if (afterDistance < beforeDistance) {\n improvements.push(afterAssessment);\n } else if (afterDistance > beforeDistance) {\n regressions.push(afterAssessment);\n }\n\n // Check if newly balanced\n if (\n beforeAssessment.status !== \"balanced\" &&\n afterAssessment.status === \"balanced\"\n ) {\n newlyBalanced.push(afterAssessment);\n }\n }\n\n return {\n before,\n after,\n improvements,\n regressions,\n newlyBalanced,\n };\n }\n\n /**\n * Calculate distance from balanced state\n */\n private distanceFromBalance(assessment: BalanceAssessment): number {\n const [min, max] = assessment.targetRange;\n const target = (min + max) / 2;\n return Math.abs(assessment.currentCount - target);\n }\n\n /**\n * Analyze connectivity changes\n */\n private analyzeConnectivity(\n before: AuditReport[\"connectivity\"],\n after: AuditReport[\"connectivity\"],\n ): ConnectivityComparison {\n const beforeStats = {\n componentCount: before.components.length,\n isolatedNodes: before.stats.isolatedNodes,\n averageDegree: before.stats.averageDegree,\n };\n\n const afterStats = {\n componentCount: after.components.length,\n isolatedNodes: after.stats.isolatedNodes,\n averageDegree: after.stats.averageDegree,\n };\n\n return {\n before: beforeStats,\n after: afterStats,\n deltas: {\n componentChange: afterStats.componentCount - beforeStats.componentCount,\n isolationChange: afterStats.isolatedNodes - beforeStats.isolatedNodes,\n degreeChange: afterStats.averageDegree - beforeStats.averageDegree,\n },\n };\n }\n\n /**\n * Generate summary report\n */\n private generateSummary(\n timestamp: string,\n coverageComparison: Map<string, CoverageComparison>,\n gapChanges: GapChanges,\n duplicateChanges: DuplicateChanges,\n balanceChanges: BalanceChanges,\n ): SummaryReport {\n const coverageChanges = Array.from(coverageComparison.values()).map(\n (comp) => ({\n layer: comp.layer,\n before: {\n isolation: comp.before.isolationPercentage,\n density: comp.before.relationshipsPerNodeType,\n },\n after: {\n isolation: comp.after.isolationPercentage,\n density: comp.after.relationshipsPerNodeType,\n },\n delta: {\n isolation: comp.deltas.isolationChange,\n density: comp.deltas.densityChange,\n },\n }),\n );\n\n // Calculate total relationships added\n const relationshipsAdded = Array.from(coverageComparison.values()).reduce(\n (sum, comp) => sum + comp.deltas.relationshipCountChange,\n 0,\n );\n\n // Generate balance improvement descriptions\n const balanceImprovements = balanceChanges.newlyBalanced.map(\n (b) => `${b.nodeType} achieved balanced density (${b.currentCount} relationships)`,\n );\n\n return {\n timestamp,\n coverageChanges,\n relationshipsAdded: Math.max(0, relationshipsAdded), // Only count additions\n gapsResolved: gapChanges.resolved.length,\n remainingGaps: gapChanges.after.length,\n duplicatesResolved: duplicateChanges.resolved.length,\n balanceImprovements,\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CoverageAnalyzer } from "./relationships/analysis/coverage-analyzer.js";
|
|
2
|
+
import { DuplicateDetector } from "./relationships/analysis/duplicate-detector.js";
|
|
3
|
+
import { GapAnalyzer } from "./relationships/analysis/gap-analyzer.js";
|
|
4
|
+
import { BalanceAssessor } from "./relationships/analysis/balance-assessor.js";
|
|
5
|
+
import { RelationshipGraph } from "./relationships/graph/relationship-graph.js";
|
|
6
|
+
import { ConnectivityAnalyzer } from "./relationships/graph/connectivity.js";
|
|
7
|
+
import { SnapshotStorage } from "./snapshot-storage.js";
|
|
8
|
+
import { DifferentialAnalyzer } from "./differential-analyzer.js";
|
|
9
|
+
import { AuditAIRunner } from "./ai/runner.js";
|
|
10
|
+
import { PromptTemplates } from "./relationships/ai/prompts.js";
|
|
11
|
+
import { ResponseParser } from "./relationships/ai/parser.js";
|
|
12
|
+
import { AIEvaluator, InMemoryProgressTracker } from "./relationships/ai/evaluator.js";
|
|
13
|
+
import { AuditOrchestrator } from "./relationships/spec/orchestrator.js";
|
|
14
|
+
import { ModelAuditOrchestrator } from "./relationships/model/orchestrator.js";
|
|
15
|
+
export {
|
|
16
|
+
AIEvaluator,
|
|
17
|
+
AuditAIRunner,
|
|
18
|
+
AuditOrchestrator,
|
|
19
|
+
BalanceAssessor,
|
|
20
|
+
ConnectivityAnalyzer,
|
|
21
|
+
CoverageAnalyzer,
|
|
22
|
+
DifferentialAnalyzer,
|
|
23
|
+
DuplicateDetector,
|
|
24
|
+
GapAnalyzer,
|
|
25
|
+
InMemoryProgressTracker,
|
|
26
|
+
ModelAuditOrchestrator,
|
|
27
|
+
PromptTemplates,
|
|
28
|
+
RelationshipGraph,
|
|
29
|
+
ResponseParser,
|
|
30
|
+
SnapshotStorage
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/audit/index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Relationship Audit System - Public API\n *\n * Exports all audit analysis components and types.\n */\n\n// Type definitions\nexport type {\n CoverageMetrics,\n DuplicateCandidate,\n GapCandidate,\n BalanceAssessment,\n ConnectedComponent,\n NodeDegree,\n TransitiveChain,\n SummaryReport,\n AuditReport,\n ConnectivityStats,\n LayerData,\n} from \"./types.js\";\n\n// Analysis components\nexport { CoverageAnalyzer } from \"./relationships/analysis/coverage-analyzer.js\";\nexport { DuplicateDetector } from \"./relationships/analysis/duplicate-detector.js\";\nexport { GapAnalyzer } from \"./relationships/analysis/gap-analyzer.js\";\nexport type { GapAnalysisResult } from \"./relationships/analysis/gap-analyzer.js\";\nexport { BalanceAssessor } from \"./relationships/analysis/balance-assessor.js\";\n\n// Graph components\nexport { RelationshipGraph } from \"./relationships/graph/relationship-graph.js\";\nexport { ConnectivityAnalyzer } from \"./relationships/graph/connectivity.js\";\n\n// Snapshot and differential analysis components\nexport { SnapshotStorage } from \"./snapshot-storage.js\";\nexport type { SnapshotMetadata, SnapshotStorageConfig } from \"./snapshot-storage.js\";\nexport { DifferentialAnalyzer } from \"./differential-analyzer.js\";\nexport type {\n DifferentialAnalysis,\n CoverageComparison,\n GapChanges,\n DuplicateChanges,\n BalanceChanges,\n ConnectivityComparison,\n SkippedLayer,\n} from \"./differential-analyzer.js\";\n\n// AI evaluation components\nexport { AuditAIRunner } from \"./ai/runner.js\";\nexport { PromptTemplates } from \"./relationships/ai/prompts.js\";\nexport { ResponseParser } from \"./relationships/ai/parser.js\";\nexport type {\n RelationshipRecommendation,\n LayerReview,\n InterLayerValidation,\n} from \"./relationships/ai/parser.js\";\nexport { AIEvaluator, InMemoryProgressTracker } from \"./relationships/ai/evaluator.js\";\nexport type { ProgressTracker, AIEvaluationConfig } from \"./relationships/ai/evaluator.js\";\n\n// Spec relationship orchestrator\nexport { AuditOrchestrator } from \"./relationships/spec/orchestrator.js\";\nexport type { AuditOptions, AuditComponents } from \"./relationships/spec/orchestrator.js\";\n\n// Model relationship orchestrator\nexport { ModelAuditOrchestrator } from \"./relationships/model/orchestrator.js\";\nexport type { ModelAuditOptions } from \"./relationships/model/orchestrator.js\";\n"],
|
|
5
|
+
"mappings": "AAsBA,SAAS,wBAAwB;AACjC,SAAS,yBAAyB;AAClC,SAAS,mBAAmB;AAE5B,SAAS,uBAAuB;AAGhC,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AAGrC,SAAS,uBAAuB;AAEhC,SAAS,4BAA4B;AAYrC,SAAS,qBAAqB;AAC9B,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAM/B,SAAS,aAAa,+BAA+B;AAIrD,SAAS,yBAAyB;AAIlC,SAAS,8BAA8B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { NodePromptTemplates } from "./prompts.js";
|
|
2
|
+
import { NodeResponseParser } from "./parser.js";
|
|
3
|
+
import { AuditAIRunner, AIEvaluationAbortError } from "../../ai/runner.js";
|
|
4
|
+
import { getErrorMessage } from "../../../utils/errors.js";
|
|
5
|
+
const INVOKE_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
6
|
+
class NodeAIEvaluator {
|
|
7
|
+
runner;
|
|
8
|
+
promptTemplates;
|
|
9
|
+
responseParser;
|
|
10
|
+
constructor() {
|
|
11
|
+
this.runner = new AuditAIRunner(), this.promptTemplates = new NodePromptTemplates(), this.responseParser = new NodeResponseParser();
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Evaluate each layer sequentially, returning one LayerAIReview per layer.
|
|
15
|
+
* Layers with zero schemas are skipped.
|
|
16
|
+
* Fails fast after maxConsecutiveFailures consecutive Claude invocation failures.
|
|
17
|
+
*/
|
|
18
|
+
async evaluateLayers(layerDefs, schemasByLayer) {
|
|
19
|
+
const reviews = [];
|
|
20
|
+
for (const layerDef of layerDefs) {
|
|
21
|
+
const schemas = schemasByLayer.get(layerDef.id) ?? [];
|
|
22
|
+
if (schemas.length === 0)
|
|
23
|
+
continue;
|
|
24
|
+
const standard = layerDef.inspiredBy ? `${layerDef.inspiredBy.standard} ${layerDef.inspiredBy.version}` : this.promptTemplates.getFallbackStandard(layerDef.id);
|
|
25
|
+
process.stderr.write(` Evaluating layer: ${layerDef.id} (${schemas.length} node types)...
|
|
26
|
+
`);
|
|
27
|
+
try {
|
|
28
|
+
const prompt = this.promptTemplates.layerEvaluation({ layerDef, schemas }), response = await this.runner.invoke(prompt, `layer: ${layerDef.id}`, INVOKE_TIMEOUT_MS), nodeEvaluations = this.responseParser.parseLayerEvaluation(response), avgAlignmentScore = nodeEvaluations.length > 0 ? nodeEvaluations.reduce((sum, e) => sum + e.alignmentScore, 0) / nodeEvaluations.length : 0, avgDocumentationScore = nodeEvaluations.length > 0 ? nodeEvaluations.reduce((sum, e) => sum + e.documentationScore, 0) / nodeEvaluations.length : 0;
|
|
29
|
+
reviews.push({
|
|
30
|
+
layerId: layerDef.id,
|
|
31
|
+
standard,
|
|
32
|
+
nodeEvaluations,
|
|
33
|
+
avgAlignmentScore: Math.round(avgAlignmentScore * 10) / 10,
|
|
34
|
+
avgDocumentationScore: Math.round(avgDocumentationScore * 10) / 10
|
|
35
|
+
});
|
|
36
|
+
} catch (error) {
|
|
37
|
+
const msg = getErrorMessage(error);
|
|
38
|
+
if (process.stderr.write(` \u26A0\uFE0F Failed to evaluate layer ${layerDef.id}: ${msg}
|
|
39
|
+
`), error instanceof AIEvaluationAbortError)
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return reviews;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
NodeAIEvaluator
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=evaluator.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/audit/nodes/ai/evaluator.ts"],
|
|
4
|
+
"sourcesContent": ["import type { LayerDefinition, ParsedNodeSchema, LayerAIReview } from \"../types.js\";\nimport { NodePromptTemplates } from \"./prompts.js\";\nimport { NodeResponseParser } from \"./parser.js\";\nimport { AuditAIRunner, AIEvaluationAbortError } from \"../../ai/runner.js\";\nimport { getErrorMessage } from \"../../../utils/errors.js\";\n\nconst INVOKE_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes per invocation\n\nexport class NodeAIEvaluator {\n private readonly runner: AuditAIRunner;\n private readonly promptTemplates: NodePromptTemplates;\n private readonly responseParser: NodeResponseParser;\n\n constructor() {\n this.runner = new AuditAIRunner();\n this.promptTemplates = new NodePromptTemplates();\n this.responseParser = new NodeResponseParser();\n }\n\n /**\n * Evaluate each layer sequentially, returning one LayerAIReview per layer.\n * Layers with zero schemas are skipped.\n * Fails fast after maxConsecutiveFailures consecutive Claude invocation failures.\n */\n async evaluateLayers(\n layerDefs: LayerDefinition[],\n schemasByLayer: Map<string, ParsedNodeSchema[]>\n ): Promise<LayerAIReview[]> {\n const reviews: LayerAIReview[] = [];\n\n for (const layerDef of layerDefs) {\n const schemas = schemasByLayer.get(layerDef.id) ?? [];\n if (schemas.length === 0) {\n continue;\n }\n\n const standard = layerDef.inspiredBy\n ? `${layerDef.inspiredBy.standard} ${layerDef.inspiredBy.version}`\n : this.promptTemplates.getFallbackStandard(layerDef.id);\n\n process.stderr.write(` Evaluating layer: ${layerDef.id} (${schemas.length} node types)...\\n`);\n\n try {\n const prompt = this.promptTemplates.layerEvaluation({ layerDef, schemas });\n const response = await this.runner.invoke(prompt, `layer: ${layerDef.id}`, INVOKE_TIMEOUT_MS);\n const nodeEvaluations = this.responseParser.parseLayerEvaluation(response);\n\n const avgAlignmentScore =\n nodeEvaluations.length > 0\n ? nodeEvaluations.reduce((sum, e) => sum + e.alignmentScore, 0) / nodeEvaluations.length\n : 0;\n const avgDocumentationScore =\n nodeEvaluations.length > 0\n ? nodeEvaluations.reduce((sum, e) => sum + e.documentationScore, 0) /\n nodeEvaluations.length\n : 0;\n\n reviews.push({\n layerId: layerDef.id,\n standard,\n nodeEvaluations,\n avgAlignmentScore: Math.round(avgAlignmentScore * 10) / 10,\n avgDocumentationScore: Math.round(avgDocumentationScore * 10) / 10,\n });\n } catch (error: unknown) {\n const msg = getErrorMessage(error);\n process.stderr.write(` \u26A0\uFE0F Failed to evaluate layer ${layerDef.id}: ${msg}\\n`);\n\n if (error instanceof AIEvaluationAbortError) {\n throw error;\n }\n }\n }\n\n return reviews;\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,2BAA2B;AACpC,SAAS,0BAA0B;AACnC,SAAS,eAAe,8BAA8B;AACtD,SAAS,uBAAuB;AAEhC,MAAM,oBAAoB,IAAI,KAAK;AAE7B,MAAO,gBAAe;EACT;EACA;EACA;EAEjB,cAAA;AACE,SAAK,SAAS,IAAI,cAAa,GAC/B,KAAK,kBAAkB,IAAI,oBAAmB,GAC9C,KAAK,iBAAiB,IAAI,mBAAkB;EAC9C;;;;;;EAOA,MAAM,eACJ,WACA,gBAA+C;AAE/C,UAAM,UAA2B,CAAA;AAEjC,eAAW,YAAY,WAAW;AAChC,YAAM,UAAU,eAAe,IAAI,SAAS,EAAE,KAAK,CAAA;AACnD,UAAI,QAAQ,WAAW;AACrB;AAGF,YAAM,WAAW,SAAS,aACtB,GAAG,SAAS,WAAW,QAAQ,IAAI,SAAS,WAAW,OAAO,KAC9D,KAAK,gBAAgB,oBAAoB,SAAS,EAAE;AAExD,cAAQ,OAAO,MAAM,uBAAuB,SAAS,EAAE,KAAK,QAAQ,MAAM;CAAmB;AAE7F,UAAI;AACF,cAAM,SAAS,KAAK,gBAAgB,gBAAgB,EAAE,UAAU,QAAO,CAAE,GACnE,WAAW,MAAM,KAAK,OAAO,OAAO,QAAQ,UAAU,SAAS,EAAE,IAAI,iBAAiB,GACtF,kBAAkB,KAAK,eAAe,qBAAqB,QAAQ,GAEnE,oBACJ,gBAAgB,SAAS,IACrB,gBAAgB,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,gBAAgB,CAAC,IAAI,gBAAgB,SAChF,GACA,wBACJ,gBAAgB,SAAS,IACrB,gBAAgB,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,oBAAoB,CAAC,IAChE,gBAAgB,SAChB;AAEN,gBAAQ,KAAK;UACX,SAAS,SAAS;UAClB;UACA;UACA,mBAAmB,KAAK,MAAM,oBAAoB,EAAE,IAAI;UACxD,uBAAuB,KAAK,MAAM,wBAAwB,EAAE,IAAI;SACjE;MACH,SAAS,OAAgB;AACvB,cAAM,MAAM,gBAAgB,KAAK;AAGjC,YAFA,QAAQ,OAAO,MAAM,4CAAkC,SAAS,EAAE,KAAK,GAAG;CAAI,GAE1E,iBAAiB;AACnB,gBAAM;MAEV;IACF;AAEA,WAAO;EACT;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { getErrorMessage } from "../../../utils/errors.js";
|
|
2
|
+
class NodeResponseParser {
|
|
3
|
+
/**
|
|
4
|
+
* Parse NodeAIEvaluation[] from a Claude response string.
|
|
5
|
+
* Tries code-fenced JSON first, falls back to raw array extraction.
|
|
6
|
+
*/
|
|
7
|
+
parseLayerEvaluation(response) {
|
|
8
|
+
const codeBlockMatch = response.match(/```json\n([\s\S]*?)\n```/), rawArrayMatch = response.match(/\[[\s\S]*\]/), jsonMatch = codeBlockMatch ?? rawArrayMatch;
|
|
9
|
+
if (!jsonMatch) {
|
|
10
|
+
const truncated = response.substring(0, 200);
|
|
11
|
+
throw new Error(`Failed to extract JSON array from AI response. Expected JSON array in code block or raw JSON array.
|
|
12
|
+
Received: ${truncated}${response.length > 200 ? "..." : ""}`);
|
|
13
|
+
}
|
|
14
|
+
const jsonString = codeBlockMatch ? codeBlockMatch[1] : jsonMatch[0];
|
|
15
|
+
let parsed;
|
|
16
|
+
try {
|
|
17
|
+
parsed = JSON.parse(jsonString);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
const truncated = jsonString.substring(0, 200);
|
|
20
|
+
throw new Error(`Failed to parse JSON from AI response: ${getErrorMessage(error)}
|
|
21
|
+
Received: ${truncated}${jsonString.length > 200 ? "..." : ""}`);
|
|
22
|
+
}
|
|
23
|
+
if (!Array.isArray(parsed))
|
|
24
|
+
throw new Error("Expected JSON array of node evaluations from AI response");
|
|
25
|
+
return parsed.map((item, index) => this.validateItem(item, index));
|
|
26
|
+
}
|
|
27
|
+
validateItem(item, index) {
|
|
28
|
+
if (typeof item != "object" || item === null)
|
|
29
|
+
throw new Error(`Node evaluation at index ${index} is not a valid object`);
|
|
30
|
+
const obj = item;
|
|
31
|
+
if (!obj.specNodeId || typeof obj.specNodeId != "string")
|
|
32
|
+
throw new Error(`Node evaluation at index ${index} missing or invalid field: specNodeId (must be non-empty string)`);
|
|
33
|
+
if (typeof obj.alignmentScore != "number")
|
|
34
|
+
throw new Error(`Node evaluation at index ${index} missing or invalid field: alignmentScore (must be number)`);
|
|
35
|
+
if (typeof obj.documentationScore != "number")
|
|
36
|
+
throw new Error(`Node evaluation at index ${index} missing or invalid field: documentationScore (must be number)`);
|
|
37
|
+
if (!obj.alignmentReasoning || typeof obj.alignmentReasoning != "string")
|
|
38
|
+
throw new Error(`Node evaluation at index ${index} missing or invalid field: alignmentReasoning (must be non-empty string)`);
|
|
39
|
+
if (!obj.documentationReasoning || typeof obj.documentationReasoning != "string")
|
|
40
|
+
throw new Error(`Node evaluation at index ${index} missing or invalid field: documentationReasoning (must be non-empty string)`);
|
|
41
|
+
const suggestions = Array.isArray(obj.suggestions) && obj.suggestions.every((s) => typeof s == "string") ? obj.suggestions : [];
|
|
42
|
+
return {
|
|
43
|
+
specNodeId: obj.specNodeId,
|
|
44
|
+
alignmentScore: Math.max(0, Math.min(100, Math.round(obj.alignmentScore))),
|
|
45
|
+
alignmentReasoning: obj.alignmentReasoning,
|
|
46
|
+
documentationScore: Math.max(0, Math.min(100, Math.round(obj.documentationScore))),
|
|
47
|
+
documentationReasoning: obj.documentationReasoning,
|
|
48
|
+
suggestions
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
NodeResponseParser
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/audit/nodes/ai/parser.ts"],
|
|
4
|
+
"sourcesContent": ["import type { NodeAIEvaluation } from \"../types.js\";\nimport { getErrorMessage } from \"../../../utils/errors.js\";\n\nexport class NodeResponseParser {\n /**\n * Parse NodeAIEvaluation[] from a Claude response string.\n * Tries code-fenced JSON first, falls back to raw array extraction.\n */\n parseLayerEvaluation(response: string): NodeAIEvaluation[] {\n // 1. Try code block: ```json\\n...\\n```\n const codeBlockMatch = response.match(/```json\\n([\\s\\S]*?)\\n```/);\n // 2. Fall back to raw array\n const rawArrayMatch = response.match(/\\[[\\s\\S]*\\]/);\n\n const jsonMatch = codeBlockMatch ?? rawArrayMatch;\n if (!jsonMatch) {\n const truncated = response.substring(0, 200);\n throw new Error(\n `Failed to extract JSON array from AI response. Expected JSON array in code block or raw JSON array.\\nReceived: ${truncated}${response.length > 200 ? \"...\" : \"\"}`\n );\n }\n\n const jsonString = codeBlockMatch ? codeBlockMatch[1] : jsonMatch[0];\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonString);\n } catch (error: unknown) {\n const truncated = jsonString.substring(0, 200);\n throw new Error(\n `Failed to parse JSON from AI response: ${getErrorMessage(error)}\\nReceived: ${truncated}${jsonString.length > 200 ? \"...\" : \"\"}`\n );\n }\n\n if (!Array.isArray(parsed)) {\n throw new Error(\"Expected JSON array of node evaluations from AI response\");\n }\n\n return parsed.map((item: unknown, index: number) => this.validateItem(item, index));\n }\n\n private validateItem(item: unknown, index: number): NodeAIEvaluation {\n if (typeof item !== \"object\" || item === null) {\n throw new Error(`Node evaluation at index ${index} is not a valid object`);\n }\n\n const obj = item as Record<string, unknown>;\n\n if (!obj.specNodeId || typeof obj.specNodeId !== \"string\") {\n throw new Error(\n `Node evaluation at index ${index} missing or invalid field: specNodeId (must be non-empty string)`\n );\n }\n\n if (typeof obj.alignmentScore !== \"number\") {\n throw new Error(\n `Node evaluation at index ${index} missing or invalid field: alignmentScore (must be number)`\n );\n }\n\n if (typeof obj.documentationScore !== \"number\") {\n throw new Error(\n `Node evaluation at index ${index} missing or invalid field: documentationScore (must be number)`\n );\n }\n\n if (!obj.alignmentReasoning || typeof obj.alignmentReasoning !== \"string\") {\n throw new Error(\n `Node evaluation at index ${index} missing or invalid field: alignmentReasoning (must be non-empty string)`\n );\n }\n\n if (!obj.documentationReasoning || typeof obj.documentationReasoning !== \"string\") {\n throw new Error(\n `Node evaluation at index ${index} missing or invalid field: documentationReasoning (must be non-empty string)`\n );\n }\n\n const suggestions = Array.isArray(obj.suggestions) &&\n obj.suggestions.every((s) => typeof s === \"string\")\n ? (obj.suggestions as string[])\n : [];\n\n return {\n specNodeId: obj.specNodeId,\n alignmentScore: Math.max(0, Math.min(100, Math.round(obj.alignmentScore))),\n alignmentReasoning: obj.alignmentReasoning,\n documentationScore: Math.max(0, Math.min(100, Math.round(obj.documentationScore))),\n documentationReasoning: obj.documentationReasoning,\n suggestions,\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,uBAAuB;AAE1B,MAAO,mBAAkB;;;;;EAK7B,qBAAqB,UAAgB;AAEnC,UAAM,iBAAiB,SAAS,MAAM,0BAA0B,GAE1D,gBAAgB,SAAS,MAAM,aAAa,GAE5C,YAAY,kBAAkB;AACpC,QAAI,CAAC,WAAW;AACd,YAAM,YAAY,SAAS,UAAU,GAAG,GAAG;AAC3C,YAAM,IAAI,MACR;YAAkH,SAAS,GAAG,SAAS,SAAS,MAAM,QAAQ,EAAE,EAAE;IAEtK;AAEA,UAAM,aAAa,iBAAiB,eAAe,CAAC,IAAI,UAAU,CAAC;AACnE,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,UAAU;IAChC,SAAS,OAAgB;AACvB,YAAM,YAAY,WAAW,UAAU,GAAG,GAAG;AAC7C,YAAM,IAAI,MACR,0CAA0C,gBAAgB,KAAK,CAAC;YAAe,SAAS,GAAG,WAAW,SAAS,MAAM,QAAQ,EAAE,EAAE;IAErI;AAEA,QAAI,CAAC,MAAM,QAAQ,MAAM;AACvB,YAAM,IAAI,MAAM,0DAA0D;AAG5E,WAAO,OAAO,IAAI,CAAC,MAAe,UAAkB,KAAK,aAAa,MAAM,KAAK,CAAC;EACpF;EAEQ,aAAa,MAAe,OAAa;AAC/C,QAAI,OAAO,QAAS,YAAY,SAAS;AACvC,YAAM,IAAI,MAAM,4BAA4B,KAAK,wBAAwB;AAG3E,UAAM,MAAM;AAEZ,QAAI,CAAC,IAAI,cAAc,OAAO,IAAI,cAAe;AAC/C,YAAM,IAAI,MACR,4BAA4B,KAAK,kEAAkE;AAIvG,QAAI,OAAO,IAAI,kBAAmB;AAChC,YAAM,IAAI,MACR,4BAA4B,KAAK,4DAA4D;AAIjG,QAAI,OAAO,IAAI,sBAAuB;AACpC,YAAM,IAAI,MACR,4BAA4B,KAAK,gEAAgE;AAIrG,QAAI,CAAC,IAAI,sBAAsB,OAAO,IAAI,sBAAuB;AAC/D,YAAM,IAAI,MACR,4BAA4B,KAAK,0EAA0E;AAI/G,QAAI,CAAC,IAAI,0BAA0B,OAAO,IAAI,0BAA2B;AACvE,YAAM,IAAI,MACR,4BAA4B,KAAK,8EAA8E;AAInH,UAAM,cAAc,MAAM,QAAQ,IAAI,WAAW,KAC/C,IAAI,YAAY,MAAM,CAAC,MAAM,OAAO,KAAM,QAAQ,IAC/C,IAAI,cACL,CAAA;AAEJ,WAAO;MACL,YAAY,IAAI;MAChB,gBAAgB,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,IAAI,cAAc,CAAC,CAAC;MACzE,oBAAoB,IAAI;MACxB,oBAAoB,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,IAAI,kBAAkB,CAAC,CAAC;MACjF,wBAAwB,IAAI;MAC5B;;EAEJ;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
class NodePromptTemplates {
|
|
2
|
+
/**
|
|
3
|
+
* Build a per-layer batch prompt that asks Claude to evaluate every node type
|
|
4
|
+
* for alignment to the layer's inspiring standard and documentation quality.
|
|
5
|
+
*/
|
|
6
|
+
layerEvaluation(context) {
|
|
7
|
+
const { layerDef, schemas } = context, standard = layerDef.inspiredBy ? `${layerDef.inspiredBy.standard} ${layerDef.inspiredBy.version}` : this.getFallbackStandard(layerDef.id), inputItems = schemas.map((s) => ({
|
|
8
|
+
specNodeId: s.specNodeId,
|
|
9
|
+
title: s.title,
|
|
10
|
+
description: s.description,
|
|
11
|
+
attributeNames: Object.keys(s.attributes.properties)
|
|
12
|
+
}));
|
|
13
|
+
return `You are evaluating node type definitions in a federated architecture specification.
|
|
14
|
+
|
|
15
|
+
Layer: ${layerDef.name} (layer ${layerDef.number})
|
|
16
|
+
Inspiring Standard: ${standard}
|
|
17
|
+
|
|
18
|
+
For each node type, score it on two dimensions (0-100 each):
|
|
19
|
+
|
|
20
|
+
ALIGNMENT SCORE \u2014 How well does this node type conceptually belong in the ${layerDef.name} layer as defined by ${standard}?
|
|
21
|
+
90-100: Core concept in the standard, perfect fit for this layer
|
|
22
|
+
70-89: Clearly related to the standard, well-placed in this layer
|
|
23
|
+
50-69: Loosely related, could belong here or in an adjacent layer
|
|
24
|
+
30-49: Weak connection to the standard's domain
|
|
25
|
+
0-29: Appears misplaced; would fit better in a different layer
|
|
26
|
+
|
|
27
|
+
DOCUMENTATION SCORE \u2014 Is the description accurate, useful, and sufficient?
|
|
28
|
+
90-100: Clear, accurate, implementation-agnostic, and complete
|
|
29
|
+
70-89: Mostly good with minor gaps
|
|
30
|
+
50-69: Generic or vague but not wrong
|
|
31
|
+
30-49: Misleading or too brief to be useful
|
|
32
|
+
0-29: Empty, missing, or actively wrong
|
|
33
|
+
|
|
34
|
+
PATTERN DETECTION \u2014 In addition to scoring, identify two structural anti-patterns. When found, apply the scoring impact below and include a specific remediation suggestion.
|
|
35
|
+
|
|
36
|
+
PATTERN A \u2014 Cross-layer reference annotation:
|
|
37
|
+
A node whose sole purpose is to carry metadata that belongs to another layer.
|
|
38
|
+
Indicators:
|
|
39
|
+
\u2022 Name uses x- prefix (e.g. x-database, x-ui, x-security, x-apm-*)
|
|
40
|
+
\u2022 Description says things like "links schema to...", "reference to ... in another layer",
|
|
41
|
+
"UI rendering hints", "security metadata", "database mapping information"
|
|
42
|
+
\u2022 Attributes describe properties of another layer's concepts, not this layer's
|
|
43
|
+
Scoring impact: Alignment score must be 0\u201329. This is a conceptual misalignment \u2014 the node
|
|
44
|
+
embeds cross-layer coupling inside a layer's type catalog instead of using relationships
|
|
45
|
+
or metadata attachments.
|
|
46
|
+
Required suggestion: Recommend moving this to a relationship property or cross-reference
|
|
47
|
+
annotation, and identify which layer it actually belongs to.
|
|
48
|
+
|
|
49
|
+
PATTERN B \u2014 Enum-masquerading node type:
|
|
50
|
+
A node that enumerates a closed set of values but is modeled as a first-class node type.
|
|
51
|
+
Indicators:
|
|
52
|
+
\u2022 Has only one attribute (commonly named "value" with type string or enum)
|
|
53
|
+
\u2022 Name or description uses words like "type", "kind", "mode", "status", or implies
|
|
54
|
+
a finite set of choices (e.g. "Core JSON data types", "String type definition")
|
|
55
|
+
\u2022 Represents a primitive value constraint rather than a structural concept
|
|
56
|
+
Scoring impact: Reduce alignment score by 20\u201330 points. These inflate the type catalog
|
|
57
|
+
and are modeling primitives incorrectly used.
|
|
58
|
+
Required suggestion: Recommend collapsing into an \`enum\`-constrained string attribute on
|
|
59
|
+
the parent schema (or a shared \`$defs\` enum referenced via \`$ref\`), and name the
|
|
60
|
+
specific attribute and schema where it should live.
|
|
61
|
+
|
|
62
|
+
Input node types:
|
|
63
|
+
\`\`\`json
|
|
64
|
+
${JSON.stringify(inputItems, null, 2)}
|
|
65
|
+
\`\`\`
|
|
66
|
+
|
|
67
|
+
Return ONLY a JSON array (no prose, no markdown outside the array) with one object per node type:
|
|
68
|
+
[
|
|
69
|
+
{
|
|
70
|
+
"specNodeId": "string",
|
|
71
|
+
"alignmentScore": 0-100,
|
|
72
|
+
"alignmentReasoning": "brief explanation",
|
|
73
|
+
"documentationScore": 0-100,
|
|
74
|
+
"documentationReasoning": "brief explanation",
|
|
75
|
+
"suggestions": ["actionable suggestion 1", ...]
|
|
76
|
+
}
|
|
77
|
+
]`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Fallback standard names for layers without inspiredBy metadata.
|
|
81
|
+
* Public so NodeAIEvaluator can use the same mapping for LayerAIReview.standard.
|
|
82
|
+
*/
|
|
83
|
+
getFallbackStandard(layerId) {
|
|
84
|
+
return {
|
|
85
|
+
motivation: "ArchiMate 3.2",
|
|
86
|
+
business: "ArchiMate 3.2",
|
|
87
|
+
security: "NIST SP 800-53",
|
|
88
|
+
application: "ArchiMate 3.2",
|
|
89
|
+
technology: "ArchiMate 3.2",
|
|
90
|
+
api: "OpenAPI 3.0",
|
|
91
|
+
"data-model": "JSON Schema Draft 7",
|
|
92
|
+
"data-store": "Database design patterns",
|
|
93
|
+
ux: "Component-based UI patterns",
|
|
94
|
+
navigation: "Application routing patterns",
|
|
95
|
+
apm: "OpenTelemetry",
|
|
96
|
+
testing: "Software testing best practices"
|
|
97
|
+
}[layerId] ?? "Architecture best practices";
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export {
|
|
101
|
+
NodePromptTemplates
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/audit/nodes/ai/prompts.ts"],
|
|
4
|
+
"sourcesContent": ["import type { LayerDefinition, ParsedNodeSchema } from \"../types.js\";\n\nexport class NodePromptTemplates {\n /**\n * Build a per-layer batch prompt that asks Claude to evaluate every node type\n * for alignment to the layer's inspiring standard and documentation quality.\n */\n layerEvaluation(context: {\n layerDef: LayerDefinition;\n schemas: ParsedNodeSchema[];\n }): string {\n const { layerDef, schemas } = context;\n const standard = layerDef.inspiredBy\n ? `${layerDef.inspiredBy.standard} ${layerDef.inspiredBy.version}`\n : this.getFallbackStandard(layerDef.id);\n\n const inputItems = schemas.map((s) => ({\n specNodeId: s.specNodeId,\n title: s.title,\n description: s.description,\n attributeNames: Object.keys(s.attributes.properties),\n }));\n\n return `You are evaluating node type definitions in a federated architecture specification.\n\nLayer: ${layerDef.name} (layer ${layerDef.number})\nInspiring Standard: ${standard}\n\nFor each node type, score it on two dimensions (0-100 each):\n\nALIGNMENT SCORE \u2014 How well does this node type conceptually belong in the ${layerDef.name} layer as defined by ${standard}?\n 90-100: Core concept in the standard, perfect fit for this layer\n 70-89: Clearly related to the standard, well-placed in this layer\n 50-69: Loosely related, could belong here or in an adjacent layer\n 30-49: Weak connection to the standard's domain\n 0-29: Appears misplaced; would fit better in a different layer\n\nDOCUMENTATION SCORE \u2014 Is the description accurate, useful, and sufficient?\n 90-100: Clear, accurate, implementation-agnostic, and complete\n 70-89: Mostly good with minor gaps\n 50-69: Generic or vague but not wrong\n 30-49: Misleading or too brief to be useful\n 0-29: Empty, missing, or actively wrong\n\nPATTERN DETECTION \u2014 In addition to scoring, identify two structural anti-patterns. When found, apply the scoring impact below and include a specific remediation suggestion.\n\nPATTERN A \u2014 Cross-layer reference annotation:\n A node whose sole purpose is to carry metadata that belongs to another layer.\n Indicators:\n \u2022 Name uses x- prefix (e.g. x-database, x-ui, x-security, x-apm-*)\n \u2022 Description says things like \"links schema to...\", \"reference to ... in another layer\",\n \"UI rendering hints\", \"security metadata\", \"database mapping information\"\n \u2022 Attributes describe properties of another layer's concepts, not this layer's\n Scoring impact: Alignment score must be 0\u201329. This is a conceptual misalignment \u2014 the node\n embeds cross-layer coupling inside a layer's type catalog instead of using relationships\n or metadata attachments.\n Required suggestion: Recommend moving this to a relationship property or cross-reference\n annotation, and identify which layer it actually belongs to.\n\nPATTERN B \u2014 Enum-masquerading node type:\n A node that enumerates a closed set of values but is modeled as a first-class node type.\n Indicators:\n \u2022 Has only one attribute (commonly named \"value\" with type string or enum)\n \u2022 Name or description uses words like \"type\", \"kind\", \"mode\", \"status\", or implies\n a finite set of choices (e.g. \"Core JSON data types\", \"String type definition\")\n \u2022 Represents a primitive value constraint rather than a structural concept\n Scoring impact: Reduce alignment score by 20\u201330 points. These inflate the type catalog\n and are modeling primitives incorrectly used.\n Required suggestion: Recommend collapsing into an \\`enum\\`-constrained string attribute on\n the parent schema (or a shared \\`$defs\\` enum referenced via \\`$ref\\`), and name the\n specific attribute and schema where it should live.\n\nInput node types:\n\\`\\`\\`json\n${JSON.stringify(inputItems, null, 2)}\n\\`\\`\\`\n\nReturn ONLY a JSON array (no prose, no markdown outside the array) with one object per node type:\n[\n {\n \"specNodeId\": \"string\",\n \"alignmentScore\": 0-100,\n \"alignmentReasoning\": \"brief explanation\",\n \"documentationScore\": 0-100,\n \"documentationReasoning\": \"brief explanation\",\n \"suggestions\": [\"actionable suggestion 1\", ...]\n }\n]`;\n }\n\n /**\n * Fallback standard names for layers without inspiredBy metadata.\n * Public so NodeAIEvaluator can use the same mapping for LayerAIReview.standard.\n */\n getFallbackStandard(layerId: string): string {\n const standards: Record<string, string> = {\n motivation: \"ArchiMate 3.2\",\n business: \"ArchiMate 3.2\",\n security: \"NIST SP 800-53\",\n application: \"ArchiMate 3.2\",\n technology: \"ArchiMate 3.2\",\n api: \"OpenAPI 3.0\",\n \"data-model\": \"JSON Schema Draft 7\",\n \"data-store\": \"Database design patterns\",\n ux: \"Component-based UI patterns\",\n navigation: \"Application routing patterns\",\n apm: \"OpenTelemetry\",\n testing: \"Software testing best practices\",\n };\n return standards[layerId] ?? \"Architecture best practices\";\n }\n}\n"],
|
|
5
|
+
"mappings": "AAEM,MAAO,oBAAmB;;;;;EAK9B,gBAAgB,SAGf;AACC,UAAM,EAAE,UAAU,QAAO,IAAK,SACxB,WAAW,SAAS,aACtB,GAAG,SAAS,WAAW,QAAQ,IAAI,SAAS,WAAW,OAAO,KAC9D,KAAK,oBAAoB,SAAS,EAAE,GAElC,aAAa,QAAQ,IAAI,CAAC,OAAO;MACrC,YAAY,EAAE;MACd,OAAO,EAAE;MACT,aAAa,EAAE;MACf,gBAAgB,OAAO,KAAK,EAAE,WAAW,UAAU;MACnD;AAEF,WAAO;;SAEF,SAAS,IAAI,WAAW,SAAS,MAAM;sBAC1B,QAAQ;;;;iFAI8C,SAAS,IAAI,wBAAwB,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4CvH,KAAK,UAAU,YAAY,MAAM,CAAC,CAAC;;;;;;;;;;;;;;EAcnC;;;;;EAMA,oBAAoB,SAAe;AAejC,WAd0C;MACxC,YAAY;MACZ,UAAU;MACV,UAAU;MACV,aAAa;MACb,YAAY;MACZ,KAAK;MACL,cAAc;MACd,cAAc;MACd,IAAI;MACJ,YAAY;MACZ,KAAK;MACL,SAAS;MAEM,OAAO,KAAK;EAC/B;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class NodeCompletenessChecker {
|
|
2
|
+
check(layerDefs, schemas) {
|
|
3
|
+
const issues = [], schemaIds = new Set(schemas.map((s) => s.specNodeId)), declaredIds = /* @__PURE__ */ new Set();
|
|
4
|
+
for (const layer of layerDefs)
|
|
5
|
+
for (const nodeType of layer.nodeTypes)
|
|
6
|
+
declaredIds.add(nodeType);
|
|
7
|
+
const layerById = new Map(layerDefs.map((l) => [l.id, l]));
|
|
8
|
+
for (const layer of layerDefs)
|
|
9
|
+
for (const nodeType of layer.nodeTypes)
|
|
10
|
+
schemaIds.has(nodeType) || issues.push({
|
|
11
|
+
layerId: layer.id,
|
|
12
|
+
specNodeId: nodeType,
|
|
13
|
+
issueType: "missing_schema",
|
|
14
|
+
detail: `"${nodeType}" is listed in ${layer.id} layer.json but has no corresponding .node.schema.json file.`
|
|
15
|
+
});
|
|
16
|
+
for (const schema of schemas)
|
|
17
|
+
if (!declaredIds.has(schema.specNodeId)) {
|
|
18
|
+
const layer = layerById.get(schema.layerId);
|
|
19
|
+
issues.push({
|
|
20
|
+
layerId: schema.layerId,
|
|
21
|
+
specNodeId: schema.specNodeId,
|
|
22
|
+
issueType: "orphaned_schema",
|
|
23
|
+
detail: `"${schema.specNodeId}" has a schema file but is not listed in ${layer ? layer.id : schema.layerId} layer.json.`
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return issues;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
NodeCompletenessChecker
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=node-completeness-checker.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/audit/nodes/analysis/node-completeness-checker.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Node schema completeness checker.\n * Pure function \u2014 no I/O.\n *\n * Compares layer.json node_types lists against actual schema files loaded from disk.\n */\n\nimport type { LayerDefinition, ParsedNodeSchema, SchemaCompletenessIssue } from \"../types.js\";\n\nexport class NodeCompletenessChecker {\n check(\n layerDefs: LayerDefinition[],\n schemas: ParsedNodeSchema[]\n ): SchemaCompletenessIssue[] {\n const issues: SchemaCompletenessIssue[] = [];\n\n // Build a set of all specNodeIds present as schema files\n const schemaIds = new Set(schemas.map((s) => s.specNodeId));\n\n // Build a set of all specNodeIds declared in layer.json files\n const declaredIds = new Set<string>();\n for (const layer of layerDefs) {\n for (const nodeType of layer.nodeTypes) {\n declaredIds.add(nodeType);\n }\n }\n\n // Build a quick lookup: layerId \u2192 layer definition\n const layerById = new Map(layerDefs.map((l) => [l.id, l]));\n\n // missing_schema: declared in layer.json but no schema file found\n for (const layer of layerDefs) {\n for (const nodeType of layer.nodeTypes) {\n if (!schemaIds.has(nodeType)) {\n issues.push({\n layerId: layer.id,\n specNodeId: nodeType,\n issueType: \"missing_schema\",\n detail: `\"${nodeType}\" is listed in ${layer.id} layer.json but has no corresponding .node.schema.json file.`,\n });\n }\n }\n }\n\n // orphaned_schema: schema file exists but not listed in any layer.json\n for (const schema of schemas) {\n if (!declaredIds.has(schema.specNodeId)) {\n const layer = layerById.get(schema.layerId);\n issues.push({\n layerId: schema.layerId,\n specNodeId: schema.specNodeId,\n issueType: \"orphaned_schema\",\n detail: `\"${schema.specNodeId}\" has a schema file but is not listed in ${layer ? layer.id : schema.layerId} layer.json.`,\n });\n }\n }\n\n return issues;\n }\n}\n"],
|
|
5
|
+
"mappings": "AASM,MAAO,wBAAuB;EAClC,MACE,WACA,SAA2B;AAE3B,UAAM,SAAoC,CAAA,GAGpC,YAAY,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,GAGpD,cAAc,oBAAI,IAAG;AAC3B,eAAW,SAAS;AAClB,iBAAW,YAAY,MAAM;AAC3B,oBAAY,IAAI,QAAQ;AAK5B,UAAM,YAAY,IAAI,IAAI,UAAU,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAGzD,eAAW,SAAS;AAClB,iBAAW,YAAY,MAAM;AAC3B,QAAK,UAAU,IAAI,QAAQ,KACzB,OAAO,KAAK;UACV,SAAS,MAAM;UACf,YAAY;UACZ,WAAW;UACX,QAAQ,IAAI,QAAQ,kBAAkB,MAAM,EAAE;SAC/C;AAMP,eAAW,UAAU;AACnB,UAAI,CAAC,YAAY,IAAI,OAAO,UAAU,GAAG;AACvC,cAAM,QAAQ,UAAU,IAAI,OAAO,OAAO;AAC1C,eAAO,KAAK;UACV,SAAS,OAAO;UAChB,YAAY,OAAO;UACnB,WAAW;UACX,QAAQ,IAAI,OAAO,UAAU,4CAA4C,QAAQ,MAAM,KAAK,OAAO,OAAO;SAC3G;MACH;AAGF,WAAO;EACT;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const GENERIC_DESCRIPTION_RE = /\w+ element in \w+ layer/i;
|
|
2
|
+
function classifyDescription(description) {
|
|
3
|
+
return !description || description.trim() === "" ? "empty" : GENERIC_DESCRIPTION_RE.test(description) ? "generic" : "good";
|
|
4
|
+
}
|
|
5
|
+
function countDocumentedAttributes(properties) {
|
|
6
|
+
return Object.values(properties).filter((p) => typeof p.description == "string" && p.description.trim() !== "").length;
|
|
7
|
+
}
|
|
8
|
+
class NodeDefinitionAnalyzer {
|
|
9
|
+
analyze(schema) {
|
|
10
|
+
const issues = [];
|
|
11
|
+
let score = 100;
|
|
12
|
+
const descriptionQuality = classifyDescription(schema.description), hasDescription = descriptionQuality !== "empty";
|
|
13
|
+
descriptionQuality === "empty" ? (issues.push({
|
|
14
|
+
severity: "error",
|
|
15
|
+
code: "EMPTY_DESCRIPTION",
|
|
16
|
+
message: `Node type "${schema.specNodeId}" has no description.`
|
|
17
|
+
}), score -= 30) : descriptionQuality === "generic" ? (issues.push({
|
|
18
|
+
severity: "warning",
|
|
19
|
+
code: "GENERIC_DESCRIPTION",
|
|
20
|
+
message: `Node type "${schema.specNodeId}" uses generic template description: "${schema.description}"`
|
|
21
|
+
}), score -= 15) : schema.description.trim().length < 20 && (issues.push({
|
|
22
|
+
severity: "info",
|
|
23
|
+
code: "SHORT_DESCRIPTION",
|
|
24
|
+
message: `Node type "${schema.specNodeId}" has a very short description (${schema.description.trim().length} chars).`
|
|
25
|
+
}), score -= 5);
|
|
26
|
+
const attributeCount = Object.keys(schema.attributes.properties).length, documentedAttributeCount = countDocumentedAttributes(schema.attributes.properties), attributeDocumentationRatio = attributeCount > 0 ? documentedAttributeCount / attributeCount : 1;
|
|
27
|
+
return attributeCount > 3 && attributeDocumentationRatio < 0.5 && (issues.push({
|
|
28
|
+
severity: "warning",
|
|
29
|
+
code: "LOW_ATTRIBUTE_DOCUMENTATION",
|
|
30
|
+
message: `Node type "${schema.specNodeId}" has low attribute documentation: ${documentedAttributeCount}/${attributeCount} attributes described.`
|
|
31
|
+
}), score -= 10), {
|
|
32
|
+
specNodeId: schema.specNodeId,
|
|
33
|
+
layerId: schema.layerId,
|
|
34
|
+
hasDescription,
|
|
35
|
+
descriptionQuality,
|
|
36
|
+
attributeCount,
|
|
37
|
+
documentedAttributeCount,
|
|
38
|
+
attributeDocumentationRatio,
|
|
39
|
+
issues,
|
|
40
|
+
score: Math.max(0, score)
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
NodeDefinitionAnalyzer
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=node-definition-analyzer.js.map
|