@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,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/audit/nodes/analysis/node-definition-analyzer.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Node definition quality analyzer.\n * Pure function \u2014 no I/O.\n */\n\nimport type { ParsedNodeSchema, NodeDefinitionQuality, DefinitionIssue } from \"../types.js\";\n\nconst GENERIC_DESCRIPTION_RE = /\\w+ element in \\w+ layer/i;\n\n/**\n * Classify description quality for a node schema.\n */\nfunction classifyDescription(description: string): \"empty\" | \"generic\" | \"good\" {\n if (!description || description.trim() === \"\") return \"empty\";\n if (GENERIC_DESCRIPTION_RE.test(description)) return \"generic\";\n return \"good\";\n}\n\n/**\n * Count how many attribute properties have a non-empty description field.\n */\nfunction countDocumentedAttributes(\n properties: Record<string, { type?: string; description?: string; format?: string; enum?: string[] }>\n): number {\n return Object.values(properties).filter(\n (p) => typeof p.description === \"string\" && p.description.trim() !== \"\"\n ).length;\n}\n\nexport class NodeDefinitionAnalyzer {\n analyze(schema: ParsedNodeSchema): NodeDefinitionQuality {\n const issues: DefinitionIssue[] = [];\n let score = 100;\n\n const descriptionQuality = classifyDescription(schema.description);\n const hasDescription = descriptionQuality !== \"empty\";\n\n // Description issues\n if (descriptionQuality === \"empty\") {\n issues.push({\n severity: \"error\",\n code: \"EMPTY_DESCRIPTION\",\n message: `Node type \"${schema.specNodeId}\" has no description.`,\n });\n score -= 30;\n } else if (descriptionQuality === \"generic\") {\n issues.push({\n severity: \"warning\",\n code: \"GENERIC_DESCRIPTION\",\n message: `Node type \"${schema.specNodeId}\" uses generic template description: \"${schema.description}\"`,\n });\n score -= 15;\n } else if (schema.description.trim().length < 20) {\n issues.push({\n severity: \"info\",\n code: \"SHORT_DESCRIPTION\",\n message: `Node type \"${schema.specNodeId}\" has a very short description (${schema.description.trim().length} chars).`,\n });\n score -= 5;\n }\n\n // Attribute documentation\n const attributeCount = Object.keys(schema.attributes.properties).length;\n const documentedAttributeCount = countDocumentedAttributes(schema.attributes.properties);\n const attributeDocumentationRatio =\n attributeCount > 0 ? documentedAttributeCount / attributeCount : 1.0;\n\n if (attributeCount > 3 && attributeDocumentationRatio < 0.5) {\n issues.push({\n severity: \"warning\",\n code: \"LOW_ATTRIBUTE_DOCUMENTATION\",\n message: `Node type \"${schema.specNodeId}\" has low attribute documentation: ${documentedAttributeCount}/${attributeCount} attributes described.`,\n });\n score -= 10;\n }\n\n return {\n specNodeId: schema.specNodeId,\n layerId: schema.layerId,\n hasDescription,\n descriptionQuality,\n attributeCount,\n documentedAttributeCount,\n attributeDocumentationRatio,\n issues,\n score: Math.max(0, score),\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "AAOA,MAAM,yBAAyB;AAK/B,SAAS,oBAAoB,aAAmB;AAC9C,SAAI,CAAC,eAAe,YAAY,KAAI,MAAO,KAAW,UAClD,uBAAuB,KAAK,WAAW,IAAU,YAC9C;AACT;AAKA,SAAS,0BACP,YAAqG;AAErG,SAAO,OAAO,OAAO,UAAU,EAAE,OAC/B,CAAC,MAAM,OAAO,EAAE,eAAgB,YAAY,EAAE,YAAY,KAAI,MAAO,EAAE,EACvE;AACJ;AAEM,MAAO,uBAAsB;EACjC,QAAQ,QAAwB;AAC9B,UAAM,SAA4B,CAAA;AAClC,QAAI,QAAQ;AAEZ,UAAM,qBAAqB,oBAAoB,OAAO,WAAW,GAC3D,iBAAiB,uBAAuB;AAG9C,IAAI,uBAAuB,WACzB,OAAO,KAAK;MACV,UAAU;MACV,MAAM;MACN,SAAS,cAAc,OAAO,UAAU;KACzC,GACD,SAAS,MACA,uBAAuB,aAChC,OAAO,KAAK;MACV,UAAU;MACV,MAAM;MACN,SAAS,cAAc,OAAO,UAAU,yCAAyC,OAAO,WAAW;KACpG,GACD,SAAS,MACA,OAAO,YAAY,KAAI,EAAG,SAAS,OAC5C,OAAO,KAAK;MACV,UAAU;MACV,MAAM;MACN,SAAS,cAAc,OAAO,UAAU,mCAAmC,OAAO,YAAY,KAAI,EAAG,MAAM;KAC5G,GACD,SAAS;AAIX,UAAM,iBAAiB,OAAO,KAAK,OAAO,WAAW,UAAU,EAAE,QAC3D,2BAA2B,0BAA0B,OAAO,WAAW,UAAU,GACjF,8BACJ,iBAAiB,IAAI,2BAA2B,iBAAiB;AAEnE,WAAI,iBAAiB,KAAK,8BAA8B,QACtD,OAAO,KAAK;MACV,UAAU;MACV,MAAM;MACN,SAAS,cAAc,OAAO,UAAU,sCAAsC,wBAAwB,IAAI,cAAc;KACzH,GACD,SAAS,KAGJ;MACL,YAAY,OAAO;MACnB,SAAS,OAAO;MAChB;MACA;MACA;MACA;MACA;MACA;MACA,OAAO,KAAK,IAAI,GAAG,KAAK;;EAE5B;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
function levenshteinDistance(a, b) {
|
|
2
|
+
const m = a.length, n = b.length, dp = Array.from({ length: m + 1 }, (_, i) => Array.from({ length: n + 1 }, (_2, j) => i === 0 ? j : j === 0 ? i : 0));
|
|
3
|
+
for (let i = 1; i <= m; i++)
|
|
4
|
+
for (let j = 1; j <= n; j++)
|
|
5
|
+
a[i - 1] === b[j - 1] ? dp[i][j] = dp[i - 1][j - 1] : dp[i][j] = 1 + Math.min(dp[i - 1][j - 1], dp[i][j - 1], dp[i - 1][j]);
|
|
6
|
+
return dp[m][n];
|
|
7
|
+
}
|
|
8
|
+
function jaccardSimilarity(a, b) {
|
|
9
|
+
if (a.size === 0 && b.size === 0)
|
|
10
|
+
return 1;
|
|
11
|
+
const intersection = new Set([...a].filter((x) => b.has(x))), union = /* @__PURE__ */ new Set([...a, ...b]);
|
|
12
|
+
return union.size === 0 ? 0 : intersection.size / union.size;
|
|
13
|
+
}
|
|
14
|
+
function tokenize(text) {
|
|
15
|
+
return new Set(text.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length > 2));
|
|
16
|
+
}
|
|
17
|
+
class NodeOverlapDetector {
|
|
18
|
+
detectOverlaps(schemas) {
|
|
19
|
+
const candidates = [], byLayer = /* @__PURE__ */ new Map();
|
|
20
|
+
for (const schema of schemas) {
|
|
21
|
+
const group = byLayer.get(schema.layerId) ?? [];
|
|
22
|
+
group.push(schema), byLayer.set(schema.layerId, group);
|
|
23
|
+
}
|
|
24
|
+
for (const [layerId, layerSchemas] of byLayer) {
|
|
25
|
+
const n = layerSchemas.length;
|
|
26
|
+
for (let i = 0; i < n; i++)
|
|
27
|
+
for (let j = i + 1; j < n; j++) {
|
|
28
|
+
const a = layerSchemas[i], b = layerSchemas[j], candidate = this.comparePair(a, b, layerId);
|
|
29
|
+
candidate && candidates.push(candidate);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return candidates;
|
|
33
|
+
}
|
|
34
|
+
comparePair(a, b, layerId) {
|
|
35
|
+
const nameA = a.typeName.toLowerCase(), nameB = b.typeName.toLowerCase(), nameDist = levenshteinDistance(nameA, nameB);
|
|
36
|
+
if (Math.min(nameA.length, nameB.length) >= 6 && nameDist <= 2)
|
|
37
|
+
return {
|
|
38
|
+
nodeTypeA: a.specNodeId,
|
|
39
|
+
nodeTypeB: b.specNodeId,
|
|
40
|
+
layerId,
|
|
41
|
+
reason: `Type names "${nameA}" and "${nameB}" differ by only ${nameDist} character(s).`,
|
|
42
|
+
confidence: "high",
|
|
43
|
+
overlapType: "name_similarity"
|
|
44
|
+
};
|
|
45
|
+
const keysA = new Set(Object.keys(a.attributes.properties)), keysB = new Set(Object.keys(b.attributes.properties));
|
|
46
|
+
if (keysA.size > 0 && keysB.size > 0) {
|
|
47
|
+
const attrJaccard = jaccardSimilarity(keysA, keysB);
|
|
48
|
+
if (attrJaccard > 0.8 && nameDist <= 4)
|
|
49
|
+
return {
|
|
50
|
+
nodeTypeA: a.specNodeId,
|
|
51
|
+
nodeTypeB: b.specNodeId,
|
|
52
|
+
layerId,
|
|
53
|
+
reason: `Attribute sets are ${(attrJaccard * 100).toFixed(0)}% similar (Jaccard) with name distance ${nameDist}.`,
|
|
54
|
+
confidence: "high",
|
|
55
|
+
overlapType: "attribute_similarity"
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (a.description && b.description) {
|
|
59
|
+
const wordsA = tokenize(a.description), wordsB = tokenize(b.description);
|
|
60
|
+
if (wordsA.size >= 4 && wordsB.size >= 4) {
|
|
61
|
+
const descJaccard = jaccardSimilarity(wordsA, wordsB);
|
|
62
|
+
if (descJaccard > 0.7)
|
|
63
|
+
return {
|
|
64
|
+
nodeTypeA: a.specNodeId,
|
|
65
|
+
nodeTypeB: b.specNodeId,
|
|
66
|
+
layerId,
|
|
67
|
+
reason: `Descriptions share ${(descJaccard * 100).toFixed(0)}% word overlap.`,
|
|
68
|
+
confidence: "medium",
|
|
69
|
+
overlapType: "description_similarity"
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export {
|
|
77
|
+
NodeOverlapDetector
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=node-overlap-detector.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/audit/nodes/analysis/node-overlap-detector.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Node semantic overlap detector.\n * Pure function \u2014 no I/O.\n *\n * Compares all pairs within a layer (O(n\u00B2)) to find potentially duplicate\n * node types based on name similarity, attribute overlap, or description overlap.\n */\n\nimport type { ParsedNodeSchema, SemanticOverlapCandidate } from \"../types.js\";\n\n/**\n * Compute Levenshtein edit distance between two strings.\n */\nfunction levenshteinDistance(a: string, b: string): number {\n const m = a.length;\n const n = b.length;\n const dp: number[][] = Array.from({ length: m + 1 }, (_, i) =>\n Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0))\n );\n\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n if (a[i - 1] === b[j - 1]) {\n dp[i][j] = dp[i - 1][j - 1];\n } else {\n dp[i][j] = 1 + Math.min(dp[i - 1][j - 1], dp[i][j - 1], dp[i - 1][j]);\n }\n }\n }\n return dp[m][n];\n}\n\n/**\n * Jaccard similarity of two sets of strings.\n */\nfunction jaccardSimilarity(a: Set<string>, b: Set<string>): number {\n if (a.size === 0 && b.size === 0) return 1.0;\n const intersection = new Set([...a].filter((x) => b.has(x)));\n const union = new Set([...a, ...b]);\n return union.size === 0 ? 0 : intersection.size / union.size;\n}\n\n/**\n * Tokenize a description into lowercase words for overlap comparison.\n */\nfunction tokenize(text: string): Set<string> {\n return new Set(\n text\n .toLowerCase()\n .replace(/[^a-z0-9\\s]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length > 2)\n );\n}\n\nexport class NodeOverlapDetector {\n detectOverlaps(schemas: ParsedNodeSchema[]): SemanticOverlapCandidate[] {\n const candidates: SemanticOverlapCandidate[] = [];\n\n // Group by layer\n const byLayer = new Map<string, ParsedNodeSchema[]>();\n for (const schema of schemas) {\n const group = byLayer.get(schema.layerId) ?? [];\n group.push(schema);\n byLayer.set(schema.layerId, group);\n }\n\n for (const [layerId, layerSchemas] of byLayer) {\n const n = layerSchemas.length;\n for (let i = 0; i < n; i++) {\n for (let j = i + 1; j < n; j++) {\n const a = layerSchemas[i];\n const b = layerSchemas[j];\n\n const candidate = this.comparePair(a, b, layerId);\n if (candidate) candidates.push(candidate);\n }\n }\n }\n\n return candidates;\n }\n\n private comparePair(\n a: ParsedNodeSchema,\n b: ParsedNodeSchema,\n layerId: string\n ): SemanticOverlapCandidate | null {\n // Name similarity: strip layer prefix, compare type names\n const nameA = a.typeName.toLowerCase();\n const nameB = b.typeName.toLowerCase();\n const nameDist = levenshteinDistance(nameA, nameB);\n const minNameLen = Math.min(nameA.length, nameB.length);\n\n if (minNameLen >= 6 && nameDist <= 2) {\n return {\n nodeTypeA: a.specNodeId,\n nodeTypeB: b.specNodeId,\n layerId,\n reason: `Type names \"${nameA}\" and \"${nameB}\" differ by only ${nameDist} character(s).`,\n confidence: \"high\",\n overlapType: \"name_similarity\",\n };\n }\n\n // Attribute similarity: Jaccard > 0.8 AND name distance <= 4\n const keysA = new Set(Object.keys(a.attributes.properties));\n const keysB = new Set(Object.keys(b.attributes.properties));\n if (keysA.size > 0 && keysB.size > 0) {\n const attrJaccard = jaccardSimilarity(keysA, keysB);\n if (attrJaccard > 0.8 && nameDist <= 4) {\n return {\n nodeTypeA: a.specNodeId,\n nodeTypeB: b.specNodeId,\n layerId,\n reason: `Attribute sets are ${(attrJaccard * 100).toFixed(0)}% similar (Jaccard) with name distance ${nameDist}.`,\n confidence: \"high\",\n overlapType: \"attribute_similarity\",\n };\n }\n }\n\n // Description similarity: Jaccard word overlap > 0.7 (only for \"good\" descriptions)\n if (a.description && b.description) {\n const wordsA = tokenize(a.description);\n const wordsB = tokenize(b.description);\n if (wordsA.size >= 4 && wordsB.size >= 4) {\n const descJaccard = jaccardSimilarity(wordsA, wordsB);\n if (descJaccard > 0.7) {\n return {\n nodeTypeA: a.specNodeId,\n nodeTypeB: b.specNodeId,\n layerId,\n reason: `Descriptions share ${(descJaccard * 100).toFixed(0)}% word overlap.`,\n confidence: \"medium\",\n overlapType: \"description_similarity\",\n };\n }\n }\n }\n\n return null;\n }\n}\n"],
|
|
5
|
+
"mappings": "AAaA,SAAS,oBAAoB,GAAW,GAAS;AAC/C,QAAM,IAAI,EAAE,QACN,IAAI,EAAE,QACN,KAAiB,MAAM,KAAK,EAAE,QAAQ,IAAI,EAAC,GAAI,CAAC,GAAG,MACvD,MAAM,KAAK,EAAE,QAAQ,IAAI,EAAC,GAAI,CAACA,IAAG,MAAO,MAAM,IAAI,IAAI,MAAM,IAAI,IAAI,CAAE,CAAC;AAG1E,WAAS,IAAI,GAAG,KAAK,GAAG;AACtB,aAAS,IAAI,GAAG,KAAK,GAAG;AACtB,MAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IACtB,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,IAAI,CAAC,IAE1B,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,KAAK,IAAI,GAAG,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;AAI1E,SAAO,GAAG,CAAC,EAAE,CAAC;AAChB;AAKA,SAAS,kBAAkB,GAAgB,GAAc;AACvD,MAAI,EAAE,SAAS,KAAK,EAAE,SAAS;AAAG,WAAO;AACzC,QAAM,eAAe,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GACrD,QAAQ,oBAAI,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;AAClC,SAAO,MAAM,SAAS,IAAI,IAAI,aAAa,OAAO,MAAM;AAC1D;AAKA,SAAS,SAAS,MAAY;AAC5B,SAAO,IAAI,IACT,KACG,YAAW,EACX,QAAQ,gBAAgB,GAAG,EAC3B,MAAM,KAAK,EACX,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAElC;AAEM,MAAO,oBAAmB;EAC9B,eAAe,SAA2B;AACxC,UAAM,aAAyC,CAAA,GAGzC,UAAU,oBAAI,IAAG;AACvB,eAAW,UAAU,SAAS;AAC5B,YAAM,QAAQ,QAAQ,IAAI,OAAO,OAAO,KAAK,CAAA;AAC7C,YAAM,KAAK,MAAM,GACjB,QAAQ,IAAI,OAAO,SAAS,KAAK;IACnC;AAEA,eAAW,CAAC,SAAS,YAAY,KAAK,SAAS;AAC7C,YAAM,IAAI,aAAa;AACvB,eAAS,IAAI,GAAG,IAAI,GAAG;AACrB,iBAAS,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;AAC9B,gBAAM,IAAI,aAAa,CAAC,GAClB,IAAI,aAAa,CAAC,GAElB,YAAY,KAAK,YAAY,GAAG,GAAG,OAAO;AAChD,UAAI,aAAW,WAAW,KAAK,SAAS;QAC1C;IAEJ;AAEA,WAAO;EACT;EAEQ,YACN,GACA,GACA,SAAe;AAGf,UAAM,QAAQ,EAAE,SAAS,YAAW,GAC9B,QAAQ,EAAE,SAAS,YAAW,GAC9B,WAAW,oBAAoB,OAAO,KAAK;AAGjD,QAFmB,KAAK,IAAI,MAAM,QAAQ,MAAM,MAAM,KAEpC,KAAK,YAAY;AACjC,aAAO;QACL,WAAW,EAAE;QACb,WAAW,EAAE;QACb;QACA,QAAQ,eAAe,KAAK,UAAU,KAAK,oBAAoB,QAAQ;QACvE,YAAY;QACZ,aAAa;;AAKjB,UAAM,QAAQ,IAAI,IAAI,OAAO,KAAK,EAAE,WAAW,UAAU,CAAC,GACpD,QAAQ,IAAI,IAAI,OAAO,KAAK,EAAE,WAAW,UAAU,CAAC;AAC1D,QAAI,MAAM,OAAO,KAAK,MAAM,OAAO,GAAG;AACpC,YAAM,cAAc,kBAAkB,OAAO,KAAK;AAClD,UAAI,cAAc,OAAO,YAAY;AACnC,eAAO;UACL,WAAW,EAAE;UACb,WAAW,EAAE;UACb;UACA,QAAQ,uBAAuB,cAAc,KAAK,QAAQ,CAAC,CAAC,0CAA0C,QAAQ;UAC9G,YAAY;UACZ,aAAa;;IAGnB;AAGA,QAAI,EAAE,eAAe,EAAE,aAAa;AAClC,YAAM,SAAS,SAAS,EAAE,WAAW,GAC/B,SAAS,SAAS,EAAE,WAAW;AACrC,UAAI,OAAO,QAAQ,KAAK,OAAO,QAAQ,GAAG;AACxC,cAAM,cAAc,kBAAkB,QAAQ,MAAM;AACpD,YAAI,cAAc;AAChB,iBAAO;YACL,WAAW,EAAE;YACb,WAAW,EAAE;YACb;YACA,QAAQ,uBAAuB,cAAc,KAAK,QAAQ,CAAC,CAAC;YAC5D,YAAY;YACZ,aAAa;;MAGnB;IACF;AAEA,WAAO;EACT;;",
|
|
6
|
+
"names": ["_"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Model } from "../../../core/model.js";
|
|
2
|
+
import { getAllLayers } from "../../../generated/layer-registry.js";
|
|
3
|
+
class ModelNodeAuditOrchestrator {
|
|
4
|
+
async runAudit(options = {}) {
|
|
5
|
+
const projectRoot = options.projectRoot ?? process.cwd();
|
|
6
|
+
let model;
|
|
7
|
+
try {
|
|
8
|
+
model = await Model.load(projectRoot);
|
|
9
|
+
} catch (err) {
|
|
10
|
+
throw new Error(`Failed to load project model from ${projectRoot}: ${err instanceof Error ? err.message : String(err)}`);
|
|
11
|
+
}
|
|
12
|
+
const allElements = [];
|
|
13
|
+
for (const layer of model.layers.values())
|
|
14
|
+
for (const el of layer.elements.values())
|
|
15
|
+
allElements.push(el);
|
|
16
|
+
const getElementLayer = (el) => el.layer_id || el.layer || "", getElementType = (el) => el.spec_node_id || el.type || "", filteredElements = options.layer ? allElements.filter((el) => getElementLayer(el) === options.layer) : allElements, elementsByLayerAndType = /* @__PURE__ */ new Map(), completenessIssues = [];
|
|
17
|
+
for (const el of filteredElements) {
|
|
18
|
+
const layerId = getElementLayer(el), typeKey = getElementType(el);
|
|
19
|
+
if (!layerId || !typeKey) {
|
|
20
|
+
const elId = el.id ?? "(no id)", missingField = layerId ? "type" : "layer";
|
|
21
|
+
process.stderr.write(` \u26A0\uFE0F Skipping malformed element "${elId}": missing ${missingField}
|
|
22
|
+
`), completenessIssues.push({
|
|
23
|
+
layerId: layerId || "(unknown)",
|
|
24
|
+
specNodeId: typeKey || "(unknown)",
|
|
25
|
+
issueType: "malformed_element",
|
|
26
|
+
detail: `Element "${elId}" is missing its ${missingField} \u2014 excluded from audit report`
|
|
27
|
+
});
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
elementsByLayerAndType.has(layerId) || elementsByLayerAndType.set(layerId, /* @__PURE__ */ new Map());
|
|
31
|
+
const typeMap = elementsByLayerAndType.get(layerId);
|
|
32
|
+
typeMap.has(typeKey) || typeMap.set(typeKey, []), typeMap.get(typeKey).push(el);
|
|
33
|
+
}
|
|
34
|
+
const layerSummaries = (options.layer ? [options.layer] : getAllLayers().map((l) => l.id)).map((layerId) => {
|
|
35
|
+
const typeMap = elementsByLayerAndType.get(layerId) ?? /* @__PURE__ */ new Map();
|
|
36
|
+
let emptyDescriptionCount = 0, genericDescriptionCount = 0, goodDescriptionCount = 0, totalScore = 0;
|
|
37
|
+
for (const [, elements] of typeMap) {
|
|
38
|
+
const descs = elements.map((e) => (e.description || "").trim()).filter((d) => d.length > 0);
|
|
39
|
+
let quality;
|
|
40
|
+
descs.length === 0 ? quality = "empty" : quality = descs.reduce((s, d) => s + d.length, 0) / descs.length < 20 ? "generic" : "good", quality === "empty" ? (emptyDescriptionCount++, totalScore += 0) : quality === "generic" ? (genericDescriptionCount++, totalScore += 30) : (goodDescriptionCount++, totalScore += 85);
|
|
41
|
+
}
|
|
42
|
+
const totalNodeTypes2 = typeMap.size, avgQualityScore = totalNodeTypes2 > 0 ? Math.round(totalScore / totalNodeTypes2 * 10) / 10 : 0;
|
|
43
|
+
return {
|
|
44
|
+
layerId,
|
|
45
|
+
totalNodeTypes: totalNodeTypes2,
|
|
46
|
+
avgQualityScore,
|
|
47
|
+
emptyDescriptionCount,
|
|
48
|
+
genericDescriptionCount,
|
|
49
|
+
goodDescriptionCount,
|
|
50
|
+
totalIssues: emptyDescriptionCount + genericDescriptionCount,
|
|
51
|
+
errorCount: 0,
|
|
52
|
+
warningCount: emptyDescriptionCount + genericDescriptionCount
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
for (const [layerId, typeMap] of elementsByLayerAndType)
|
|
56
|
+
for (const specNodeId of typeMap.keys())
|
|
57
|
+
specNodeId.startsWith(`${layerId}.`) || completenessIssues.push({
|
|
58
|
+
layerId,
|
|
59
|
+
specNodeId,
|
|
60
|
+
issueType: "orphaned_schema",
|
|
61
|
+
detail: `Element uses spec_node_id "${specNodeId}" which does not belong to layer "${layerId}"`
|
|
62
|
+
});
|
|
63
|
+
const totalNodeTypes = [...elementsByLayerAndType.values()].reduce((sum, m) => sum + m.size, 0);
|
|
64
|
+
return options.verbose && process.stderr.write(`Model node audit: ${filteredElements.length} elements, ${totalNodeTypes} unique types across ${elementsByLayerAndType.size} layers
|
|
65
|
+
`), {
|
|
66
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
67
|
+
spec: {
|
|
68
|
+
version: model.manifest.version ?? "1.0.0",
|
|
69
|
+
totalNodeTypes,
|
|
70
|
+
totalLayers: elementsByLayerAndType.size
|
|
71
|
+
},
|
|
72
|
+
layerSummaries,
|
|
73
|
+
definitionQuality: [],
|
|
74
|
+
overlaps: [],
|
|
75
|
+
completenessIssues
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export {
|
|
80
|
+
ModelNodeAuditOrchestrator
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/audit/nodes/model/orchestrator.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Model Node Audit Orchestrator\n *\n * Analyzes the project's actual model elements to report which node types\n * are in use, their distribution across layers, and types that exist in the\n * model but not in the spec (orphaned) or vice versa.\n *\n * This is the model-side counterpart to NodeAuditOrchestrator (spec audit).\n * Use `dr audit --type nodes` to invoke this from the CLI.\n */\n\nimport { Model } from \"../../../core/model.js\";\nimport { getAllLayers } from \"../../../generated/layer-registry.js\";\nimport type { Element } from \"../../../core/element.js\";\nimport type {\n NodeAuditReport,\n NodeLayerSummary,\n SchemaCompletenessIssue,\n} from \"../types.js\";\n\nexport interface ModelNodeAuditOptions {\n layer?: string;\n verbose?: boolean;\n projectRoot?: string;\n}\n\nexport class ModelNodeAuditOrchestrator {\n async runAudit(options: ModelNodeAuditOptions = {}): Promise<NodeAuditReport> {\n const projectRoot = options.projectRoot ?? process.cwd();\n\n let model: Model;\n try {\n model = await Model.load(projectRoot);\n } catch (err) {\n throw new Error(\n `Failed to load project model from ${projectRoot}: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n\n // Collect all elements across all layers\n const allElements: Element[] = [];\n for (const layer of model.layers.values()) {\n for (const el of layer.elements.values()) {\n allElements.push(el);\n }\n }\n\n const getElementLayer = (el: Element): string => el.layer_id || el.layer || \"\";\n const getElementType = (el: Element): string => el.spec_node_id || el.type || \"\";\n\n // Filter by layer if specified\n const filteredElements = options.layer\n ? allElements.filter((el) => getElementLayer(el) === options.layer)\n : allElements;\n\n // Group elements by layer \u2192 type \u2192 element list (for quality scoring)\n const elementsByLayerAndType = new Map<string, Map<string, Element[]>>();\n const completenessIssues: SchemaCompletenessIssue[] = [];\n\n for (const el of filteredElements) {\n const layerId = getElementLayer(el);\n const typeKey = getElementType(el);\n if (!layerId || !typeKey) {\n const elId = (el as unknown as { id?: string }).id ?? \"(no id)\";\n const missingField = !layerId ? \"layer\" : \"type\";\n process.stderr.write(\n ` \u26A0\uFE0F Skipping malformed element \"${elId}\": missing ${missingField}\\n`\n );\n completenessIssues.push({\n layerId: layerId || \"(unknown)\",\n specNodeId: typeKey || \"(unknown)\",\n issueType: \"malformed_element\",\n detail: `Element \"${elId}\" is missing its ${missingField} \u2014 excluded from audit report`,\n });\n continue;\n }\n if (!elementsByLayerAndType.has(layerId)) elementsByLayerAndType.set(layerId, new Map());\n const typeMap = elementsByLayerAndType.get(layerId)!;\n if (!typeMap.has(typeKey)) typeMap.set(typeKey, []);\n typeMap.get(typeKey)!.push(el);\n }\n\n // Determine target layers\n const targetLayerIds = options.layer\n ? [options.layer]\n : getAllLayers().map((l) => l.id);\n\n // Build layer summaries with actual description quality scores\n const layerSummaries: NodeLayerSummary[] = targetLayerIds.map((layerId) => {\n const typeMap = elementsByLayerAndType.get(layerId) ?? new Map();\n let emptyDescriptionCount = 0;\n let genericDescriptionCount = 0;\n let goodDescriptionCount = 0;\n let totalScore = 0;\n\n for (const [, elements] of typeMap) {\n const descs = elements.map((e: Element) => (e.description || \"\").trim()).filter((d: string) => d.length > 0);\n let quality: \"empty\" | \"generic\" | \"good\";\n if (descs.length === 0) {\n quality = \"empty\";\n } else {\n const avgLen = descs.reduce((s: number, d: string) => s + d.length, 0) / descs.length;\n quality = avgLen < 20 ? \"generic\" : \"good\";\n }\n if (quality === \"empty\") { emptyDescriptionCount++; totalScore += 0; }\n else if (quality === \"generic\") { genericDescriptionCount++; totalScore += 30; }\n else { goodDescriptionCount++; totalScore += 85; }\n }\n\n const totalNodeTypes = typeMap.size;\n const avgQualityScore = totalNodeTypes > 0\n ? Math.round((totalScore / totalNodeTypes) * 10) / 10\n : 0;\n\n return {\n layerId,\n totalNodeTypes,\n avgQualityScore,\n emptyDescriptionCount,\n genericDescriptionCount,\n goodDescriptionCount,\n totalIssues: emptyDescriptionCount + genericDescriptionCount,\n errorCount: 0,\n warningCount: emptyDescriptionCount + genericDescriptionCount,\n };\n });\n\n // Detect orphaned types: spec_node_ids in model that don't follow the\n // expected \"{layer}.{type}\" naming convention\n for (const [layerId, typeMap] of elementsByLayerAndType) {\n for (const specNodeId of typeMap.keys()) {\n // spec_node_id should start with \"{layerId}.\"\n if (!specNodeId.startsWith(`${layerId}.`)) {\n completenessIssues.push({\n layerId,\n specNodeId,\n issueType: \"orphaned_schema\",\n detail: `Element uses spec_node_id \"${specNodeId}\" which does not belong to layer \"${layerId}\"`,\n });\n }\n }\n }\n\n const totalNodeTypes = [...elementsByLayerAndType.values()].reduce(\n (sum, m) => sum + m.size,\n 0\n );\n\n if (options.verbose) {\n process.stderr.write(\n `Model node audit: ${filteredElements.length} elements, ${totalNodeTypes} unique types across ${elementsByLayerAndType.size} layers\\n`\n );\n }\n\n return {\n timestamp: new Date().toISOString(),\n spec: {\n version: model.manifest.version ?? \"1.0.0\",\n totalNodeTypes,\n totalLayers: elementsByLayerAndType.size,\n },\n layerSummaries,\n definitionQuality: [],\n overlaps: [],\n completenessIssues,\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["totalNodeTypes"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { join, basename, dirname } from "node:path";
|
|
3
|
+
class NodeSchemaLoader {
|
|
4
|
+
specDir;
|
|
5
|
+
constructor(specDir) {
|
|
6
|
+
this.specDir = specDir;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Scan spec/schemas/nodes/{layer}/*.node.schema.json and parse each file.
|
|
10
|
+
* Optionally filter to a single layer by canonical name.
|
|
11
|
+
*/
|
|
12
|
+
async loadAllSchemas(layerFilter) {
|
|
13
|
+
const nodesDir = join(this.specDir, "schemas", "nodes"), layerDirs = await readdir(nodesDir, { withFileTypes: !0 }), schemas = [];
|
|
14
|
+
for (const entry of layerDirs) {
|
|
15
|
+
if (!entry.isDirectory())
|
|
16
|
+
continue;
|
|
17
|
+
const layerName = entry.name;
|
|
18
|
+
if (layerFilter && layerName !== layerFilter)
|
|
19
|
+
continue;
|
|
20
|
+
const layerDir = join(nodesDir, layerName), files = await readdir(layerDir);
|
|
21
|
+
for (const file of files) {
|
|
22
|
+
if (!file.endsWith(".node.schema.json"))
|
|
23
|
+
continue;
|
|
24
|
+
const filePath = join(layerDir, file), raw = await readFile(filePath, "utf-8");
|
|
25
|
+
let json;
|
|
26
|
+
try {
|
|
27
|
+
json = JSON.parse(raw);
|
|
28
|
+
} catch {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const parsed = this.parseSchema(json, filePath);
|
|
32
|
+
parsed && schemas.push(parsed);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return schemas;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Read spec/layers/*.layer.json and return layer definitions.
|
|
39
|
+
*/
|
|
40
|
+
async loadLayerDefinitions() {
|
|
41
|
+
const layersDir = join(this.specDir, "layers"), files = await readdir(layersDir), defs = [];
|
|
42
|
+
for (const file of files) {
|
|
43
|
+
if (!file.endsWith(".layer.json"))
|
|
44
|
+
continue;
|
|
45
|
+
const filePath = join(layersDir, file), raw = await readFile(filePath, "utf-8");
|
|
46
|
+
let json;
|
|
47
|
+
try {
|
|
48
|
+
json = JSON.parse(raw);
|
|
49
|
+
} catch (err) {
|
|
50
|
+
process.stderr.write(`warn: skipping malformed layer file ${filePath}: ${err}
|
|
51
|
+
`);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
defs.push(this.parseLayerDefinition(json));
|
|
55
|
+
}
|
|
56
|
+
return defs.sort((a, b) => a.number - b.number), defs;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Read spec/VERSION
|
|
60
|
+
*/
|
|
61
|
+
async loadSpecVersion() {
|
|
62
|
+
const versionPath = join(this.specDir, "VERSION");
|
|
63
|
+
return (await readFile(versionPath, "utf-8")).trim();
|
|
64
|
+
}
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Private helpers
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
parseSchema(json, filePath) {
|
|
69
|
+
const properties = json.properties;
|
|
70
|
+
if (!properties)
|
|
71
|
+
return null;
|
|
72
|
+
const specNodeId = this.extractConst(properties, "spec_node_id"), layerId = this.extractConst(properties, "layer_id"), typeName = this.extractConst(properties, "type");
|
|
73
|
+
if (!specNodeId || !layerId || !typeName) {
|
|
74
|
+
const fileName = basename(filePath, ".node.schema.json"), dirName = basename(dirname(filePath)), derivedLayerId = layerId ?? dirName, derivedTypeName = typeName ?? fileName, derivedSpecNodeId = specNodeId ?? `${derivedLayerId}.${derivedTypeName}`;
|
|
75
|
+
return this.buildParsedSchema(json, properties, filePath, derivedSpecNodeId, derivedLayerId, derivedTypeName);
|
|
76
|
+
}
|
|
77
|
+
return this.buildParsedSchema(json, properties, filePath, specNodeId, layerId, typeName);
|
|
78
|
+
}
|
|
79
|
+
buildParsedSchema(json, properties, filePath, specNodeId, layerId, typeName) {
|
|
80
|
+
const attributesProp = properties.attributes, attrProperties = attributesProp?.properties ?? {}, attrRequired = attributesProp?.required ?? [], attrAdditional = attributesProp?.additionalProperties ?? !1;
|
|
81
|
+
return {
|
|
82
|
+
specNodeId,
|
|
83
|
+
layerId,
|
|
84
|
+
typeName,
|
|
85
|
+
title: json.title ?? "",
|
|
86
|
+
description: json.description ?? "",
|
|
87
|
+
filePath,
|
|
88
|
+
attributes: {
|
|
89
|
+
properties: attrProperties,
|
|
90
|
+
required: attrRequired,
|
|
91
|
+
additionalProperties: attrAdditional
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
extractConst(properties, key) {
|
|
96
|
+
const prop = properties[key];
|
|
97
|
+
if (!prop)
|
|
98
|
+
return;
|
|
99
|
+
const constVal = prop.const;
|
|
100
|
+
return typeof constVal == "string" ? constVal : void 0;
|
|
101
|
+
}
|
|
102
|
+
parseLayerDefinition(json) {
|
|
103
|
+
const inspiredBy = json.inspired_by;
|
|
104
|
+
return {
|
|
105
|
+
id: json.id ?? "",
|
|
106
|
+
number: json.number ?? 0,
|
|
107
|
+
name: json.name ?? "",
|
|
108
|
+
nodeTypes: json.node_types ?? [],
|
|
109
|
+
inspiredBy: inspiredBy ? { standard: inspiredBy.standard, version: inspiredBy.version, url: inspiredBy.url } : void 0
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export {
|
|
114
|
+
NodeSchemaLoader
|
|
115
|
+
};
|
|
116
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/audit/nodes/spec/loader.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Node schema loader \u2014 file I/O only.\n * Reads spec/ schema files and layer definitions from disk.\n */\n\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join, basename, dirname } from \"node:path\";\nimport type { ParsedNodeSchema, LayerDefinition } from \"../types.js\";\n\nexport class NodeSchemaLoader {\n constructor(private readonly specDir: string) {}\n\n /**\n * Scan spec/schemas/nodes/{layer}/*.node.schema.json and parse each file.\n * Optionally filter to a single layer by canonical name.\n */\n async loadAllSchemas(layerFilter?: string): Promise<ParsedNodeSchema[]> {\n const nodesDir = join(this.specDir, \"schemas\", \"nodes\");\n const layerDirs = await readdir(nodesDir, { withFileTypes: true });\n const schemas: ParsedNodeSchema[] = [];\n\n for (const entry of layerDirs) {\n if (!entry.isDirectory()) continue;\n const layerName = entry.name;\n if (layerFilter && layerName !== layerFilter) continue;\n\n const layerDir = join(nodesDir, layerName);\n const files = await readdir(layerDir);\n\n for (const file of files) {\n if (!file.endsWith(\".node.schema.json\")) continue;\n const filePath = join(layerDir, file);\n const raw = await readFile(filePath, \"utf-8\");\n let json: Record<string, unknown>;\n try {\n json = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // Skip unparseable files\n continue;\n }\n const parsed = this.parseSchema(json, filePath);\n if (parsed) schemas.push(parsed);\n }\n }\n\n return schemas;\n }\n\n /**\n * Read spec/layers/*.layer.json and return layer definitions.\n */\n async loadLayerDefinitions(): Promise<LayerDefinition[]> {\n const layersDir = join(this.specDir, \"layers\");\n const files = await readdir(layersDir);\n const defs: LayerDefinition[] = [];\n\n for (const file of files) {\n if (!file.endsWith(\".layer.json\")) continue;\n const filePath = join(layersDir, file);\n const raw = await readFile(filePath, \"utf-8\");\n let json: Record<string, unknown>;\n try {\n json = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n process.stderr.write(`warn: skipping malformed layer file ${filePath}: ${err}\\n`);\n continue;\n }\n defs.push(this.parseLayerDefinition(json));\n }\n\n // Sort by layer number\n defs.sort((a, b) => a.number - b.number);\n return defs;\n }\n\n /**\n * Read spec/VERSION\n */\n async loadSpecVersion(): Promise<string> {\n const versionPath = join(this.specDir, \"VERSION\");\n const content = await readFile(versionPath, \"utf-8\");\n return content.trim();\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private parseSchema(\n json: Record<string, unknown>,\n filePath: string\n ): ParsedNodeSchema | null {\n // Extract spec_node_id, layer_id, type from properties.*.const\n const properties = json[\"properties\"] as Record<string, unknown> | undefined;\n if (!properties) return null;\n\n const specNodeId = this.extractConst(properties, \"spec_node_id\");\n const layerId = this.extractConst(properties, \"layer_id\");\n const typeName = this.extractConst(properties, \"type\");\n\n if (!specNodeId || !layerId || !typeName) {\n // Fall back to deriving from file name\n const fileName = basename(filePath, \".node.schema.json\");\n const dirName = basename(dirname(filePath));\n const derivedLayerId = layerId ?? dirName;\n const derivedTypeName = typeName ?? fileName;\n const derivedSpecNodeId = specNodeId ?? `${derivedLayerId}.${derivedTypeName}`;\n\n return this.buildParsedSchema(json, properties, filePath, derivedSpecNodeId, derivedLayerId, derivedTypeName);\n }\n\n return this.buildParsedSchema(json, properties, filePath, specNodeId, layerId, typeName);\n }\n\n private buildParsedSchema(\n json: Record<string, unknown>,\n properties: Record<string, unknown>,\n filePath: string,\n specNodeId: string,\n layerId: string,\n typeName: string\n ): ParsedNodeSchema {\n const attributesProp = properties[\"attributes\"] as Record<string, unknown> | undefined;\n const attrProperties = (attributesProp?.[\"properties\"] as Record<string, { type?: string; description?: string; format?: string; enum?: string[] }>) ?? {};\n const attrRequired = (attributesProp?.[\"required\"] as string[]) ?? [];\n const attrAdditional = (attributesProp?.[\"additionalProperties\"] as boolean) ?? false;\n\n return {\n specNodeId,\n layerId,\n typeName,\n title: (json[\"title\"] as string) ?? \"\",\n description: (json[\"description\"] as string) ?? \"\",\n filePath,\n attributes: {\n properties: attrProperties,\n required: attrRequired,\n additionalProperties: attrAdditional,\n },\n };\n }\n\n private extractConst(properties: Record<string, unknown>, key: string): string | undefined {\n const prop = properties[key] as Record<string, unknown> | undefined;\n if (!prop) return undefined;\n const constVal = prop[\"const\"];\n return typeof constVal === \"string\" ? constVal : undefined;\n }\n\n private parseLayerDefinition(json: Record<string, unknown>): LayerDefinition {\n const inspiredBy = json[\"inspired_by\"] as { standard: string; version: string; url?: string } | undefined;\n return {\n id: (json[\"id\"] as string) ?? \"\",\n number: (json[\"number\"] as number) ?? 0,\n name: (json[\"name\"] as string) ?? \"\",\n nodeTypes: (json[\"node_types\"] as string[]) ?? [],\n inspiredBy: inspiredBy\n ? { standard: inspiredBy.standard, version: inspiredBy.version, url: inspiredBy.url }\n : undefined,\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { NodeSchemaLoader } from "./loader.js";
|
|
2
|
+
import { NodeDefinitionAnalyzer } from "../analysis/node-definition-analyzer.js";
|
|
3
|
+
import { NodeOverlapDetector } from "../analysis/node-overlap-detector.js";
|
|
4
|
+
import { NodeCompletenessChecker } from "../analysis/node-completeness-checker.js";
|
|
5
|
+
import { NodeAIEvaluator } from "../ai/evaluator.js";
|
|
6
|
+
class NodeAuditOrchestrator {
|
|
7
|
+
async runAudit(options) {
|
|
8
|
+
const loader = new NodeSchemaLoader(options.specDir), [specVersion, layerDefs, allSchemas] = await Promise.all([
|
|
9
|
+
loader.loadSpecVersion(),
|
|
10
|
+
loader.loadLayerDefinitions(),
|
|
11
|
+
loader.loadAllSchemas()
|
|
12
|
+
]), schemas = options.layer ? allSchemas.filter((s) => s.layerId === options.layer) : allSchemas, definitionAnalyzer = new NodeDefinitionAnalyzer(), definitionQuality = schemas.map((s) => definitionAnalyzer.analyze(s)), overlaps = new NodeOverlapDetector().detectOverlaps(schemas), completenessIssues = new NodeCompletenessChecker().check(layerDefs, allSchemas).filter((issue) => !options.layer || issue.layerId === options.layer), qualityByLayer = groupQualityByLayer(definitionQuality), layerSummaries = layerDefs.filter((l) => !options.layer || l.id === options.layer).map((layerDef) => buildLayerSummary(layerDef.id, qualityByLayer.get(layerDef.id) ?? [])), report = {
|
|
13
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14
|
+
spec: {
|
|
15
|
+
version: specVersion,
|
|
16
|
+
totalNodeTypes: allSchemas.length,
|
|
17
|
+
totalLayers: layerDefs.length
|
|
18
|
+
},
|
|
19
|
+
layerSummaries,
|
|
20
|
+
definitionQuality,
|
|
21
|
+
overlaps,
|
|
22
|
+
completenessIssues
|
|
23
|
+
};
|
|
24
|
+
if (options.enableAi) {
|
|
25
|
+
const schemasByLayer = /* @__PURE__ */ new Map();
|
|
26
|
+
for (const schema of allSchemas) {
|
|
27
|
+
const group = schemasByLayer.get(schema.layerId) ?? [];
|
|
28
|
+
group.push(schema), schemasByLayer.set(schema.layerId, group);
|
|
29
|
+
}
|
|
30
|
+
const filteredLayerDefs = layerDefs.filter((l) => !options.layer || l.id === options.layer), evaluator = new NodeAIEvaluator();
|
|
31
|
+
report.aiReviews = await evaluator.evaluateLayers(filteredLayerDefs, schemasByLayer);
|
|
32
|
+
}
|
|
33
|
+
return report;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function groupQualityByLayer(quality) {
|
|
37
|
+
const map = /* @__PURE__ */ new Map();
|
|
38
|
+
for (const q of quality) {
|
|
39
|
+
const group = map.get(q.layerId) ?? [];
|
|
40
|
+
group.push(q), map.set(q.layerId, group);
|
|
41
|
+
}
|
|
42
|
+
return map;
|
|
43
|
+
}
|
|
44
|
+
function buildLayerSummary(layerId, qualities) {
|
|
45
|
+
const total = qualities.length, avgScore = total > 0 ? qualities.reduce((sum, q) => sum + q.score, 0) / total : 0;
|
|
46
|
+
let emptyDescriptionCount = 0, genericDescriptionCount = 0, goodDescriptionCount = 0, errorCount = 0, warningCount = 0;
|
|
47
|
+
for (const q of qualities) {
|
|
48
|
+
q.descriptionQuality === "empty" ? emptyDescriptionCount++ : q.descriptionQuality === "generic" ? genericDescriptionCount++ : goodDescriptionCount++;
|
|
49
|
+
for (const issue of q.issues)
|
|
50
|
+
issue.severity === "error" ? errorCount++ : issue.severity === "warning" && warningCount++;
|
|
51
|
+
}
|
|
52
|
+
const totalIssues = qualities.reduce((sum, q) => sum + q.issues.length, 0);
|
|
53
|
+
return {
|
|
54
|
+
layerId,
|
|
55
|
+
totalNodeTypes: total,
|
|
56
|
+
avgQualityScore: Math.round(avgScore * 10) / 10,
|
|
57
|
+
emptyDescriptionCount,
|
|
58
|
+
genericDescriptionCount,
|
|
59
|
+
goodDescriptionCount,
|
|
60
|
+
totalIssues,
|
|
61
|
+
errorCount,
|
|
62
|
+
warningCount
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
NodeAuditOrchestrator
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/audit/nodes/spec/orchestrator.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Node audit orchestrator.\n * Wires all analysis modules and returns a NodeAuditReport.\n */\n\nimport { NodeSchemaLoader } from \"./loader.js\";\nimport { NodeDefinitionAnalyzer } from \"../analysis/node-definition-analyzer.js\";\nimport { NodeOverlapDetector } from \"../analysis/node-overlap-detector.js\";\nimport { NodeCompletenessChecker } from \"../analysis/node-completeness-checker.js\";\nimport { NodeAIEvaluator } from \"../ai/evaluator.js\";\nimport type {\n NodeAuditReport,\n NodeLayerSummary,\n NodeDefinitionQuality,\n ParsedNodeSchema,\n} from \"../types.js\";\n\nexport interface NodeAuditOptions {\n layer?: string;\n verbose?: boolean;\n specDir: string;\n enableAi?: boolean;\n}\n\nexport class NodeAuditOrchestrator {\n async runAudit(options: NodeAuditOptions): Promise<NodeAuditReport> {\n const loader = new NodeSchemaLoader(options.specDir);\n\n // 1. Load data \u2014 always load all schemas once, then filter in memory.\n // This avoids a second disk scan when --layer is active and ensures\n // completeness checking always runs against the full spec.\n const [specVersion, layerDefs, allSchemas] = await Promise.all([\n loader.loadSpecVersion(),\n loader.loadLayerDefinitions(),\n loader.loadAllSchemas(),\n ]);\n\n // Filtered view used by definition quality and overlap detection.\n const schemas = options.layer\n ? allSchemas.filter((s) => s.layerId === options.layer)\n : allSchemas;\n\n // 2. Definition quality \u2014 per schema\n const definitionAnalyzer = new NodeDefinitionAnalyzer();\n const definitionQuality: NodeDefinitionQuality[] = schemas.map((s) =>\n definitionAnalyzer.analyze(s)\n );\n\n // 3. Overlap detection \u2014 per layer within the loaded schemas\n const overlapDetector = new NodeOverlapDetector();\n const overlaps = overlapDetector.detectOverlaps(schemas);\n\n // 4. Completeness check \u2014 always against all schemas vs all layer defs,\n // then filter to the requested layer so per-layer reports stay scoped.\n const completenessChecker = new NodeCompletenessChecker();\n const completenessIssues = completenessChecker\n .check(layerDefs, allSchemas)\n .filter((issue) => !options.layer || issue.layerId === options.layer);\n\n // 5. Layer summaries\n const qualityByLayer = groupQualityByLayer(definitionQuality);\n const layerSummaries: NodeLayerSummary[] = layerDefs\n .filter((l) => !options.layer || l.id === options.layer)\n .map((layerDef) => buildLayerSummary(layerDef.id, qualityByLayer.get(layerDef.id) ?? []));\n\n const report: NodeAuditReport = {\n timestamp: new Date().toISOString(),\n spec: {\n version: specVersion,\n totalNodeTypes: allSchemas.length,\n totalLayers: layerDefs.length,\n },\n layerSummaries,\n definitionQuality,\n overlaps,\n completenessIssues,\n };\n\n // 6. Optional AI step\n if (options.enableAi) {\n const schemasByLayer = new Map<string, ParsedNodeSchema[]>();\n for (const schema of allSchemas) {\n const group = schemasByLayer.get(schema.layerId) ?? [];\n group.push(schema);\n schemasByLayer.set(schema.layerId, group);\n }\n // Respect --layer filter: only evaluate the filtered layer defs\n const filteredLayerDefs = layerDefs.filter(\n (l) => !options.layer || l.id === options.layer\n );\n const evaluator = new NodeAIEvaluator();\n report.aiReviews = await evaluator.evaluateLayers(filteredLayerDefs, schemasByLayer);\n }\n\n return report;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction groupQualityByLayer(\n quality: NodeDefinitionQuality[]\n): Map<string, NodeDefinitionQuality[]> {\n const map = new Map<string, NodeDefinitionQuality[]>();\n for (const q of quality) {\n const group = map.get(q.layerId) ?? [];\n group.push(q);\n map.set(q.layerId, group);\n }\n return map;\n}\n\nfunction buildLayerSummary(\n layerId: string,\n qualities: NodeDefinitionQuality[]\n): NodeLayerSummary {\n const total = qualities.length;\n const avgScore = total > 0\n ? qualities.reduce((sum, q) => sum + q.score, 0) / total\n : 0;\n\n let emptyDescriptionCount = 0;\n let genericDescriptionCount = 0;\n let goodDescriptionCount = 0;\n let errorCount = 0;\n let warningCount = 0;\n\n for (const q of qualities) {\n if (q.descriptionQuality === \"empty\") emptyDescriptionCount++;\n else if (q.descriptionQuality === \"generic\") genericDescriptionCount++;\n else goodDescriptionCount++;\n\n for (const issue of q.issues) {\n if (issue.severity === \"error\") errorCount++;\n else if (issue.severity === \"warning\") warningCount++;\n }\n }\n\n const totalIssues = qualities.reduce((sum, q) => sum + q.issues.length, 0);\n\n return {\n layerId,\n totalNodeTypes: total,\n avgQualityScore: Math.round(avgScore * 10) / 10,\n emptyDescriptionCount,\n genericDescriptionCount,\n goodDescriptionCount,\n totalIssues,\n errorCount,\n warningCount,\n };\n}\n"],
|
|
5
|
+
"mappings": "AAKA,SAAS,wBAAwB;AACjC,SAAS,8BAA8B;AACvC,SAAS,2BAA2B;AACpC,SAAS,+BAA+B;AACxC,SAAS,uBAAuB;AAe1B,MAAO,sBAAqB;EAChC,MAAM,SAAS,SAAyB;AACtC,UAAM,SAAS,IAAI,iBAAiB,QAAQ,OAAO,GAK7C,CAAC,aAAa,WAAW,UAAU,IAAI,MAAM,QAAQ,IAAI;MAC7D,OAAO,gBAAe;MACtB,OAAO,qBAAoB;MAC3B,OAAO,eAAc;KACtB,GAGK,UAAU,QAAQ,QACpB,WAAW,OAAO,CAAC,MAAM,EAAE,YAAY,QAAQ,KAAK,IACpD,YAGE,qBAAqB,IAAI,uBAAsB,GAC/C,oBAA6C,QAAQ,IAAI,CAAC,MAC9D,mBAAmB,QAAQ,CAAC,CAAC,GAKzB,WADkB,IAAI,oBAAmB,EACd,eAAe,OAAO,GAKjD,qBADsB,IAAI,wBAAuB,EAEpD,MAAM,WAAW,UAAU,EAC3B,OAAO,CAAC,UAAU,CAAC,QAAQ,SAAS,MAAM,YAAY,QAAQ,KAAK,GAGhE,iBAAiB,oBAAoB,iBAAiB,GACtD,iBAAqC,UACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,SAAS,EAAE,OAAO,QAAQ,KAAK,EACtD,IAAI,CAAC,aAAa,kBAAkB,SAAS,IAAI,eAAe,IAAI,SAAS,EAAE,KAAK,CAAA,CAAE,CAAC,GAEpF,SAA0B;MAC9B,YAAW,oBAAI,KAAI,GAAG,YAAW;MACjC,MAAM;QACJ,SAAS;QACT,gBAAgB,WAAW;QAC3B,aAAa,UAAU;;MAEzB;MACA;MACA;MACA;;AAIF,QAAI,QAAQ,UAAU;AACpB,YAAM,iBAAiB,oBAAI,IAAG;AAC9B,iBAAW,UAAU,YAAY;AAC/B,cAAM,QAAQ,eAAe,IAAI,OAAO,OAAO,KAAK,CAAA;AACpD,cAAM,KAAK,MAAM,GACjB,eAAe,IAAI,OAAO,SAAS,KAAK;MAC1C;AAEA,YAAM,oBAAoB,UAAU,OAClC,CAAC,MAAM,CAAC,QAAQ,SAAS,EAAE,OAAO,QAAQ,KAAK,GAE3C,YAAY,IAAI,gBAAe;AACrC,aAAO,YAAY,MAAM,UAAU,eAAe,mBAAmB,cAAc;IACrF;AAEA,WAAO;EACT;;AAOF,SAAS,oBACP,SAAgC;AAEhC,QAAM,MAAM,oBAAI,IAAG;AACnB,aAAW,KAAK,SAAS;AACvB,UAAM,QAAQ,IAAI,IAAI,EAAE,OAAO,KAAK,CAAA;AACpC,UAAM,KAAK,CAAC,GACZ,IAAI,IAAI,EAAE,SAAS,KAAK;EAC1B;AACA,SAAO;AACT;AAEA,SAAS,kBACP,SACA,WAAkC;AAElC,QAAM,QAAQ,UAAU,QAClB,WAAW,QAAQ,IACrB,UAAU,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC,IAAI,QACjD;AAEJ,MAAI,wBAAwB,GACxB,0BAA0B,GAC1B,uBAAuB,GACvB,aAAa,GACb,eAAe;AAEnB,aAAW,KAAK,WAAW;AACzB,IAAI,EAAE,uBAAuB,UAAS,0BAC7B,EAAE,uBAAuB,YAAW,4BACxC;AAEL,eAAW,SAAS,EAAE;AACpB,MAAI,MAAM,aAAa,UAAS,eACvB,MAAM,aAAa,aAAW;EAE3C;AAEA,QAAM,cAAc,UAAU,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,QAAQ,CAAC;AAEzE,SAAO;IACL;IACA,gBAAgB;IAChB,iBAAiB,KAAK,MAAM,WAAW,EAAE,IAAI;IAC7C;IACA;IACA;IACA;IACA;IACA;;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.js.map
|