@contractspec/bundle.workspace 0.0.0-canary-20260113162409
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 +83 -0
- package/dist/_virtual/rolldown_runtime.mjs +20 -0
- package/dist/adapters/ai.d.mts +12 -0
- package/dist/adapters/ai.d.mts.map +1 -0
- package/dist/adapters/ai.mjs +83 -0
- package/dist/adapters/ai.mjs.map +1 -0
- package/dist/adapters/factory.d.mts +29 -0
- package/dist/adapters/factory.d.mts.map +1 -0
- package/dist/adapters/factory.mjs +37 -0
- package/dist/adapters/factory.mjs.map +1 -0
- package/dist/adapters/fs.d.mts +12 -0
- package/dist/adapters/fs.d.mts.map +1 -0
- package/dist/adapters/fs.mjs +133 -0
- package/dist/adapters/fs.mjs.map +1 -0
- package/dist/adapters/git.d.mts +11 -0
- package/dist/adapters/git.d.mts.map +1 -0
- package/dist/adapters/git.mjs +84 -0
- package/dist/adapters/git.mjs.map +1 -0
- package/dist/adapters/index.d.mts +7 -0
- package/dist/adapters/index.mjs +9 -0
- package/dist/adapters/logger.d.mts +18 -0
- package/dist/adapters/logger.d.mts.map +1 -0
- package/dist/adapters/logger.mjs +81 -0
- package/dist/adapters/logger.mjs.map +1 -0
- package/dist/adapters/watcher.d.mts +11 -0
- package/dist/adapters/watcher.d.mts.map +1 -0
- package/dist/adapters/watcher.mjs +74 -0
- package/dist/adapters/watcher.mjs.map +1 -0
- package/dist/adapters/workspace.d.mts +148 -0
- package/dist/adapters/workspace.d.mts.map +1 -0
- package/dist/adapters/workspace.mjs +275 -0
- package/dist/adapters/workspace.mjs.map +1 -0
- package/dist/ai/agents/claude-code-agent.d.mts +22 -0
- package/dist/ai/agents/claude-code-agent.d.mts.map +1 -0
- package/dist/ai/agents/claude-code-agent.mjs +182 -0
- package/dist/ai/agents/claude-code-agent.mjs.map +1 -0
- package/dist/ai/agents/cursor-agent.d.mts +68 -0
- package/dist/ai/agents/cursor-agent.d.mts.map +1 -0
- package/dist/ai/agents/cursor-agent.mjs +436 -0
- package/dist/ai/agents/cursor-agent.mjs.map +1 -0
- package/dist/ai/agents/index.mjs +7 -0
- package/dist/ai/agents/openai-codex-agent.d.mts +22 -0
- package/dist/ai/agents/openai-codex-agent.d.mts.map +1 -0
- package/dist/ai/agents/openai-codex-agent.mjs +167 -0
- package/dist/ai/agents/openai-codex-agent.mjs.map +1 -0
- package/dist/ai/agents/orchestrator.d.mts +50 -0
- package/dist/ai/agents/orchestrator.d.mts.map +1 -0
- package/dist/ai/agents/orchestrator.mjs +143 -0
- package/dist/ai/agents/orchestrator.mjs.map +1 -0
- package/dist/ai/agents/simple-agent.d.mts +17 -0
- package/dist/ai/agents/simple-agent.d.mts.map +1 -0
- package/dist/ai/agents/simple-agent.mjs +92 -0
- package/dist/ai/agents/simple-agent.mjs.map +1 -0
- package/dist/ai/agents/types.d.mts +36 -0
- package/dist/ai/agents/types.d.mts.map +1 -0
- package/dist/ai/client.d.mts +97 -0
- package/dist/ai/client.d.mts.map +1 -0
- package/dist/ai/client.mjs +189 -0
- package/dist/ai/client.mjs.map +1 -0
- package/dist/ai/index.d.mts +9 -0
- package/dist/ai/index.mjs +11 -0
- package/dist/ai/prompts/code-generation.d.mts +26 -0
- package/dist/ai/prompts/code-generation.d.mts.map +1 -0
- package/dist/ai/prompts/code-generation.mjs +143 -0
- package/dist/ai/prompts/code-generation.mjs.map +1 -0
- package/dist/ai/prompts/index.d.mts +10 -0
- package/dist/ai/prompts/index.d.mts.map +1 -0
- package/dist/ai/prompts/index.mjs +13 -0
- package/dist/ai/prompts/index.mjs.map +1 -0
- package/dist/ai/prompts/spec-creation.d.mts +29 -0
- package/dist/ai/prompts/spec-creation.d.mts.map +1 -0
- package/dist/ai/prompts/spec-creation.mjs +111 -0
- package/dist/ai/prompts/spec-creation.mjs.map +1 -0
- package/dist/ai/providers.d.mts +29 -0
- package/dist/ai/providers.d.mts.map +1 -0
- package/dist/ai/providers.mjs +39 -0
- package/dist/ai/providers.mjs.map +1 -0
- package/dist/formatters/index.d.mts +11 -0
- package/dist/formatters/index.d.mts.map +1 -0
- package/dist/formatters/index.mjs +17 -0
- package/dist/formatters/index.mjs.map +1 -0
- package/dist/formatters/json.d.mts +56 -0
- package/dist/formatters/json.d.mts.map +1 -0
- package/dist/formatters/json.mjs +43 -0
- package/dist/formatters/json.mjs.map +1 -0
- package/dist/formatters/sarif.d.mts +101 -0
- package/dist/formatters/sarif.d.mts.map +1 -0
- package/dist/formatters/sarif.mjs +163 -0
- package/dist/formatters/sarif.mjs.map +1 -0
- package/dist/formatters/text.d.mts +35 -0
- package/dist/formatters/text.d.mts.map +1 -0
- package/dist/formatters/text.mjs +209 -0
- package/dist/formatters/text.mjs.map +1 -0
- package/dist/index.d.mts +125 -0
- package/dist/index.mjs +110 -0
- package/dist/ports/ai.d.mts +59 -0
- package/dist/ports/ai.d.mts.map +1 -0
- package/dist/ports/fs.d.mts +81 -0
- package/dist/ports/fs.d.mts.map +1 -0
- package/dist/ports/git.d.mts +46 -0
- package/dist/ports/git.d.mts.map +1 -0
- package/dist/ports/index.d.mts +6 -0
- package/dist/ports/logger.d.mts +88 -0
- package/dist/ports/logger.d.mts.map +1 -0
- package/dist/ports/rulesync.d.mts +38 -0
- package/dist/ports/rulesync.d.mts.map +1 -0
- package/dist/ports/watcher.d.mts +52 -0
- package/dist/ports/watcher.d.mts.map +1 -0
- package/dist/services/agent-guide/adapters/claude-code.d.mts +35 -0
- package/dist/services/agent-guide/adapters/claude-code.d.mts.map +1 -0
- package/dist/services/agent-guide/adapters/claude-code.mjs +144 -0
- package/dist/services/agent-guide/adapters/claude-code.mjs.map +1 -0
- package/dist/services/agent-guide/adapters/cursor-cli.d.mts +39 -0
- package/dist/services/agent-guide/adapters/cursor-cli.d.mts.map +1 -0
- package/dist/services/agent-guide/adapters/cursor-cli.mjs +135 -0
- package/dist/services/agent-guide/adapters/cursor-cli.mjs.map +1 -0
- package/dist/services/agent-guide/adapters/generic-mcp.d.mts +53 -0
- package/dist/services/agent-guide/adapters/generic-mcp.d.mts.map +1 -0
- package/dist/services/agent-guide/adapters/generic-mcp.mjs +159 -0
- package/dist/services/agent-guide/adapters/generic-mcp.mjs.map +1 -0
- package/dist/services/agent-guide/adapters/index.d.mts +23 -0
- package/dist/services/agent-guide/adapters/index.d.mts.map +1 -0
- package/dist/services/agent-guide/adapters/index.mjs +31 -0
- package/dist/services/agent-guide/adapters/index.mjs.map +1 -0
- package/dist/services/agent-guide/agent-guide-service.d.mts +56 -0
- package/dist/services/agent-guide/agent-guide-service.d.mts.map +1 -0
- package/dist/services/agent-guide/agent-guide-service.mjs +147 -0
- package/dist/services/agent-guide/agent-guide-service.mjs.map +1 -0
- package/dist/services/agent-guide/index.d.mts +6 -0
- package/dist/services/agent-guide/index.mjs +7 -0
- package/dist/services/agent-guide/types.d.mts +58 -0
- package/dist/services/agent-guide/types.d.mts.map +1 -0
- package/dist/services/build.d.mts +61 -0
- package/dist/services/build.d.mts.map +1 -0
- package/dist/services/build.mjs +151 -0
- package/dist/services/build.mjs.map +1 -0
- package/dist/services/ci-check/checks/coverage.mjs +77 -0
- package/dist/services/ci-check/checks/coverage.mjs.map +1 -0
- package/dist/services/ci-check/checks/deps.mjs +32 -0
- package/dist/services/ci-check/checks/deps.mjs.map +1 -0
- package/dist/services/ci-check/checks/doctor.mjs +38 -0
- package/dist/services/ci-check/checks/doctor.mjs.map +1 -0
- package/dist/services/ci-check/checks/drift.mjs +40 -0
- package/dist/services/ci-check/checks/drift.mjs.map +1 -0
- package/dist/services/ci-check/checks/handlers.mjs +38 -0
- package/dist/services/ci-check/checks/handlers.mjs.map +1 -0
- package/dist/services/ci-check/checks/implementation.mjs +73 -0
- package/dist/services/ci-check/checks/implementation.mjs.map +1 -0
- package/dist/services/ci-check/checks/index.mjs +13 -0
- package/dist/services/ci-check/checks/integrity.mjs +31 -0
- package/dist/services/ci-check/checks/integrity.mjs.map +1 -0
- package/dist/services/ci-check/checks/layers.mjs +66 -0
- package/dist/services/ci-check/checks/layers.mjs.map +1 -0
- package/dist/services/ci-check/checks/structure.mjs +35 -0
- package/dist/services/ci-check/checks/structure.mjs.map +1 -0
- package/dist/services/ci-check/checks/test-refs.mjs +63 -0
- package/dist/services/ci-check/checks/test-refs.mjs.map +1 -0
- package/dist/services/ci-check/checks/tests.mjs +38 -0
- package/dist/services/ci-check/checks/tests.mjs.map +1 -0
- package/dist/services/ci-check/ci-check-service.d.mts +16 -0
- package/dist/services/ci-check/ci-check-service.d.mts.map +1 -0
- package/dist/services/ci-check/ci-check-service.mjs +129 -0
- package/dist/services/ci-check/ci-check-service.mjs.map +1 -0
- package/dist/services/ci-check/index.d.mts +2 -0
- package/dist/services/ci-check/index.mjs +4 -0
- package/dist/services/ci-check/types.d.mts +147 -0
- package/dist/services/ci-check/types.d.mts.map +1 -0
- package/dist/services/ci-check/types.mjs +37 -0
- package/dist/services/ci-check/types.mjs.map +1 -0
- package/dist/services/ci-check/utils.mjs +76 -0
- package/dist/services/ci-check/utils.mjs.map +1 -0
- package/dist/services/clean.d.mts +41 -0
- package/dist/services/clean.d.mts.map +1 -0
- package/dist/services/clean.mjs +72 -0
- package/dist/services/clean.mjs.map +1 -0
- package/dist/services/config.d.mts +16 -0
- package/dist/services/config.d.mts.map +1 -0
- package/dist/services/config.mjs +63 -0
- package/dist/services/config.mjs.map +1 -0
- package/dist/services/coverage/parsers/index.mjs +34 -0
- package/dist/services/coverage/parsers/index.mjs.map +1 -0
- package/dist/services/coverage/parsers/istanbul-parser.mjs +108 -0
- package/dist/services/coverage/parsers/istanbul-parser.mjs.map +1 -0
- package/dist/services/coverage/validator.mjs +55 -0
- package/dist/services/coverage/validator.mjs.map +1 -0
- package/dist/services/create/ai-generator.d.mts +84 -0
- package/dist/services/create/ai-generator.d.mts.map +1 -0
- package/dist/services/create/ai-generator.mjs +178 -0
- package/dist/services/create/ai-generator.mjs.map +1 -0
- package/dist/services/create/index.d.mts +28 -0
- package/dist/services/create/index.d.mts.map +1 -0
- package/dist/services/create/index.mjs +37 -0
- package/dist/services/create/index.mjs.map +1 -0
- package/dist/services/create/templates.d.mts +22 -0
- package/dist/services/create/templates.d.mts.map +1 -0
- package/dist/services/create/templates.mjs +39 -0
- package/dist/services/create/templates.mjs.map +1 -0
- package/dist/services/deps.d.mts +53 -0
- package/dist/services/deps.d.mts.map +1 -0
- package/dist/services/deps.mjs +62 -0
- package/dist/services/deps.mjs.map +1 -0
- package/dist/services/diff.d.mts +34 -0
- package/dist/services/diff.d.mts.map +1 -0
- package/dist/services/diff.mjs +34 -0
- package/dist/services/diff.mjs.map +1 -0
- package/dist/services/docs/docs-service.d.mts +20 -0
- package/dist/services/docs/docs-service.d.mts.map +1 -0
- package/dist/services/docs/docs-service.mjs +59 -0
- package/dist/services/docs/docs-service.mjs.map +1 -0
- package/dist/services/docs/index.d.mts +1 -0
- package/dist/services/docs/index.mjs +3 -0
- package/dist/services/doctor/checks/ai.mjs +119 -0
- package/dist/services/doctor/checks/ai.mjs.map +1 -0
- package/dist/services/doctor/checks/cli.mjs +156 -0
- package/dist/services/doctor/checks/cli.mjs.map +1 -0
- package/dist/services/doctor/checks/config.mjs +303 -0
- package/dist/services/doctor/checks/config.mjs.map +1 -0
- package/dist/services/doctor/checks/deps.mjs +267 -0
- package/dist/services/doctor/checks/deps.mjs.map +1 -0
- package/dist/services/doctor/checks/index.mjs +9 -0
- package/dist/services/doctor/checks/layers.mjs +139 -0
- package/dist/services/doctor/checks/layers.mjs.map +1 -0
- package/dist/services/doctor/checks/mcp.mjs +145 -0
- package/dist/services/doctor/checks/mcp.mjs.map +1 -0
- package/dist/services/doctor/checks/workspace.mjs +263 -0
- package/dist/services/doctor/checks/workspace.mjs.map +1 -0
- package/dist/services/doctor/doctor-service.d.mts +24 -0
- package/dist/services/doctor/doctor-service.d.mts.map +1 -0
- package/dist/services/doctor/doctor-service.mjs +118 -0
- package/dist/services/doctor/doctor-service.mjs.map +1 -0
- package/dist/services/doctor/index.d.mts +2 -0
- package/dist/services/doctor/index.mjs +4 -0
- package/dist/services/doctor/types.d.mts +118 -0
- package/dist/services/doctor/types.d.mts.map +1 -0
- package/dist/services/doctor/types.mjs +29 -0
- package/dist/services/doctor/types.mjs.map +1 -0
- package/dist/services/drift.mjs +73 -0
- package/dist/services/drift.mjs.map +1 -0
- package/dist/services/extract.d.mts +12 -0
- package/dist/services/extract.d.mts.map +1 -0
- package/dist/services/extract.mjs +33 -0
- package/dist/services/extract.mjs.map +1 -0
- package/dist/services/features/completion.d.mts +21 -0
- package/dist/services/features/completion.d.mts.map +1 -0
- package/dist/services/features/completion.mjs +70 -0
- package/dist/services/features/completion.mjs.map +1 -0
- package/dist/services/features/feature-editor.d.mts +27 -0
- package/dist/services/features/feature-editor.d.mts.map +1 -0
- package/dist/services/features/feature-editor.mjs +37 -0
- package/dist/services/features/feature-editor.mjs.map +1 -0
- package/dist/services/features/index.d.mts +11 -0
- package/dist/services/features/index.d.mts.map +1 -0
- package/dist/services/features/index.mjs +16 -0
- package/dist/services/features/index.mjs.map +1 -0
- package/dist/services/features/validation.d.mts +21 -0
- package/dist/services/features/validation.d.mts.map +1 -0
- package/dist/services/features/validation.mjs +27 -0
- package/dist/services/features/validation.mjs.map +1 -0
- package/dist/services/fix/fix-link-formatter.d.mts +12 -0
- package/dist/services/fix/fix-link-formatter.d.mts.map +1 -0
- package/dist/services/fix/fix-link-formatter.mjs +38 -0
- package/dist/services/fix/fix-link-formatter.mjs.map +1 -0
- package/dist/services/fix/fix-service.d.mts +74 -0
- package/dist/services/fix/fix-service.d.mts.map +1 -0
- package/dist/services/fix/fix-service.mjs +169 -0
- package/dist/services/fix/fix-service.mjs.map +1 -0
- package/dist/services/fix/index.d.mts +16 -0
- package/dist/services/fix/index.d.mts.map +1 -0
- package/dist/services/fix/index.mjs +24 -0
- package/dist/services/fix/index.mjs.map +1 -0
- package/dist/services/fix/path-resolver.mjs +83 -0
- package/dist/services/fix/path-resolver.mjs.map +1 -0
- package/dist/services/fix/schemas.d.mts +17 -0
- package/dist/services/fix/schemas.d.mts.map +1 -0
- package/dist/services/fix/schemas.mjs +12 -0
- package/dist/services/fix/schemas.mjs.map +1 -0
- package/dist/services/fix/strategies/implement-ai.d.mts +18 -0
- package/dist/services/fix/strategies/implement-ai.d.mts.map +1 -0
- package/dist/services/fix/strategies/implement-ai.mjs +139 -0
- package/dist/services/fix/strategies/implement-ai.mjs.map +1 -0
- package/dist/services/fix/strategies/implement-skeleton.d.mts +14 -0
- package/dist/services/fix/strategies/implement-skeleton.d.mts.map +1 -0
- package/dist/services/fix/strategies/implement-skeleton.mjs +77 -0
- package/dist/services/fix/strategies/implement-skeleton.mjs.map +1 -0
- package/dist/services/fix/strategies/index.d.mts +3 -0
- package/dist/services/fix/strategies/remove-reference.d.mts +17 -0
- package/dist/services/fix/strategies/remove-reference.d.mts.map +1 -0
- package/dist/services/fix/strategies/remove-reference.mjs +98 -0
- package/dist/services/fix/strategies/remove-reference.mjs.map +1 -0
- package/dist/services/fix/types.d.mts +207 -0
- package/dist/services/fix/types.d.mts.map +1 -0
- package/dist/services/fix/types.mjs +20 -0
- package/dist/services/fix/types.mjs.map +1 -0
- package/dist/services/formatter.d.mts +15 -0
- package/dist/services/formatter.d.mts.map +1 -0
- package/dist/services/formatter.mjs +26 -0
- package/dist/services/formatter.mjs.map +1 -0
- package/dist/services/gap.d.mts +18 -0
- package/dist/services/gap.d.mts.map +1 -0
- package/dist/services/gap.mjs +44 -0
- package/dist/services/gap.mjs.map +1 -0
- package/dist/services/generate-artifacts.d.mts +11 -0
- package/dist/services/generate-artifacts.d.mts.map +1 -0
- package/dist/services/generate-artifacts.mjs +27 -0
- package/dist/services/generate-artifacts.mjs.map +1 -0
- package/dist/services/hooks/hooks-service.d.mts +24 -0
- package/dist/services/hooks/hooks-service.d.mts.map +1 -0
- package/dist/services/hooks/hooks-service.mjs +126 -0
- package/dist/services/hooks/hooks-service.mjs.map +1 -0
- package/dist/services/hooks/index.d.mts +10 -0
- package/dist/services/hooks/index.d.mts.map +1 -0
- package/dist/services/hooks/index.mjs +12 -0
- package/dist/services/hooks/index.mjs.map +1 -0
- package/dist/services/hooks/types.d.mts +56 -0
- package/dist/services/hooks/types.d.mts.map +1 -0
- package/dist/services/impact/formatters.d.mts +27 -0
- package/dist/services/impact/formatters.d.mts.map +1 -0
- package/dist/services/impact/formatters.mjs +139 -0
- package/dist/services/impact/formatters.mjs.map +1 -0
- package/dist/services/impact/impact-detection-service.d.mts +22 -0
- package/dist/services/impact/impact-detection-service.d.mts.map +1 -0
- package/dist/services/impact/impact-detection-service.mjs +96 -0
- package/dist/services/impact/impact-detection-service.mjs.map +1 -0
- package/dist/services/impact/index.d.mts +11 -0
- package/dist/services/impact/index.d.mts.map +1 -0
- package/dist/services/impact/index.mjs +16 -0
- package/dist/services/impact/index.mjs.map +1 -0
- package/dist/services/impact/types.d.mts +63 -0
- package/dist/services/impact/types.d.mts.map +1 -0
- package/dist/services/implementation/discovery.d.mts +30 -0
- package/dist/services/implementation/discovery.d.mts.map +1 -0
- package/dist/services/implementation/discovery.mjs +144 -0
- package/dist/services/implementation/discovery.mjs.map +1 -0
- package/dist/services/implementation/index.d.mts +6 -0
- package/dist/services/implementation/index.mjs +7 -0
- package/dist/services/implementation/resolver/conventions.d.mts +18 -0
- package/dist/services/implementation/resolver/conventions.d.mts.map +1 -0
- package/dist/services/implementation/resolver/conventions.mjs +59 -0
- package/dist/services/implementation/resolver/conventions.mjs.map +1 -0
- package/dist/services/implementation/resolver/index.d.mts +24 -0
- package/dist/services/implementation/resolver/index.d.mts.map +1 -0
- package/dist/services/implementation/resolver/index.mjs +111 -0
- package/dist/services/implementation/resolver/index.mjs.map +1 -0
- package/dist/services/implementation/resolver/parsers.d.mts +16 -0
- package/dist/services/implementation/resolver/parsers.d.mts.map +1 -0
- package/dist/services/implementation/resolver/parsers.mjs +100 -0
- package/dist/services/implementation/resolver/parsers.mjs.map +1 -0
- package/dist/services/implementation/resolver/status.d.mts +21 -0
- package/dist/services/implementation/resolver/status.d.mts.map +1 -0
- package/dist/services/implementation/resolver/status.mjs +31 -0
- package/dist/services/implementation/resolver/status.mjs.map +1 -0
- package/dist/services/implementation/types.d.mts +89 -0
- package/dist/services/implementation/types.d.mts.map +1 -0
- package/dist/services/index.d.mts +103 -0
- package/dist/services/index.mjs +100 -0
- package/dist/services/integrity-diagram.d.mts +36 -0
- package/dist/services/integrity-diagram.d.mts.map +1 -0
- package/dist/services/integrity-diagram.mjs +275 -0
- package/dist/services/integrity-diagram.mjs.map +1 -0
- package/dist/services/integrity.d.mts +152 -0
- package/dist/services/integrity.d.mts.map +1 -0
- package/dist/services/integrity.mjs +361 -0
- package/dist/services/integrity.mjs.map +1 -0
- package/dist/services/layer-discovery.d.mts +77 -0
- package/dist/services/layer-discovery.d.mts.map +1 -0
- package/dist/services/layer-discovery.mjs +121 -0
- package/dist/services/layer-discovery.mjs.map +1 -0
- package/dist/services/list.d.mts +37 -0
- package/dist/services/list.d.mts.map +1 -0
- package/dist/services/list.mjs +46 -0
- package/dist/services/list.mjs.map +1 -0
- package/dist/services/llm/index.d.mts +28 -0
- package/dist/services/llm/index.d.mts.map +1 -0
- package/dist/services/llm/index.mjs +187 -0
- package/dist/services/llm/index.mjs.map +1 -0
- package/dist/services/llm/verify-static.d.mts +26 -0
- package/dist/services/llm/verify-static.d.mts.map +1 -0
- package/dist/services/llm/verify-static.mjs +82 -0
- package/dist/services/llm/verify-static.mjs.map +1 -0
- package/dist/services/modules/module-resolver.mjs +61 -0
- package/dist/services/modules/module-resolver.mjs.map +1 -0
- package/dist/services/openapi/export-service.d.mts +53 -0
- package/dist/services/openapi/export-service.d.mts.map +1 -0
- package/dist/services/openapi/export-service.mjs +50 -0
- package/dist/services/openapi/export-service.mjs.map +1 -0
- package/dist/services/openapi/import-service.d.mts +17 -0
- package/dist/services/openapi/import-service.d.mts.map +1 -0
- package/dist/services/openapi/import-service.mjs +168 -0
- package/dist/services/openapi/import-service.mjs.map +1 -0
- package/dist/services/openapi/index.d.mts +5 -0
- package/dist/services/openapi/index.mjs +6 -0
- package/dist/services/openapi/sync-service.d.mts +17 -0
- package/dist/services/openapi/sync-service.d.mts.map +1 -0
- package/dist/services/openapi/sync-service.mjs +120 -0
- package/dist/services/openapi/sync-service.mjs.map +1 -0
- package/dist/services/openapi/types.d.mts +162 -0
- package/dist/services/openapi/types.d.mts.map +1 -0
- package/dist/services/openapi/validate-service.d.mts +16 -0
- package/dist/services/openapi/validate-service.d.mts.map +1 -0
- package/dist/services/openapi/validate-service.mjs +130 -0
- package/dist/services/openapi/validate-service.mjs.map +1 -0
- package/dist/services/quickstart/dependencies.d.mts +31 -0
- package/dist/services/quickstart/dependencies.d.mts.map +1 -0
- package/dist/services/quickstart/dependencies.mjs +57 -0
- package/dist/services/quickstart/dependencies.mjs.map +1 -0
- package/dist/services/quickstart/index.mjs +4 -0
- package/dist/services/quickstart/quickstart-service.d.mts +20 -0
- package/dist/services/quickstart/quickstart-service.d.mts.map +1 -0
- package/dist/services/quickstart/quickstart-service.mjs +196 -0
- package/dist/services/quickstart/quickstart-service.mjs.map +1 -0
- package/dist/services/quickstart/types.d.mts +81 -0
- package/dist/services/quickstart/types.d.mts.map +1 -0
- package/dist/services/regenerator.d.mts +18 -0
- package/dist/services/regenerator.d.mts.map +1 -0
- package/dist/services/regenerator.mjs +23 -0
- package/dist/services/regenerator.mjs.map +1 -0
- package/dist/services/registry.d.mts +53 -0
- package/dist/services/registry.d.mts.map +1 -0
- package/dist/services/registry.mjs +74 -0
- package/dist/services/registry.mjs.map +1 -0
- package/dist/services/rulesync.d.mts +17 -0
- package/dist/services/rulesync.d.mts.map +1 -0
- package/dist/services/rulesync.mjs +71 -0
- package/dist/services/rulesync.mjs.map +1 -0
- package/dist/services/setup/config-generators.d.mts +42 -0
- package/dist/services/setup/config-generators.d.mts.map +1 -0
- package/dist/services/setup/config-generators.mjs +252 -0
- package/dist/services/setup/config-generators.mjs.map +1 -0
- package/dist/services/setup/file-merger.d.mts +27 -0
- package/dist/services/setup/file-merger.d.mts.map +1 -0
- package/dist/services/setup/file-merger.mjs +61 -0
- package/dist/services/setup/file-merger.mjs.map +1 -0
- package/dist/services/setup/setup-service.d.mts +12 -0
- package/dist/services/setup/setup-service.d.mts.map +1 -0
- package/dist/services/setup/setup-service.mjs +96 -0
- package/dist/services/setup/setup-service.mjs.map +1 -0
- package/dist/services/setup/targets/agents-md.mjs +47 -0
- package/dist/services/setup/targets/agents-md.mjs.map +1 -0
- package/dist/services/setup/targets/cli-config.mjs +60 -0
- package/dist/services/setup/targets/cli-config.mjs.map +1 -0
- package/dist/services/setup/targets/cursor-rules.mjs +48 -0
- package/dist/services/setup/targets/cursor-rules.mjs.map +1 -0
- package/dist/services/setup/targets/mcp-claude.mjs +60 -0
- package/dist/services/setup/targets/mcp-claude.mjs.map +1 -0
- package/dist/services/setup/targets/mcp-cursor.mjs +59 -0
- package/dist/services/setup/targets/mcp-cursor.mjs.map +1 -0
- package/dist/services/setup/targets/vscode-settings.mjs +63 -0
- package/dist/services/setup/targets/vscode-settings.mjs.map +1 -0
- package/dist/services/setup/types.d.mts +85 -0
- package/dist/services/setup/types.d.mts.map +1 -0
- package/dist/services/setup/types.mjs +27 -0
- package/dist/services/setup/types.mjs.map +1 -0
- package/dist/services/sync.d.mts +42 -0
- package/dist/services/sync.d.mts.map +1 -0
- package/dist/services/sync.mjs +64 -0
- package/dist/services/sync.mjs.map +1 -0
- package/dist/services/test/index.d.mts +2 -0
- package/dist/services/test/index.mjs +4 -0
- package/dist/services/test/test-generator-service.d.mts +24 -0
- package/dist/services/test/test-generator-service.d.mts.map +1 -0
- package/dist/services/test/test-generator-service.mjs +92 -0
- package/dist/services/test/test-generator-service.mjs.map +1 -0
- package/dist/services/test/test-service.d.mts +27 -0
- package/dist/services/test/test-service.d.mts.map +1 -0
- package/dist/services/test/test-service.mjs +94 -0
- package/dist/services/test/test-service.mjs.map +1 -0
- package/dist/services/test-link/index.d.mts +18 -0
- package/dist/services/test-link/index.d.mts.map +1 -0
- package/dist/services/test-link/index.mjs +60 -0
- package/dist/services/test-link/index.mjs.map +1 -0
- package/dist/services/test-link/test-ref-validator.d.mts +2 -0
- package/dist/services/test-link/test-ref-validator.mjs +50 -0
- package/dist/services/test-link/test-ref-validator.mjs.map +1 -0
- package/dist/services/upgrade/index.d.mts +10 -0
- package/dist/services/upgrade/index.d.mts.map +1 -0
- package/dist/services/upgrade/index.mjs +15 -0
- package/dist/services/upgrade/index.mjs.map +1 -0
- package/dist/services/upgrade/types.d.mts +78 -0
- package/dist/services/upgrade/types.d.mts.map +1 -0
- package/dist/services/upgrade/upgrade-service.d.mts +38 -0
- package/dist/services/upgrade/upgrade-service.d.mts.map +1 -0
- package/dist/services/upgrade/upgrade-service.mjs +201 -0
- package/dist/services/upgrade/upgrade-service.mjs.map +1 -0
- package/dist/services/validate/blueprint-validator.d.mts +23 -0
- package/dist/services/validate/blueprint-validator.d.mts.map +1 -0
- package/dist/services/validate/blueprint-validator.mjs +50 -0
- package/dist/services/validate/blueprint-validator.mjs.map +1 -0
- package/dist/services/validate/implementation-agent-validator.d.mts +20 -0
- package/dist/services/validate/implementation-agent-validator.d.mts.map +1 -0
- package/dist/services/validate/implementation-agent-validator.mjs +42 -0
- package/dist/services/validate/implementation-agent-validator.mjs.map +1 -0
- package/dist/services/validate/implementation-validator.d.mts +32 -0
- package/dist/services/validate/implementation-validator.d.mts.map +1 -0
- package/dist/services/validate/implementation-validator.mjs +64 -0
- package/dist/services/validate/implementation-validator.mjs.map +1 -0
- package/dist/services/validate/index.d.mts +5 -0
- package/dist/services/validate/index.mjs +7 -0
- package/dist/services/validate/spec-validator.d.mts +42 -0
- package/dist/services/validate/spec-validator.d.mts.map +1 -0
- package/dist/services/validate/spec-validator.mjs +49 -0
- package/dist/services/validate/spec-validator.mjs.map +1 -0
- package/dist/services/validate/tenant-validator.d.mts +21 -0
- package/dist/services/validate/tenant-validator.d.mts.map +1 -0
- package/dist/services/validate/tenant-validator.mjs +165 -0
- package/dist/services/validate/tenant-validator.mjs.map +1 -0
- package/dist/services/verification-cache/adapters/filesystem.d.mts +46 -0
- package/dist/services/verification-cache/adapters/filesystem.d.mts.map +1 -0
- package/dist/services/verification-cache/adapters/filesystem.mjs +120 -0
- package/dist/services/verification-cache/adapters/filesystem.mjs.map +1 -0
- package/dist/services/verification-cache/adapters/in-memory.d.mts +27 -0
- package/dist/services/verification-cache/adapters/in-memory.d.mts.map +1 -0
- package/dist/services/verification-cache/adapters/in-memory.mjs +46 -0
- package/dist/services/verification-cache/adapters/in-memory.mjs.map +1 -0
- package/dist/services/verification-cache/adapters/index.d.mts +3 -0
- package/dist/services/verification-cache/adapters/index.mjs +5 -0
- package/dist/services/verification-cache/adapters/workspace-state.d.mts +49 -0
- package/dist/services/verification-cache/adapters/workspace-state.d.mts.map +1 -0
- package/dist/services/verification-cache/adapters/workspace-state.mjs +91 -0
- package/dist/services/verification-cache/adapters/workspace-state.mjs.map +1 -0
- package/dist/services/verification-cache/cache-service.d.mts +70 -0
- package/dist/services/verification-cache/cache-service.d.mts.map +1 -0
- package/dist/services/verification-cache/cache-service.mjs +256 -0
- package/dist/services/verification-cache/cache-service.mjs.map +1 -0
- package/dist/services/verification-cache/index.d.mts +6 -0
- package/dist/services/verification-cache/index.mjs +8 -0
- package/dist/services/verification-cache/types.d.mts +124 -0
- package/dist/services/verification-cache/types.d.mts.map +1 -0
- package/dist/services/verification-cache/types.mjs +16 -0
- package/dist/services/verification-cache/types.mjs.map +1 -0
- package/dist/services/verify/ai-verifier.d.mts +25 -0
- package/dist/services/verify/ai-verifier.d.mts.map +1 -0
- package/dist/services/verify/ai-verifier.mjs +403 -0
- package/dist/services/verify/ai-verifier.mjs.map +1 -0
- package/dist/services/verify/behavior-verifier.d.mts +12 -0
- package/dist/services/verify/behavior-verifier.d.mts.map +1 -0
- package/dist/services/verify/behavior-verifier.mjs +186 -0
- package/dist/services/verify/behavior-verifier.mjs.map +1 -0
- package/dist/services/verify/index.d.mts +5 -0
- package/dist/services/verify/index.mjs +6 -0
- package/dist/services/verify/structure-verifier.d.mts +12 -0
- package/dist/services/verify/structure-verifier.d.mts.map +1 -0
- package/dist/services/verify/structure-verifier.mjs +196 -0
- package/dist/services/verify/structure-verifier.mjs.map +1 -0
- package/dist/services/verify/types.d.mts +137 -0
- package/dist/services/verify/types.d.mts.map +1 -0
- package/dist/services/verify/verify-service.d.mts +60 -0
- package/dist/services/verify/verify-service.d.mts.map +1 -0
- package/dist/services/verify/verify-service.mjs +204 -0
- package/dist/services/verify/verify-service.mjs.map +1 -0
- package/dist/services/versioning/changelog-formatter.d.mts +24 -0
- package/dist/services/versioning/changelog-formatter.d.mts.map +1 -0
- package/dist/services/versioning/changelog-formatter.mjs +155 -0
- package/dist/services/versioning/changelog-formatter.mjs.map +1 -0
- package/dist/services/versioning/conventional-commits.d.mts +95 -0
- package/dist/services/versioning/conventional-commits.d.mts.map +1 -0
- package/dist/services/versioning/conventional-commits.mjs +184 -0
- package/dist/services/versioning/conventional-commits.mjs.map +1 -0
- package/dist/services/versioning/index.d.mts +12 -0
- package/dist/services/versioning/index.d.mts.map +1 -0
- package/dist/services/versioning/index.mjs +28 -0
- package/dist/services/versioning/index.mjs.map +1 -0
- package/dist/services/versioning/types.d.mts +135 -0
- package/dist/services/versioning/types.d.mts.map +1 -0
- package/dist/services/versioning/versioning-service.d.mts +74 -0
- package/dist/services/versioning/versioning-service.d.mts.map +1 -0
- package/dist/services/versioning/versioning-service.mjs +501 -0
- package/dist/services/versioning/versioning-service.mjs.map +1 -0
- package/dist/services/vibe/config.d.mts +12 -0
- package/dist/services/vibe/config.d.mts.map +1 -0
- package/dist/services/vibe/config.mjs +43 -0
- package/dist/services/vibe/config.mjs.map +1 -0
- package/dist/services/vibe/context.d.mts +19 -0
- package/dist/services/vibe/context.d.mts.map +1 -0
- package/dist/services/vibe/context.mjs +92 -0
- package/dist/services/vibe/context.mjs.map +1 -0
- package/dist/services/vibe/definitions.d.mts +8 -0
- package/dist/services/vibe/definitions.d.mts.map +1 -0
- package/dist/services/vibe/definitions.mjs +129 -0
- package/dist/services/vibe/definitions.mjs.map +1 -0
- package/dist/services/vibe/engine.d.mts +44 -0
- package/dist/services/vibe/engine.d.mts.map +1 -0
- package/dist/services/vibe/engine.mjs +147 -0
- package/dist/services/vibe/engine.mjs.map +1 -0
- package/dist/services/vibe/index.d.mts +15 -0
- package/dist/services/vibe/index.d.mts.map +1 -0
- package/dist/services/vibe/index.mjs +26 -0
- package/dist/services/vibe/index.mjs.map +1 -0
- package/dist/services/vibe/loader.d.mts +15 -0
- package/dist/services/vibe/loader.d.mts.map +1 -0
- package/dist/services/vibe/loader.mjs +48 -0
- package/dist/services/vibe/loader.mjs.map +1 -0
- package/dist/services/vibe/pack.d.mts +19 -0
- package/dist/services/vibe/pack.d.mts.map +1 -0
- package/dist/services/vibe/pack.mjs +66 -0
- package/dist/services/vibe/pack.mjs.map +1 -0
- package/dist/services/vibe/types.d.mts +59 -0
- package/dist/services/vibe/types.d.mts.map +1 -0
- package/dist/services/vibe/types.mjs +12 -0
- package/dist/services/vibe/types.mjs.map +1 -0
- package/dist/services/view/index.d.mts +11 -0
- package/dist/services/view/index.d.mts.map +1 -0
- package/dist/services/view/index.mjs +119 -0
- package/dist/services/view/index.mjs.map +1 -0
- package/dist/services/watch.d.mts +25 -0
- package/dist/services/watch.d.mts.map +1 -0
- package/dist/services/watch.mjs +33 -0
- package/dist/services/watch.mjs.map +1 -0
- package/dist/services/workspace-info.d.mts +62 -0
- package/dist/services/workspace-info.d.mts.map +1 -0
- package/dist/services/workspace-info.mjs +103 -0
- package/dist/services/workspace-info.mjs.map +1 -0
- package/dist/templates/app-config.template.d.mts +7 -0
- package/dist/templates/app-config.template.d.mts.map +1 -0
- package/dist/templates/app-config.template.mjs +107 -0
- package/dist/templates/app-config.template.mjs.map +1 -0
- package/dist/templates/data-view.template.d.mts +7 -0
- package/dist/templates/data-view.template.d.mts.map +1 -0
- package/dist/templates/data-view.template.mjs +70 -0
- package/dist/templates/data-view.template.mjs.map +1 -0
- package/dist/templates/event.template.d.mts +11 -0
- package/dist/templates/event.template.d.mts.map +1 -0
- package/dist/templates/event.template.mjs +42 -0
- package/dist/templates/event.template.mjs.map +1 -0
- package/dist/templates/experiment.template.d.mts +7 -0
- package/dist/templates/experiment.template.d.mts.map +1 -0
- package/dist/templates/experiment.template.mjs +89 -0
- package/dist/templates/experiment.template.mjs.map +1 -0
- package/dist/templates/feature.template.d.mts +33 -0
- package/dist/templates/feature.template.d.mts.map +1 -0
- package/dist/templates/feature.template.mjs +52 -0
- package/dist/templates/feature.template.mjs.map +1 -0
- package/dist/templates/fix/skeleton-capability.mjs +49 -0
- package/dist/templates/fix/skeleton-capability.mjs.map +1 -0
- package/dist/templates/fix/skeleton-event.mjs +56 -0
- package/dist/templates/fix/skeleton-event.mjs.map +1 -0
- package/dist/templates/fix/skeleton-operation.mjs +122 -0
- package/dist/templates/fix/skeleton-operation.mjs.map +1 -0
- package/dist/templates/fix/skeleton-presentation.mjs +65 -0
- package/dist/templates/fix/skeleton-presentation.mjs.map +1 -0
- package/dist/templates/fix/utils.mjs +34 -0
- package/dist/templates/fix/utils.mjs.map +1 -0
- package/dist/templates/handler.template.d.mts +16 -0
- package/dist/templates/handler.template.d.mts.map +1 -0
- package/dist/templates/handler.template.mjs +100 -0
- package/dist/templates/handler.template.mjs.map +1 -0
- package/dist/templates/index.d.mts +22 -0
- package/dist/templates/index.d.mts.map +1 -0
- package/dist/templates/index.mjs +39 -0
- package/dist/templates/index.mjs.map +1 -0
- package/dist/templates/integration.template.d.mts +7 -0
- package/dist/templates/integration.template.d.mts.map +1 -0
- package/dist/templates/integration.template.mjs +160 -0
- package/dist/templates/integration.template.mjs.map +1 -0
- package/dist/templates/knowledge.template.d.mts +7 -0
- package/dist/templates/knowledge.template.d.mts.map +1 -0
- package/dist/templates/knowledge.template.mjs +75 -0
- package/dist/templates/knowledge.template.mjs.map +1 -0
- package/dist/templates/migration.template.d.mts +7 -0
- package/dist/templates/migration.template.d.mts.map +1 -0
- package/dist/templates/migration.template.mjs +62 -0
- package/dist/templates/migration.template.mjs.map +1 -0
- package/dist/templates/operation.template.d.mts +11 -0
- package/dist/templates/operation.template.d.mts.map +1 -0
- package/dist/templates/operation.template.mjs +107 -0
- package/dist/templates/operation.template.mjs.map +1 -0
- package/dist/templates/presentation.template.d.mts +11 -0
- package/dist/templates/presentation.template.d.mts.map +1 -0
- package/dist/templates/presentation.template.mjs +80 -0
- package/dist/templates/presentation.template.mjs.map +1 -0
- package/dist/templates/telemetry.template.d.mts +7 -0
- package/dist/templates/telemetry.template.d.mts.map +1 -0
- package/dist/templates/telemetry.template.mjs +91 -0
- package/dist/templates/telemetry.template.mjs.map +1 -0
- package/dist/templates/workflow-runner.template.d.mts +16 -0
- package/dist/templates/workflow-runner.template.d.mts.map +1 -0
- package/dist/templates/workflow-runner.template.mjs +50 -0
- package/dist/templates/workflow-runner.template.mjs.map +1 -0
- package/dist/templates/workflow.template.d.mts +7 -0
- package/dist/templates/workflow.template.d.mts.map +1 -0
- package/dist/templates/workflow.template.mjs +69 -0
- package/dist/templates/workflow.template.mjs.map +1 -0
- package/dist/types/config.d.mts +34 -0
- package/dist/types/config.d.mts.map +1 -0
- package/dist/types.d.mts +324 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/utils/filter.d.mts +16 -0
- package/dist/utils/filter.d.mts.map +1 -0
- package/dist/utils/filter.mjs +22 -0
- package/dist/utils/filter.mjs.map +1 -0
- package/dist/utils/index.d.mts +11 -0
- package/dist/utils/index.d.mts.map +1 -0
- package/dist/utils/index.mjs +20 -0
- package/dist/utils/index.mjs.map +1 -0
- package/dist/utils/module-loader.d.mts +5 -0
- package/dist/utils/module-loader.d.mts.map +1 -0
- package/dist/utils/module-loader.mjs +41 -0
- package/dist/utils/module-loader.mjs.map +1 -0
- package/dist/utils/validation.d.mts +37 -0
- package/dist/utils/validation.d.mts.map +1 -0
- package/dist/utils/validation.mjs +43 -0
- package/dist/utils/validation.mjs.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { buildTestIndex } from "./test-link/index.mjs";
|
|
2
|
+
import { isFeatureFile, scanAllSpecsFromSource, scanFeatureSource } from "@contractspec/module.workspace";
|
|
3
|
+
|
|
4
|
+
//#region src/services/integrity.ts
|
|
5
|
+
/**
|
|
6
|
+
* Contract integrity analysis service.
|
|
7
|
+
*
|
|
8
|
+
* Analyzes contract specs and features to detect:
|
|
9
|
+
* - Orphaned specs (not linked to any feature)
|
|
10
|
+
* - Unresolved references (broken event/op/presentation refs)
|
|
11
|
+
* - Feature coverage metrics
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Build a spec key from name and version.
|
|
15
|
+
*/
|
|
16
|
+
function specKey(key, version) {
|
|
17
|
+
return `${key}.v${version}`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create an empty spec inventory.
|
|
21
|
+
*/
|
|
22
|
+
function createEmptyInventory() {
|
|
23
|
+
return {
|
|
24
|
+
operations: /* @__PURE__ */ new Map(),
|
|
25
|
+
events: /* @__PURE__ */ new Map(),
|
|
26
|
+
presentations: /* @__PURE__ */ new Map(),
|
|
27
|
+
capabilities: /* @__PURE__ */ new Map(),
|
|
28
|
+
workflows: /* @__PURE__ */ new Map(),
|
|
29
|
+
dataViews: /* @__PURE__ */ new Map(),
|
|
30
|
+
forms: /* @__PURE__ */ new Map(),
|
|
31
|
+
migrations: /* @__PURE__ */ new Map(),
|
|
32
|
+
experiments: /* @__PURE__ */ new Map(),
|
|
33
|
+
integrations: /* @__PURE__ */ new Map(),
|
|
34
|
+
knowledge: /* @__PURE__ */ new Map(),
|
|
35
|
+
telemetry: /* @__PURE__ */ new Map(),
|
|
36
|
+
appConfigs: /* @__PURE__ */ new Map(),
|
|
37
|
+
policies: /* @__PURE__ */ new Map(),
|
|
38
|
+
testSpecs: /* @__PURE__ */ new Map()
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get the inventory map for a spec type.
|
|
43
|
+
*/
|
|
44
|
+
function getInventoryMap(inventory, specType) {
|
|
45
|
+
return {
|
|
46
|
+
operation: inventory.operations,
|
|
47
|
+
event: inventory.events,
|
|
48
|
+
presentation: inventory.presentations,
|
|
49
|
+
capability: inventory.capabilities,
|
|
50
|
+
workflow: inventory.workflows,
|
|
51
|
+
"data-view": inventory.dataViews,
|
|
52
|
+
form: inventory.forms,
|
|
53
|
+
migration: inventory.migrations,
|
|
54
|
+
experiment: inventory.experiments,
|
|
55
|
+
integration: inventory.integrations,
|
|
56
|
+
knowledge: inventory.knowledge,
|
|
57
|
+
telemetry: inventory.telemetry,
|
|
58
|
+
"app-config": inventory.appConfigs,
|
|
59
|
+
policy: inventory.policies,
|
|
60
|
+
"test-spec": inventory.testSpecs
|
|
61
|
+
}[specType];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Analyze contract integrity.
|
|
65
|
+
*/
|
|
66
|
+
async function analyzeIntegrity(adapters, options = {}) {
|
|
67
|
+
const { fs, logger } = adapters;
|
|
68
|
+
logger.info("Starting integrity analysis...", { options });
|
|
69
|
+
const files = await fs.glob({
|
|
70
|
+
pattern: options.pattern,
|
|
71
|
+
cwd: options.cwd
|
|
72
|
+
});
|
|
73
|
+
const inventory = createEmptyInventory();
|
|
74
|
+
const features = [];
|
|
75
|
+
const issues = [];
|
|
76
|
+
for (const file of files) {
|
|
77
|
+
if ((await fs.stat(file)).isDirectory) continue;
|
|
78
|
+
const content = await fs.readFile(file);
|
|
79
|
+
if (isFeatureFile(file)) {
|
|
80
|
+
const feature = scanFeatureSource(content, file);
|
|
81
|
+
features.push(feature);
|
|
82
|
+
} else {
|
|
83
|
+
const specs = scanAllSpecsFromSource(content, file);
|
|
84
|
+
for (const spec of specs) if (spec.specType !== "unknown" && spec.specType !== "feature") {
|
|
85
|
+
const map = getInventoryMap(inventory, spec.specType);
|
|
86
|
+
if (map && spec.key && spec.version !== void 0) {
|
|
87
|
+
const key = specKey(spec.key, spec.version);
|
|
88
|
+
map.set(key, {
|
|
89
|
+
key: spec.key,
|
|
90
|
+
version: spec.version,
|
|
91
|
+
file: spec.filePath,
|
|
92
|
+
type: spec.specType,
|
|
93
|
+
stability: spec.stability,
|
|
94
|
+
testTarget: spec.testTarget,
|
|
95
|
+
testCoverage: spec.testCoverage
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const relevantFeatures = options.featureKey ? features.filter((f) => f.key === options.featureKey) : features;
|
|
102
|
+
const referencedSpecs = /* @__PURE__ */ new Set();
|
|
103
|
+
for (const feature of relevantFeatures) {
|
|
104
|
+
for (const ref of feature.operations) {
|
|
105
|
+
const key = specKey(ref.key, ref.version);
|
|
106
|
+
referencedSpecs.add(`operation:${key}`);
|
|
107
|
+
if (!inventory.operations.has(key)) issues.push({
|
|
108
|
+
severity: "error",
|
|
109
|
+
type: "unresolved-ref",
|
|
110
|
+
message: `Operation ${ref.key}.v${ref.version} not found`,
|
|
111
|
+
file: feature.filePath,
|
|
112
|
+
featureKey: feature.key,
|
|
113
|
+
specType: "operation",
|
|
114
|
+
ref
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
for (const ref of feature.events) {
|
|
118
|
+
const key = specKey(ref.key, ref.version);
|
|
119
|
+
referencedSpecs.add(`event:${key}`);
|
|
120
|
+
if (!inventory.events.has(key)) issues.push({
|
|
121
|
+
severity: "error",
|
|
122
|
+
type: "unresolved-ref",
|
|
123
|
+
message: `Event ${ref.key}.v${ref.version} not found`,
|
|
124
|
+
file: feature.filePath,
|
|
125
|
+
featureKey: feature.key,
|
|
126
|
+
specType: "event",
|
|
127
|
+
ref
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
for (const ref of feature.presentations) {
|
|
131
|
+
const key = specKey(ref.key, ref.version);
|
|
132
|
+
referencedSpecs.add(`presentation:${key}`);
|
|
133
|
+
if (!inventory.presentations.has(key)) issues.push({
|
|
134
|
+
severity: "error",
|
|
135
|
+
type: "unresolved-ref",
|
|
136
|
+
message: `Presentation ${ref.key}.v${ref.version} not found`,
|
|
137
|
+
file: feature.filePath,
|
|
138
|
+
featureKey: feature.key,
|
|
139
|
+
specType: "presentation",
|
|
140
|
+
ref
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
for (const ref of feature.experiments) {
|
|
144
|
+
const key = specKey(ref.key, ref.version);
|
|
145
|
+
referencedSpecs.add(`experiment:${key}`);
|
|
146
|
+
if (!inventory.experiments.has(key)) issues.push({
|
|
147
|
+
severity: "error",
|
|
148
|
+
type: "unresolved-ref",
|
|
149
|
+
message: `Experiment ${ref.key}.v${ref.version} not found`,
|
|
150
|
+
file: feature.filePath,
|
|
151
|
+
featureKey: feature.key,
|
|
152
|
+
specType: "experiment",
|
|
153
|
+
ref
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
for (const ref of feature.capabilities.provides) {
|
|
157
|
+
const key = specKey(ref.key, ref.version);
|
|
158
|
+
referencedSpecs.add(`capability:${key}`);
|
|
159
|
+
if (!inventory.capabilities.has(key)) issues.push({
|
|
160
|
+
severity: "warning",
|
|
161
|
+
type: "unresolved-ref",
|
|
162
|
+
message: `Provided capability ${ref.key}.v${ref.version} not found`,
|
|
163
|
+
file: feature.filePath,
|
|
164
|
+
featureKey: feature.key,
|
|
165
|
+
specType: "capability",
|
|
166
|
+
ref
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
for (const ref of feature.capabilities.requires) {
|
|
170
|
+
const key = specKey(ref.key, ref.version);
|
|
171
|
+
referencedSpecs.add(`capability:${key}`);
|
|
172
|
+
}
|
|
173
|
+
for (const link of feature.opToPresentationLinks) {
|
|
174
|
+
const opKey = specKey(link.op.key, link.op.version);
|
|
175
|
+
const presKey = specKey(link.pres.key, link.pres.version);
|
|
176
|
+
if (!inventory.operations.has(opKey)) issues.push({
|
|
177
|
+
severity: "error",
|
|
178
|
+
type: "broken-link",
|
|
179
|
+
message: `Linked operation ${link.op.key}.v${link.op.version} not found`,
|
|
180
|
+
file: feature.filePath,
|
|
181
|
+
featureKey: feature.key,
|
|
182
|
+
specType: "operation",
|
|
183
|
+
ref: link.op
|
|
184
|
+
});
|
|
185
|
+
if (!inventory.presentations.has(presKey)) issues.push({
|
|
186
|
+
severity: "error",
|
|
187
|
+
type: "broken-link",
|
|
188
|
+
message: `Linked presentation ${link.pres.key}.v${link.pres.version} not found`,
|
|
189
|
+
file: feature.filePath,
|
|
190
|
+
featureKey: feature.key,
|
|
191
|
+
specType: "presentation",
|
|
192
|
+
ref: link.pres
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (feature.presentationsTargets) for (const pt of feature.presentationsTargets) {
|
|
196
|
+
const presKey = specKey(pt.key, pt.version);
|
|
197
|
+
if (!inventory.presentations.has(presKey)) issues.push({
|
|
198
|
+
severity: "error",
|
|
199
|
+
type: "broken-link",
|
|
200
|
+
message: `Targeted presentation ${pt.key}.v${pt.version} not found`,
|
|
201
|
+
file: feature.filePath,
|
|
202
|
+
featureKey: feature.key,
|
|
203
|
+
specType: "presentation",
|
|
204
|
+
ref: {
|
|
205
|
+
key: pt.key,
|
|
206
|
+
version: pt.version
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const orphanedSpecs = [];
|
|
212
|
+
const typesThatCanBeOrphaned = [
|
|
213
|
+
"operation",
|
|
214
|
+
"event",
|
|
215
|
+
"presentation",
|
|
216
|
+
"experiment"
|
|
217
|
+
];
|
|
218
|
+
for (const type of typesThatCanBeOrphaned) {
|
|
219
|
+
const map = getInventoryMap(inventory, type);
|
|
220
|
+
if (!map) continue;
|
|
221
|
+
for (const [key, location] of map) if (!referencedSpecs.has(`${type}:${key}`)) {
|
|
222
|
+
orphanedSpecs.push(location);
|
|
223
|
+
issues.push({
|
|
224
|
+
severity: "warning",
|
|
225
|
+
type: "orphaned",
|
|
226
|
+
message: `${type} ${location.key}.v${location.version} is not linked to any feature`,
|
|
227
|
+
file: location.file,
|
|
228
|
+
specKey: location.key,
|
|
229
|
+
specType: location.type
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const testSpecScans = [];
|
|
234
|
+
for (const [, location] of inventory.testSpecs) testSpecScans.push({
|
|
235
|
+
filePath: location.file,
|
|
236
|
+
specType: "test-spec",
|
|
237
|
+
key: location.key,
|
|
238
|
+
version: location.version,
|
|
239
|
+
testTarget: location.testTarget,
|
|
240
|
+
hasMeta: true,
|
|
241
|
+
hasIo: false,
|
|
242
|
+
hasPolicy: false,
|
|
243
|
+
hasPayload: false,
|
|
244
|
+
hasContent: false,
|
|
245
|
+
hasDefinition: false
|
|
246
|
+
});
|
|
247
|
+
const testIndex = buildTestIndex(testSpecScans, inventory);
|
|
248
|
+
for (const feature of relevantFeatures) for (const link of feature.opToPresentationLinks) {
|
|
249
|
+
const opKey = specKey(link.op.key, link.op.version);
|
|
250
|
+
const tests = testIndex.targetToTests.get(opKey);
|
|
251
|
+
let hasSuccess = false;
|
|
252
|
+
let hasError = false;
|
|
253
|
+
if (tests) for (const testKey of tests) {
|
|
254
|
+
const testSpec = inventory.testSpecs.get(testKey);
|
|
255
|
+
if (testSpec?.testCoverage) {
|
|
256
|
+
if (testSpec.testCoverage.hasSuccess) hasSuccess = true;
|
|
257
|
+
if (testSpec.testCoverage.hasError) hasError = true;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (!tests || !hasSuccess || !hasError) {
|
|
261
|
+
const missing = [];
|
|
262
|
+
if (!hasSuccess) missing.push("success scenario");
|
|
263
|
+
if (!hasError) missing.push("error scenario");
|
|
264
|
+
issues.push({
|
|
265
|
+
severity: "error",
|
|
266
|
+
type: "missing-test-coverage",
|
|
267
|
+
message: `Operation ${link.op.key}.v${link.op.version} linked to presentation requires tests covering: ${missing.join(", ")}`,
|
|
268
|
+
file: feature.filePath,
|
|
269
|
+
featureKey: feature.key,
|
|
270
|
+
specType: "operation",
|
|
271
|
+
ref: link.op
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const coverageByType = {};
|
|
276
|
+
let totalMissingTests = 0;
|
|
277
|
+
for (const type of typesThatCanBeOrphaned) {
|
|
278
|
+
const map = getInventoryMap(inventory, type);
|
|
279
|
+
if (!map) continue;
|
|
280
|
+
const total = map.size;
|
|
281
|
+
let covered = 0;
|
|
282
|
+
let missingTest = 0;
|
|
283
|
+
const requireTest = options.requireTestsFor?.includes(type);
|
|
284
|
+
for (const [key, location] of map) {
|
|
285
|
+
if (referencedSpecs.has(`${type}:${key}`)) covered++;
|
|
286
|
+
if (requireTest) {
|
|
287
|
+
const targetKey = specKey(location.key, location.version);
|
|
288
|
+
const hasTargetedTest = testIndex.targetToTests.has(targetKey);
|
|
289
|
+
const conventionTestKey = `${location.key}.test`;
|
|
290
|
+
const hasConventionTest = inventory.testSpecs.has(specKey(conventionTestKey, location.version));
|
|
291
|
+
if (!hasTargetedTest && !hasConventionTest) {
|
|
292
|
+
missingTest++;
|
|
293
|
+
totalMissingTests++;
|
|
294
|
+
issues.push({
|
|
295
|
+
severity: "warning",
|
|
296
|
+
type: "missing-test",
|
|
297
|
+
message: `${type} ${location.key}.v${location.version} is missing a test spec (no TestSpec.target or naming convention match)`,
|
|
298
|
+
file: location.file,
|
|
299
|
+
specKey: location.key,
|
|
300
|
+
specType: location.type
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
coverageByType[type] = {
|
|
306
|
+
total,
|
|
307
|
+
covered,
|
|
308
|
+
orphaned: total - covered,
|
|
309
|
+
missingTest: requireTest ? missingTest : 0
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
const totalSpecs = Object.values(coverageByType).reduce((sum, c) => sum + c.total, 0);
|
|
313
|
+
const coveredSpecs = Object.values(coverageByType).reduce((sum, c) => sum + c.covered, 0);
|
|
314
|
+
const coverage = {
|
|
315
|
+
total: totalSpecs,
|
|
316
|
+
linkedToFeature: coveredSpecs,
|
|
317
|
+
orphaned: totalSpecs - coveredSpecs,
|
|
318
|
+
missingTest: totalMissingTests,
|
|
319
|
+
byType: coverageByType
|
|
320
|
+
};
|
|
321
|
+
const healthy = !issues.some((i) => i.severity === "error");
|
|
322
|
+
logger.info("Integrity analysis complete", {
|
|
323
|
+
features: features.length,
|
|
324
|
+
totalSpecs,
|
|
325
|
+
orphaned: orphanedSpecs.length,
|
|
326
|
+
issues: issues.length,
|
|
327
|
+
healthy
|
|
328
|
+
});
|
|
329
|
+
return {
|
|
330
|
+
inventory,
|
|
331
|
+
features: relevantFeatures,
|
|
332
|
+
coverage,
|
|
333
|
+
issues,
|
|
334
|
+
orphanedSpecs,
|
|
335
|
+
healthy
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Get all specs from inventory as a flat list.
|
|
340
|
+
*/
|
|
341
|
+
function getAllSpecs(inventory) {
|
|
342
|
+
const all = [];
|
|
343
|
+
for (const map of Object.values(inventory)) for (const spec of map.values()) all.push(spec);
|
|
344
|
+
return all;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Filter issues by type.
|
|
348
|
+
*/
|
|
349
|
+
function filterIssuesByType(issues, type) {
|
|
350
|
+
return issues.filter((i) => i.type === type);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Filter issues by severity.
|
|
354
|
+
*/
|
|
355
|
+
function filterIssuesBySeverity(issues, severity) {
|
|
356
|
+
return issues.filter((i) => i.severity === severity);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
//#endregion
|
|
360
|
+
export { analyzeIntegrity, filterIssuesBySeverity, filterIssuesByType, getAllSpecs };
|
|
361
|
+
//# sourceMappingURL=integrity.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integrity.mjs","names":[],"sources":["../../src/services/integrity.ts"],"sourcesContent":["/**\n * Contract integrity analysis service.\n *\n * Analyzes contract specs and features to detect:\n * - Orphaned specs (not linked to any feature)\n * - Unresolved references (broken event/op/presentation refs)\n * - Feature coverage metrics\n */\n\nimport {\n type AnalyzedSpecType,\n type FeatureScanResult,\n isFeatureFile,\n type RefInfo,\n scanAllSpecsFromSource,\n scanFeatureSource,\n} from '@contractspec/module.workspace';\nimport type { FsAdapter } from '../ports/fs';\nimport type { LoggerAdapter } from '../ports/logger';\nimport {\n buildTestIndex,\n type ExtractedTestTarget,\n type TestSpecScanResult,\n} from './test-link';\n\n/**\n * Options for integrity analysis.\n */\nexport interface IntegrityAnalysisOptions {\n /**\n * Glob pattern for file discovery.\n */\n pattern?: string;\n /**\n * Working directory for scanning.\n */\n cwd?: string;\n\n /**\n * Scan all packages in monorepo.\n */\n all?: boolean;\n\n /**\n * Analyze only a specific feature by key.\n */\n featureKey?: string;\n\n /**\n * Filter by spec type.\n */\n specType?: AnalyzedSpecType;\n\n /**\n * Require tests for specific spec types.\n */\n requireTestsFor?: AnalyzedSpecType[];\n}\n\n/**\n * Location of a spec in the codebase.\n */\nexport interface SpecLocation {\n key: string;\n version: string;\n file: string;\n type: AnalyzedSpecType;\n stability?: string;\n /** Test target for test-spec files (extracted from TestSpec.target) */\n testTarget?: ExtractedTestTarget;\n /** Test coverage info (extracted from TestSpec.scenarios) */\n testCoverage?: { hasSuccess: boolean; hasError: boolean };\n}\n\n/**\n * Inventory of all discovered specs organized by type.\n */\nexport interface SpecInventory {\n operations: Map<string, SpecLocation>;\n events: Map<string, SpecLocation>;\n presentations: Map<string, SpecLocation>;\n capabilities: Map<string, SpecLocation>;\n workflows: Map<string, SpecLocation>;\n dataViews: Map<string, SpecLocation>;\n forms: Map<string, SpecLocation>;\n migrations: Map<string, SpecLocation>;\n experiments: Map<string, SpecLocation>;\n integrations: Map<string, SpecLocation>;\n knowledge: Map<string, SpecLocation>;\n telemetry: Map<string, SpecLocation>;\n appConfigs: Map<string, SpecLocation>;\n policies: Map<string, SpecLocation>;\n testSpecs: Map<string, SpecLocation>;\n}\n\n/**\n * An integrity issue found during analysis.\n */\nexport interface IntegrityIssue {\n severity: 'error' | 'warning';\n type:\n | 'orphaned'\n | 'unresolved-ref'\n | 'missing-feature'\n | 'broken-link'\n | 'missing-test'\n | 'missing-test-coverage';\n message: string;\n file: string;\n specKey?: string;\n specType?: AnalyzedSpecType;\n ref?: RefInfo;\n featureKey?: string;\n}\n\n/**\n * Coverage metrics by spec type.\n */\nexport interface CoverageByType {\n total: number;\n covered: number;\n orphaned: number;\n missingTest?: number;\n}\n\n/**\n * Result of integrity analysis.\n */\nexport interface IntegrityAnalysisResult {\n /**\n * All discovered specs organized by type.\n */\n inventory: SpecInventory;\n\n /**\n * All discovered features.\n */\n features: FeatureScanResult[];\n\n /**\n * Coverage metrics.\n */\n coverage: {\n total: number;\n linkedToFeature: number;\n orphaned: number;\n missingTest: number;\n byType: Record<string, CoverageByType>;\n };\n\n /**\n * Issues found during analysis.\n */\n issues: IntegrityIssue[];\n\n /**\n * Specs not linked to any feature.\n */\n orphanedSpecs: SpecLocation[];\n\n /**\n * Overall health status.\n */\n healthy: boolean;\n}\n\n/**\n * Build a spec key from name and version.\n */\nfunction specKey(key: string, version: string): string {\n return `${key}.v${version}`;\n}\n\n/**\n * Create an empty spec inventory.\n */\nfunction createEmptyInventory(): SpecInventory {\n return {\n operations: new Map(),\n events: new Map(),\n presentations: new Map(),\n capabilities: new Map(),\n workflows: new Map(),\n dataViews: new Map(),\n forms: new Map(),\n migrations: new Map(),\n experiments: new Map(),\n integrations: new Map(),\n knowledge: new Map(),\n telemetry: new Map(),\n appConfigs: new Map(),\n policies: new Map(),\n testSpecs: new Map(),\n };\n}\n\n/**\n * Get the inventory map for a spec type.\n */\nfunction getInventoryMap(\n inventory: SpecInventory,\n specType: AnalyzedSpecType\n): Map<string, SpecLocation> | undefined {\n const typeToMap: Record<string, Map<string, SpecLocation>> = {\n operation: inventory.operations,\n event: inventory.events,\n presentation: inventory.presentations,\n capability: inventory.capabilities,\n workflow: inventory.workflows,\n 'data-view': inventory.dataViews,\n form: inventory.forms,\n migration: inventory.migrations,\n experiment: inventory.experiments,\n integration: inventory.integrations,\n knowledge: inventory.knowledge,\n telemetry: inventory.telemetry,\n 'app-config': inventory.appConfigs,\n policy: inventory.policies,\n 'test-spec': inventory.testSpecs,\n };\n\n return typeToMap[specType];\n}\n\n/**\n * Analyze contract integrity.\n */\nexport async function analyzeIntegrity(\n adapters: { fs: FsAdapter; logger: LoggerAdapter },\n options: IntegrityAnalysisOptions = {}\n): Promise<IntegrityAnalysisResult> {\n const { fs, logger } = adapters;\n\n logger.info('Starting integrity analysis...', { options });\n\n // Discover all spec and feature files\n const files = await fs.glob({ pattern: options.pattern, cwd: options.cwd });\n\n const inventory = createEmptyInventory();\n const features: FeatureScanResult[] = [];\n const issues: IntegrityIssue[] = [];\n\n // Scan all files\n for (const file of files) {\n // Skip directories to avoid EISDIR\n const stats = await fs.stat(file);\n if (stats.isDirectory) continue;\n\n const content = await fs.readFile(file);\n\n if (isFeatureFile(file)) {\n // Scan as feature\n const feature = scanFeatureSource(content, file);\n features.push(feature);\n } else {\n // Scan as spec - use the multi-spec scanner to find ALL specs in the file\n const specs = scanAllSpecsFromSource(content, file);\n\n for (const spec of specs) {\n if (spec.specType !== 'unknown' && spec.specType !== 'feature') {\n const map = getInventoryMap(inventory, spec.specType);\n\n if (map && spec.key && spec.version !== undefined) {\n const key = specKey(spec.key, spec.version);\n map.set(key, {\n key: spec.key,\n version: spec.version,\n file: spec.filePath,\n type: spec.specType,\n stability: spec.stability,\n // Include testTarget for test-spec files\n testTarget: spec.testTarget,\n testCoverage: spec.testCoverage,\n });\n }\n }\n }\n }\n }\n\n // Filter features if featureKey is specified\n const relevantFeatures = options.featureKey\n ? features.filter((f) => f.key === options.featureKey)\n : features;\n\n // Build set of specs referenced by features\n const referencedSpecs = new Set<string>();\n\n for (const feature of relevantFeatures) {\n // Check operation refs\n for (const ref of feature.operations) {\n const key = specKey(ref.key, ref.version);\n referencedSpecs.add(`operation:${key}`);\n\n if (!inventory.operations.has(key)) {\n issues.push({\n severity: 'error',\n type: 'unresolved-ref',\n message: `Operation ${ref.key}.v${ref.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'operation',\n ref,\n });\n }\n }\n\n // Check event refs\n for (const ref of feature.events) {\n const key = specKey(ref.key, ref.version);\n referencedSpecs.add(`event:${key}`);\n\n if (!inventory.events.has(key)) {\n issues.push({\n severity: 'error',\n type: 'unresolved-ref',\n message: `Event ${ref.key}.v${ref.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'event',\n ref,\n });\n }\n }\n\n // Check presentation refs\n for (const ref of feature.presentations) {\n const key = specKey(ref.key, ref.version);\n referencedSpecs.add(`presentation:${key}`);\n\n if (!inventory.presentations.has(key)) {\n issues.push({\n severity: 'error',\n type: 'unresolved-ref',\n message: `Presentation ${ref.key}.v${ref.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'presentation',\n ref,\n });\n }\n }\n\n // Check experiment refs\n for (const ref of feature.experiments) {\n const key = specKey(ref.key, ref.version);\n referencedSpecs.add(`experiment:${key}`);\n\n if (!inventory.experiments.has(key)) {\n issues.push({\n severity: 'error',\n type: 'unresolved-ref',\n message: `Experiment ${ref.key}.v${ref.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'experiment',\n ref,\n });\n }\n }\n\n // Check capability refs (provides and requires)\n for (const ref of feature.capabilities.provides) {\n const key = specKey(ref.key, ref.version);\n referencedSpecs.add(`capability:${key}`);\n\n if (!inventory.capabilities.has(key)) {\n issues.push({\n severity: 'warning',\n type: 'unresolved-ref',\n message: `Provided capability ${ref.key}.v${ref.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'capability',\n ref,\n });\n }\n }\n\n for (const ref of feature.capabilities.requires) {\n const key = specKey(ref.key, ref.version);\n // Required capabilities are expected to be provided by other features\n // We just track the reference\n referencedSpecs.add(`capability:${key}`);\n }\n\n // Check op to presentation links\n for (const link of feature.opToPresentationLinks) {\n const opKey = specKey(link.op.key, link.op.version);\n const presKey = specKey(link.pres.key, link.pres.version);\n\n if (!inventory.operations.has(opKey)) {\n issues.push({\n severity: 'error',\n type: 'broken-link',\n message: `Linked operation ${link.op.key}.v${link.op.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'operation',\n ref: link.op,\n });\n }\n\n if (!inventory.presentations.has(presKey)) {\n issues.push({\n severity: 'error',\n type: 'broken-link',\n message: `Linked presentation ${link.pres.key}.v${link.pres.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'presentation',\n ref: link.pres,\n });\n }\n }\n\n // Check presentations targets\n if (feature.presentationsTargets) {\n for (const pt of feature.presentationsTargets) {\n const presKey = specKey(pt.key, pt.version);\n if (!inventory.presentations.has(presKey)) {\n issues.push({\n severity: 'error',\n type: 'broken-link',\n message: `Targeted presentation ${pt.key}.v${pt.version} not found`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'presentation',\n ref: { key: pt.key, version: pt.version },\n });\n }\n }\n }\n }\n\n // Find orphaned specs (not referenced by any feature)\n const orphanedSpecs: SpecLocation[] = [];\n const typesThatCanBeOrphaned: AnalyzedSpecType[] = [\n 'operation',\n 'event',\n 'presentation',\n 'experiment',\n ];\n\n for (const type of typesThatCanBeOrphaned) {\n const map = getInventoryMap(inventory, type);\n if (!map) continue;\n\n for (const [key, location] of map) {\n if (!referencedSpecs.has(`${type}:${key}`)) {\n orphanedSpecs.push(location);\n issues.push({\n severity: 'warning',\n type: 'orphaned',\n message: `${type} ${location.key}.v${location.version} is not linked to any feature`,\n file: location.file,\n specKey: location.key,\n specType: location.type,\n });\n }\n }\n }\n\n // Build test-to-target index for contract-first test discovery\n const testSpecScans: TestSpecScanResult[] = [];\n for (const [, location] of inventory.testSpecs) {\n testSpecScans.push({\n filePath: location.file,\n specType: 'test-spec',\n key: location.key,\n version: location.version,\n testTarget: location.testTarget,\n hasMeta: true,\n hasIo: false,\n hasPolicy: false,\n hasPayload: false,\n hasContent: false,\n hasDefinition: false,\n });\n }\n const testIndex = buildTestIndex(testSpecScans, inventory);\n\n // Check test coverage for linked operations\n for (const feature of relevantFeatures) {\n for (const link of feature.opToPresentationLinks) {\n const opKey = specKey(link.op.key, link.op.version);\n const tests = testIndex.targetToTests.get(opKey);\n\n let hasSuccess = false;\n let hasError = false;\n\n if (tests) {\n for (const testKey of tests) {\n const testSpec = inventory.testSpecs.get(testKey);\n if (testSpec?.testCoverage) {\n if (testSpec.testCoverage.hasSuccess) hasSuccess = true;\n if (testSpec.testCoverage.hasError) hasError = true;\n }\n }\n }\n\n if (!tests || !hasSuccess || !hasError) {\n const missing: string[] = [];\n if (!hasSuccess) missing.push('success scenario');\n if (!hasError) missing.push('error scenario');\n\n issues.push({\n severity: 'error',\n type: 'missing-test-coverage',\n message: `Operation ${link.op.key}.v${link.op.version} linked to presentation requires tests covering: ${missing.join(', ')}`,\n file: feature.filePath,\n featureKey: feature.key,\n specType: 'operation',\n ref: link.op,\n });\n }\n }\n }\n\n // Calculate coverage metrics\n const coverageByType: Record<string, CoverageByType> = {};\n let totalMissingTests = 0;\n\n for (const type of typesThatCanBeOrphaned) {\n const map = getInventoryMap(inventory, type);\n if (!map) continue;\n\n const total = map.size;\n let covered = 0;\n let missingTest = 0;\n\n const requireTest = options.requireTestsFor?.includes(type);\n\n for (const [key, location] of map) {\n if (referencedSpecs.has(`${type}:${key}`)) {\n covered++;\n }\n\n if (requireTest) {\n const targetKey = specKey(location.key, location.version);\n\n // Primary: Check if any TestSpec targets this spec via TestSpec.target\n const hasTargetedTest = testIndex.targetToTests.has(targetKey);\n\n // Backwards compatibility: Also check naming convention ({specKey}.test)\n const conventionTestKey = `${location.key}.test`;\n const hasConventionTest = inventory.testSpecs.has(\n specKey(conventionTestKey, location.version)\n );\n\n if (!hasTargetedTest && !hasConventionTest) {\n missingTest++;\n totalMissingTests++;\n issues.push({\n severity: 'warning',\n type: 'missing-test',\n message: `${type} ${location.key}.v${location.version} is missing a test spec (no TestSpec.target or naming convention match)`,\n file: location.file,\n specKey: location.key,\n specType: location.type,\n });\n }\n }\n }\n\n coverageByType[type] = {\n total,\n covered,\n orphaned: total - covered,\n missingTest: requireTest ? missingTest : 0,\n };\n }\n\n const totalSpecs = Object.values(coverageByType).reduce(\n (sum, c) => sum + c.total,\n 0\n );\n const coveredSpecs = Object.values(coverageByType).reduce(\n (sum, c) => sum + c.covered,\n 0\n );\n\n const coverage = {\n total: totalSpecs,\n linkedToFeature: coveredSpecs,\n orphaned: totalSpecs - coveredSpecs,\n missingTest: totalMissingTests,\n byType: coverageByType,\n };\n\n // Determine overall health\n const hasErrors = issues.some((i) => i.severity === 'error');\n const healthy = !hasErrors;\n\n logger.info('Integrity analysis complete', {\n features: features.length,\n totalSpecs,\n orphaned: orphanedSpecs.length,\n issues: issues.length,\n healthy,\n });\n\n return {\n inventory,\n features: relevantFeatures,\n coverage,\n issues,\n orphanedSpecs,\n healthy,\n };\n}\n\n/**\n * Get all specs from inventory as a flat list.\n */\nexport function getAllSpecs(inventory: SpecInventory): SpecLocation[] {\n const all: SpecLocation[] = [];\n\n for (const map of Object.values(inventory)) {\n for (const spec of map.values()) {\n all.push(spec);\n }\n }\n\n return all;\n}\n\n/**\n * Filter issues by type.\n */\nexport function filterIssuesByType(\n issues: IntegrityIssue[],\n type: IntegrityIssue['type']\n): IntegrityIssue[] {\n return issues.filter((i) => i.type === type);\n}\n\n/**\n * Filter issues by severity.\n */\nexport function filterIssuesBySeverity(\n issues: IntegrityIssue[],\n severity: IntegrityIssue['severity']\n): IntegrityIssue[] {\n return issues.filter((i) => i.severity === severity);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { FsAdapter } from "../ports/fs.mjs";
|
|
2
|
+
import { LoggerAdapter } from "../ports/logger.mjs";
|
|
3
|
+
import { ExampleScanResult, FeatureScanResult, SpecScanResult } from "@contractspec/module.workspace";
|
|
4
|
+
|
|
5
|
+
//#region src/services/layer-discovery.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Location of a layer file in the codebase.
|
|
9
|
+
*/
|
|
10
|
+
interface LayerLocation {
|
|
11
|
+
key: string;
|
|
12
|
+
version?: string;
|
|
13
|
+
file: string;
|
|
14
|
+
type: 'feature' | 'example' | 'app-config' | 'workspace-config';
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Inventory of all discovered layers.
|
|
18
|
+
*/
|
|
19
|
+
interface LayerInventory {
|
|
20
|
+
/** Discovered features */
|
|
21
|
+
features: Map<string, FeatureScanResult>;
|
|
22
|
+
/** Discovered examples */
|
|
23
|
+
examples: Map<string, ExampleScanResult>;
|
|
24
|
+
/** Discovered app configs */
|
|
25
|
+
appConfigs: Map<string, SpecScanResult>;
|
|
26
|
+
/** Discovered workspace configs */
|
|
27
|
+
workspaceConfigs: Map<string, WorkspaceConfigInfo>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Workspace config information.
|
|
31
|
+
*/
|
|
32
|
+
interface WorkspaceConfigInfo {
|
|
33
|
+
file: string;
|
|
34
|
+
config: Record<string, unknown>;
|
|
35
|
+
valid: boolean;
|
|
36
|
+
errors: string[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Options for layer discovery.
|
|
40
|
+
*/
|
|
41
|
+
interface LayerDiscoveryOptions {
|
|
42
|
+
/** Glob pattern for file discovery */
|
|
43
|
+
pattern?: string;
|
|
44
|
+
/** Scan all packages in monorepo */
|
|
45
|
+
all?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Result of layer discovery.
|
|
49
|
+
*/
|
|
50
|
+
interface LayerDiscoveryResult {
|
|
51
|
+
inventory: LayerInventory;
|
|
52
|
+
stats: {
|
|
53
|
+
features: number;
|
|
54
|
+
examples: number;
|
|
55
|
+
appConfigs: number;
|
|
56
|
+
workspaceConfigs: number;
|
|
57
|
+
total: number;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Create an empty layer inventory.
|
|
62
|
+
*/
|
|
63
|
+
declare function createEmptyLayerInventory(): LayerInventory;
|
|
64
|
+
/**
|
|
65
|
+
* Discover all contract layers in a workspace.
|
|
66
|
+
*/
|
|
67
|
+
declare function discoverLayers(adapters: {
|
|
68
|
+
fs: FsAdapter;
|
|
69
|
+
logger: LoggerAdapter;
|
|
70
|
+
}, options?: LayerDiscoveryOptions): Promise<LayerDiscoveryResult>;
|
|
71
|
+
/**
|
|
72
|
+
* Get all layers as a flat list with locations.
|
|
73
|
+
*/
|
|
74
|
+
declare function getAllLayerLocations(inventory: LayerInventory): LayerLocation[];
|
|
75
|
+
//#endregion
|
|
76
|
+
export { LayerDiscoveryOptions, LayerDiscoveryResult, LayerInventory, LayerLocation, WorkspaceConfigInfo, createEmptyLayerInventory, discoverLayers, getAllLayerLocations };
|
|
77
|
+
//# sourceMappingURL=layer-discovery.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layer-discovery.d.mts","names":[],"sources":["../../src/services/layer-discovery.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AA4CuB,UAlBN,aAAA,CAkBM;EAMN,GAAA,EAAA,MAAA;EAUA,OAAA,CAAA,EAAA,MAAA;EAUA,IAAA,EAAA,MAAA;EAcD,IAAA,EAAA,SAAA,GAAA,SAAA,GAAyB,YAAI,GAAA,kBAAc;AAY3D;;;;AAGW,UA/DM,cAAA,CA+DN;EAAR;EAAO,QAAA,EA7DE,GA6DF,CAAA,MAAA,EA7Dc,iBA6Dd,CAAA;EAoGM;YA/JJ,YAAY;;cAEV,YAAY;;oBAEN,YAAY;;;;;UAMf,mBAAA;;UAEP;;;;;;;UAQO,qBAAA;;;;;;;;;UAUA,oBAAA;aACJ;;;;;;;;;;;;iBAaG,yBAAA,CAAA,GAA6B;;;;iBAYvB,cAAA;MACJ;UAAmB;aAC1B,wBACR,QAAQ;;;;iBAoGK,oBAAA,YACH,iBACV"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { isExampleFile, isFeatureFile, scanAllSpecsFromSource, scanExampleSource, scanFeatureSource } from "@contractspec/module.workspace";
|
|
2
|
+
|
|
3
|
+
//#region src/services/layer-discovery.ts
|
|
4
|
+
/**
|
|
5
|
+
* Layer discovery service.
|
|
6
|
+
*
|
|
7
|
+
* Discovers all contract layer files in a workspace:
|
|
8
|
+
* - Features (*.feature.ts)
|
|
9
|
+
* - Examples (example.ts, *.example.ts)
|
|
10
|
+
* - App Configs (*.app-config.ts, *.blueprint.ts)
|
|
11
|
+
* - Workspace Config (.contractsrc.json)
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Create an empty layer inventory.
|
|
15
|
+
*/
|
|
16
|
+
function createEmptyLayerInventory() {
|
|
17
|
+
return {
|
|
18
|
+
features: /* @__PURE__ */ new Map(),
|
|
19
|
+
examples: /* @__PURE__ */ new Map(),
|
|
20
|
+
appConfigs: /* @__PURE__ */ new Map(),
|
|
21
|
+
workspaceConfigs: /* @__PURE__ */ new Map()
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Discover all contract layers in a workspace.
|
|
26
|
+
*/
|
|
27
|
+
async function discoverLayers(adapters, options = {}) {
|
|
28
|
+
const { fs, logger } = adapters;
|
|
29
|
+
const inventory = createEmptyLayerInventory();
|
|
30
|
+
const pattern = options.pattern ?? "**/*.{ts,tsx}";
|
|
31
|
+
logger.info("Scanning for contract layer files...");
|
|
32
|
+
const files = await fs.glob({ pattern });
|
|
33
|
+
for (const file of files) {
|
|
34
|
+
if (file.includes("node_modules") || file.includes("/dist/")) continue;
|
|
35
|
+
try {
|
|
36
|
+
const code = await fs.readFile(file);
|
|
37
|
+
if (isFeatureFile(file)) {
|
|
38
|
+
const result = scanFeatureSource(code, file);
|
|
39
|
+
inventory.features.set(result.key, result);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (isExampleFile(file)) {
|
|
43
|
+
const result = scanExampleSource(code, file);
|
|
44
|
+
inventory.examples.set(result.key, result);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (file.includes(".app-config.") || file.includes(".blueprint.")) {
|
|
48
|
+
const specs = scanAllSpecsFromSource(code, file);
|
|
49
|
+
for (const spec of specs) if (spec.specType === "app-config" && spec.key) inventory.appConfigs.set(spec.key, spec);
|
|
50
|
+
}
|
|
51
|
+
} catch {}
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const configFiles = await fs.glob({ pattern: "**/.contractsrc.json" });
|
|
55
|
+
for (const configFile of configFiles) {
|
|
56
|
+
if (configFile.includes("node_modules")) continue;
|
|
57
|
+
try {
|
|
58
|
+
const content = await fs.readFile(configFile);
|
|
59
|
+
const config = JSON.parse(content);
|
|
60
|
+
inventory.workspaceConfigs.set(configFile, {
|
|
61
|
+
file: configFile,
|
|
62
|
+
config,
|
|
63
|
+
valid: true,
|
|
64
|
+
errors: []
|
|
65
|
+
});
|
|
66
|
+
} catch (e) {
|
|
67
|
+
inventory.workspaceConfigs.set(configFile, {
|
|
68
|
+
file: configFile,
|
|
69
|
+
config: {},
|
|
70
|
+
valid: false,
|
|
71
|
+
errors: [e instanceof Error ? e.message : "Parse error"]
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
} catch {}
|
|
76
|
+
const stats = {
|
|
77
|
+
features: inventory.features.size,
|
|
78
|
+
examples: inventory.examples.size,
|
|
79
|
+
appConfigs: inventory.appConfigs.size,
|
|
80
|
+
workspaceConfigs: inventory.workspaceConfigs.size,
|
|
81
|
+
total: inventory.features.size + inventory.examples.size + inventory.appConfigs.size + inventory.workspaceConfigs.size
|
|
82
|
+
};
|
|
83
|
+
logger.info(`Discovered ${stats.features} features, ${stats.examples} examples, ${stats.appConfigs} app configs, ${stats.workspaceConfigs} workspace configs`);
|
|
84
|
+
return {
|
|
85
|
+
inventory,
|
|
86
|
+
stats
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get all layers as a flat list with locations.
|
|
91
|
+
*/
|
|
92
|
+
function getAllLayerLocations(inventory) {
|
|
93
|
+
const locations = [];
|
|
94
|
+
for (const [key, feature] of inventory.features) locations.push({
|
|
95
|
+
key,
|
|
96
|
+
file: feature.filePath,
|
|
97
|
+
type: "feature"
|
|
98
|
+
});
|
|
99
|
+
for (const [key, example] of inventory.examples) locations.push({
|
|
100
|
+
key,
|
|
101
|
+
version: example.version,
|
|
102
|
+
file: example.filePath,
|
|
103
|
+
type: "example"
|
|
104
|
+
});
|
|
105
|
+
for (const [key, appConfig] of inventory.appConfigs) locations.push({
|
|
106
|
+
key,
|
|
107
|
+
version: appConfig.version,
|
|
108
|
+
file: appConfig.filePath,
|
|
109
|
+
type: "app-config"
|
|
110
|
+
});
|
|
111
|
+
for (const [, config] of inventory.workspaceConfigs) locations.push({
|
|
112
|
+
key: config.file,
|
|
113
|
+
file: config.file,
|
|
114
|
+
type: "workspace-config"
|
|
115
|
+
});
|
|
116
|
+
return locations;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
//#endregion
|
|
120
|
+
export { createEmptyLayerInventory, discoverLayers, getAllLayerLocations };
|
|
121
|
+
//# sourceMappingURL=layer-discovery.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layer-discovery.mjs","names":[],"sources":["../../src/services/layer-discovery.ts"],"sourcesContent":["/**\n * Layer discovery service.\n *\n * Discovers all contract layer files in a workspace:\n * - Features (*.feature.ts)\n * - Examples (example.ts, *.example.ts)\n * - App Configs (*.app-config.ts, *.blueprint.ts)\n * - Workspace Config (.contractsrc.json)\n */\n\nimport {\n isFeatureFile,\n scanFeatureSource,\n isExampleFile,\n scanExampleSource,\n type FeatureScanResult,\n type ExampleScanResult,\n type SpecScanResult,\n scanAllSpecsFromSource,\n} from '@contractspec/module.workspace';\nimport type { FsAdapter } from '../ports/fs';\nimport type { LoggerAdapter } from '../ports/logger';\n\n/**\n * Location of a layer file in the codebase.\n */\nexport interface LayerLocation {\n key: string;\n version?: string;\n file: string;\n type: 'feature' | 'example' | 'app-config' | 'workspace-config';\n}\n\n/**\n * Inventory of all discovered layers.\n */\nexport interface LayerInventory {\n /** Discovered features */\n features: Map<string, FeatureScanResult>;\n /** Discovered examples */\n examples: Map<string, ExampleScanResult>;\n /** Discovered app configs */\n appConfigs: Map<string, SpecScanResult>;\n /** Discovered workspace configs */\n workspaceConfigs: Map<string, WorkspaceConfigInfo>;\n}\n\n/**\n * Workspace config information.\n */\nexport interface WorkspaceConfigInfo {\n file: string;\n config: Record<string, unknown>;\n valid: boolean;\n errors: string[];\n}\n\n/**\n * Options for layer discovery.\n */\nexport interface LayerDiscoveryOptions {\n /** Glob pattern for file discovery */\n pattern?: string;\n /** Scan all packages in monorepo */\n all?: boolean;\n}\n\n/**\n * Result of layer discovery.\n */\nexport interface LayerDiscoveryResult {\n inventory: LayerInventory;\n stats: {\n features: number;\n examples: number;\n appConfigs: number;\n workspaceConfigs: number;\n total: number;\n };\n}\n\n/**\n * Create an empty layer inventory.\n */\nexport function createEmptyLayerInventory(): LayerInventory {\n return {\n features: new Map(),\n examples: new Map(),\n appConfigs: new Map(),\n workspaceConfigs: new Map(),\n };\n}\n\n/**\n * Discover all contract layers in a workspace.\n */\nexport async function discoverLayers(\n adapters: { fs: FsAdapter; logger: LoggerAdapter },\n options: LayerDiscoveryOptions = {}\n): Promise<LayerDiscoveryResult> {\n const { fs, logger } = adapters;\n const inventory = createEmptyLayerInventory();\n\n // Default pattern for spec files\n const pattern = options.pattern ?? '**/*.{ts,tsx}';\n\n // Find all TypeScript files\n logger.info('Scanning for contract layer files...');\n const files = await fs.glob({ pattern });\n\n // Process each file\n for (const file of files) {\n // Skip node_modules and dist\n if (file.includes('node_modules') || file.includes('/dist/')) {\n continue;\n }\n\n try {\n const code = await fs.readFile(file);\n\n // Check for feature files\n if (isFeatureFile(file)) {\n const result = scanFeatureSource(code, file);\n inventory.features.set(result.key, result);\n continue;\n }\n\n // Check for example files\n if (isExampleFile(file)) {\n const result = scanExampleSource(code, file);\n inventory.examples.set(result.key, result);\n continue;\n }\n\n // Check for app-config files\n if (file.includes('.app-config.') || file.includes('.blueprint.')) {\n const specs = scanAllSpecsFromSource(code, file);\n for (const spec of specs) {\n if (spec.specType === 'app-config' && spec.key) {\n inventory.appConfigs.set(spec.key, spec);\n }\n }\n }\n } catch {\n // Skip files that can't be read\n }\n }\n\n // Find workspace config files\n try {\n const configFiles = await fs.glob({ pattern: '**/.contractsrc.json' });\n for (const configFile of configFiles) {\n if (configFile.includes('node_modules')) continue;\n\n try {\n const content = await fs.readFile(configFile);\n const config = JSON.parse(content) as Record<string, unknown>;\n inventory.workspaceConfigs.set(configFile, {\n file: configFile,\n config,\n valid: true,\n errors: [],\n });\n } catch (e) {\n inventory.workspaceConfigs.set(configFile, {\n file: configFile,\n config: {},\n valid: false,\n errors: [e instanceof Error ? e.message : 'Parse error'],\n });\n }\n }\n } catch {\n // Glob failed, no config files found\n }\n\n const stats = {\n features: inventory.features.size,\n examples: inventory.examples.size,\n appConfigs: inventory.appConfigs.size,\n workspaceConfigs: inventory.workspaceConfigs.size,\n total:\n inventory.features.size +\n inventory.examples.size +\n inventory.appConfigs.size +\n inventory.workspaceConfigs.size,\n };\n\n logger.info(\n `Discovered ${stats.features} features, ${stats.examples} examples, ` +\n `${stats.appConfigs} app configs, ${stats.workspaceConfigs} workspace configs`\n );\n\n return { inventory, stats };\n}\n\n/**\n * Get all layers as a flat list with locations.\n */\nexport function getAllLayerLocations(\n inventory: LayerInventory\n): LayerLocation[] {\n const locations: LayerLocation[] = [];\n\n for (const [key, feature] of inventory.features) {\n locations.push({\n key,\n file: feature.filePath,\n type: 'feature',\n });\n }\n\n for (const [key, example] of inventory.examples) {\n locations.push({\n key,\n version: example.version,\n file: example.filePath,\n type: 'example',\n });\n }\n\n for (const [key, appConfig] of inventory.appConfigs) {\n locations.push({\n key,\n version: appConfig.version,\n file: appConfig.filePath,\n type: 'app-config',\n });\n }\n\n for (const [, config] of inventory.workspaceConfigs) {\n locations.push({\n key: config.file,\n file: config.file,\n type: 'workspace-config',\n });\n }\n\n return locations;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAoFA,SAAgB,4BAA4C;AAC1D,QAAO;EACL,0BAAU,IAAI,KAAK;EACnB,0BAAU,IAAI,KAAK;EACnB,4BAAY,IAAI,KAAK;EACrB,kCAAkB,IAAI,KAAK;EAC5B;;;;;AAMH,eAAsB,eACpB,UACA,UAAiC,EAAE,EACJ;CAC/B,MAAM,EAAE,IAAI,WAAW;CACvB,MAAM,YAAY,2BAA2B;CAG7C,MAAM,UAAU,QAAQ,WAAW;AAGnC,QAAO,KAAK,uCAAuC;CACnD,MAAM,QAAQ,MAAM,GAAG,KAAK,EAAE,SAAS,CAAC;AAGxC,MAAK,MAAM,QAAQ,OAAO;AAExB,MAAI,KAAK,SAAS,eAAe,IAAI,KAAK,SAAS,SAAS,CAC1D;AAGF,MAAI;GACF,MAAM,OAAO,MAAM,GAAG,SAAS,KAAK;AAGpC,OAAI,cAAc,KAAK,EAAE;IACvB,MAAM,SAAS,kBAAkB,MAAM,KAAK;AAC5C,cAAU,SAAS,IAAI,OAAO,KAAK,OAAO;AAC1C;;AAIF,OAAI,cAAc,KAAK,EAAE;IACvB,MAAM,SAAS,kBAAkB,MAAM,KAAK;AAC5C,cAAU,SAAS,IAAI,OAAO,KAAK,OAAO;AAC1C;;AAIF,OAAI,KAAK,SAAS,eAAe,IAAI,KAAK,SAAS,cAAc,EAAE;IACjE,MAAM,QAAQ,uBAAuB,MAAM,KAAK;AAChD,SAAK,MAAM,QAAQ,MACjB,KAAI,KAAK,aAAa,gBAAgB,KAAK,IACzC,WAAU,WAAW,IAAI,KAAK,KAAK,KAAK;;UAIxC;;AAMV,KAAI;EACF,MAAM,cAAc,MAAM,GAAG,KAAK,EAAE,SAAS,wBAAwB,CAAC;AACtE,OAAK,MAAM,cAAc,aAAa;AACpC,OAAI,WAAW,SAAS,eAAe,CAAE;AAEzC,OAAI;IACF,MAAM,UAAU,MAAM,GAAG,SAAS,WAAW;IAC7C,MAAM,SAAS,KAAK,MAAM,QAAQ;AAClC,cAAU,iBAAiB,IAAI,YAAY;KACzC,MAAM;KACN;KACA,OAAO;KACP,QAAQ,EAAE;KACX,CAAC;YACK,GAAG;AACV,cAAU,iBAAiB,IAAI,YAAY;KACzC,MAAM;KACN,QAAQ,EAAE;KACV,OAAO;KACP,QAAQ,CAAC,aAAa,QAAQ,EAAE,UAAU,cAAc;KACzD,CAAC;;;SAGA;CAIR,MAAM,QAAQ;EACZ,UAAU,UAAU,SAAS;EAC7B,UAAU,UAAU,SAAS;EAC7B,YAAY,UAAU,WAAW;EACjC,kBAAkB,UAAU,iBAAiB;EAC7C,OACE,UAAU,SAAS,OACnB,UAAU,SAAS,OACnB,UAAU,WAAW,OACrB,UAAU,iBAAiB;EAC9B;AAED,QAAO,KACL,cAAc,MAAM,SAAS,aAAa,MAAM,SAAS,aACpD,MAAM,WAAW,gBAAgB,MAAM,iBAAiB,oBAC9D;AAED,QAAO;EAAE;EAAW;EAAO;;;;;AAM7B,SAAgB,qBACd,WACiB;CACjB,MAAM,YAA6B,EAAE;AAErC,MAAK,MAAM,CAAC,KAAK,YAAY,UAAU,SACrC,WAAU,KAAK;EACb;EACA,MAAM,QAAQ;EACd,MAAM;EACP,CAAC;AAGJ,MAAK,MAAM,CAAC,KAAK,YAAY,UAAU,SACrC,WAAU,KAAK;EACb;EACA,SAAS,QAAQ;EACjB,MAAM,QAAQ;EACd,MAAM;EACP,CAAC;AAGJ,MAAK,MAAM,CAAC,KAAK,cAAc,UAAU,WACvC,WAAU,KAAK;EACb;EACA,SAAS,UAAU;EACnB,MAAM,UAAU;EAChB,MAAM;EACP,CAAC;AAGJ,MAAK,MAAM,GAAG,WAAW,UAAU,iBACjC,WAAU,KAAK;EACb,KAAK,OAAO;EACZ,MAAM,OAAO;EACb,MAAM;EACP,CAAC;AAGJ,QAAO"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { FsAdapter } from "../ports/fs.mjs";
|
|
2
|
+
import { SpecScanResult, scanSpecSource } from "@contractspec/module.workspace";
|
|
3
|
+
import { ContractsrcConfig } from "@contractspec/lib.contracts/workspace-config";
|
|
4
|
+
|
|
5
|
+
//#region src/services/list.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for listing specs.
|
|
9
|
+
*/
|
|
10
|
+
interface ListSpecsOptions {
|
|
11
|
+
/**
|
|
12
|
+
* File pattern to search.
|
|
13
|
+
*/
|
|
14
|
+
pattern?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Filter by spec type.
|
|
17
|
+
*/
|
|
18
|
+
type?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Workspace configuration
|
|
21
|
+
*/
|
|
22
|
+
config?: ContractsrcConfig;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* List all spec files in the workspace.
|
|
26
|
+
*/
|
|
27
|
+
declare function listSpecs(adapters: {
|
|
28
|
+
fs: FsAdapter;
|
|
29
|
+
scan?: typeof scanSpecSource;
|
|
30
|
+
}, options?: ListSpecsOptions): Promise<SpecScanResult[]>;
|
|
31
|
+
/**
|
|
32
|
+
* Group specs by type.
|
|
33
|
+
*/
|
|
34
|
+
declare function groupSpecsByType(specs: SpecScanResult[]): Map<string, SpecScanResult[]>;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { ListSpecsOptions, groupSpecsByType, listSpecs };
|
|
37
|
+
//# sourceMappingURL=list.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.mts","names":[],"sources":["../../src/services/list.ts"],"sourcesContent":[],"mappings":";;;;;;AAoCA;;;AAEW,UAtBM,gBAAA,CAsBN;EACA;;;EAsDK,OAAA,CAAA,EAAA,MAAA;EACP;;;EACH,IAAA,CAAA,EAAA,MAAA;;;;WAjEK;;;;;iBAMW,SAAA;MACJ;gBAAyB;aAChC,mBACR,QAAQ;;;;iBAsDK,gBAAA,QACP,mBACN,YAAY"}
|