@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
package/dist/core/element.js
CHANGED
|
@@ -1,62 +1,133 @@
|
|
|
1
1
|
class Element {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
// Spec-node aligned required fields
|
|
3
|
+
id = "";
|
|
4
|
+
path = "";
|
|
5
|
+
spec_node_id = "";
|
|
6
|
+
type = "";
|
|
7
|
+
layer_id = "";
|
|
8
|
+
name = "";
|
|
9
|
+
// Spec-node aligned optional fields
|
|
5
10
|
description;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
11
|
+
attributes = {};
|
|
12
|
+
source_reference;
|
|
13
|
+
metadata;
|
|
14
|
+
// Relationship tracking
|
|
15
|
+
references = [];
|
|
16
|
+
relationships = [];
|
|
17
|
+
// Internal tracking (unchanged)
|
|
9
18
|
layer;
|
|
10
|
-
// Track which layer this element belongs to (Python CLI compatibility)
|
|
11
19
|
filePath;
|
|
12
|
-
// Track source file path for saving back (Python CLI compatibility)
|
|
13
20
|
rawData;
|
|
14
|
-
//
|
|
21
|
+
// Original semantic ID mapping (for legacy format elements converted to UUID)
|
|
22
|
+
// Used to look up elements by their original semantic ID after UUID conversion
|
|
23
|
+
semanticId;
|
|
15
24
|
constructor(data) {
|
|
16
|
-
this.
|
|
25
|
+
this.initializeFromSpecNode(data);
|
|
17
26
|
}
|
|
18
27
|
/**
|
|
19
|
-
*
|
|
28
|
+
* Initialize Element from spec-node aligned format
|
|
20
29
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
30
|
+
initializeFromSpecNode(data) {
|
|
31
|
+
if (!data.id)
|
|
32
|
+
throw new Error("Element must have an 'id' field. Missing ID prevents proper element tracking and causes silent data loss.");
|
|
33
|
+
this.id = data.id, this.path = data.path || "", this.spec_node_id = data.spec_node_id || "", this.type = data.type || "", this.layer_id = data.layer_id || "", this.name = data.name || "", this.description = data.description, this.attributes = data.attributes || {}, data.source_reference && (this.source_reference = data.source_reference), this.metadata = data.metadata, this.references = data.references || [], this.relationships = data.relationships || [], this.layer = data.layer || data.layer_id, this.filePath = data.filePath, this.rawData = data.rawData, this.semanticId = data.semanticId;
|
|
23
34
|
}
|
|
24
35
|
/**
|
|
25
|
-
*
|
|
36
|
+
* Convert Element to spec-node format for validation
|
|
37
|
+
* Returns object that matches spec-node.schema.json structure
|
|
26
38
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
39
|
+
toSpecNode() {
|
|
40
|
+
return {
|
|
41
|
+
id: this.id,
|
|
42
|
+
path: this.path,
|
|
43
|
+
spec_node_id: this.spec_node_id,
|
|
44
|
+
type: this.type,
|
|
45
|
+
layer_id: this.layer_id,
|
|
46
|
+
name: this.name,
|
|
47
|
+
...this.description && { description: this.description },
|
|
48
|
+
attributes: this.attributes,
|
|
49
|
+
...this.source_reference && { source_reference: this.source_reference },
|
|
50
|
+
...this.metadata && { metadata: this.metadata }
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Create Element from spec-node format
|
|
55
|
+
*/
|
|
56
|
+
static fromSpecNode(data) {
|
|
57
|
+
return new Element({
|
|
58
|
+
id: data.id,
|
|
59
|
+
path: data.path,
|
|
60
|
+
spec_node_id: data.spec_node_id,
|
|
61
|
+
type: data.type,
|
|
62
|
+
layer_id: data.layer_id,
|
|
63
|
+
name: data.name,
|
|
64
|
+
description: data.description,
|
|
65
|
+
attributes: data.attributes || {},
|
|
66
|
+
source_reference: data.source_reference,
|
|
67
|
+
metadata: data.metadata
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get metadata with defensive copy for audit integrity
|
|
72
|
+
*
|
|
73
|
+
* Returns a deep copy of metadata to prevent external code from mutating
|
|
74
|
+
* the internal metadata object. This ensures timestamp immutability
|
|
75
|
+
* for audit trail integrity.
|
|
76
|
+
*
|
|
77
|
+
* @returns A defensive copy of the metadata object, or undefined if not set
|
|
78
|
+
*/
|
|
79
|
+
getMetadata() {
|
|
80
|
+
if (this.metadata)
|
|
81
|
+
return {
|
|
82
|
+
created_at: this.metadata.created_at,
|
|
83
|
+
updated_at: this.metadata.updated_at,
|
|
84
|
+
created_by: this.metadata.created_by,
|
|
85
|
+
version: this.metadata.version
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get source reference from element
|
|
90
|
+
*
|
|
91
|
+
* Returns the source reference from the top-level source_reference field.
|
|
92
|
+
*
|
|
93
|
+
* @returns The source reference if found, undefined otherwise
|
|
94
|
+
*/
|
|
95
|
+
getSourceReference() {
|
|
96
|
+
return this.source_reference;
|
|
29
97
|
}
|
|
30
98
|
/**
|
|
31
|
-
*
|
|
99
|
+
* Set source reference on element
|
|
100
|
+
*
|
|
101
|
+
* @param sourceRef The source reference to set, or undefined to remove existing reference
|
|
32
102
|
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return Array.isArray(value) ? value : [];
|
|
103
|
+
setSourceReference(sourceRef) {
|
|
104
|
+
this.source_reference = sourceRef;
|
|
36
105
|
}
|
|
37
106
|
/**
|
|
38
|
-
*
|
|
107
|
+
* Check if element has a source reference
|
|
39
108
|
*/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
current.push(item), this.properties[key] = current;
|
|
109
|
+
hasSourceReference() {
|
|
110
|
+
return this.getSourceReference() !== void 0;
|
|
43
111
|
}
|
|
44
112
|
/**
|
|
45
|
-
* Serialize to JSON representation
|
|
113
|
+
* Serialize to JSON representation (spec-node aligned format)
|
|
46
114
|
*/
|
|
47
115
|
toJSON() {
|
|
48
116
|
const result = {
|
|
49
117
|
id: this.id,
|
|
118
|
+
path: this.path,
|
|
119
|
+
spec_node_id: this.spec_node_id,
|
|
50
120
|
type: this.type,
|
|
121
|
+
layer_id: this.layer_id,
|
|
51
122
|
name: this.name
|
|
52
123
|
};
|
|
53
|
-
return this.description && (result.description = this.description), Object.keys(this.
|
|
124
|
+
return this.description && (result.description = this.description), Object.keys(this.attributes).length > 0 && (result.attributes = this.attributes), this.source_reference && (result.source_reference = this.source_reference), this.metadata && (result.metadata = this.metadata), this.references.length > 0 && (result.references = this.references), this.relationships.length > 0 && (result.relationships = this.relationships), result;
|
|
54
125
|
}
|
|
55
126
|
/**
|
|
56
127
|
* String representation
|
|
57
128
|
*/
|
|
58
129
|
toString() {
|
|
59
|
-
return `Element(${this.id})`;
|
|
130
|
+
return `Element(${this.path || this.id})`;
|
|
60
131
|
}
|
|
61
132
|
}
|
|
62
133
|
export {
|
package/dist/core/element.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/core/element.ts"],
|
|
4
|
-
"sourcesContent": ["import type {
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import type {\n Element as IElement,\n ElementMetadata,\n Reference,\n Relationship,\n SourceReference,\n} from \"../types/index.js\";\n\n/**\n * Element class representing an individual architecture item\n *\n * Aligns with spec-node.schema.json structure for direct validation.\n * Provides type-safe access to spec-node aligned fields with source reference support.\n */\nexport class Element implements IElement {\n // Spec-node aligned required fields\n id: string = \"\";\n path: string = \"\";\n spec_node_id: string = \"\";\n type: string = \"\";\n layer_id: string = \"\";\n name: string = \"\";\n\n // Spec-node aligned optional fields\n description?: string;\n attributes: Record<string, unknown> = {};\n source_reference?: SourceReference;\n metadata?: ElementMetadata;\n\n // Relationship tracking\n references: Reference[] = [];\n relationships: Relationship[] = [];\n\n // Internal tracking (unchanged)\n layer?: string;\n filePath?: string;\n rawData?: any;\n\n // Original semantic ID mapping (for legacy format elements converted to UUID)\n // Used to look up elements by their original semantic ID after UUID conversion\n semanticId?: string;\n\n constructor(data: Partial<IElement>) {\n this.initializeFromSpecNode(data);\n }\n\n /**\n * Initialize Element from spec-node aligned format\n */\n private initializeFromSpecNode(data: Partial<IElement>): void {\n // ID is required\n if (!data.id) {\n throw new Error(\n \"Element must have an 'id' field. Missing ID prevents proper element tracking and causes silent data loss.\"\n );\n }\n\n this.id = data.id;\n this.path = data.path || \"\";\n this.spec_node_id = data.spec_node_id || \"\";\n this.type = data.type || \"\";\n this.layer_id = data.layer_id || \"\";\n this.name = data.name || \"\";\n this.description = data.description;\n\n // Handle attributes - spec requires 'attributes' field only\n this.attributes = data.attributes || {};\n\n // Extract source_reference\n if (data.source_reference) {\n this.source_reference = data.source_reference;\n }\n\n this.metadata = data.metadata;\n\n // Relationship tracking\n this.references = data.references || [];\n this.relationships = data.relationships || [];\n\n // Internal tracking\n this.layer = data.layer || data.layer_id;\n this.filePath = data.filePath;\n this.rawData = data.rawData;\n\n // Semantic ID (for legacy format elements converted to UUID)\n this.semanticId = (data as any).semanticId;\n }\n\n /**\n * Convert Element to spec-node format for validation\n * Returns object that matches spec-node.schema.json structure\n */\n toSpecNode(): Record<string, unknown> {\n return {\n id: this.id,\n path: this.path,\n spec_node_id: this.spec_node_id,\n type: this.type,\n layer_id: this.layer_id,\n name: this.name,\n ...(this.description && { description: this.description }),\n attributes: this.attributes,\n ...(this.source_reference && { source_reference: this.source_reference }),\n ...(this.metadata && { metadata: this.metadata }),\n };\n }\n\n /**\n * Create Element from spec-node format\n */\n static fromSpecNode(data: Record<string, unknown>): Element {\n return new Element({\n id: data.id as string,\n path: data.path as string | undefined,\n spec_node_id: data.spec_node_id as string,\n type: data.type as string,\n layer_id: data.layer_id as string,\n name: data.name as string,\n description: data.description as string | undefined,\n attributes: (data.attributes as Record<string, unknown>) || {},\n source_reference: data.source_reference as SourceReference | undefined,\n metadata: data.metadata as ElementMetadata | undefined,\n });\n }\n\n /**\n * Get metadata with defensive copy for audit integrity\n *\n * Returns a deep copy of metadata to prevent external code from mutating\n * the internal metadata object. This ensures timestamp immutability\n * for audit trail integrity.\n *\n * @returns A defensive copy of the metadata object, or undefined if not set\n */\n getMetadata(): ElementMetadata | undefined {\n if (!this.metadata) {\n return undefined;\n }\n\n // Return a defensive copy to prevent external mutations\n return {\n created_at: this.metadata.created_at,\n updated_at: this.metadata.updated_at,\n created_by: this.metadata.created_by,\n version: this.metadata.version,\n };\n }\n\n /**\n * Get source reference from element\n *\n * Returns the source reference from the top-level source_reference field.\n *\n * @returns The source reference if found, undefined otherwise\n */\n getSourceReference(): SourceReference | undefined {\n return this.source_reference;\n }\n\n /**\n * Set source reference on element\n *\n * @param sourceRef The source reference to set, or undefined to remove existing reference\n */\n setSourceReference(sourceRef: SourceReference | undefined): void {\n this.source_reference = sourceRef;\n }\n\n /**\n * Check if element has a source reference\n */\n hasSourceReference(): boolean {\n return this.getSourceReference() !== undefined;\n }\n\n /**\n * Serialize to JSON representation (spec-node aligned format)\n */\n toJSON(): IElement {\n const result: IElement = {\n id: this.id,\n path: this.path,\n spec_node_id: this.spec_node_id,\n type: this.type,\n layer_id: this.layer_id,\n name: this.name,\n };\n\n if (this.description) {\n result.description = this.description;\n }\n\n if (Object.keys(this.attributes).length > 0) {\n result.attributes = this.attributes;\n }\n\n if (this.source_reference) {\n result.source_reference = this.source_reference;\n }\n\n if (this.metadata) {\n result.metadata = this.metadata;\n }\n\n if (this.references.length > 0) {\n result.references = this.references;\n }\n\n if (this.relationships.length > 0) {\n result.relationships = this.relationships;\n }\n\n return result;\n }\n\n /**\n * String representation\n */\n toString(): string {\n return `Element(${this.path || this.id})`;\n }\n}\n"],
|
|
5
|
+
"mappings": "AAcM,MAAO,QAAO;;EAElB,KAAa;EACb,OAAe;EACf,eAAuB;EACvB,OAAe;EACf,WAAmB;EACnB,OAAe;;EAGf;EACA,aAAsC,CAAA;EACtC;EACA;;EAGA,aAA0B,CAAA;EAC1B,gBAAgC,CAAA;;EAGhC;EACA;EACA;;;EAIA;EAEA,YAAY,MAAuB;AACjC,SAAK,uBAAuB,IAAI;EAClC;;;;EAKQ,uBAAuB,MAAuB;AAEpD,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MACR,2GAA2G;AAI/G,SAAK,KAAK,KAAK,IACf,KAAK,OAAO,KAAK,QAAQ,IACzB,KAAK,eAAe,KAAK,gBAAgB,IACzC,KAAK,OAAO,KAAK,QAAQ,IACzB,KAAK,WAAW,KAAK,YAAY,IACjC,KAAK,OAAO,KAAK,QAAQ,IACzB,KAAK,cAAc,KAAK,aAGxB,KAAK,aAAa,KAAK,cAAc,CAAA,GAGjC,KAAK,qBACP,KAAK,mBAAmB,KAAK,mBAG/B,KAAK,WAAW,KAAK,UAGrB,KAAK,aAAa,KAAK,cAAc,CAAA,GACrC,KAAK,gBAAgB,KAAK,iBAAiB,CAAA,GAG3C,KAAK,QAAQ,KAAK,SAAS,KAAK,UAChC,KAAK,WAAW,KAAK,UACrB,KAAK,UAAU,KAAK,SAGpB,KAAK,aAAc,KAAa;EAClC;;;;;EAMA,aAAU;AACR,WAAO;MACL,IAAI,KAAK;MACT,MAAM,KAAK;MACX,cAAc,KAAK;MACnB,MAAM,KAAK;MACX,UAAU,KAAK;MACf,MAAM,KAAK;MACX,GAAI,KAAK,eAAe,EAAE,aAAa,KAAK,YAAW;MACvD,YAAY,KAAK;MACjB,GAAI,KAAK,oBAAoB,EAAE,kBAAkB,KAAK,iBAAgB;MACtE,GAAI,KAAK,YAAY,EAAE,UAAU,KAAK,SAAQ;;EAElD;;;;EAKA,OAAO,aAAa,MAA6B;AAC/C,WAAO,IAAI,QAAQ;MACjB,IAAI,KAAK;MACT,MAAM,KAAK;MACX,cAAc,KAAK;MACnB,MAAM,KAAK;MACX,UAAU,KAAK;MACf,MAAM,KAAK;MACX,aAAa,KAAK;MAClB,YAAa,KAAK,cAA0C,CAAA;MAC5D,kBAAkB,KAAK;MACvB,UAAU,KAAK;KAChB;EACH;;;;;;;;;;EAWA,cAAW;AACT,QAAK,KAAK;AAKV,aAAO;QACL,YAAY,KAAK,SAAS;QAC1B,YAAY,KAAK,SAAS;QAC1B,YAAY,KAAK,SAAS;QAC1B,SAAS,KAAK,SAAS;;EAE3B;;;;;;;;EASA,qBAAkB;AAChB,WAAO,KAAK;EACd;;;;;;EAOA,mBAAmB,WAAsC;AACvD,SAAK,mBAAmB;EAC1B;;;;EAKA,qBAAkB;AAChB,WAAO,KAAK,mBAAkB,MAAO;EACvC;;;;EAKA,SAAM;AACJ,UAAM,SAAmB;MACvB,IAAI,KAAK;MACT,MAAM,KAAK;MACX,cAAc,KAAK;MACnB,MAAM,KAAK;MACX,UAAU,KAAK;MACf,MAAM,KAAK;;AAGb,WAAI,KAAK,gBACP,OAAO,cAAc,KAAK,cAGxB,OAAO,KAAK,KAAK,UAAU,EAAE,SAAS,MACxC,OAAO,aAAa,KAAK,aAGvB,KAAK,qBACP,OAAO,mBAAmB,KAAK,mBAG7B,KAAK,aACP,OAAO,WAAW,KAAK,WAGrB,KAAK,WAAW,SAAS,MAC3B,OAAO,aAAa,KAAK,aAGvB,KAAK,cAAc,SAAS,MAC9B,OAAO,gBAAgB,KAAK,gBAGvB;EACT;;;;EAKA,WAAQ;AACN,WAAO,WAAW,KAAK,QAAQ,KAAK,EAAE;EACxC;;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { Model } from "./model.js";
|
|
2
|
+
import { Layer } from "./layer.js";
|
|
3
|
+
import { Element } from "./element.js";
|
|
4
|
+
import { mkdir, cp, rm, access } from "fs/promises";
|
|
5
|
+
import { join } from "path";
|
|
6
|
+
import { tmpdir } from "os";
|
|
7
|
+
import { getErrorMessage } from "../utils/errors.js";
|
|
8
|
+
class GoldenCopyCacheManager {
|
|
9
|
+
static instance = null;
|
|
10
|
+
static lastConfig;
|
|
11
|
+
goldenModel = null;
|
|
12
|
+
goldenRootPath = null;
|
|
13
|
+
config;
|
|
14
|
+
lifecycleState = { status: "uninitialized" };
|
|
15
|
+
stats = {
|
|
16
|
+
initCount: 0,
|
|
17
|
+
cloneCount: 0,
|
|
18
|
+
totalInitTime: 0,
|
|
19
|
+
totalCloneTime: 0,
|
|
20
|
+
avgInitTime: 0,
|
|
21
|
+
avgCloneTime: 0
|
|
22
|
+
};
|
|
23
|
+
constructor(config = {}) {
|
|
24
|
+
this.config = {
|
|
25
|
+
cacheDir: config.cacheDir || join(tmpdir(), "dr-golden-copy-cache"),
|
|
26
|
+
eagerLoad: config.eagerLoad ?? !1,
|
|
27
|
+
warmup: config.warmup ?? !1,
|
|
28
|
+
modelOptions: config.modelOptions || {
|
|
29
|
+
name: "Golden Copy Test Model",
|
|
30
|
+
version: "0.1.0",
|
|
31
|
+
specVersion: "0.7.1",
|
|
32
|
+
description: "Shared golden copy for test initialization",
|
|
33
|
+
author: "Test Suite"
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get or create the singleton instance
|
|
39
|
+
*
|
|
40
|
+
* Thread-safe: If multiple threads/workers call getInstance() concurrently
|
|
41
|
+
* with different configs, the first one wins. This is acceptable because
|
|
42
|
+
* getInstance() should be called early in test setup with consistent config.
|
|
43
|
+
*
|
|
44
|
+
* @throws Error if config differs from existing instance and GOLDEN_COPY_STRICT is enabled
|
|
45
|
+
*/
|
|
46
|
+
static getInstance(config) {
|
|
47
|
+
if (!GoldenCopyCacheManager.instance)
|
|
48
|
+
GoldenCopyCacheManager.instance = new GoldenCopyCacheManager(config), GoldenCopyCacheManager.lastConfig = config;
|
|
49
|
+
else if (process.env.GOLDEN_COPY_STRICT === "true") {
|
|
50
|
+
const configStr = JSON.stringify(config || {}), lastConfigStr = JSON.stringify(GoldenCopyCacheManager.lastConfig || {});
|
|
51
|
+
configStr !== lastConfigStr && console.warn(`[GoldenCopy] WARNING: getInstance() called with different config. First config wins. Current: ${configStr}, Last: ${lastConfigStr}`);
|
|
52
|
+
}
|
|
53
|
+
return GoldenCopyCacheManager.instance;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Reset the singleton instance (useful for testing)
|
|
57
|
+
*/
|
|
58
|
+
static resetInstance() {
|
|
59
|
+
GoldenCopyCacheManager.instance = null;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Initialize the golden copy cache
|
|
63
|
+
*
|
|
64
|
+
* Creates or loads a shared golden model that serves as the basis
|
|
65
|
+
* for all test model clones. This should be called once per test worker.
|
|
66
|
+
* Subsequent calls are idempotent (no-op if already initialized).
|
|
67
|
+
*
|
|
68
|
+
* Thread-safe: Concurrent calls before initialization completes are handled
|
|
69
|
+
* via initializationPromise lock. Only the first call performs actual work.
|
|
70
|
+
*
|
|
71
|
+
* @returns Promise resolving when golden copy is ready
|
|
72
|
+
*/
|
|
73
|
+
async init() {
|
|
74
|
+
if (this.lifecycleState.status === "initialized") {
|
|
75
|
+
process.env.DEBUG_GOLDEN_COPY && console.log("[GoldenCopy] Already initialized, skipping init");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (this.lifecycleState.status === "initializing")
|
|
79
|
+
return process.env.DEBUG_GOLDEN_COPY && console.log("[GoldenCopy] Initialization in progress, waiting..."), this.lifecycleState.promise;
|
|
80
|
+
if (this.lifecycleState.status === "cleaned-up")
|
|
81
|
+
throw new Error("Golden copy manager has been cleaned up. Create a new instance.");
|
|
82
|
+
const initPromise = this.performInitialization();
|
|
83
|
+
this.lifecycleState = { status: "initializing", promise: initPromise };
|
|
84
|
+
try {
|
|
85
|
+
await initPromise;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
throw this.lifecycleState = { status: "uninitialized" }, error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Perform the actual initialization work
|
|
92
|
+
* @private
|
|
93
|
+
*/
|
|
94
|
+
async performInitialization() {
|
|
95
|
+
const startTime = Date.now();
|
|
96
|
+
try {
|
|
97
|
+
await mkdir(this.config.cacheDir, { recursive: !0 });
|
|
98
|
+
const goldenPath = join(this.config.cacheDir, "golden-model");
|
|
99
|
+
let modelExists = !1;
|
|
100
|
+
try {
|
|
101
|
+
await access(goldenPath), modelExists = !0;
|
|
102
|
+
} catch {
|
|
103
|
+
}
|
|
104
|
+
if (modelExists)
|
|
105
|
+
this.goldenModel = await Model.load(goldenPath, { lazyLoad: !this.config.eagerLoad }), this.goldenRootPath = goldenPath;
|
|
106
|
+
else {
|
|
107
|
+
const created = await Model.init(goldenPath, {
|
|
108
|
+
name: this.config.modelOptions.name || "Golden Copy Test Model",
|
|
109
|
+
version: this.config.modelOptions.version || "0.1.0",
|
|
110
|
+
specVersion: this.config.modelOptions.specVersion || "0.7.1",
|
|
111
|
+
description: this.config.modelOptions.description || "Shared golden copy for test initialization",
|
|
112
|
+
author: this.config.modelOptions.author || "Test Suite",
|
|
113
|
+
created: (/* @__PURE__ */ new Date()).toISOString()
|
|
114
|
+
}, { lazyLoad: !this.config.eagerLoad });
|
|
115
|
+
this.goldenModel = created, this.goldenRootPath = goldenPath, this.config.warmup && (await this.populateGoldenCopy(), await created.save());
|
|
116
|
+
}
|
|
117
|
+
this.stats.initCount++, this.stats.totalInitTime += Date.now() - startTime, this.stats.avgInitTime = this.stats.totalInitTime / this.stats.initCount, this.goldenModel && this.goldenRootPath && (this.lifecycleState = {
|
|
118
|
+
status: "initialized",
|
|
119
|
+
model: this.goldenModel,
|
|
120
|
+
rootPath: this.goldenRootPath
|
|
121
|
+
}), process.env.DEBUG_GOLDEN_COPY && console.log(`[GoldenCopy] Initialized in ${Date.now() - startTime}ms`);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
throw new Error(`Failed to initialize golden copy cache: ${getErrorMessage(error)}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Clone the golden model for test use
|
|
128
|
+
*
|
|
129
|
+
* Creates an independent copy of the golden model that a test can safely modify
|
|
130
|
+
* without affecting other tests. The clone is isolated in its own temporary directory.
|
|
131
|
+
*
|
|
132
|
+
* Handles filesystem errors:
|
|
133
|
+
* - EEXIST: Retries with new random suffix (collision handling)
|
|
134
|
+
* - ENOSPC: Reports disk full error with guidance
|
|
135
|
+
* - Other: Reports with context
|
|
136
|
+
*
|
|
137
|
+
* Differentiates between copy failures and model load failures in error messages.
|
|
138
|
+
*
|
|
139
|
+
* @returns Promise resolving to the cloned model with cleanup handler
|
|
140
|
+
*/
|
|
141
|
+
async clone() {
|
|
142
|
+
if (!this.goldenModel || !this.goldenRootPath)
|
|
143
|
+
throw new Error("Golden copy cache not initialized. Call init() first.");
|
|
144
|
+
const startTime = Date.now();
|
|
145
|
+
let clonePath = null, copySuccessful = !1;
|
|
146
|
+
try {
|
|
147
|
+
clonePath = await this.generateClonePath();
|
|
148
|
+
try {
|
|
149
|
+
await cp(this.goldenRootPath, clonePath, { recursive: !0 }), copySuccessful = !0;
|
|
150
|
+
} catch (copyError) {
|
|
151
|
+
throw copyError instanceof Error && copyError.code === "ENOSPC" ? new Error(`Disk space exhausted while cloning golden copy. Ensure at least 100MB free space is available. Error: ${copyError.message}`) : new Error(`Failed to copy golden model to ${clonePath}: ${copyError instanceof Error ? copyError.message : String(copyError)}`);
|
|
152
|
+
}
|
|
153
|
+
let clonedModel;
|
|
154
|
+
try {
|
|
155
|
+
clonedModel = await Model.load(clonePath);
|
|
156
|
+
} catch (loadError) {
|
|
157
|
+
throw new Error(`Successfully copied golden model to ${clonePath}, but failed to load cloned model. This suggests corrupted source data. Error: ${loadError instanceof Error ? loadError.message : String(loadError)}`);
|
|
158
|
+
}
|
|
159
|
+
const cloneTime = Date.now() - startTime;
|
|
160
|
+
this.stats.cloneCount++, this.stats.totalCloneTime += cloneTime, this.stats.avgCloneTime = this.stats.totalCloneTime / this.stats.cloneCount, process.env.DEBUG_GOLDEN_COPY && console.log(`[GoldenCopy] Cloned model in ${cloneTime}ms (clone ${this.stats.cloneCount})`);
|
|
161
|
+
let cleanupCalled = !1;
|
|
162
|
+
return {
|
|
163
|
+
model: clonedModel,
|
|
164
|
+
rootPath: clonePath,
|
|
165
|
+
cleanup: async () => {
|
|
166
|
+
if (cleanupCalled) {
|
|
167
|
+
process.env.DEBUG_GOLDEN_COPY && console.log(`[GoldenCopy] Cleanup already called for ${clonePath}`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
cleanupCalled = !0;
|
|
171
|
+
try {
|
|
172
|
+
await rm(clonePath, { recursive: !0, force: !0 });
|
|
173
|
+
} catch (e) {
|
|
174
|
+
console.error(`[GoldenCopy] ERROR: Failed to clean up cloned model at ${clonePath}. This may cause disk space issues. Error: ${e instanceof Error ? e.message : String(e)}`);
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
stats: {
|
|
178
|
+
cloneTime
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
} catch (error) {
|
|
182
|
+
if (copySuccessful && clonePath)
|
|
183
|
+
try {
|
|
184
|
+
await rm(clonePath, { recursive: !0, force: !0 });
|
|
185
|
+
} catch (cleanupError) {
|
|
186
|
+
console.error(`[GoldenCopy] ERROR: Model load failed AND cleanup failed. Orphaned directory may exist at ${clonePath}. Load error: ${getErrorMessage(error)}. Cleanup error: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
|
|
187
|
+
}
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Generate a unique clone path with retry logic for EEXIST collisions
|
|
193
|
+
* @private
|
|
194
|
+
*/
|
|
195
|
+
async generateClonePath(maxRetries = 5) {
|
|
196
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
197
|
+
const cloneId = `${Date.now()}-${Math.random().toString(36).substring(2, 9)}-attempt${attempt}`, clonePath = join(tmpdir(), `dr-test-clone-${cloneId}`);
|
|
198
|
+
try {
|
|
199
|
+
await access(clonePath);
|
|
200
|
+
} catch {
|
|
201
|
+
return clonePath;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
throw new Error(`Failed to generate unique clone path after ${maxRetries} attempts. Potential issue with concurrent test execution or stale directories.`);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Populate the golden copy with standard test data
|
|
208
|
+
*
|
|
209
|
+
* This is called during warmup to pre-populate the golden model with
|
|
210
|
+
* a canonical set of test elements across layers.
|
|
211
|
+
*
|
|
212
|
+
* @private
|
|
213
|
+
*/
|
|
214
|
+
async populateGoldenCopy() {
|
|
215
|
+
if (!this.goldenModel)
|
|
216
|
+
throw new Error("Golden model not initialized");
|
|
217
|
+
const addElement = async (layerName, type, id, name, attributes) => {
|
|
218
|
+
let layer = await this.goldenModel.getLayer(layerName);
|
|
219
|
+
layer || (layer = new Layer(layerName), this.goldenModel.addLayer(layer));
|
|
220
|
+
const element = new Element({
|
|
221
|
+
id,
|
|
222
|
+
type,
|
|
223
|
+
name,
|
|
224
|
+
description: `Golden copy element: ${name}`,
|
|
225
|
+
attributes: attributes || {}
|
|
226
|
+
});
|
|
227
|
+
layer.addElement(element);
|
|
228
|
+
};
|
|
229
|
+
await addElement("motivation", "goal", "motivation.goal.golden-1", "Golden Goal 1"), await addElement("motivation", "goal", "motivation.goal.golden-2", "Golden Goal 2"), await addElement("motivation", "requirement", "motivation.requirement.golden-1", "Golden Requirement 1"), await addElement("business", "process", "business.process.golden-1", "Golden Process 1"), await addElement("business", "service", "business.service.golden-1", "Golden Service 1"), await addElement("application", "component", "application.component.golden-1", "Golden Component 1"), await addElement("application", "service", "application.service.golden-1", "Golden Service 1"), await addElement("technology", "infrastructure", "technology.infrastructure.golden-1", "Golden Infrastructure 1"), await addElement("technology", "platform", "technology.platform.golden-1", "Golden Platform 1"), await addElement("api", "endpoint", "api.endpoint.golden-1", "Golden Endpoint 1", {
|
|
230
|
+
method: "GET",
|
|
231
|
+
path: "/golden/1"
|
|
232
|
+
}), await addElement("api", "endpoint", "api.endpoint.golden-2", "Golden Endpoint 2", {
|
|
233
|
+
method: "POST",
|
|
234
|
+
path: "/golden/2"
|
|
235
|
+
}), await addElement("data-model", "entity", "data-model.entity.golden-1", "Golden Entity 1"), await addElement("data-model", "entity", "data-model.entity.golden-2", "Golden Entity 2");
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Get statistics about golden copy cache performance
|
|
239
|
+
*/
|
|
240
|
+
getStats() {
|
|
241
|
+
return { ...this.stats };
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Check if golden copy is initialized
|
|
245
|
+
*/
|
|
246
|
+
isInitialized() {
|
|
247
|
+
return this.goldenModel !== null && this.goldenRootPath !== null;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Get the golden model (immutable reference)
|
|
251
|
+
*
|
|
252
|
+
* Returns a frozen reference to prevent accidental mutations that could
|
|
253
|
+
* corrupt the shared golden copy. Direct modifications through the returned
|
|
254
|
+
* object will fail at runtime.
|
|
255
|
+
*
|
|
256
|
+
* @returns Frozen golden model or null if not initialized
|
|
257
|
+
*/
|
|
258
|
+
getGoldenModel() {
|
|
259
|
+
return this.goldenModel ? Object.freeze(Object.create(Object.getPrototypeOf(this.goldenModel), Object.getOwnPropertyDescriptors(this.goldenModel))) : null;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Get the cache directory path
|
|
263
|
+
*/
|
|
264
|
+
getCacheDir() {
|
|
265
|
+
return this.config.cacheDir;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Clean up the golden copy cache
|
|
269
|
+
*
|
|
270
|
+
* Removes the cached golden model and resets the cache manager.
|
|
271
|
+
* Should be called at the end of test suite execution.
|
|
272
|
+
*
|
|
273
|
+
* Idempotent: Safe to call multiple times without error.
|
|
274
|
+
*/
|
|
275
|
+
async cleanup() {
|
|
276
|
+
if (this.lifecycleState.status === "cleaned-up") {
|
|
277
|
+
process.env.DEBUG_GOLDEN_COPY && console.log("[GoldenCopy] Already cleaned up, skipping");
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
try {
|
|
281
|
+
this.goldenRootPath && await rm(this.goldenRootPath, { recursive: !0, force: !0 }), this.goldenModel = null, this.goldenRootPath = null, this.lifecycleState = { status: "cleaned-up" }, GoldenCopyCacheManager.resetInstance(), process.env.DEBUG_GOLDEN_COPY && (console.log("[GoldenCopy] Cache cleaned up"), console.log("[GoldenCopy] Stats:", this.stats));
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.error(`[GoldenCopy] ERROR: Failed to clean up golden copy cache at ${this.goldenRootPath}. This may cause disk space issues. Error: ${getErrorMessage(error)}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
export {
|
|
288
|
+
GoldenCopyCacheManager
|
|
289
|
+
};
|
|
290
|
+
//# sourceMappingURL=golden-copy-cache.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/core/golden-copy-cache.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Golden Copy Cache Management\n *\n * Provides a shared golden copy of a test model that can be efficiently cloned\n * for use across multiple tests, improving test initialization performance.\n *\n * Key Features:\n * - Single initialization of a canonical test model on first use\n * - Fast cloning via filesystem copy (copy-on-write semantics)\n * - Automatic cache lifecycle management\n * - Optional warm-up for eager element loading\n * - Support for custom golden copy configurations\n */\n\nimport { Model } from \"./model.js\";\nimport { Layer } from \"./layer.js\";\nimport { Element } from \"./element.js\";\nimport { mkdir, cp, rm, access } from \"fs/promises\";\nimport { join } from \"path\";\nimport { tmpdir } from \"os\";\nimport { getErrorMessage } from \"../utils/errors.js\";\n\n/**\n * Configuration for the golden copy cache\n */\nexport interface GoldenCopyCacheConfig {\n /** Base directory for golden copy cache (defaults to temp directory) */\n cacheDir?: string;\n\n /** Whether to eagerly load all layers when creating golden copy */\n eagerLoad?: boolean;\n\n /** Whether to enable warm-up (populate with sample data) */\n warmup?: boolean;\n\n /** Custom test model options */\n modelOptions?: {\n name?: string;\n version?: string;\n specVersion?: string;\n description?: string;\n author?: string;\n };\n}\n\n/**\n * Statistics for golden copy cache operations\n */\nexport interface GoldenCopyStats {\n initCount: number;\n cloneCount: number;\n totalInitTime: number;\n totalCloneTime: number;\n avgInitTime: number;\n avgCloneTime: number;\n}\n\n/**\n * Result of a golden copy clone operation\n */\nexport interface ClonedModel {\n model: Model;\n rootPath: string;\n cleanup: () => Promise<void>;\n stats: {\n cloneTime: number;\n };\n}\n\n/**\n * Lifecycle state of the golden copy manager\n */\ntype ManagerLifecycleState =\n | { status: \"uninitialized\" }\n | { status: \"initializing\"; promise: Promise<void> }\n | { status: \"initialized\"; model: Model; rootPath: string }\n | { status: \"cleaned-up\" };\n\n/**\n * Golden Copy Cache Manager\n *\n * Manages the lifecycle of a shared golden test model and provides\n * efficient cloning for individual test use.\n */\nexport class GoldenCopyCacheManager {\n private static instance: GoldenCopyCacheManager | null = null;\n private static lastConfig: GoldenCopyCacheConfig | undefined;\n private goldenModel: Model | null = null;\n private goldenRootPath: string | null = null;\n private config: Required<GoldenCopyCacheConfig>;\n private lifecycleState: ManagerLifecycleState = { status: \"uninitialized\" };\n private stats: GoldenCopyStats = {\n initCount: 0,\n cloneCount: 0,\n totalInitTime: 0,\n totalCloneTime: 0,\n avgInitTime: 0,\n avgCloneTime: 0,\n };\n\n private constructor(config: GoldenCopyCacheConfig = {}) {\n this.config = {\n cacheDir: config.cacheDir || join(tmpdir(), \"dr-golden-copy-cache\"),\n eagerLoad: config.eagerLoad ?? false,\n warmup: config.warmup ?? false,\n modelOptions: config.modelOptions || {\n name: \"Golden Copy Test Model\",\n version: \"0.1.0\",\n specVersion: \"0.7.1\",\n description: \"Shared golden copy for test initialization\",\n author: \"Test Suite\",\n },\n };\n }\n\n /**\n * Get or create the singleton instance\n *\n * Thread-safe: If multiple threads/workers call getInstance() concurrently\n * with different configs, the first one wins. This is acceptable because\n * getInstance() should be called early in test setup with consistent config.\n *\n * @throws Error if config differs from existing instance and GOLDEN_COPY_STRICT is enabled\n */\n static getInstance(config?: GoldenCopyCacheConfig): GoldenCopyCacheManager {\n if (!GoldenCopyCacheManager.instance) {\n GoldenCopyCacheManager.instance = new GoldenCopyCacheManager(config);\n GoldenCopyCacheManager.lastConfig = config;\n } else if (process.env.GOLDEN_COPY_STRICT === \"true\") {\n // In strict mode, warn if config differs\n const configStr = JSON.stringify(config || {});\n const lastConfigStr = JSON.stringify(GoldenCopyCacheManager.lastConfig || {});\n if (configStr !== lastConfigStr) {\n console.warn(\n `[GoldenCopy] WARNING: getInstance() called with different config. ` +\n `First config wins. Current: ${configStr}, Last: ${lastConfigStr}`\n );\n }\n }\n return GoldenCopyCacheManager.instance;\n }\n\n /**\n * Reset the singleton instance (useful for testing)\n */\n static resetInstance(): void {\n GoldenCopyCacheManager.instance = null;\n }\n\n /**\n * Initialize the golden copy cache\n *\n * Creates or loads a shared golden model that serves as the basis\n * for all test model clones. This should be called once per test worker.\n * Subsequent calls are idempotent (no-op if already initialized).\n *\n * Thread-safe: Concurrent calls before initialization completes are handled\n * via initializationPromise lock. Only the first call performs actual work.\n *\n * @returns Promise resolving when golden copy is ready\n */\n async init(): Promise<void> {\n // If already initialized, return early (idempotent)\n if (this.lifecycleState.status === \"initialized\") {\n if (process.env.DEBUG_GOLDEN_COPY) {\n console.log(\"[GoldenCopy] Already initialized, skipping init\");\n }\n return;\n }\n\n // If initialization is in progress, wait for it to complete\n if (this.lifecycleState.status === \"initializing\") {\n if (process.env.DEBUG_GOLDEN_COPY) {\n console.log(\"[GoldenCopy] Initialization in progress, waiting...\");\n }\n return this.lifecycleState.promise;\n }\n\n // If cleaned up, cannot reinitialize\n if (this.lifecycleState.status === \"cleaned-up\") {\n throw new Error(\"Golden copy manager has been cleaned up. Create a new instance.\");\n }\n\n // Mark initialization as in progress\n const initPromise = this.performInitialization();\n this.lifecycleState = { status: \"initializing\", promise: initPromise };\n\n try {\n await initPromise;\n } catch (error) {\n // Reset to uninitialized on failure\n this.lifecycleState = { status: \"uninitialized\" };\n throw error;\n }\n }\n\n /**\n * Perform the actual initialization work\n * @private\n */\n private async performInitialization(): Promise<void> {\n const startTime = Date.now();\n\n try {\n // Create cache directory\n await mkdir(this.config.cacheDir, { recursive: true });\n\n // Check if golden copy already exists on disk\n const goldenPath = join(this.config.cacheDir, \"golden-model\");\n let modelExists = false;\n\n try {\n await access(goldenPath);\n modelExists = true;\n } catch {\n // Directory doesn't exist, will create new\n }\n\n if (!modelExists) {\n // Create new golden model\n const created = await Model.init(\n goldenPath,\n {\n name: this.config.modelOptions.name || \"Golden Copy Test Model\",\n version: this.config.modelOptions.version || \"0.1.0\",\n specVersion: this.config.modelOptions.specVersion || \"0.7.1\",\n description:\n this.config.modelOptions.description || \"Shared golden copy for test initialization\",\n author: this.config.modelOptions.author || \"Test Suite\",\n created: new Date().toISOString(),\n },\n { lazyLoad: !this.config.eagerLoad }\n );\n\n this.goldenModel = created;\n this.goldenRootPath = goldenPath;\n\n // Optional warm-up: populate with sample data\n if (this.config.warmup) {\n await this.populateGoldenCopy();\n await created.save();\n }\n } else {\n // Load existing golden model\n this.goldenModel = await Model.load(goldenPath, { lazyLoad: !this.config.eagerLoad });\n this.goldenRootPath = goldenPath;\n }\n\n this.stats.initCount++;\n this.stats.totalInitTime += Date.now() - startTime;\n this.stats.avgInitTime = this.stats.totalInitTime / this.stats.initCount;\n\n // Mark as initialized\n if (this.goldenModel && this.goldenRootPath) {\n this.lifecycleState = {\n status: \"initialized\",\n model: this.goldenModel,\n rootPath: this.goldenRootPath,\n };\n }\n\n if (process.env.DEBUG_GOLDEN_COPY) {\n console.log(`[GoldenCopy] Initialized in ${Date.now() - startTime}ms`);\n }\n } catch (error) {\n throw new Error(\n `Failed to initialize golden copy cache: ${getErrorMessage(error)}`\n );\n }\n }\n\n /**\n * Clone the golden model for test use\n *\n * Creates an independent copy of the golden model that a test can safely modify\n * without affecting other tests. The clone is isolated in its own temporary directory.\n *\n * Handles filesystem errors:\n * - EEXIST: Retries with new random suffix (collision handling)\n * - ENOSPC: Reports disk full error with guidance\n * - Other: Reports with context\n *\n * Differentiates between copy failures and model load failures in error messages.\n *\n * @returns Promise resolving to the cloned model with cleanup handler\n */\n async clone(): Promise<ClonedModel> {\n if (!this.goldenModel || !this.goldenRootPath) {\n throw new Error(\"Golden copy cache not initialized. Call init() first.\");\n }\n\n const startTime = Date.now();\n let clonePath: string | null = null;\n let copySuccessful = false;\n\n try {\n // Generate clone path with retry logic for collisions\n clonePath = await this.generateClonePath();\n\n // Create a filesystem copy of the golden model\n // This is efficient and provides copy-on-write semantics\n try {\n await cp(this.goldenRootPath, clonePath, { recursive: true });\n copySuccessful = true;\n } catch (copyError) {\n // Distinguish copy errors\n if (copyError instanceof Error && (copyError as NodeJS.ErrnoException).code === \"ENOSPC\") {\n throw new Error(\n `Disk space exhausted while cloning golden copy. ` +\n `Ensure at least 100MB free space is available. ` +\n `Error: ${copyError.message}`\n );\n }\n throw new Error(\n `Failed to copy golden model to ${clonePath}: ${copyError instanceof Error ? copyError.message : String(copyError)}`\n );\n }\n\n // Load the cloned model\n let clonedModel: Model;\n try {\n clonedModel = await Model.load(clonePath);\n } catch (loadError) {\n throw new Error(\n `Successfully copied golden model to ${clonePath}, but failed to load cloned model. ` +\n `This suggests corrupted source data. Error: ${loadError instanceof Error ? loadError.message : String(loadError)}`\n );\n }\n\n const cloneTime = Date.now() - startTime;\n this.stats.cloneCount++;\n this.stats.totalCloneTime += cloneTime;\n this.stats.avgCloneTime = this.stats.totalCloneTime / this.stats.cloneCount;\n\n if (process.env.DEBUG_GOLDEN_COPY) {\n console.log(`[GoldenCopy] Cloned model in ${cloneTime}ms (clone ${this.stats.cloneCount})`);\n }\n\n let cleanupCalled = false;\n\n return {\n model: clonedModel,\n rootPath: clonePath,\n cleanup: async () => {\n if (cleanupCalled) {\n if (process.env.DEBUG_GOLDEN_COPY) {\n console.log(`[GoldenCopy] Cleanup already called for ${clonePath}`);\n }\n return;\n }\n cleanupCalled = true;\n\n try {\n await rm(clonePath!, { recursive: true, force: true });\n } catch (e) {\n // Always log cleanup errors - they can cause disk space issues\n console.error(\n `[GoldenCopy] ERROR: Failed to clean up cloned model at ${clonePath}. ` +\n `This may cause disk space issues. ` +\n `Error: ${e instanceof Error ? e.message : String(e)}`\n );\n }\n },\n stats: {\n cloneTime,\n },\n };\n } catch (error) {\n // Attempt cleanup only if copy was successful\n if (copySuccessful && clonePath) {\n try {\n await rm(clonePath, { recursive: true, force: true });\n } catch (cleanupError) {\n // Log cleanup failures even in error paths\n console.error(\n `[GoldenCopy] ERROR: Model load failed AND cleanup failed. ` +\n `Orphaned directory may exist at ${clonePath}. ` +\n `Load error: ${getErrorMessage(error)}. ` +\n `Cleanup error: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`\n );\n }\n }\n throw error;\n }\n }\n\n /**\n * Generate a unique clone path with retry logic for EEXIST collisions\n * @private\n */\n private async generateClonePath(maxRetries: number = 5): Promise<string> {\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n const cloneId = `${Date.now()}-${Math.random().toString(36).substring(2, 9)}-attempt${attempt}`;\n const clonePath = join(tmpdir(), `dr-test-clone-${cloneId}`);\n\n try {\n // Check if path already exists\n await access(clonePath);\n // Path exists, continue to next attempt\n } catch {\n // Path doesn't exist, we can use it\n return clonePath;\n }\n }\n\n throw new Error(\n `Failed to generate unique clone path after ${maxRetries} attempts. ` +\n `Potential issue with concurrent test execution or stale directories.`\n );\n }\n\n /**\n * Populate the golden copy with standard test data\n *\n * This is called during warmup to pre-populate the golden model with\n * a canonical set of test elements across layers.\n *\n * @private\n */\n private async populateGoldenCopy(): Promise<void> {\n if (!this.goldenModel) {\n throw new Error(\"Golden model not initialized\");\n }\n\n const addElement = async (\n layerName: string,\n type: string,\n id: string,\n name: string,\n attributes?: Record<string, unknown>\n ) => {\n let layer = await this.goldenModel!.getLayer(layerName);\n if (!layer) {\n layer = new Layer(layerName);\n this.goldenModel!.addLayer(layer);\n }\n\n const element = new Element({\n id,\n type,\n name,\n description: `Golden copy element: ${name}`,\n attributes: attributes || {},\n });\n\n layer.addElement(element);\n };\n\n // Motivation layer\n await addElement(\"motivation\", \"goal\", \"motivation.goal.golden-1\", \"Golden Goal 1\");\n await addElement(\"motivation\", \"goal\", \"motivation.goal.golden-2\", \"Golden Goal 2\");\n await addElement(\n \"motivation\",\n \"requirement\",\n \"motivation.requirement.golden-1\",\n \"Golden Requirement 1\"\n );\n\n // Business layer\n await addElement(\"business\", \"process\", \"business.process.golden-1\", \"Golden Process 1\");\n await addElement(\"business\", \"service\", \"business.service.golden-1\", \"Golden Service 1\");\n\n // Application layer\n await addElement(\n \"application\",\n \"component\",\n \"application.component.golden-1\",\n \"Golden Component 1\"\n );\n await addElement(\"application\", \"service\", \"application.service.golden-1\", \"Golden Service 1\");\n\n // Technology layer\n await addElement(\n \"technology\",\n \"infrastructure\",\n \"technology.infrastructure.golden-1\",\n \"Golden Infrastructure 1\"\n );\n await addElement(\"technology\", \"platform\", \"technology.platform.golden-1\", \"Golden Platform 1\");\n\n // API layer\n await addElement(\"api\", \"endpoint\", \"api.endpoint.golden-1\", \"Golden Endpoint 1\", {\n method: \"GET\",\n path: \"/golden/1\",\n });\n await addElement(\"api\", \"endpoint\", \"api.endpoint.golden-2\", \"Golden Endpoint 2\", {\n method: \"POST\",\n path: \"/golden/2\",\n });\n\n // Data Model layer\n await addElement(\"data-model\", \"entity\", \"data-model.entity.golden-1\", \"Golden Entity 1\");\n await addElement(\"data-model\", \"entity\", \"data-model.entity.golden-2\", \"Golden Entity 2\");\n }\n\n /**\n * Get statistics about golden copy cache performance\n */\n getStats(): GoldenCopyStats {\n return { ...this.stats };\n }\n\n /**\n * Check if golden copy is initialized\n */\n isInitialized(): boolean {\n return this.goldenModel !== null && this.goldenRootPath !== null;\n }\n\n /**\n * Get the golden model (immutable reference)\n *\n * Returns a frozen reference to prevent accidental mutations that could\n * corrupt the shared golden copy. Direct modifications through the returned\n * object will fail at runtime.\n *\n * @returns Frozen golden model or null if not initialized\n */\n getGoldenModel(): Readonly<Model> | null {\n if (!this.goldenModel) {\n return null;\n }\n // Return frozen reference to prevent mutations\n return Object.freeze(\n Object.create(\n Object.getPrototypeOf(this.goldenModel),\n Object.getOwnPropertyDescriptors(this.goldenModel)\n )\n );\n }\n\n /**\n * Get the cache directory path\n */\n getCacheDir(): string {\n return this.config.cacheDir;\n }\n\n /**\n * Clean up the golden copy cache\n *\n * Removes the cached golden model and resets the cache manager.\n * Should be called at the end of test suite execution.\n *\n * Idempotent: Safe to call multiple times without error.\n */\n async cleanup(): Promise<void> {\n // If already cleaned up, this is a no-op\n if (this.lifecycleState.status === \"cleaned-up\") {\n if (process.env.DEBUG_GOLDEN_COPY) {\n console.log(\"[GoldenCopy] Already cleaned up, skipping\");\n }\n return;\n }\n\n try {\n if (this.goldenRootPath) {\n await rm(this.goldenRootPath, { recursive: true, force: true });\n }\n this.goldenModel = null;\n this.goldenRootPath = null;\n this.lifecycleState = { status: \"cleaned-up\" };\n GoldenCopyCacheManager.resetInstance();\n\n if (process.env.DEBUG_GOLDEN_COPY) {\n console.log(\"[GoldenCopy] Cache cleaned up\");\n console.log(\"[GoldenCopy] Stats:\", this.stats);\n }\n } catch (error) {\n // Always log cleanup errors\n console.error(\n `[GoldenCopy] ERROR: Failed to clean up golden copy cache at ${this.goldenRootPath}. ` +\n `This may cause disk space issues. ` +\n `Error: ${getErrorMessage(error)}`\n );\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|