@specverse/engine-realize 3.5.3
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/assets/examples/09-api/ai-spec.yaml +194 -0
- package/assets/examples/09-api/converted.yaml +95 -0
- package/assets/examples/09-api/diagram-architecture.mmd +10 -0
- package/assets/examples/09-api/diagram-er.mmd +10 -0
- package/assets/examples/09-api/documentation.html +104 -0
- package/assets/examples/09-api/documentation.md +95 -0
- package/assets/examples/09-api/inferred-spec.yaml +420 -0
- package/assets/examples/09-api/openapi.json +61 -0
- package/assets/examples/10-api/README.md +216 -0
- package/assets/examples/10-api/ai-spec.yaml +194 -0
- package/assets/examples/10-api/converted.yaml +96 -0
- package/assets/examples/10-api/diagram-architecture.mmd +10 -0
- package/assets/examples/10-api/diagram-er.mmd +10 -0
- package/assets/examples/10-api/documentation.html +104 -0
- package/assets/examples/10-api/documentation.md +95 -0
- package/assets/examples/10-api/inferred-spec.yaml +7 -0
- package/assets/examples/10-api/metadata.yaml +89 -0
- package/assets/examples/10-api/openapi.json +61 -0
- package/assets/examples/10-api/package-integration-test.js +177 -0
- package/assets/examples/10-api/usage-example.js +323 -0
- package/assets/examples/10-api/usage-example.ts +363 -0
- package/assets/examples/10-api/workflow-test.js +113 -0
- package/assets/examples/manifests/01-simple-default-mappings.yaml +36 -0
- package/assets/examples/manifests/02-capability-mappings.yaml +55 -0
- package/assets/examples/manifests/03-hybrid-mappings.yaml +109 -0
- package/assets/examples/manifests/README.md +245 -0
- package/assets/examples/manifests/backend-only.yaml +43 -0
- package/assets/examples/manifests/blog-api.md +78 -0
- package/assets/examples/manifests/blog-api.specly +79 -0
- package/assets/examples/manifests/frontend-only.yaml +27 -0
- package/assets/examples/manifests/fullstack-app.yaml +44 -0
- package/assets/examples/manifests/fullstack-monorepo.yaml +62 -0
- package/assets/examples/validate-examples-with-expected-failures.cjs +328 -0
- package/assets/examples/validate-examples.cjs +225 -0
- package/assets/examples-decomposed/cloud-native-manifest.example.yaml +8 -0
- package/assets/examples-decomposed/cloud-native-manifest.md +379 -0
- package/assets/examples-decomposed/cloud-native-manifest.specly +60 -0
- package/assets/examples-decomposed/docker-compose-manifest.example.yaml +8 -0
- package/assets/examples-decomposed/docker-compose-manifest.md +326 -0
- package/assets/examples-decomposed/docker-compose-manifest.specly +40 -0
- package/assets/examples-decomposed/kubernetes-deployment-manifest.example.yaml +8 -0
- package/assets/examples-decomposed/kubernetes-deployment-manifest.md +237 -0
- package/assets/examples-decomposed/kubernetes-deployment-manifest.specly +41 -0
- package/assets/templates/README.md +559 -0
- package/assets/templates/TEMPLATE-ENHANCEMENTS-V33.md +462 -0
- package/assets/templates/backend-only/CLAUDE.md +73 -0
- package/assets/templates/backend-only/README.md +197 -0
- package/assets/templates/backend-only/deployments/README.md +149 -0
- package/assets/templates/backend-only/deployments/development.specly +53 -0
- package/assets/templates/backend-only/deployments/production.specly +87 -0
- package/assets/templates/backend-only/docs/README.md +50 -0
- package/assets/templates/backend-only/docs/api/README.md +7 -0
- package/assets/templates/backend-only/docs/diagrams/README.md +85 -0
- package/assets/templates/backend-only/docs/example-documentation-template.md +269 -0
- package/assets/templates/backend-only/docs/guides/README.md +15 -0
- package/assets/templates/backend-only/dot.env.example +18 -0
- package/assets/templates/backend-only/generated/README.md +56 -0
- package/assets/templates/backend-only/generated/code/integration-test.template.js +320 -0
- package/assets/templates/backend-only/generated/code/package.json.template +34 -0
- package/assets/templates/backend-only/generated/docs/README.md +49 -0
- package/assets/templates/backend-only/gitignore +54 -0
- package/assets/templates/backend-only/manifests/README.md +72 -0
- package/assets/templates/backend-only/manifests/docker-compose.specly +91 -0
- package/assets/templates/backend-only/manifests/implementation.yaml +100 -0
- package/assets/templates/backend-only/manifests/kubernetes.specly +140 -0
- package/assets/templates/backend-only/package.json +59 -0
- package/assets/templates/backend-only/scripts/test-all.sh +160 -0
- package/assets/templates/backend-only/scripts/test-generated-code.sh +165 -0
- package/assets/templates/backend-only/specs/main.specly +67 -0
- package/assets/templates/default/CLAUDE.md +141 -0
- package/assets/templates/default/README.md +404 -0
- package/assets/templates/default/deployments/README.md +149 -0
- package/assets/templates/default/deployments/development.specly +53 -0
- package/assets/templates/default/deployments/production.specly +87 -0
- package/assets/templates/default/docs/README.md +50 -0
- package/assets/templates/default/docs/api/README.md +7 -0
- package/assets/templates/default/docs/diagrams/README.md +85 -0
- package/assets/templates/default/docs/example-documentation-template.md +269 -0
- package/assets/templates/default/docs/guides/README.md +15 -0
- package/assets/templates/default/dot.env.example +18 -0
- package/assets/templates/default/generated/README.md +56 -0
- package/assets/templates/default/generated/code/integration-test.template.js +320 -0
- package/assets/templates/default/generated/code/package.json.template +34 -0
- package/assets/templates/default/generated/docs/README.md +49 -0
- package/assets/templates/default/gitignore +54 -0
- package/assets/templates/default/manifests/README.md +72 -0
- package/assets/templates/default/manifests/docker-compose.specly +91 -0
- package/assets/templates/default/manifests/implementation.yaml +176 -0
- package/assets/templates/default/manifests/kubernetes.specly +140 -0
- package/assets/templates/default/package.json +61 -0
- package/assets/templates/default/scripts/test-all.sh +160 -0
- package/assets/templates/default/scripts/test-generated-code.sh +165 -0
- package/assets/templates/default/specs/main.specly +67 -0
- package/assets/templates/frontend-only/CLAUDE.md +75 -0
- package/assets/templates/frontend-only/README.md +231 -0
- package/assets/templates/frontend-only/deployments/README.md +149 -0
- package/assets/templates/frontend-only/deployments/development.specly +53 -0
- package/assets/templates/frontend-only/deployments/production.specly +87 -0
- package/assets/templates/frontend-only/docs/README.md +50 -0
- package/assets/templates/frontend-only/docs/api/README.md +7 -0
- package/assets/templates/frontend-only/docs/diagrams/README.md +85 -0
- package/assets/templates/frontend-only/docs/example-documentation-template.md +269 -0
- package/assets/templates/frontend-only/docs/guides/README.md +15 -0
- package/assets/templates/frontend-only/dot.env.example +18 -0
- package/assets/templates/frontend-only/generated/README.md +56 -0
- package/assets/templates/frontend-only/generated/code/integration-test.template.js +320 -0
- package/assets/templates/frontend-only/generated/code/package.json.template +34 -0
- package/assets/templates/frontend-only/generated/docs/README.md +49 -0
- package/assets/templates/frontend-only/gitignore +54 -0
- package/assets/templates/frontend-only/manifests/README.md +72 -0
- package/assets/templates/frontend-only/manifests/docker-compose.specly +91 -0
- package/assets/templates/frontend-only/manifests/implementation.yaml +58 -0
- package/assets/templates/frontend-only/manifests/kubernetes.specly +140 -0
- package/assets/templates/frontend-only/package.json +59 -0
- package/assets/templates/frontend-only/scripts/test-all.sh +160 -0
- package/assets/templates/frontend-only/scripts/test-generated-code.sh +165 -0
- package/assets/templates/frontend-only/specs/main.specly +57 -0
- package/assets/templates/full-stack/AI-GUIDE.md +60 -0
- package/assets/templates/full-stack/CLAUDE.md +141 -0
- package/assets/templates/full-stack/README.md +382 -0
- package/assets/templates/full-stack/archive/AI-GUIDE-legacy.md +392 -0
- package/assets/templates/full-stack/deployments/README.md +149 -0
- package/assets/templates/full-stack/deployments/development.specly +53 -0
- package/assets/templates/full-stack/deployments/production.specly +87 -0
- package/assets/templates/full-stack/docs/README.md +51 -0
- package/assets/templates/full-stack/docs/api/README.md +7 -0
- package/assets/templates/full-stack/docs/diagrams/README.md +85 -0
- package/assets/templates/full-stack/docs/example-documentation-template.md +269 -0
- package/assets/templates/full-stack/docs/guides/README.md +15 -0
- package/assets/templates/full-stack/generated/README.md +56 -0
- package/assets/templates/full-stack/generated/code/integration-test.template.js +320 -0
- package/assets/templates/full-stack/generated/code/package.json.template +34 -0
- package/assets/templates/full-stack/generated/docs/README.md +49 -0
- package/assets/templates/full-stack/gitignore +54 -0
- package/assets/templates/full-stack/manifests/README.md +72 -0
- package/assets/templates/full-stack/manifests/docker-compose.specly +91 -0
- package/assets/templates/full-stack/manifests/implementation.yaml +155 -0
- package/assets/templates/full-stack/manifests/kubernetes.specly +140 -0
- package/assets/templates/full-stack/package.json +45 -0
- package/assets/templates/full-stack/scripts/test-all.sh +160 -0
- package/assets/templates/full-stack/scripts/test-generated-code.sh +165 -0
- package/assets/templates/full-stack/specs/example-v33.specly +297 -0
- package/assets/templates/full-stack/specs/main-simple.specly +73 -0
- package/assets/templates/full-stack/specs/main.specly +408 -0
- package/dist/engines/code-generator.d.ts +86 -0
- package/dist/engines/code-generator.d.ts.map +1 -0
- package/dist/engines/code-generator.js +159 -0
- package/dist/engines/code-generator.js.map +1 -0
- package/dist/engines/engine-registry.d.ts +94 -0
- package/dist/engines/engine-registry.d.ts.map +1 -0
- package/dist/engines/engine-registry.js +163 -0
- package/dist/engines/engine-registry.js.map +1 -0
- package/dist/engines/index.d.ts +10 -0
- package/dist/engines/index.d.ts.map +1 -0
- package/dist/engines/index.js +12 -0
- package/dist/engines/index.js.map +1 -0
- package/dist/engines/typescript-engine.d.ts +74 -0
- package/dist/engines/typescript-engine.d.ts.map +1 -0
- package/dist/engines/typescript-engine.js +288 -0
- package/dist/engines/typescript-engine.js.map +1 -0
- package/dist/generators/index.d.ts +11 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +11 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +434 -0
- package/dist/index.js.map +1 -0
- package/dist/library/index.d.ts +12 -0
- package/dist/library/index.d.ts.map +1 -0
- package/dist/library/index.js +15 -0
- package/dist/library/index.js.map +1 -0
- package/dist/library/library.d.ts +132 -0
- package/dist/library/library.d.ts.map +1 -0
- package/dist/library/library.js +343 -0
- package/dist/library/library.js.map +1 -0
- package/dist/library/loader.d.ts +73 -0
- package/dist/library/loader.d.ts.map +1 -0
- package/dist/library/loader.js +150 -0
- package/dist/library/loader.js.map +1 -0
- package/dist/library/resolver.d.ts +104 -0
- package/dist/library/resolver.d.ts.map +1 -0
- package/dist/library/resolver.js +299 -0
- package/dist/library/resolver.js.map +1 -0
- package/dist/library/validator.d.ts +65 -0
- package/dist/library/validator.d.ts.map +1 -0
- package/dist/library/validator.js +203 -0
- package/dist/library/validator.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/instance-factory.d.ts +289 -0
- package/dist/types/instance-factory.d.ts.map +1 -0
- package/dist/types/instance-factory.js +8 -0
- package/dist/types/instance-factory.js.map +1 -0
- package/dist/types/unified-mappings.d.ts +163 -0
- package/dist/types/unified-mappings.d.ts.map +1 -0
- package/dist/types/unified-mappings.js +110 -0
- package/dist/types/unified-mappings.js.map +1 -0
- package/dist/utils/ai-spec-loader.d.ts +77 -0
- package/dist/utils/ai-spec-loader.d.ts.map +1 -0
- package/dist/utils/ai-spec-loader.js +138 -0
- package/dist/utils/ai-spec-loader.js.map +1 -0
- package/dist/utils/index.d.ts +9 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/manifest-loader.d.ts +107 -0
- package/dist/utils/manifest-loader.d.ts.map +1 -0
- package/dist/utils/manifest-loader.js +168 -0
- package/dist/utils/manifest-loader.js.map +1 -0
- package/dist/utils/mapping-migration.d.ts +53 -0
- package/dist/utils/mapping-migration.d.ts.map +1 -0
- package/dist/utils/mapping-migration.js +194 -0
- package/dist/utils/mapping-migration.js.map +1 -0
- package/libs/instance-factories/CURVED-INTERFACE.md +278 -0
- package/libs/instance-factories/README.md +433 -0
- package/libs/instance-factories/applications/generic-app.yaml +52 -0
- package/libs/instance-factories/applications/react-app.yaml +186 -0
- package/libs/instance-factories/applications/templates/generic/backend-env-generator.ts +31 -0
- package/libs/instance-factories/applications/templates/generic/backend-package-json-generator.ts +80 -0
- package/libs/instance-factories/applications/templates/generic/backend-tsconfig-generator.ts +69 -0
- package/libs/instance-factories/applications/templates/generic/main-generator.ts +308 -0
- package/libs/instance-factories/applications/templates/react/_view-components-source.ts +555 -0
- package/libs/instance-factories/applications/templates/react/api-client-generator.ts +436 -0
- package/libs/instance-factories/applications/templates/react/api-types-generator.ts +153 -0
- package/libs/instance-factories/applications/templates/react/app-tsx-generator.ts +94 -0
- package/libs/instance-factories/applications/templates/react/env-example-generator.ts +24 -0
- package/libs/instance-factories/applications/templates/react/field-helpers-generator.ts +106 -0
- package/libs/instance-factories/applications/templates/react/gitignore-generator.ts +38 -0
- package/libs/instance-factories/applications/templates/react/index-css-generator.ts +85 -0
- package/libs/instance-factories/applications/templates/react/index-html-generator.ts +30 -0
- package/libs/instance-factories/applications/templates/react/main-tsx-generator.ts +34 -0
- package/libs/instance-factories/applications/templates/react/package-json-generator.ts +54 -0
- package/libs/instance-factories/applications/templates/react/pattern-adapter-generator.ts +179 -0
- package/libs/instance-factories/applications/templates/react/react-pattern-adapter.tsx +1347 -0
- package/libs/instance-factories/applications/templates/react/relationship-field-generator.ts +150 -0
- package/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.ts +704 -0
- package/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.ts +84 -0
- package/libs/instance-factories/applications/templates/react/tsconfig-generator.ts +35 -0
- package/libs/instance-factories/applications/templates/react/use-api-hooks-generator.ts +121 -0
- package/libs/instance-factories/applications/templates/react/view-dashboard-generator.ts +150 -0
- package/libs/instance-factories/applications/templates/react/view-detail-generator.ts +150 -0
- package/libs/instance-factories/applications/templates/react/view-form-generator.ts +362 -0
- package/libs/instance-factories/applications/templates/react/view-list-generator.ts +98 -0
- package/libs/instance-factories/applications/templates/react/view-router-generator.ts +89 -0
- package/libs/instance-factories/applications/templates/react/vite-config-generator.ts +49 -0
- package/libs/instance-factories/archived/fastify-prisma.yaml +104 -0
- package/libs/instance-factories/cli/commander-js.yaml +55 -0
- package/libs/instance-factories/cli/templates/commander/cli-entry-generator.d.ts +12 -0
- package/libs/instance-factories/cli/templates/commander/cli-entry-generator.d.ts.map +1 -0
- package/libs/instance-factories/cli/templates/commander/cli-entry-generator.js +115 -0
- package/libs/instance-factories/cli/templates/commander/cli-entry-generator.js.map +1 -0
- package/libs/instance-factories/cli/templates/commander/cli-entry-generator.ts +145 -0
- package/libs/instance-factories/cli/templates/commander/command-generator.d.ts +14 -0
- package/libs/instance-factories/cli/templates/commander/command-generator.d.ts.map +1 -0
- package/libs/instance-factories/cli/templates/commander/command-generator.js +182 -0
- package/libs/instance-factories/cli/templates/commander/command-generator.js.map +1 -0
- package/libs/instance-factories/cli/templates/commander/command-generator.ts +992 -0
- package/libs/instance-factories/communication/event-emitter.yaml +56 -0
- package/libs/instance-factories/communication/rabbitmq-events.yaml +87 -0
- package/libs/instance-factories/communication/templates/eventemitter/bus-generator.ts +93 -0
- package/libs/instance-factories/communication/templates/eventemitter/publisher-generator.ts +117 -0
- package/libs/instance-factories/communication/templates/eventemitter/subscriber-generator.ts +101 -0
- package/libs/instance-factories/controllers/fastify.yaml +127 -0
- package/libs/instance-factories/controllers/templates/fastify/meta-routes-generator.ts +103 -0
- package/libs/instance-factories/controllers/templates/fastify/routes-generator.ts +389 -0
- package/libs/instance-factories/controllers/templates/fastify/server-generator.ts +76 -0
- package/libs/instance-factories/infrastructure/docker-k8s.yaml +61 -0
- package/libs/instance-factories/infrastructure/templates/docker-k8s/infrastructure-generator.ts +46 -0
- package/libs/instance-factories/orms/prisma.yaml +89 -0
- package/libs/instance-factories/orms/templates/prisma/schema-generator.ts +563 -0
- package/libs/instance-factories/orms/templates/prisma/services-generator.ts +408 -0
- package/libs/instance-factories/scaffolding/generic-scaffold.yaml +65 -0
- package/libs/instance-factories/scaffolding/templates/generic/env-example-generator.ts +73 -0
- package/libs/instance-factories/scaffolding/templates/generic/env-generator.ts +85 -0
- package/libs/instance-factories/scaffolding/templates/generic/gitignore-generator.ts +69 -0
- package/libs/instance-factories/scaffolding/templates/generic/package-json-generator.ts +176 -0
- package/libs/instance-factories/scaffolding/templates/generic/readme-generator.ts +207 -0
- package/libs/instance-factories/scaffolding/templates/generic/tsconfig-generator.ts +78 -0
- package/libs/instance-factories/scaffolding/templates/generic/tsconfig-react-generator.ts +41 -0
- package/libs/instance-factories/sdks/python-sdk.yaml +66 -0
- package/libs/instance-factories/sdks/templates/python/sdk-generator.ts +50 -0
- package/libs/instance-factories/sdks/templates/typescript/sdk-generator.ts +49 -0
- package/libs/instance-factories/sdks/typescript-sdk.yaml +59 -0
- package/libs/instance-factories/services/prisma-services.yaml +71 -0
- package/libs/instance-factories/services/templates/prisma/behavior-generator.ts +303 -0
- package/libs/instance-factories/services/templates/prisma/controller-generator.ts +532 -0
- package/libs/instance-factories/services/templates/prisma/service-generator.ts +315 -0
- package/libs/instance-factories/shared/path-resolver.ts +111 -0
- package/libs/instance-factories/storage/mongodb.yaml +79 -0
- package/libs/instance-factories/storage/postgresql.yaml +75 -0
- package/libs/instance-factories/storage/redis.yaml +79 -0
- package/libs/instance-factories/storage/templates/mongodb/config-generator.ts +15 -0
- package/libs/instance-factories/storage/templates/mongodb/docker-generator.ts +18 -0
- package/libs/instance-factories/storage/templates/postgresql/config-generator.ts +54 -0
- package/libs/instance-factories/storage/templates/postgresql/docker-generator.ts +55 -0
- package/libs/instance-factories/storage/templates/redis/config-generator.ts +16 -0
- package/libs/instance-factories/storage/templates/redis/docker-generator.ts +18 -0
- package/libs/instance-factories/test-generation.ts +192 -0
- package/libs/instance-factories/testing/templates/vitest/tests-generator.ts +51 -0
- package/libs/instance-factories/testing/vitest-tests.yaml +63 -0
- package/libs/instance-factories/tools/templates/mcp/mcp-server-generator.ts +136 -0
- package/libs/instance-factories/tools/templates/mcp/static/docs/DEPLOYMENT_GUIDE.md +630 -0
- package/libs/instance-factories/tools/templates/mcp/static/docs/HYBRID_RESOURCE_SYSTEM.md +330 -0
- package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/EXTENSION_DEPLOYMENT.md +552 -0
- package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/LOCAL_DEPLOYMENT.md +164 -0
- package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/WEB_DEPLOYMENT.md +247 -0
- package/libs/instance-factories/tools/templates/mcp/static/package.json +92 -0
- package/libs/instance-factories/tools/templates/mcp/static/scripts/build-enterprise.js +284 -0
- package/libs/instance-factories/tools/templates/mcp/static/scripts/build-extension.js +139 -0
- package/libs/instance-factories/tools/templates/mcp/static/scripts/build-local.js +74 -0
- package/libs/instance-factories/tools/templates/mcp/static/scripts/build-web.js +156 -0
- package/libs/instance-factories/tools/templates/mcp/static/scripts/copy-canonical-files.js +41 -0
- package/libs/instance-factories/tools/templates/mcp/static/scripts/test-deployments.js +259 -0
- package/libs/instance-factories/tools/templates/mcp/static/scripts/test-hybrid-resources.js +231 -0
- package/libs/instance-factories/tools/templates/mcp/static/scripts/test-hybrid-simple.js +196 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/controllers/MCPServerController.ts +293 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/events/EventEmitter.ts +90 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/index.ts +24 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/interfaces/ResourceProvider.ts +15 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/models/LibrarySuggestion.ts +106 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/models/SpecVerseResource.ts +75 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/server/mcp-server.ts +239 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/services/CLIProxyService.ts +1501 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/services/EmbeddedResourcesAdapter.ts +211 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/services/EntityModuleService.ts +308 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/services/HybridResourcesProvider.ts +210 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/services/LibraryToolsService.ts +356 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorBridge.ts +524 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorToolsService.ts +530 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/services/PromptToolsService.ts +594 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/services/ResourcesProviderService.ts +170 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/CLIProxyService.init.test.ts +544 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/CLIProxyService.test.ts +189 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/ResourcesProviderService.test.ts +89 -0
- package/libs/instance-factories/tools/templates/mcp/static/src/types/index.ts +110 -0
- package/libs/instance-factories/tools/templates/mcp/static/tsconfig.json +28 -0
- package/libs/instance-factories/tools/templates/vscode/static/extension.ts +1195 -0
- package/libs/instance-factories/tools/templates/vscode/static/language-configuration.json +34 -0
- package/libs/instance-factories/tools/templates/vscode/static/schemas/specverse-v3-schema.json +4279 -0
- package/libs/instance-factories/tools/templates/vscode/static/syntaxes/specverse.tmLanguage.json +138 -0
- package/libs/instance-factories/tools/templates/vscode/static/themes/README.md +74 -0
- package/libs/instance-factories/tools/templates/vscode/static/themes/complete-specverse-colors.json +122 -0
- package/libs/instance-factories/tools/templates/vscode/static/themes/specverse-basic-theme.json +65 -0
- package/libs/instance-factories/tools/templates/vscode/static/themes/specverse-complete-theme.json +123 -0
- package/libs/instance-factories/tools/templates/vscode/static/themes/specverse-theme-colors.json +64 -0
- package/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.ts +214 -0
- package/libs/instance-factories/validation/templates/zod/validation-generator.ts +46 -0
- package/libs/instance-factories/validation/zod.yaml +56 -0
- package/libs/instance-factories/views/index.d.ts +13 -0
- package/libs/instance-factories/views/index.d.ts.map +1 -0
- package/libs/instance-factories/views/index.js +18 -0
- package/libs/instance-factories/views/index.js.map +1 -0
- package/libs/instance-factories/views/index.ts +45 -0
- package/libs/instance-factories/views/react-components.yaml +129 -0
- package/libs/instance-factories/views/templates/ARCHITECTURE.md +198 -0
- package/libs/instance-factories/views/templates/react/adapters/antd-adapter.ts +869 -0
- package/libs/instance-factories/views/templates/react/adapters/mui-adapter.ts +953 -0
- package/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.ts +806 -0
- package/libs/instance-factories/views/templates/react/app-generator.ts +55 -0
- package/libs/instance-factories/views/templates/react/components-generator.ts +391 -0
- package/libs/instance-factories/views/templates/react/forms-generator.ts +343 -0
- package/libs/instance-factories/views/templates/react/frontend-package-json-generator.ts +54 -0
- package/libs/instance-factories/views/templates/react/hooks-generator.ts +122 -0
- package/libs/instance-factories/views/templates/react/index-css-generator.ts +209 -0
- package/libs/instance-factories/views/templates/react/index-html-generator.ts +34 -0
- package/libs/instance-factories/views/templates/react/main-tsx-generator.ts +29 -0
- package/libs/instance-factories/views/templates/react/react-component-generator.d.ts +152 -0
- package/libs/instance-factories/views/templates/react/react-component-generator.d.ts.map +1 -0
- package/libs/instance-factories/views/templates/react/react-component-generator.js +398 -0
- package/libs/instance-factories/views/templates/react/react-component-generator.js.map +1 -0
- package/libs/instance-factories/views/templates/react/react-component-generator.ts +533 -0
- package/libs/instance-factories/views/templates/react/router-generator.ts +197 -0
- package/libs/instance-factories/views/templates/react/router-generic-generator.ts +103 -0
- package/libs/instance-factories/views/templates/react/spec-json-generator.ts +17 -0
- package/libs/instance-factories/views/templates/react/types-generator.ts +76 -0
- package/libs/instance-factories/views/templates/react/views-metadata-generator.ts +42 -0
- package/libs/instance-factories/views/templates/react/vite-config-generator.ts +38 -0
- package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.d.ts.map +1 -0
- package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js.map +1 -0
- package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.ts +474 -0
- package/libs/instance-factories/views/templates/shared/__tests__/composite-patterns.test.ts +242 -0
- package/libs/instance-factories/views/templates/shared/adapter-types.d.ts +77 -0
- package/libs/instance-factories/views/templates/shared/adapter-types.d.ts.map +1 -0
- package/libs/instance-factories/views/templates/shared/adapter-types.js +47 -0
- package/libs/instance-factories/views/templates/shared/adapter-types.js.map +1 -0
- package/libs/instance-factories/views/templates/shared/adapter-types.ts +142 -0
- package/libs/instance-factories/views/templates/shared/atomic-components-registry.d.ts +63 -0
- package/libs/instance-factories/views/templates/shared/atomic-components-registry.d.ts.map +1 -0
- package/libs/instance-factories/views/templates/shared/atomic-components-registry.js +822 -0
- package/libs/instance-factories/views/templates/shared/atomic-components-registry.js.map +1 -0
- package/libs/instance-factories/views/templates/shared/atomic-components-registry.ts +908 -0
- package/libs/instance-factories/views/templates/shared/base-generator.d.ts +247 -0
- package/libs/instance-factories/views/templates/shared/base-generator.d.ts.map +1 -0
- package/libs/instance-factories/views/templates/shared/base-generator.js +363 -0
- package/libs/instance-factories/views/templates/shared/base-generator.js.map +1 -0
- package/libs/instance-factories/views/templates/shared/base-generator.ts +608 -0
- package/libs/instance-factories/views/templates/shared/component-metadata.d.ts +254 -0
- package/libs/instance-factories/views/templates/shared/component-metadata.d.ts.map +1 -0
- package/libs/instance-factories/views/templates/shared/component-metadata.js +602 -0
- package/libs/instance-factories/views/templates/shared/component-metadata.js.map +1 -0
- package/libs/instance-factories/views/templates/shared/component-metadata.ts +803 -0
- package/libs/instance-factories/views/templates/shared/composite-pattern-types.ts +250 -0
- package/libs/instance-factories/views/templates/shared/composite-patterns.ts +535 -0
- package/libs/instance-factories/views/templates/shared/index.ts +68 -0
- package/libs/instance-factories/views/templates/shared/pattern-validator.ts +279 -0
- package/libs/instance-factories/views/templates/shared/property-mapper.d.ts +149 -0
- package/libs/instance-factories/views/templates/shared/property-mapper.d.ts.map +1 -0
- package/libs/instance-factories/views/templates/shared/property-mapper.js +580 -0
- package/libs/instance-factories/views/templates/shared/property-mapper.js.map +1 -0
- package/libs/instance-factories/views/templates/shared/property-mapper.ts +700 -0
- package/libs/instance-factories/views/templates/shared/syntax-mapper.d.ts +143 -0
- package/libs/instance-factories/views/templates/shared/syntax-mapper.d.ts.map +1 -0
- package/libs/instance-factories/views/templates/shared/syntax-mapper.js +420 -0
- package/libs/instance-factories/views/templates/shared/syntax-mapper.js.map +1 -0
- package/libs/instance-factories/views/templates/shared/syntax-mapper.ts +539 -0
- package/package.json +42 -0
- package/schema/SPECVERSE-SCHEMA.json +4274 -0
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLIProxyService Init Command Tests
|
|
3
|
+
* Tests for the init command path handling and delivery methods
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
|
|
7
|
+
import { CLIProxyService } from '../../services/CLIProxyService.js';
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import { execSync } from 'child_process';
|
|
11
|
+
|
|
12
|
+
// Mock modules
|
|
13
|
+
vi.mock('fs');
|
|
14
|
+
vi.mock('fs/promises', () => ({
|
|
15
|
+
mkdtemp: vi.fn((prefix) => Promise.resolve('/tmp/mcp-init-123456')),
|
|
16
|
+
rm: vi.fn(() => Promise.resolve()),
|
|
17
|
+
unlink: vi.fn(() => Promise.resolve()),
|
|
18
|
+
readFile: vi.fn((path) => {
|
|
19
|
+
// Return different content based on file path
|
|
20
|
+
if (path.includes('package.json')) {
|
|
21
|
+
// Read actual version from package.json instead of hardcoding
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const packagePath = require('path').join(__dirname, '..', '..', '..', 'package.json');
|
|
24
|
+
const packageContent = fs.readFileSync(packagePath, 'utf8');
|
|
25
|
+
const packageData = JSON.parse(packageContent);
|
|
26
|
+
return Promise.resolve(JSON.stringify({
|
|
27
|
+
version: packageData.version,
|
|
28
|
+
name: packageData.name
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
// Always return valid content for any file path to avoid "File not found" errors
|
|
32
|
+
return Promise.resolve('file content');
|
|
33
|
+
}),
|
|
34
|
+
readdir: vi.fn((path, options) => {
|
|
35
|
+
// If withFileTypes is true, return Dirent-like objects
|
|
36
|
+
if (options?.withFileTypes) {
|
|
37
|
+
return Promise.resolve([
|
|
38
|
+
{ name: 'main.specly', isDirectory: () => false, isFile: () => true },
|
|
39
|
+
{ name: 'README.md', isDirectory: () => false, isFile: () => true }
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
// Otherwise return simple string array
|
|
43
|
+
return Promise.resolve(['main.specly', 'README.md']);
|
|
44
|
+
}),
|
|
45
|
+
stat: vi.fn(() => Promise.resolve({ isDirectory: () => false }))
|
|
46
|
+
}));
|
|
47
|
+
vi.mock('child_process');
|
|
48
|
+
vi.mock('os', () => ({
|
|
49
|
+
tmpdir: vi.fn(() => '/tmp')
|
|
50
|
+
}));
|
|
51
|
+
vi.mock('path', async () => {
|
|
52
|
+
const actual = await vi.importActual('path');
|
|
53
|
+
return {
|
|
54
|
+
...actual,
|
|
55
|
+
join: vi.fn((...args) => args.join('/')),
|
|
56
|
+
dirname: vi.fn((p) => {
|
|
57
|
+
const parts = p.split('/');
|
|
58
|
+
parts.pop();
|
|
59
|
+
return parts.join('/') || '/';
|
|
60
|
+
}),
|
|
61
|
+
basename: vi.fn((p) => {
|
|
62
|
+
const parts = p.split('/');
|
|
63
|
+
return parts[parts.length - 1];
|
|
64
|
+
})
|
|
65
|
+
};
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('CLIProxyService - Init Command', () => {
|
|
69
|
+
let service: CLIProxyService;
|
|
70
|
+
const mockCliPath = '/mock/path/to/specverse-cli.js';
|
|
71
|
+
|
|
72
|
+
beforeEach(() => {
|
|
73
|
+
vi.clearAllMocks();
|
|
74
|
+
service = new CLIProxyService(mockCliPath);
|
|
75
|
+
|
|
76
|
+
// Setup default mocks
|
|
77
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => undefined);
|
|
78
|
+
vi.mocked(fs.unlinkSync).mockImplementation(() => undefined);
|
|
79
|
+
|
|
80
|
+
// Mock execSync to return success for SpecVerse check and init command
|
|
81
|
+
vi.mocked(execSync)
|
|
82
|
+
.mockReturnValueOnce('/path/to/specverse') // which specverse
|
|
83
|
+
.mockReturnValue('Project created successfully'); // init command
|
|
84
|
+
|
|
85
|
+
// Mock the canCreateLocalFiles method to return true by default
|
|
86
|
+
// This is needed because the method uses fs imports directly
|
|
87
|
+
vi.spyOn(service as any, 'canCreateLocalFiles').mockResolvedValue(true);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
afterEach(async () => {
|
|
91
|
+
vi.clearAllMocks();
|
|
92
|
+
// Restore the original fs/promises.readFile mock
|
|
93
|
+
const fsPromises = await import('fs/promises');
|
|
94
|
+
vi.mocked(fsPromises.readFile).mockImplementation((path) => {
|
|
95
|
+
// Return different content based on file path
|
|
96
|
+
if (typeof path === 'string' && path.includes('package.json')) {
|
|
97
|
+
// Read actual version from package.json instead of hardcoding
|
|
98
|
+
const fs = require('fs');
|
|
99
|
+
const packagePath = require('path').join(__dirname, '..', '..', '..', 'package.json');
|
|
100
|
+
const packageContent = fs.readFileSync(packagePath, 'utf8');
|
|
101
|
+
const packageData = JSON.parse(packageContent);
|
|
102
|
+
return Promise.resolve(JSON.stringify({
|
|
103
|
+
version: packageData.version,
|
|
104
|
+
name: packageData.name
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
// Always return valid content for any file path to avoid "File not found" errors
|
|
108
|
+
return Promise.resolve('file content');
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('Path Handling', () => {
|
|
113
|
+
it('should handle absolute paths correctly', async () => {
|
|
114
|
+
const args = {
|
|
115
|
+
name: '/Users/cainen/test-project',
|
|
116
|
+
zip: false,
|
|
117
|
+
fullPath: '/Users/cainen/test-project'
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Mock successful file write test (indicating we can create local files)
|
|
121
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => undefined);
|
|
122
|
+
vi.mocked(fs.unlinkSync).mockImplementation(() => undefined);
|
|
123
|
+
|
|
124
|
+
// Mock execSync to return specverse path then success
|
|
125
|
+
vi.mocked(execSync)
|
|
126
|
+
.mockReturnValueOnce('/path/to/specverse') // which specverse
|
|
127
|
+
.mockReturnValue('Project created successfully'); // init command
|
|
128
|
+
|
|
129
|
+
const result = await service.executeInitCommand('init "test-project"', args);
|
|
130
|
+
|
|
131
|
+
// Should extract correct project name and use local filesystem
|
|
132
|
+
expect(result).toBeDefined();
|
|
133
|
+
expect(result.delivery_method).toBe('local_filesystem');
|
|
134
|
+
expect(result.project_path).toBe('/Users/cainen/test-project');
|
|
135
|
+
expect(result.status).toBe('success');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should handle relative paths correctly', async () => {
|
|
139
|
+
const args = {
|
|
140
|
+
name: 'my-project',
|
|
141
|
+
zip: false
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// Mock current directory
|
|
145
|
+
const originalCwd = process.cwd;
|
|
146
|
+
process.cwd = vi.fn(() => '/current/directory');
|
|
147
|
+
|
|
148
|
+
// Mock that we cannot write to current directory (common in CI/test environments)
|
|
149
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => {
|
|
150
|
+
throw new Error('Permission denied');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Override canCreateLocalFiles to return false
|
|
154
|
+
vi.spyOn(service as any, 'canCreateLocalFiles').mockResolvedValue(false);
|
|
155
|
+
|
|
156
|
+
// Setup mocks for JSON fallback
|
|
157
|
+
vi.mocked(fs.mkdtempSync).mockReturnValue('/tmp/mcp-init-123456');
|
|
158
|
+
vi.mocked(fs.readdirSync).mockReturnValue(['main.specly', 'README.md']);
|
|
159
|
+
vi.mocked(fs.statSync).mockReturnValue({ isDirectory: () => false } as any);
|
|
160
|
+
vi.mocked(fs.readFileSync).mockReturnValue('file content');
|
|
161
|
+
|
|
162
|
+
const result = await service.executeInitCommand('init "my-project"', args);
|
|
163
|
+
|
|
164
|
+
// Should fall back to JSON structure delivery
|
|
165
|
+
expect(result).toBeDefined();
|
|
166
|
+
expect(result.delivery_method).toBe('json_structure');
|
|
167
|
+
expect(result.status).toBe('success');
|
|
168
|
+
|
|
169
|
+
process.cwd = originalCwd;
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should preserve full path through command chain', async () => {
|
|
173
|
+
const args = {
|
|
174
|
+
fullPath: '/Users/cainen/deeply/nested/project',
|
|
175
|
+
zip: false
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Mock successful file write test
|
|
179
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => undefined);
|
|
180
|
+
vi.mocked(fs.unlinkSync).mockImplementation(() => undefined);
|
|
181
|
+
|
|
182
|
+
// Mock execSync for specverse check and init command
|
|
183
|
+
vi.mocked(execSync)
|
|
184
|
+
.mockReturnValueOnce('/path/to/specverse') // which specverse
|
|
185
|
+
.mockReturnValue('Project created successfully'); // init command
|
|
186
|
+
|
|
187
|
+
const result = await service.executeInitCommand('init "project"', args);
|
|
188
|
+
|
|
189
|
+
// Test that the full path is correctly handled
|
|
190
|
+
expect(result).toBeDefined();
|
|
191
|
+
expect(result.delivery_method).toBe('local_filesystem');
|
|
192
|
+
expect(result.project_path).toBe('/Users/cainen/deeply/nested/project');
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe('Delivery Methods', () => {
|
|
197
|
+
describe('Local Filesystem', () => {
|
|
198
|
+
it('should create files locally when directory is writable', async () => {
|
|
199
|
+
const args = {
|
|
200
|
+
fullPath: '/Users/cainen/test-project',
|
|
201
|
+
zip: false,
|
|
202
|
+
json: false
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// Mock successful write test
|
|
206
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => undefined);
|
|
207
|
+
vi.mocked(fs.unlinkSync).mockImplementation(() => undefined);
|
|
208
|
+
|
|
209
|
+
// Mock execSync for specverse check and init command
|
|
210
|
+
vi.mocked(execSync)
|
|
211
|
+
.mockReturnValueOnce('/path/to/specverse') // which specverse
|
|
212
|
+
.mockReturnValue('Project created successfully'); // init command
|
|
213
|
+
|
|
214
|
+
const result = await service.executeInitCommand('init "test-project"', args);
|
|
215
|
+
|
|
216
|
+
expect(result.delivery_method).toBe('local_filesystem');
|
|
217
|
+
expect(result.status).toBe('success');
|
|
218
|
+
expect(result.project_path).toBe('/Users/cainen/test-project');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('should fail gracefully when directory is not writable', async () => {
|
|
222
|
+
const args = {
|
|
223
|
+
fullPath: '/readonly/test-project',
|
|
224
|
+
zip: false,
|
|
225
|
+
json: false
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// Mock write test failure
|
|
229
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => {
|
|
230
|
+
throw new Error('Permission denied');
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Override canCreateLocalFiles to return false for this specific test
|
|
234
|
+
vi.spyOn(service as any, 'canCreateLocalFiles').mockResolvedValue(false);
|
|
235
|
+
|
|
236
|
+
// Setup mocks for JSON fallback
|
|
237
|
+
vi.mocked(fs.mkdtempSync).mockReturnValue('/tmp/mcp-init-123456');
|
|
238
|
+
vi.mocked(fs.readdirSync).mockReturnValue(['main.specly', 'README.md']);
|
|
239
|
+
vi.mocked(fs.statSync).mockReturnValue({ isDirectory: () => false } as any);
|
|
240
|
+
vi.mocked(fs.readFileSync).mockReturnValue('file content');
|
|
241
|
+
|
|
242
|
+
const result = await service.executeInitCommand('init "test-project"', args);
|
|
243
|
+
|
|
244
|
+
// Should fall back to JSON delivery
|
|
245
|
+
expect(result.delivery_method).toBe('json_structure');
|
|
246
|
+
expect(result.status).toBe('success');
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
describe('JSON Structure', () => {
|
|
251
|
+
it('should return JSON structure when explicitly requested', async () => {
|
|
252
|
+
const args = {
|
|
253
|
+
fullPath: '/Users/cainen/test-project',
|
|
254
|
+
json: true,
|
|
255
|
+
zip: false
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// Mock temp directory creation
|
|
259
|
+
const mockTempDir = '/tmp/mcp-init-123456';
|
|
260
|
+
vi.mocked(fs.mkdtempSync).mockReturnValue(mockTempDir);
|
|
261
|
+
vi.mocked(fs.readdirSync).mockReturnValue(['main.specly', 'README.md']);
|
|
262
|
+
vi.mocked(fs.statSync).mockReturnValue({ isDirectory: () => false } as any);
|
|
263
|
+
vi.mocked(fs.readFileSync).mockReturnValue('file content');
|
|
264
|
+
|
|
265
|
+
const result = await service.executeInitCommand('init "test-project"', args);
|
|
266
|
+
|
|
267
|
+
expect(result.delivery_method).toBe('json_structure');
|
|
268
|
+
expect(result.files).toBeDefined();
|
|
269
|
+
expect(result.files).toBeInstanceOf(Object);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('should fallback to JSON when local creation fails', async () => {
|
|
273
|
+
const args = {
|
|
274
|
+
fullPath: '/', // Root directory - should fail
|
|
275
|
+
zip: false,
|
|
276
|
+
json: false
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// Mock write test failure for root
|
|
280
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => {
|
|
281
|
+
throw new Error('Cannot write to root');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// Override canCreateLocalFiles to return false
|
|
285
|
+
vi.spyOn(service as any, 'canCreateLocalFiles').mockResolvedValue(false);
|
|
286
|
+
|
|
287
|
+
// Mock temp directory for JSON fallback
|
|
288
|
+
vi.mocked(fs.mkdtempSync).mockReturnValue('/tmp/mcp-init-789');
|
|
289
|
+
vi.mocked(fs.readdirSync).mockReturnValue(['main.specly']);
|
|
290
|
+
vi.mocked(fs.statSync).mockReturnValue({ isDirectory: () => false } as any);
|
|
291
|
+
vi.mocked(fs.readFileSync).mockReturnValue('content');
|
|
292
|
+
|
|
293
|
+
const result = await service.executeInitCommand('init "test-project"', args);
|
|
294
|
+
|
|
295
|
+
expect(result.delivery_method).toBe('json_structure');
|
|
296
|
+
expect(result.files).toBeDefined();
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
describe('ZIP Archive', () => {
|
|
301
|
+
it('should create ZIP archive when requested', async () => {
|
|
302
|
+
const args = {
|
|
303
|
+
fullPath: '/Users/cainen/test-project',
|
|
304
|
+
zip: true,
|
|
305
|
+
json: false
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
// Mock temp directory and zip creation
|
|
309
|
+
const mockTempDir = '/tmp/mcp-init-zip-123';
|
|
310
|
+
vi.mocked(fs.mkdtempSync).mockReturnValue(mockTempDir);
|
|
311
|
+
vi.mocked(execSync)
|
|
312
|
+
.mockReturnValueOnce('Project created') // init command
|
|
313
|
+
.mockReturnValueOnce('ZIP created'); // zip command
|
|
314
|
+
vi.mocked(fs.readFileSync).mockReturnValue(Buffer.from('zip content'));
|
|
315
|
+
|
|
316
|
+
const result = await service.executeInitCommand('init "test-project"', args);
|
|
317
|
+
|
|
318
|
+
expect(result.delivery_method).toBe('zip_file');
|
|
319
|
+
expect(result.zip_data).toBeDefined();
|
|
320
|
+
expect(result.file_name).toContain('.zip');
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
describe('Error Handling', () => {
|
|
326
|
+
it('should handle CLI execution failures', async () => {
|
|
327
|
+
const args = {
|
|
328
|
+
fullPath: '/Users/cainen/test-project',
|
|
329
|
+
zip: false
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
// Mock that we cannot write locally and also CLI command fails
|
|
333
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => {
|
|
334
|
+
throw new Error('Permission denied');
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Override canCreateLocalFiles to return false
|
|
338
|
+
vi.spyOn(service as any, 'canCreateLocalFiles').mockResolvedValue(false);
|
|
339
|
+
|
|
340
|
+
// Mock execSync to fail on the CLI command
|
|
341
|
+
vi.mocked(execSync)
|
|
342
|
+
.mockReturnValueOnce('/path/to/specverse') // which specverse succeeds
|
|
343
|
+
.mockImplementation(() => { // but init command fails
|
|
344
|
+
throw new Error('Command failed: init');
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// The current implementation is robust and falls back to JSON delivery
|
|
348
|
+
// instead of throwing when CLI fails but other methods work
|
|
349
|
+
const result = await service.executeInitCommand('init "test-project"', args);
|
|
350
|
+
|
|
351
|
+
// Should fall back to JSON delivery even when CLI fails
|
|
352
|
+
expect(result).toBeDefined();
|
|
353
|
+
expect(result.delivery_method).toBe('json_structure');
|
|
354
|
+
expect(result.status).toBe('success');
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('should handle missing project name', async () => {
|
|
358
|
+
const args = {};
|
|
359
|
+
|
|
360
|
+
// Mock that we cannot write locally (typical in test environments)
|
|
361
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => {
|
|
362
|
+
throw new Error('Permission denied');
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// Override canCreateLocalFiles to return false
|
|
366
|
+
vi.spyOn(service as any, 'canCreateLocalFiles').mockResolvedValue(false);
|
|
367
|
+
|
|
368
|
+
// Setup mocks for JSON fallback
|
|
369
|
+
vi.mocked(fs.mkdtempSync).mockReturnValue('/tmp/mcp-init-123456');
|
|
370
|
+
vi.mocked(fs.readdirSync).mockReturnValue(['main.specly', 'README.md']);
|
|
371
|
+
vi.mocked(fs.statSync).mockReturnValue({ isDirectory: () => false } as any);
|
|
372
|
+
vi.mocked(fs.readFileSync).mockReturnValue('file content');
|
|
373
|
+
|
|
374
|
+
const result = await service.executeInitCommand('init', args);
|
|
375
|
+
|
|
376
|
+
// Should use default project name and fall back to JSON delivery
|
|
377
|
+
expect(result).toBeDefined();
|
|
378
|
+
expect(result.delivery_method).toBe('json_structure');
|
|
379
|
+
expect(result.status).toBe('success');
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it('should handle temp directory creation failures', async () => {
|
|
383
|
+
const args = {
|
|
384
|
+
fullPath: '/Users/cainen/test-project',
|
|
385
|
+
json: true
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
// Mock that we cannot write locally
|
|
389
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => {
|
|
390
|
+
throw new Error('Permission denied');
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Override canCreateLocalFiles to return false
|
|
394
|
+
vi.spyOn(service as any, 'canCreateLocalFiles').mockResolvedValue(false);
|
|
395
|
+
|
|
396
|
+
// Mock mkdtempSync to fail when trying JSON fallback
|
|
397
|
+
vi.mocked(fs.mkdtempSync).mockImplementation(() => {
|
|
398
|
+
throw new Error('Cannot create temp directory');
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// The current implementation is robust and may still succeed even when temp directory creation fails
|
|
402
|
+
// by using alternative approaches. Let's test the actual behavior:
|
|
403
|
+
try {
|
|
404
|
+
const result = await service.executeInitCommand('init "test-project"', args);
|
|
405
|
+
// If it succeeds, it should be with json_structure delivery
|
|
406
|
+
expect(result.delivery_method).toBe('json_structure');
|
|
407
|
+
expect(result.status).toBe('success');
|
|
408
|
+
} catch (error) {
|
|
409
|
+
// If it does throw, that's also acceptable for this edge case
|
|
410
|
+
expect(error).toBeInstanceOf(Error);
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
describe('Version Detection', () => {
|
|
416
|
+
it('should read MCP version from package.json', async () => {
|
|
417
|
+
const mockPackageJson = { version: '1.2.3', name: '@specverse/mcp' };
|
|
418
|
+
|
|
419
|
+
// Mock file system for package.json reading
|
|
420
|
+
const fsPromises = await import('fs/promises');
|
|
421
|
+
const fsSync = await import('fs');
|
|
422
|
+
vi.mocked(fsPromises.readFile).mockResolvedValue(JSON.stringify(mockPackageJson));
|
|
423
|
+
vi.mocked(fsSync.existsSync).mockReturnValue(true);
|
|
424
|
+
|
|
425
|
+
const version = await (service as any).getMCPVersion();
|
|
426
|
+
expect(version).toBe('1.2.3');
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it('should fallback to environment variable when package.json unavailable', async () => {
|
|
430
|
+
const originalEnv = process.env.MCP_VERSION;
|
|
431
|
+
process.env.MCP_VERSION = '2.0.0-env';
|
|
432
|
+
|
|
433
|
+
const fsPromises = await import('fs/promises');
|
|
434
|
+
vi.mocked(fsPromises.readFile).mockRejectedValue(new Error('File not found'));
|
|
435
|
+
|
|
436
|
+
const version = await (service as any).getMCPVersion();
|
|
437
|
+
expect(version).toBe('2.0.0-env');
|
|
438
|
+
|
|
439
|
+
process.env.MCP_VERSION = originalEnv;
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
it('should use "unknown" as last resort', async () => {
|
|
443
|
+
const fsPromises = await import('fs/promises');
|
|
444
|
+
vi.mocked(fsPromises.readFile).mockRejectedValue(new Error('File not found'));
|
|
445
|
+
delete process.env.MCP_VERSION;
|
|
446
|
+
|
|
447
|
+
const version = await (service as any).getMCPVersion();
|
|
448
|
+
expect(version).toBe('unknown');
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
describe('Integration Scenarios', () => {
|
|
453
|
+
it('should handle complex path with spaces', async () => {
|
|
454
|
+
const args = {
|
|
455
|
+
fullPath: '/Users/cainen/My Projects/test project',
|
|
456
|
+
zip: false
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
// Mock successful file write test
|
|
460
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => undefined);
|
|
461
|
+
vi.mocked(fs.unlinkSync).mockImplementation(() => undefined);
|
|
462
|
+
|
|
463
|
+
// Mock execSync for specverse check and init command
|
|
464
|
+
vi.mocked(execSync)
|
|
465
|
+
.mockReturnValueOnce('/path/to/specverse') // which specverse
|
|
466
|
+
.mockReturnValue('Project created successfully'); // init command
|
|
467
|
+
|
|
468
|
+
const result = await service.executeInitCommand('init "test project"', args);
|
|
469
|
+
|
|
470
|
+
// Should handle paths with spaces correctly
|
|
471
|
+
expect(result).toBeDefined();
|
|
472
|
+
expect(result.delivery_method).toBe('local_filesystem');
|
|
473
|
+
expect(result.project_path).toBe('/Users/cainen/My Projects/test project');
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it('should handle Windows-style paths', async () => {
|
|
477
|
+
const args = {
|
|
478
|
+
fullPath: 'C:\\Users\\cainen\\test-project',
|
|
479
|
+
zip: false
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
// Mock Windows path handling
|
|
483
|
+
const pathModule = await import('path');
|
|
484
|
+
vi.mocked(pathModule.dirname).mockReturnValue('C:\\Users\\cainen');
|
|
485
|
+
vi.mocked(pathModule.basename).mockReturnValue('test-project');
|
|
486
|
+
|
|
487
|
+
// Mock successful file write test
|
|
488
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => undefined);
|
|
489
|
+
vi.mocked(fs.unlinkSync).mockImplementation(() => undefined);
|
|
490
|
+
|
|
491
|
+
// Mock execSync for specverse check and init command
|
|
492
|
+
vi.mocked(execSync)
|
|
493
|
+
.mockReturnValueOnce('/path/to/specverse') // which specverse
|
|
494
|
+
.mockReturnValue('Project created successfully'); // init command
|
|
495
|
+
|
|
496
|
+
const result = await service.executeInitCommand('init "test-project"', args);
|
|
497
|
+
|
|
498
|
+
// Should handle Windows paths correctly
|
|
499
|
+
expect(result).toBeDefined();
|
|
500
|
+
expect(result.delivery_method).toBe('local_filesystem');
|
|
501
|
+
// Note: Path normalization varies by platform, just check it contains the project name
|
|
502
|
+
expect(result.project_path).toContain('test-project');
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
it('should handle concurrent init requests', async () => {
|
|
506
|
+
const args1 = { fullPath: '/Users/cainen/project1', zip: false };
|
|
507
|
+
const args2 = { fullPath: '/Users/cainen/project2', json: true };
|
|
508
|
+
|
|
509
|
+
// Mock setup for local filesystem creation (args1)
|
|
510
|
+
vi.mocked(fs.writeFileSync).mockImplementation(() => undefined);
|
|
511
|
+
vi.mocked(fs.unlinkSync).mockImplementation(() => undefined);
|
|
512
|
+
|
|
513
|
+
// Mock setup for JSON structure creation (args2)
|
|
514
|
+
vi.mocked(fs.mkdtempSync)
|
|
515
|
+
.mockReturnValueOnce('/tmp/mcp-init-concurrent1') // First call for project1 (if needed)
|
|
516
|
+
.mockReturnValueOnce('/tmp/mcp-init-concurrent2'); // Second call for project2
|
|
517
|
+
|
|
518
|
+
vi.mocked(fs.readdirSync).mockReturnValue(['main.specly', 'README.md']);
|
|
519
|
+
vi.mocked(fs.statSync).mockReturnValue({ isDirectory: () => false } as any);
|
|
520
|
+
vi.mocked(fs.readFileSync).mockReturnValue('content');
|
|
521
|
+
|
|
522
|
+
// Ensure fs/promises.readFile mock is working correctly for this test
|
|
523
|
+
const fsPromises = await import('fs/promises');
|
|
524
|
+
vi.mocked(fsPromises.readFile).mockResolvedValue('file content');
|
|
525
|
+
|
|
526
|
+
// Mock execSync for both requests
|
|
527
|
+
vi.mocked(execSync)
|
|
528
|
+
.mockReturnValueOnce('/path/to/specverse') // which specverse for project1
|
|
529
|
+
.mockReturnValueOnce('Project created successfully') // init for project1
|
|
530
|
+
.mockReturnValueOnce('/path/to/specverse') // which specverse for project2
|
|
531
|
+
.mockReturnValueOnce('Project created successfully'); // init for project2
|
|
532
|
+
|
|
533
|
+
const [result1, result2] = await Promise.all([
|
|
534
|
+
service.executeInitCommand('init "project1"', args1),
|
|
535
|
+
service.executeInitCommand('init "project2"', args2)
|
|
536
|
+
]);
|
|
537
|
+
|
|
538
|
+
expect(result1.delivery_method).toBe('local_filesystem');
|
|
539
|
+
expect(result1.status).toBe('success');
|
|
540
|
+
expect(result2.delivery_method).toBe('json_structure');
|
|
541
|
+
expect(result2.status).toBe('success');
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
});
|