@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.
Files changed (420) hide show
  1. package/assets/examples/09-api/ai-spec.yaml +194 -0
  2. package/assets/examples/09-api/converted.yaml +95 -0
  3. package/assets/examples/09-api/diagram-architecture.mmd +10 -0
  4. package/assets/examples/09-api/diagram-er.mmd +10 -0
  5. package/assets/examples/09-api/documentation.html +104 -0
  6. package/assets/examples/09-api/documentation.md +95 -0
  7. package/assets/examples/09-api/inferred-spec.yaml +420 -0
  8. package/assets/examples/09-api/openapi.json +61 -0
  9. package/assets/examples/10-api/README.md +216 -0
  10. package/assets/examples/10-api/ai-spec.yaml +194 -0
  11. package/assets/examples/10-api/converted.yaml +96 -0
  12. package/assets/examples/10-api/diagram-architecture.mmd +10 -0
  13. package/assets/examples/10-api/diagram-er.mmd +10 -0
  14. package/assets/examples/10-api/documentation.html +104 -0
  15. package/assets/examples/10-api/documentation.md +95 -0
  16. package/assets/examples/10-api/inferred-spec.yaml +7 -0
  17. package/assets/examples/10-api/metadata.yaml +89 -0
  18. package/assets/examples/10-api/openapi.json +61 -0
  19. package/assets/examples/10-api/package-integration-test.js +177 -0
  20. package/assets/examples/10-api/usage-example.js +323 -0
  21. package/assets/examples/10-api/usage-example.ts +363 -0
  22. package/assets/examples/10-api/workflow-test.js +113 -0
  23. package/assets/examples/manifests/01-simple-default-mappings.yaml +36 -0
  24. package/assets/examples/manifests/02-capability-mappings.yaml +55 -0
  25. package/assets/examples/manifests/03-hybrid-mappings.yaml +109 -0
  26. package/assets/examples/manifests/README.md +245 -0
  27. package/assets/examples/manifests/backend-only.yaml +43 -0
  28. package/assets/examples/manifests/blog-api.md +78 -0
  29. package/assets/examples/manifests/blog-api.specly +79 -0
  30. package/assets/examples/manifests/frontend-only.yaml +27 -0
  31. package/assets/examples/manifests/fullstack-app.yaml +44 -0
  32. package/assets/examples/manifests/fullstack-monorepo.yaml +62 -0
  33. package/assets/examples/validate-examples-with-expected-failures.cjs +328 -0
  34. package/assets/examples/validate-examples.cjs +225 -0
  35. package/assets/examples-decomposed/cloud-native-manifest.example.yaml +8 -0
  36. package/assets/examples-decomposed/cloud-native-manifest.md +379 -0
  37. package/assets/examples-decomposed/cloud-native-manifest.specly +60 -0
  38. package/assets/examples-decomposed/docker-compose-manifest.example.yaml +8 -0
  39. package/assets/examples-decomposed/docker-compose-manifest.md +326 -0
  40. package/assets/examples-decomposed/docker-compose-manifest.specly +40 -0
  41. package/assets/examples-decomposed/kubernetes-deployment-manifest.example.yaml +8 -0
  42. package/assets/examples-decomposed/kubernetes-deployment-manifest.md +237 -0
  43. package/assets/examples-decomposed/kubernetes-deployment-manifest.specly +41 -0
  44. package/assets/templates/README.md +559 -0
  45. package/assets/templates/TEMPLATE-ENHANCEMENTS-V33.md +462 -0
  46. package/assets/templates/backend-only/CLAUDE.md +73 -0
  47. package/assets/templates/backend-only/README.md +197 -0
  48. package/assets/templates/backend-only/deployments/README.md +149 -0
  49. package/assets/templates/backend-only/deployments/development.specly +53 -0
  50. package/assets/templates/backend-only/deployments/production.specly +87 -0
  51. package/assets/templates/backend-only/docs/README.md +50 -0
  52. package/assets/templates/backend-only/docs/api/README.md +7 -0
  53. package/assets/templates/backend-only/docs/diagrams/README.md +85 -0
  54. package/assets/templates/backend-only/docs/example-documentation-template.md +269 -0
  55. package/assets/templates/backend-only/docs/guides/README.md +15 -0
  56. package/assets/templates/backend-only/dot.env.example +18 -0
  57. package/assets/templates/backend-only/generated/README.md +56 -0
  58. package/assets/templates/backend-only/generated/code/integration-test.template.js +320 -0
  59. package/assets/templates/backend-only/generated/code/package.json.template +34 -0
  60. package/assets/templates/backend-only/generated/docs/README.md +49 -0
  61. package/assets/templates/backend-only/gitignore +54 -0
  62. package/assets/templates/backend-only/manifests/README.md +72 -0
  63. package/assets/templates/backend-only/manifests/docker-compose.specly +91 -0
  64. package/assets/templates/backend-only/manifests/implementation.yaml +100 -0
  65. package/assets/templates/backend-only/manifests/kubernetes.specly +140 -0
  66. package/assets/templates/backend-only/package.json +59 -0
  67. package/assets/templates/backend-only/scripts/test-all.sh +160 -0
  68. package/assets/templates/backend-only/scripts/test-generated-code.sh +165 -0
  69. package/assets/templates/backend-only/specs/main.specly +67 -0
  70. package/assets/templates/default/CLAUDE.md +141 -0
  71. package/assets/templates/default/README.md +404 -0
  72. package/assets/templates/default/deployments/README.md +149 -0
  73. package/assets/templates/default/deployments/development.specly +53 -0
  74. package/assets/templates/default/deployments/production.specly +87 -0
  75. package/assets/templates/default/docs/README.md +50 -0
  76. package/assets/templates/default/docs/api/README.md +7 -0
  77. package/assets/templates/default/docs/diagrams/README.md +85 -0
  78. package/assets/templates/default/docs/example-documentation-template.md +269 -0
  79. package/assets/templates/default/docs/guides/README.md +15 -0
  80. package/assets/templates/default/dot.env.example +18 -0
  81. package/assets/templates/default/generated/README.md +56 -0
  82. package/assets/templates/default/generated/code/integration-test.template.js +320 -0
  83. package/assets/templates/default/generated/code/package.json.template +34 -0
  84. package/assets/templates/default/generated/docs/README.md +49 -0
  85. package/assets/templates/default/gitignore +54 -0
  86. package/assets/templates/default/manifests/README.md +72 -0
  87. package/assets/templates/default/manifests/docker-compose.specly +91 -0
  88. package/assets/templates/default/manifests/implementation.yaml +176 -0
  89. package/assets/templates/default/manifests/kubernetes.specly +140 -0
  90. package/assets/templates/default/package.json +61 -0
  91. package/assets/templates/default/scripts/test-all.sh +160 -0
  92. package/assets/templates/default/scripts/test-generated-code.sh +165 -0
  93. package/assets/templates/default/specs/main.specly +67 -0
  94. package/assets/templates/frontend-only/CLAUDE.md +75 -0
  95. package/assets/templates/frontend-only/README.md +231 -0
  96. package/assets/templates/frontend-only/deployments/README.md +149 -0
  97. package/assets/templates/frontend-only/deployments/development.specly +53 -0
  98. package/assets/templates/frontend-only/deployments/production.specly +87 -0
  99. package/assets/templates/frontend-only/docs/README.md +50 -0
  100. package/assets/templates/frontend-only/docs/api/README.md +7 -0
  101. package/assets/templates/frontend-only/docs/diagrams/README.md +85 -0
  102. package/assets/templates/frontend-only/docs/example-documentation-template.md +269 -0
  103. package/assets/templates/frontend-only/docs/guides/README.md +15 -0
  104. package/assets/templates/frontend-only/dot.env.example +18 -0
  105. package/assets/templates/frontend-only/generated/README.md +56 -0
  106. package/assets/templates/frontend-only/generated/code/integration-test.template.js +320 -0
  107. package/assets/templates/frontend-only/generated/code/package.json.template +34 -0
  108. package/assets/templates/frontend-only/generated/docs/README.md +49 -0
  109. package/assets/templates/frontend-only/gitignore +54 -0
  110. package/assets/templates/frontend-only/manifests/README.md +72 -0
  111. package/assets/templates/frontend-only/manifests/docker-compose.specly +91 -0
  112. package/assets/templates/frontend-only/manifests/implementation.yaml +58 -0
  113. package/assets/templates/frontend-only/manifests/kubernetes.specly +140 -0
  114. package/assets/templates/frontend-only/package.json +59 -0
  115. package/assets/templates/frontend-only/scripts/test-all.sh +160 -0
  116. package/assets/templates/frontend-only/scripts/test-generated-code.sh +165 -0
  117. package/assets/templates/frontend-only/specs/main.specly +57 -0
  118. package/assets/templates/full-stack/AI-GUIDE.md +60 -0
  119. package/assets/templates/full-stack/CLAUDE.md +141 -0
  120. package/assets/templates/full-stack/README.md +382 -0
  121. package/assets/templates/full-stack/archive/AI-GUIDE-legacy.md +392 -0
  122. package/assets/templates/full-stack/deployments/README.md +149 -0
  123. package/assets/templates/full-stack/deployments/development.specly +53 -0
  124. package/assets/templates/full-stack/deployments/production.specly +87 -0
  125. package/assets/templates/full-stack/docs/README.md +51 -0
  126. package/assets/templates/full-stack/docs/api/README.md +7 -0
  127. package/assets/templates/full-stack/docs/diagrams/README.md +85 -0
  128. package/assets/templates/full-stack/docs/example-documentation-template.md +269 -0
  129. package/assets/templates/full-stack/docs/guides/README.md +15 -0
  130. package/assets/templates/full-stack/generated/README.md +56 -0
  131. package/assets/templates/full-stack/generated/code/integration-test.template.js +320 -0
  132. package/assets/templates/full-stack/generated/code/package.json.template +34 -0
  133. package/assets/templates/full-stack/generated/docs/README.md +49 -0
  134. package/assets/templates/full-stack/gitignore +54 -0
  135. package/assets/templates/full-stack/manifests/README.md +72 -0
  136. package/assets/templates/full-stack/manifests/docker-compose.specly +91 -0
  137. package/assets/templates/full-stack/manifests/implementation.yaml +155 -0
  138. package/assets/templates/full-stack/manifests/kubernetes.specly +140 -0
  139. package/assets/templates/full-stack/package.json +45 -0
  140. package/assets/templates/full-stack/scripts/test-all.sh +160 -0
  141. package/assets/templates/full-stack/scripts/test-generated-code.sh +165 -0
  142. package/assets/templates/full-stack/specs/example-v33.specly +297 -0
  143. package/assets/templates/full-stack/specs/main-simple.specly +73 -0
  144. package/assets/templates/full-stack/specs/main.specly +408 -0
  145. package/dist/engines/code-generator.d.ts +86 -0
  146. package/dist/engines/code-generator.d.ts.map +1 -0
  147. package/dist/engines/code-generator.js +159 -0
  148. package/dist/engines/code-generator.js.map +1 -0
  149. package/dist/engines/engine-registry.d.ts +94 -0
  150. package/dist/engines/engine-registry.d.ts.map +1 -0
  151. package/dist/engines/engine-registry.js +163 -0
  152. package/dist/engines/engine-registry.js.map +1 -0
  153. package/dist/engines/index.d.ts +10 -0
  154. package/dist/engines/index.d.ts.map +1 -0
  155. package/dist/engines/index.js +12 -0
  156. package/dist/engines/index.js.map +1 -0
  157. package/dist/engines/typescript-engine.d.ts +74 -0
  158. package/dist/engines/typescript-engine.d.ts.map +1 -0
  159. package/dist/engines/typescript-engine.js +288 -0
  160. package/dist/engines/typescript-engine.js.map +1 -0
  161. package/dist/generators/index.d.ts +11 -0
  162. package/dist/generators/index.d.ts.map +1 -0
  163. package/dist/generators/index.js +11 -0
  164. package/dist/generators/index.js.map +1 -0
  165. package/dist/index.d.ts +48 -0
  166. package/dist/index.d.ts.map +1 -0
  167. package/dist/index.js +434 -0
  168. package/dist/index.js.map +1 -0
  169. package/dist/library/index.d.ts +12 -0
  170. package/dist/library/index.d.ts.map +1 -0
  171. package/dist/library/index.js +15 -0
  172. package/dist/library/index.js.map +1 -0
  173. package/dist/library/library.d.ts +132 -0
  174. package/dist/library/library.d.ts.map +1 -0
  175. package/dist/library/library.js +343 -0
  176. package/dist/library/library.js.map +1 -0
  177. package/dist/library/loader.d.ts +73 -0
  178. package/dist/library/loader.d.ts.map +1 -0
  179. package/dist/library/loader.js +150 -0
  180. package/dist/library/loader.js.map +1 -0
  181. package/dist/library/resolver.d.ts +104 -0
  182. package/dist/library/resolver.d.ts.map +1 -0
  183. package/dist/library/resolver.js +299 -0
  184. package/dist/library/resolver.js.map +1 -0
  185. package/dist/library/validator.d.ts +65 -0
  186. package/dist/library/validator.d.ts.map +1 -0
  187. package/dist/library/validator.js +203 -0
  188. package/dist/library/validator.js.map +1 -0
  189. package/dist/types/index.d.ts +7 -0
  190. package/dist/types/index.d.ts.map +1 -0
  191. package/dist/types/index.js +7 -0
  192. package/dist/types/index.js.map +1 -0
  193. package/dist/types/instance-factory.d.ts +289 -0
  194. package/dist/types/instance-factory.d.ts.map +1 -0
  195. package/dist/types/instance-factory.js +8 -0
  196. package/dist/types/instance-factory.js.map +1 -0
  197. package/dist/types/unified-mappings.d.ts +163 -0
  198. package/dist/types/unified-mappings.d.ts.map +1 -0
  199. package/dist/types/unified-mappings.js +110 -0
  200. package/dist/types/unified-mappings.js.map +1 -0
  201. package/dist/utils/ai-spec-loader.d.ts +77 -0
  202. package/dist/utils/ai-spec-loader.d.ts.map +1 -0
  203. package/dist/utils/ai-spec-loader.js +138 -0
  204. package/dist/utils/ai-spec-loader.js.map +1 -0
  205. package/dist/utils/index.d.ts +9 -0
  206. package/dist/utils/index.d.ts.map +1 -0
  207. package/dist/utils/index.js +9 -0
  208. package/dist/utils/index.js.map +1 -0
  209. package/dist/utils/manifest-loader.d.ts +107 -0
  210. package/dist/utils/manifest-loader.d.ts.map +1 -0
  211. package/dist/utils/manifest-loader.js +168 -0
  212. package/dist/utils/manifest-loader.js.map +1 -0
  213. package/dist/utils/mapping-migration.d.ts +53 -0
  214. package/dist/utils/mapping-migration.d.ts.map +1 -0
  215. package/dist/utils/mapping-migration.js +194 -0
  216. package/dist/utils/mapping-migration.js.map +1 -0
  217. package/libs/instance-factories/CURVED-INTERFACE.md +278 -0
  218. package/libs/instance-factories/README.md +433 -0
  219. package/libs/instance-factories/applications/generic-app.yaml +52 -0
  220. package/libs/instance-factories/applications/react-app.yaml +186 -0
  221. package/libs/instance-factories/applications/templates/generic/backend-env-generator.ts +31 -0
  222. package/libs/instance-factories/applications/templates/generic/backend-package-json-generator.ts +80 -0
  223. package/libs/instance-factories/applications/templates/generic/backend-tsconfig-generator.ts +69 -0
  224. package/libs/instance-factories/applications/templates/generic/main-generator.ts +308 -0
  225. package/libs/instance-factories/applications/templates/react/_view-components-source.ts +555 -0
  226. package/libs/instance-factories/applications/templates/react/api-client-generator.ts +436 -0
  227. package/libs/instance-factories/applications/templates/react/api-types-generator.ts +153 -0
  228. package/libs/instance-factories/applications/templates/react/app-tsx-generator.ts +94 -0
  229. package/libs/instance-factories/applications/templates/react/env-example-generator.ts +24 -0
  230. package/libs/instance-factories/applications/templates/react/field-helpers-generator.ts +106 -0
  231. package/libs/instance-factories/applications/templates/react/gitignore-generator.ts +38 -0
  232. package/libs/instance-factories/applications/templates/react/index-css-generator.ts +85 -0
  233. package/libs/instance-factories/applications/templates/react/index-html-generator.ts +30 -0
  234. package/libs/instance-factories/applications/templates/react/main-tsx-generator.ts +34 -0
  235. package/libs/instance-factories/applications/templates/react/package-json-generator.ts +54 -0
  236. package/libs/instance-factories/applications/templates/react/pattern-adapter-generator.ts +179 -0
  237. package/libs/instance-factories/applications/templates/react/react-pattern-adapter.tsx +1347 -0
  238. package/libs/instance-factories/applications/templates/react/relationship-field-generator.ts +150 -0
  239. package/libs/instance-factories/applications/templates/react/tailwind-adapter-generator.ts +704 -0
  240. package/libs/instance-factories/applications/templates/react/tailwind-adapter-wrapper-generator.ts +84 -0
  241. package/libs/instance-factories/applications/templates/react/tsconfig-generator.ts +35 -0
  242. package/libs/instance-factories/applications/templates/react/use-api-hooks-generator.ts +121 -0
  243. package/libs/instance-factories/applications/templates/react/view-dashboard-generator.ts +150 -0
  244. package/libs/instance-factories/applications/templates/react/view-detail-generator.ts +150 -0
  245. package/libs/instance-factories/applications/templates/react/view-form-generator.ts +362 -0
  246. package/libs/instance-factories/applications/templates/react/view-list-generator.ts +98 -0
  247. package/libs/instance-factories/applications/templates/react/view-router-generator.ts +89 -0
  248. package/libs/instance-factories/applications/templates/react/vite-config-generator.ts +49 -0
  249. package/libs/instance-factories/archived/fastify-prisma.yaml +104 -0
  250. package/libs/instance-factories/cli/commander-js.yaml +55 -0
  251. package/libs/instance-factories/cli/templates/commander/cli-entry-generator.d.ts +12 -0
  252. package/libs/instance-factories/cli/templates/commander/cli-entry-generator.d.ts.map +1 -0
  253. package/libs/instance-factories/cli/templates/commander/cli-entry-generator.js +115 -0
  254. package/libs/instance-factories/cli/templates/commander/cli-entry-generator.js.map +1 -0
  255. package/libs/instance-factories/cli/templates/commander/cli-entry-generator.ts +145 -0
  256. package/libs/instance-factories/cli/templates/commander/command-generator.d.ts +14 -0
  257. package/libs/instance-factories/cli/templates/commander/command-generator.d.ts.map +1 -0
  258. package/libs/instance-factories/cli/templates/commander/command-generator.js +182 -0
  259. package/libs/instance-factories/cli/templates/commander/command-generator.js.map +1 -0
  260. package/libs/instance-factories/cli/templates/commander/command-generator.ts +992 -0
  261. package/libs/instance-factories/communication/event-emitter.yaml +56 -0
  262. package/libs/instance-factories/communication/rabbitmq-events.yaml +87 -0
  263. package/libs/instance-factories/communication/templates/eventemitter/bus-generator.ts +93 -0
  264. package/libs/instance-factories/communication/templates/eventemitter/publisher-generator.ts +117 -0
  265. package/libs/instance-factories/communication/templates/eventemitter/subscriber-generator.ts +101 -0
  266. package/libs/instance-factories/controllers/fastify.yaml +127 -0
  267. package/libs/instance-factories/controllers/templates/fastify/meta-routes-generator.ts +103 -0
  268. package/libs/instance-factories/controllers/templates/fastify/routes-generator.ts +389 -0
  269. package/libs/instance-factories/controllers/templates/fastify/server-generator.ts +76 -0
  270. package/libs/instance-factories/infrastructure/docker-k8s.yaml +61 -0
  271. package/libs/instance-factories/infrastructure/templates/docker-k8s/infrastructure-generator.ts +46 -0
  272. package/libs/instance-factories/orms/prisma.yaml +89 -0
  273. package/libs/instance-factories/orms/templates/prisma/schema-generator.ts +563 -0
  274. package/libs/instance-factories/orms/templates/prisma/services-generator.ts +408 -0
  275. package/libs/instance-factories/scaffolding/generic-scaffold.yaml +65 -0
  276. package/libs/instance-factories/scaffolding/templates/generic/env-example-generator.ts +73 -0
  277. package/libs/instance-factories/scaffolding/templates/generic/env-generator.ts +85 -0
  278. package/libs/instance-factories/scaffolding/templates/generic/gitignore-generator.ts +69 -0
  279. package/libs/instance-factories/scaffolding/templates/generic/package-json-generator.ts +176 -0
  280. package/libs/instance-factories/scaffolding/templates/generic/readme-generator.ts +207 -0
  281. package/libs/instance-factories/scaffolding/templates/generic/tsconfig-generator.ts +78 -0
  282. package/libs/instance-factories/scaffolding/templates/generic/tsconfig-react-generator.ts +41 -0
  283. package/libs/instance-factories/sdks/python-sdk.yaml +66 -0
  284. package/libs/instance-factories/sdks/templates/python/sdk-generator.ts +50 -0
  285. package/libs/instance-factories/sdks/templates/typescript/sdk-generator.ts +49 -0
  286. package/libs/instance-factories/sdks/typescript-sdk.yaml +59 -0
  287. package/libs/instance-factories/services/prisma-services.yaml +71 -0
  288. package/libs/instance-factories/services/templates/prisma/behavior-generator.ts +303 -0
  289. package/libs/instance-factories/services/templates/prisma/controller-generator.ts +532 -0
  290. package/libs/instance-factories/services/templates/prisma/service-generator.ts +315 -0
  291. package/libs/instance-factories/shared/path-resolver.ts +111 -0
  292. package/libs/instance-factories/storage/mongodb.yaml +79 -0
  293. package/libs/instance-factories/storage/postgresql.yaml +75 -0
  294. package/libs/instance-factories/storage/redis.yaml +79 -0
  295. package/libs/instance-factories/storage/templates/mongodb/config-generator.ts +15 -0
  296. package/libs/instance-factories/storage/templates/mongodb/docker-generator.ts +18 -0
  297. package/libs/instance-factories/storage/templates/postgresql/config-generator.ts +54 -0
  298. package/libs/instance-factories/storage/templates/postgresql/docker-generator.ts +55 -0
  299. package/libs/instance-factories/storage/templates/redis/config-generator.ts +16 -0
  300. package/libs/instance-factories/storage/templates/redis/docker-generator.ts +18 -0
  301. package/libs/instance-factories/test-generation.ts +192 -0
  302. package/libs/instance-factories/testing/templates/vitest/tests-generator.ts +51 -0
  303. package/libs/instance-factories/testing/vitest-tests.yaml +63 -0
  304. package/libs/instance-factories/tools/templates/mcp/mcp-server-generator.ts +136 -0
  305. package/libs/instance-factories/tools/templates/mcp/static/docs/DEPLOYMENT_GUIDE.md +630 -0
  306. package/libs/instance-factories/tools/templates/mcp/static/docs/HYBRID_RESOURCE_SYSTEM.md +330 -0
  307. package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/EXTENSION_DEPLOYMENT.md +552 -0
  308. package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/LOCAL_DEPLOYMENT.md +164 -0
  309. package/libs/instance-factories/tools/templates/mcp/static/docs/deployments/WEB_DEPLOYMENT.md +247 -0
  310. package/libs/instance-factories/tools/templates/mcp/static/package.json +92 -0
  311. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-enterprise.js +284 -0
  312. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-extension.js +139 -0
  313. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-local.js +74 -0
  314. package/libs/instance-factories/tools/templates/mcp/static/scripts/build-web.js +156 -0
  315. package/libs/instance-factories/tools/templates/mcp/static/scripts/copy-canonical-files.js +41 -0
  316. package/libs/instance-factories/tools/templates/mcp/static/scripts/test-deployments.js +259 -0
  317. package/libs/instance-factories/tools/templates/mcp/static/scripts/test-hybrid-resources.js +231 -0
  318. package/libs/instance-factories/tools/templates/mcp/static/scripts/test-hybrid-simple.js +196 -0
  319. package/libs/instance-factories/tools/templates/mcp/static/src/controllers/MCPServerController.ts +293 -0
  320. package/libs/instance-factories/tools/templates/mcp/static/src/events/EventEmitter.ts +90 -0
  321. package/libs/instance-factories/tools/templates/mcp/static/src/index.ts +24 -0
  322. package/libs/instance-factories/tools/templates/mcp/static/src/interfaces/ResourceProvider.ts +15 -0
  323. package/libs/instance-factories/tools/templates/mcp/static/src/models/LibrarySuggestion.ts +106 -0
  324. package/libs/instance-factories/tools/templates/mcp/static/src/models/SpecVerseResource.ts +75 -0
  325. package/libs/instance-factories/tools/templates/mcp/static/src/server/mcp-server.ts +239 -0
  326. package/libs/instance-factories/tools/templates/mcp/static/src/services/CLIProxyService.ts +1501 -0
  327. package/libs/instance-factories/tools/templates/mcp/static/src/services/EmbeddedResourcesAdapter.ts +211 -0
  328. package/libs/instance-factories/tools/templates/mcp/static/src/services/EntityModuleService.ts +308 -0
  329. package/libs/instance-factories/tools/templates/mcp/static/src/services/HybridResourcesProvider.ts +210 -0
  330. package/libs/instance-factories/tools/templates/mcp/static/src/services/LibraryToolsService.ts +356 -0
  331. package/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorBridge.ts +524 -0
  332. package/libs/instance-factories/tools/templates/mcp/static/src/services/OrchestratorToolsService.ts +530 -0
  333. package/libs/instance-factories/tools/templates/mcp/static/src/services/PromptToolsService.ts +594 -0
  334. package/libs/instance-factories/tools/templates/mcp/static/src/services/ResourcesProviderService.ts +170 -0
  335. package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/CLIProxyService.init.test.ts +544 -0
  336. package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/CLIProxyService.test.ts +189 -0
  337. package/libs/instance-factories/tools/templates/mcp/static/src/tests/unit/ResourcesProviderService.test.ts +89 -0
  338. package/libs/instance-factories/tools/templates/mcp/static/src/types/index.ts +110 -0
  339. package/libs/instance-factories/tools/templates/mcp/static/tsconfig.json +28 -0
  340. package/libs/instance-factories/tools/templates/vscode/static/extension.ts +1195 -0
  341. package/libs/instance-factories/tools/templates/vscode/static/language-configuration.json +34 -0
  342. package/libs/instance-factories/tools/templates/vscode/static/schemas/specverse-v3-schema.json +4279 -0
  343. package/libs/instance-factories/tools/templates/vscode/static/syntaxes/specverse.tmLanguage.json +138 -0
  344. package/libs/instance-factories/tools/templates/vscode/static/themes/README.md +74 -0
  345. package/libs/instance-factories/tools/templates/vscode/static/themes/complete-specverse-colors.json +122 -0
  346. package/libs/instance-factories/tools/templates/vscode/static/themes/specverse-basic-theme.json +65 -0
  347. package/libs/instance-factories/tools/templates/vscode/static/themes/specverse-complete-theme.json +123 -0
  348. package/libs/instance-factories/tools/templates/vscode/static/themes/specverse-theme-colors.json +64 -0
  349. package/libs/instance-factories/tools/templates/vscode/vscode-extension-generator.ts +214 -0
  350. package/libs/instance-factories/validation/templates/zod/validation-generator.ts +46 -0
  351. package/libs/instance-factories/validation/zod.yaml +56 -0
  352. package/libs/instance-factories/views/index.d.ts +13 -0
  353. package/libs/instance-factories/views/index.d.ts.map +1 -0
  354. package/libs/instance-factories/views/index.js +18 -0
  355. package/libs/instance-factories/views/index.js.map +1 -0
  356. package/libs/instance-factories/views/index.ts +45 -0
  357. package/libs/instance-factories/views/react-components.yaml +129 -0
  358. package/libs/instance-factories/views/templates/ARCHITECTURE.md +198 -0
  359. package/libs/instance-factories/views/templates/react/adapters/antd-adapter.ts +869 -0
  360. package/libs/instance-factories/views/templates/react/adapters/mui-adapter.ts +953 -0
  361. package/libs/instance-factories/views/templates/react/adapters/shadcn-adapter.ts +806 -0
  362. package/libs/instance-factories/views/templates/react/app-generator.ts +55 -0
  363. package/libs/instance-factories/views/templates/react/components-generator.ts +391 -0
  364. package/libs/instance-factories/views/templates/react/forms-generator.ts +343 -0
  365. package/libs/instance-factories/views/templates/react/frontend-package-json-generator.ts +54 -0
  366. package/libs/instance-factories/views/templates/react/hooks-generator.ts +122 -0
  367. package/libs/instance-factories/views/templates/react/index-css-generator.ts +209 -0
  368. package/libs/instance-factories/views/templates/react/index-html-generator.ts +34 -0
  369. package/libs/instance-factories/views/templates/react/main-tsx-generator.ts +29 -0
  370. package/libs/instance-factories/views/templates/react/react-component-generator.d.ts +152 -0
  371. package/libs/instance-factories/views/templates/react/react-component-generator.d.ts.map +1 -0
  372. package/libs/instance-factories/views/templates/react/react-component-generator.js +398 -0
  373. package/libs/instance-factories/views/templates/react/react-component-generator.js.map +1 -0
  374. package/libs/instance-factories/views/templates/react/react-component-generator.ts +533 -0
  375. package/libs/instance-factories/views/templates/react/router-generator.ts +197 -0
  376. package/libs/instance-factories/views/templates/react/router-generic-generator.ts +103 -0
  377. package/libs/instance-factories/views/templates/react/spec-json-generator.ts +17 -0
  378. package/libs/instance-factories/views/templates/react/types-generator.ts +76 -0
  379. package/libs/instance-factories/views/templates/react/views-metadata-generator.ts +42 -0
  380. package/libs/instance-factories/views/templates/react/vite-config-generator.ts +38 -0
  381. package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.d.ts.map +1 -0
  382. package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.js.map +1 -0
  383. package/libs/instance-factories/views/templates/runtime/runtime-view-renderer.ts +474 -0
  384. package/libs/instance-factories/views/templates/shared/__tests__/composite-patterns.test.ts +242 -0
  385. package/libs/instance-factories/views/templates/shared/adapter-types.d.ts +77 -0
  386. package/libs/instance-factories/views/templates/shared/adapter-types.d.ts.map +1 -0
  387. package/libs/instance-factories/views/templates/shared/adapter-types.js +47 -0
  388. package/libs/instance-factories/views/templates/shared/adapter-types.js.map +1 -0
  389. package/libs/instance-factories/views/templates/shared/adapter-types.ts +142 -0
  390. package/libs/instance-factories/views/templates/shared/atomic-components-registry.d.ts +63 -0
  391. package/libs/instance-factories/views/templates/shared/atomic-components-registry.d.ts.map +1 -0
  392. package/libs/instance-factories/views/templates/shared/atomic-components-registry.js +822 -0
  393. package/libs/instance-factories/views/templates/shared/atomic-components-registry.js.map +1 -0
  394. package/libs/instance-factories/views/templates/shared/atomic-components-registry.ts +908 -0
  395. package/libs/instance-factories/views/templates/shared/base-generator.d.ts +247 -0
  396. package/libs/instance-factories/views/templates/shared/base-generator.d.ts.map +1 -0
  397. package/libs/instance-factories/views/templates/shared/base-generator.js +363 -0
  398. package/libs/instance-factories/views/templates/shared/base-generator.js.map +1 -0
  399. package/libs/instance-factories/views/templates/shared/base-generator.ts +608 -0
  400. package/libs/instance-factories/views/templates/shared/component-metadata.d.ts +254 -0
  401. package/libs/instance-factories/views/templates/shared/component-metadata.d.ts.map +1 -0
  402. package/libs/instance-factories/views/templates/shared/component-metadata.js +602 -0
  403. package/libs/instance-factories/views/templates/shared/component-metadata.js.map +1 -0
  404. package/libs/instance-factories/views/templates/shared/component-metadata.ts +803 -0
  405. package/libs/instance-factories/views/templates/shared/composite-pattern-types.ts +250 -0
  406. package/libs/instance-factories/views/templates/shared/composite-patterns.ts +535 -0
  407. package/libs/instance-factories/views/templates/shared/index.ts +68 -0
  408. package/libs/instance-factories/views/templates/shared/pattern-validator.ts +279 -0
  409. package/libs/instance-factories/views/templates/shared/property-mapper.d.ts +149 -0
  410. package/libs/instance-factories/views/templates/shared/property-mapper.d.ts.map +1 -0
  411. package/libs/instance-factories/views/templates/shared/property-mapper.js +580 -0
  412. package/libs/instance-factories/views/templates/shared/property-mapper.js.map +1 -0
  413. package/libs/instance-factories/views/templates/shared/property-mapper.ts +700 -0
  414. package/libs/instance-factories/views/templates/shared/syntax-mapper.d.ts +143 -0
  415. package/libs/instance-factories/views/templates/shared/syntax-mapper.d.ts.map +1 -0
  416. package/libs/instance-factories/views/templates/shared/syntax-mapper.js +420 -0
  417. package/libs/instance-factories/views/templates/shared/syntax-mapper.js.map +1 -0
  418. package/libs/instance-factories/views/templates/shared/syntax-mapper.ts +539 -0
  419. package/package.json +42 -0
  420. package/schema/SPECVERSE-SCHEMA.json +4274 -0
@@ -0,0 +1,1501 @@
1
+ /**
2
+ * CLIProxyService
3
+ * Dynamic CLI integration service for MCP server
4
+ *
5
+ * This service uses the shared CLI discovery utility to dynamically discover
6
+ * and execute CLI commands with --json output, ensuring the MCP server
7
+ * always stays in sync with CLI capabilities.
8
+ */
9
+
10
+ // Runtime import resolution for development vs published package
11
+ async function loadSpecVerseAPI() {
12
+ const { createRequire } = await import('module');
13
+ const { fileURLToPath } = await import('url');
14
+ const { join, dirname } = await import('path');
15
+ const require = createRequire(import.meta.url);
16
+
17
+ // Construct import paths dynamically to avoid TypeScript compile-time resolution
18
+ const publishedPackage = '@' + 'specverse/lang';
19
+
20
+ // Get current file location and calculate path to dist/index.js
21
+ const __filename = fileURLToPath(import.meta.url);
22
+ const __dirname = dirname(__filename);
23
+
24
+ // Determine if we're in src/ (tests) or dist/ (runtime)
25
+ // Runtime: tools/specverse-mcp/dist/local/services/ -> go up 5 to root
26
+ // Tests: tools/specverse-mcp/src/services/ -> go up 4 to root
27
+ const isInDist = __dirname.includes('/dist/');
28
+ const levelsUp = isInDist ? 5 : 4;
29
+ const pathParts = Array(levelsUp).fill('..').concat(['dist', 'index.js']);
30
+ const localPath = join(__dirname, ...pathParts);
31
+
32
+ // In development, prefer local build over published package
33
+ // Use import directly - if it fails, we'll fall back to published
34
+ try {
35
+ return await import(localPath);
36
+ } catch (localError) {
37
+ // Local build doesn't exist or failed to load
38
+ try {
39
+ // Try to resolve the published package
40
+ require.resolve(publishedPackage);
41
+ return await import(publishedPackage);
42
+ } catch (publishedError) {
43
+ // Neither worked - throw original error
44
+ throw new Error(`Failed to load SpecVerse API: local (${localError.message}) and published (${publishedError.message})`);
45
+ }
46
+ }
47
+ }
48
+
49
+ // This will be initialized in the class constructor
50
+ let specverseAPI: any = null;
51
+
52
+ type CLICapabilities = any;
53
+ type CLICommand = any;
54
+ type GroupedCommand = any;
55
+ import { writeFileSync, unlinkSync, mkdtempSync } from 'fs';
56
+ import { join } from 'path';
57
+ import { tmpdir } from 'os';
58
+ import type { MCPToolResult } from '../types/index.js';
59
+
60
+ export interface MCPTool {
61
+ name: string;
62
+ description: string;
63
+ inputSchema: {
64
+ type: 'object';
65
+ properties: Record<string, any>;
66
+ required?: string[];
67
+ };
68
+ }
69
+
70
+ export class CLIProxyService {
71
+ private capabilities: CLICapabilities | null = null;
72
+ private cliPath: string | null = null;
73
+ private lastDiscovery: number = 0;
74
+ private readonly DISCOVERY_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
75
+ private initialized = false;
76
+
77
+ constructor(private workingDirectory?: string) {
78
+ // API will be loaded lazily in init()
79
+ }
80
+
81
+ /**
82
+ * Initialize the API - called once before first use
83
+ */
84
+ private async init() {
85
+ if (this.initialized) return;
86
+
87
+ specverseAPI = await loadSpecVerseAPI();
88
+ this.cliPath = specverseAPI.getCliPath(this.workingDirectory);
89
+
90
+ if (!this.cliPath && process.env.MCP_DEBUG) {
91
+ // Only warn to stderr in debug mode - stdout must be clean for MCP protocol
92
+ console.error('⚠️ SpecVerse CLI not found. CLI proxy functionality will be limited.');
93
+ }
94
+
95
+ this.initialized = true;
96
+ }
97
+
98
+ /**
99
+ * Discover CLI capabilities (cached for performance)
100
+ */
101
+ async discoverCapabilities(): Promise<CLICapabilities> {
102
+ await this.init();
103
+
104
+ const now = Date.now();
105
+
106
+ // Return cached capabilities if still fresh
107
+ if (this.capabilities && (now - this.lastDiscovery) < this.DISCOVERY_CACHE_TTL) {
108
+ return this.capabilities;
109
+ }
110
+
111
+ // Discover fresh capabilities
112
+ try {
113
+ this.capabilities = specverseAPI.getAllCliCapabilities(this.cliPath || undefined);
114
+ this.lastDiscovery = now;
115
+
116
+ // Don't log to console in MCP mode - it breaks the JSON protocol
117
+ // Only log if explicitly in debug mode
118
+ if (process.env.MCP_DEBUG) {
119
+ console.error(`🔍 Discovered ${this.capabilities.coreCommands.length} core commands, ` +
120
+ `${this.capabilities.groupedCommands.length} grouped commands, ` +
121
+ `${this.capabilities.aiCommands.length} AI commands`);
122
+ }
123
+
124
+ return this.capabilities;
125
+ } catch (error) {
126
+ // Log errors to stderr, not stdout
127
+ if (process.env.MCP_DEBUG) {
128
+ console.error('❌ Failed to discover CLI capabilities:', error);
129
+ }
130
+ // Return empty capabilities as fallback
131
+ return {
132
+ coreCommands: [],
133
+ groupedCommands: [],
134
+ aiCommands: []
135
+ };
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Generate MCP tool definitions from CLI capabilities
141
+ */
142
+ async generateMCPTools(): Promise<MCPTool[]> {
143
+ const capabilities = await this.discoverCapabilities();
144
+ const tools: MCPTool[] = [];
145
+
146
+ // Add MCP-specific debug tool first
147
+ tools.push({
148
+ name: 'specverse_mcp_debug',
149
+ description: 'Show MCP server diagnostic information including SpecVerse installation details, path resolution, and environment analysis',
150
+ inputSchema: {
151
+ type: 'object',
152
+ properties: {
153
+ verbose: {
154
+ type: 'boolean',
155
+ description: 'Show detailed path resolution information'
156
+ }
157
+ },
158
+ required: []
159
+ }
160
+ });
161
+
162
+ // Core commands (validate, infer, init)
163
+ for (const cmd of capabilities.coreCommands) {
164
+ tools.push(this.createMCPToolFromCommand(cmd));
165
+ }
166
+
167
+ // Grouped commands (gen yaml, dev format, test cycle, etc.)
168
+ for (const cmd of capabilities.groupedCommands) {
169
+ tools.push(this.createMCPToolFromGroupedCommand(cmd));
170
+ }
171
+
172
+ // AI commands are handled specially since they have complex arguments
173
+ for (const cmd of capabilities.aiCommands) {
174
+ tools.push(...this.createAIMCPTools());
175
+ break; // Only need to process AI commands once
176
+ }
177
+
178
+ // Add content-based tools for direct LLM interaction
179
+ tools.push(...this.createContentBasedTools());
180
+
181
+ return tools;
182
+ }
183
+
184
+ /**
185
+ * Execute a CLI command via the proxy
186
+ */
187
+ async executeCommand(toolName: string, args: Record<string, any>): Promise<MCPToolResult> {
188
+ try {
189
+ // Initialize if not already done
190
+ await this.init();
191
+
192
+ // Handle MCP-specific debug tool
193
+ if (toolName === 'specverse_mcp_debug') {
194
+ return await this.executeMCPDebugTool(args.verbose || false);
195
+ }
196
+
197
+ if (!this.cliPath) {
198
+ return {
199
+ content: [{
200
+ type: 'text',
201
+ text: 'SpecVerse CLI not found. Please ensure SpecVerse is installed and accessible.'
202
+ }],
203
+ isError: true
204
+ };
205
+ }
206
+
207
+ // Handle content-based tools by creating temporary files
208
+ if (toolName.endsWith('_content')) {
209
+ return await this.handleContentBasedCommand(toolName, args);
210
+ }
211
+
212
+ // Map MCP tool name back to CLI command
213
+ const baseCommand = this.mapToolNameToCommand(toolName);
214
+
215
+ // Handle commands with positional arguments
216
+ let command = baseCommand;
217
+ let commandArgs = { ...args };
218
+
219
+ // Handle AI commands - append operation as positional argument
220
+ if (baseCommand.startsWith('ai ') && args.operation) {
221
+ command = `${baseCommand} ${args.operation}`;
222
+ const { operation, ...remainingArgs } = args;
223
+ commandArgs = remainingArgs;
224
+ }
225
+
226
+ // Handle lib commands with positional arguments
227
+ else if (baseCommand.startsWith('lib ')) {
228
+ if (baseCommand === 'lib search' && args.query) {
229
+ command = `${baseCommand} "${args.query}"`;
230
+ const { query, ...remainingArgs } = args;
231
+ commandArgs = remainingArgs;
232
+ } else if (baseCommand === 'lib info' && args.name) {
233
+ command = `${baseCommand} "${args.name}"`;
234
+ const { name, ...remainingArgs } = args;
235
+ commandArgs = remainingArgs;
236
+ }
237
+ // lib list, lib tags, lib cache don't have positional arguments
238
+ }
239
+
240
+ // Handle init command - append name as positional argument
241
+ else if (baseCommand === 'init') {
242
+ // Init command special handling
243
+ console.error(`MCP Debug: Received args.name: "${args.name}"`);
244
+ console.error(`MCP Debug: Full args object:`, JSON.stringify(args, null, 2));
245
+ if (args.name) {
246
+ // Pass the full path to executeInitCommand in args, use basename for CLI
247
+ const fullPath = args.name;
248
+ const projectName = args.name.includes('/') ? args.name.split('/').pop() : args.name;
249
+ command = `${baseCommand} "${projectName}"`;
250
+ const { name, ...remainingArgs } = args;
251
+ // Preserve the full path in commandArgs for proper directory handling
252
+ commandArgs = { ...remainingArgs, fullPath };
253
+ }
254
+
255
+ // Init doesn't support --json, so we need to handle its output specially
256
+ try {
257
+ const result = await this.executeInitCommand(command, commandArgs);
258
+ return {
259
+ content: [{
260
+ type: 'text',
261
+ text: JSON.stringify(result, null, 2)
262
+ }]
263
+ };
264
+ } catch (error) {
265
+ const errorMessage = error instanceof Error ? error.message : String(error);
266
+ return {
267
+ content: [{
268
+ type: 'text',
269
+ text: JSON.stringify({
270
+ status: 'error',
271
+ message: 'Init command failed',
272
+ details: errorMessage,
273
+ timestamp: new Date().toISOString()
274
+ }, null, 2)
275
+ }],
276
+ isError: true
277
+ };
278
+ }
279
+ }
280
+
281
+ // Handle other commands with positional file arguments
282
+ else if (args.file) {
283
+ command = `${baseCommand} "${args.file}"`;
284
+ const { file, ...remainingArgs } = args;
285
+ commandArgs = remainingArgs;
286
+ }
287
+
288
+ // Execute with JSON output
289
+ const result = await specverseAPI.executeCliCommand(command, commandArgs, {
290
+ cliPath: this.cliPath,
291
+ timeout: 60000 // 1 minute timeout
292
+ });
293
+
294
+ return {
295
+ content: [{
296
+ type: 'text',
297
+ text: JSON.stringify(result, null, 2)
298
+ }]
299
+ };
300
+
301
+ } catch (error) {
302
+ const errorMessage = error instanceof Error ? error.message : String(error);
303
+
304
+ // Try to parse error as JSON (CLI returns structured errors)
305
+ try {
306
+ const parsedError = JSON.parse(errorMessage);
307
+ return {
308
+ content: [{
309
+ type: 'text',
310
+ text: JSON.stringify(parsedError, null, 2)
311
+ }],
312
+ isError: true
313
+ };
314
+ } catch {
315
+ return {
316
+ content: [{
317
+ type: 'text',
318
+ text: JSON.stringify({
319
+ status: 'error',
320
+ message: 'CLI command execution failed',
321
+ details: errorMessage,
322
+ timestamp: new Date().toISOString()
323
+ }, null, 2)
324
+ }],
325
+ isError: true
326
+ };
327
+ }
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Create MCP tool definition from core CLI command
333
+ */
334
+ private createMCPToolFromCommand(cmd: CLICommand): MCPTool {
335
+ const properties: Record<string, any> = {};
336
+ const required: string[] = [];
337
+
338
+ // Parse arguments and options
339
+ if (cmd.args) {
340
+ if (cmd.args.includes('<file>')) {
341
+ properties.file = {
342
+ type: 'string',
343
+ description: 'SpecVerse specification file path'
344
+ };
345
+ required.push('file');
346
+ }
347
+ if (cmd.args.includes('[name]')) {
348
+ properties.name = {
349
+ type: 'string',
350
+ description: 'Project name (optional)'
351
+ };
352
+ }
353
+ }
354
+
355
+ // Special handling for init command based on known CLI structure
356
+ if (cmd.command === 'init') {
357
+ properties.name = {
358
+ type: 'string',
359
+ description: 'Project name'
360
+ };
361
+ // Add template option that init supports
362
+ properties.template = {
363
+ type: 'string',
364
+ description: 'Template to use (default: "default")'
365
+ };
366
+ // Add MCP-specific flags
367
+ properties.zip = {
368
+ type: 'boolean',
369
+ description: 'Return project as ZIP file'
370
+ };
371
+ properties.json = {
372
+ type: 'boolean',
373
+ description: 'Return project as JSON file structure'
374
+ };
375
+ // Don't add verbose for init - it doesn't support it
376
+ } else if (cmd.command === 'validate' || cmd.command === 'infer') {
377
+ // These commands support verbose
378
+ properties.verbose = {
379
+ type: 'boolean',
380
+ description: 'Show detailed output'
381
+ };
382
+ }
383
+
384
+ // Add zip parameter for file-generating commands
385
+ if (this.isFileGeneratingCommand(cmd.command)) {
386
+ properties.zip = {
387
+ type: 'boolean',
388
+ description: 'Return files as ZIP package instead of creating locally (useful for remote servers or consistent delivery)'
389
+ };
390
+ }
391
+
392
+ return {
393
+ name: `specverse_${cmd.command}`,
394
+ description: cmd.description,
395
+ inputSchema: {
396
+ type: 'object',
397
+ properties,
398
+ required
399
+ }
400
+ };
401
+ }
402
+
403
+ /**
404
+ * Check if a command generates files that could benefit from ZIP packaging
405
+ */
406
+ private isFileGeneratingCommand(command: string): boolean {
407
+ return ['init'].includes(command);
408
+ }
409
+
410
+ /**
411
+ * Check if a grouped command generates files that could benefit from ZIP packaging
412
+ */
413
+ private isFileGeneratingGroupedCommand(cmd: any): boolean {
414
+ // All gen commands generate files
415
+ if (cmd.group === 'gen') {
416
+ return true;
417
+ }
418
+ // Other commands that generate files can be added here
419
+ return false;
420
+ }
421
+
422
+ /**
423
+ * Create MCP tool definition from grouped command
424
+ */
425
+ private createMCPToolFromGroupedCommand(cmd: GroupedCommand): MCPTool {
426
+ const properties: Record<string, any> = {};
427
+ const required: string[] = [];
428
+
429
+ // Most grouped commands need a file
430
+ if (cmd.args?.includes('<file>')) {
431
+ properties.file = {
432
+ type: 'string',
433
+ description: 'SpecVerse specification file path'
434
+ };
435
+ required.push('file');
436
+ }
437
+
438
+ // Add group-specific options
439
+ if (cmd.group === 'gen') {
440
+ properties.output = {
441
+ type: 'string',
442
+ description: 'Output file or directory path'
443
+ };
444
+ } else if (cmd.group === 'dev' && cmd.subcommand === 'watch') {
445
+ properties.directory = {
446
+ type: 'string',
447
+ description: 'Directory to watch for changes'
448
+ };
449
+ } else if (cmd.group === 'lib') {
450
+ // Add lib-specific options based on subcommand
451
+ if (cmd.subcommand === 'search') {
452
+ if (cmd.args?.includes('[query]')) {
453
+ properties.query = {
454
+ type: 'string',
455
+ description: 'Search term (name, description, tags)'
456
+ };
457
+ }
458
+ properties.type = {
459
+ type: 'string',
460
+ enum: ['component', 'deployment', 'manifest'],
461
+ description: 'Filter by type'
462
+ };
463
+ properties.category = {
464
+ type: 'string',
465
+ description: 'Filter by category'
466
+ };
467
+ properties.tags = {
468
+ type: 'string',
469
+ description: 'Filter by tags (comma-separated: auth,jwt,session)'
470
+ };
471
+ properties.limit = {
472
+ type: 'number',
473
+ description: 'Results limit (default: 20)'
474
+ };
475
+ properties.format = {
476
+ type: 'string',
477
+ enum: ['table', 'json'],
478
+ description: 'Output format (default: table)'
479
+ };
480
+ } else if (cmd.subcommand === 'info') {
481
+ if (cmd.args?.includes('<name>')) {
482
+ properties.name = {
483
+ type: 'string',
484
+ description: 'Library name'
485
+ };
486
+ required.push('name');
487
+ }
488
+ properties.version = {
489
+ type: 'string',
490
+ description: 'Specific version (default: latest)'
491
+ };
492
+ properties.format = {
493
+ type: 'string',
494
+ enum: ['table', 'json'],
495
+ description: 'Output format (default: table)'
496
+ };
497
+ properties.content = {
498
+ type: 'boolean',
499
+ description: 'Show library content'
500
+ };
501
+ } else if (cmd.subcommand === 'list') {
502
+ properties.cached = {
503
+ type: 'boolean',
504
+ description: 'Show locally cached libraries'
505
+ };
506
+ properties.used = {
507
+ type: 'boolean',
508
+ description: 'Show libraries used in current project'
509
+ };
510
+ properties.format = {
511
+ type: 'string',
512
+ enum: ['table', 'json'],
513
+ description: 'Output format (default: table)'
514
+ };
515
+ } else if (cmd.subcommand === 'tags') {
516
+ properties.format = {
517
+ type: 'string',
518
+ enum: ['table', 'json'],
519
+ description: 'Output format (default: table)'
520
+ };
521
+ }
522
+ }
523
+
524
+ // Add zip parameter for file-generating grouped commands
525
+ if (this.isFileGeneratingGroupedCommand(cmd)) {
526
+ properties.zip = {
527
+ type: 'boolean',
528
+ description: 'Return files as ZIP package instead of creating locally (useful for remote servers or consistent delivery)'
529
+ };
530
+ }
531
+
532
+ return {
533
+ name: `specverse_${cmd.command.replace(/\s+/g, '_')}`,
534
+ description: cmd.description,
535
+ inputSchema: {
536
+ type: 'object',
537
+ properties,
538
+ required
539
+ }
540
+ };
541
+ }
542
+
543
+ /**
544
+ * Create MCP tools for AI commands
545
+ */
546
+ private createAIMCPTools(): MCPTool[] {
547
+ return [
548
+ {
549
+ name: 'specverse_ai_template',
550
+ description: 'Get AI prompt templates for SpecVerse operations',
551
+ inputSchema: {
552
+ type: 'object',
553
+ properties: {
554
+ operation: {
555
+ type: 'string',
556
+ enum: ['analyse', 'create', 'materialise', 'realize'],
557
+ description: 'AI operation type'
558
+ },
559
+ pver: {
560
+ type: 'string',
561
+ description: 'Prompt version (v1|v2|v3|v4|v5|v6|v7) (default: v1)'
562
+ },
563
+ output: {
564
+ type: 'string',
565
+ description: 'Output file path'
566
+ },
567
+ copy: {
568
+ type: 'boolean',
569
+ description: 'Copy result to clipboard'
570
+ }
571
+ },
572
+ required: ['operation']
573
+ }
574
+ },
575
+ {
576
+ name: 'specverse_ai_fill',
577
+ description: 'Fill AI prompt templates with requirements',
578
+ inputSchema: {
579
+ type: 'object',
580
+ properties: {
581
+ operation: {
582
+ type: 'string',
583
+ enum: ['analyse', 'create', 'materialise', 'realize'],
584
+ description: 'AI operation type'
585
+ },
586
+ requirements: {
587
+ type: 'string',
588
+ description: 'Project requirements'
589
+ },
590
+ scale: {
591
+ type: 'string',
592
+ enum: ['personal', 'business', 'enterprise'],
593
+ description: 'Project scale (default: business)'
594
+ },
595
+ framework: {
596
+ type: 'string',
597
+ description: 'Framework preference'
598
+ },
599
+ domain: {
600
+ type: 'string',
601
+ description: 'Project domain'
602
+ },
603
+ compliance: {
604
+ type: 'string',
605
+ description: 'Compliance requirements (comma-separated)'
606
+ },
607
+ tech: {
608
+ type: 'string',
609
+ description: 'Technology preferences (comma-separated)'
610
+ },
611
+ pver: {
612
+ type: 'string',
613
+ description: 'Prompt version (v1|v2|v3|v4|v5|v6|v7) (default: v1)'
614
+ },
615
+ output: {
616
+ type: 'string',
617
+ description: 'Output file path'
618
+ },
619
+ copy: {
620
+ type: 'boolean',
621
+ description: 'Copy result to clipboard'
622
+ }
623
+ },
624
+ required: ['operation', 'requirements']
625
+ }
626
+ },
627
+ {
628
+ name: 'specverse_ai_suggest',
629
+ description: 'Get AI library suggestions for project requirements',
630
+ inputSchema: {
631
+ type: 'object',
632
+ properties: {
633
+ requirements: {
634
+ type: 'string',
635
+ description: 'Project requirements'
636
+ },
637
+ domain: {
638
+ type: 'string',
639
+ description: 'Project domain'
640
+ },
641
+ scale: {
642
+ type: 'string',
643
+ enum: ['personal', 'business', 'enterprise'],
644
+ default: 'business',
645
+ description: 'Project scale'
646
+ }
647
+ },
648
+ required: ['requirements']
649
+ }
650
+ },
651
+ {
652
+ name: 'specverse_ai_enhance',
653
+ description: 'Get enhanced AI prompts with library context (BEST)',
654
+ inputSchema: {
655
+ type: 'object',
656
+ properties: {
657
+ operation: {
658
+ type: 'string',
659
+ enum: ['analyse', 'create', 'materialise', 'realize'],
660
+ description: 'AI operation type'
661
+ },
662
+ requirements: {
663
+ type: 'string',
664
+ description: 'Project requirements'
665
+ },
666
+ scale: {
667
+ type: 'string',
668
+ enum: ['personal', 'business', 'enterprise'],
669
+ description: 'Project scale (default: business)'
670
+ },
671
+ framework: {
672
+ type: 'string',
673
+ description: 'Framework preference'
674
+ },
675
+ domain: {
676
+ type: 'string',
677
+ description: 'Project domain'
678
+ },
679
+ compliance: {
680
+ type: 'string',
681
+ description: 'Compliance requirements (comma-separated)'
682
+ },
683
+ tech: {
684
+ type: 'string',
685
+ description: 'Technology preferences (comma-separated)'
686
+ },
687
+ pver: {
688
+ type: 'string',
689
+ description: 'Prompt version (v1|v2|v3|v4|v5|v6|v7) (default: v1)'
690
+ },
691
+ output: {
692
+ type: 'string',
693
+ description: 'Output file path'
694
+ },
695
+ copy: {
696
+ type: 'boolean',
697
+ description: 'Copy result to clipboard'
698
+ }
699
+ },
700
+ required: ['operation', 'requirements']
701
+ }
702
+ }
703
+ ];
704
+ }
705
+
706
+ /**
707
+ * Create content-based tools for direct LLM interaction
708
+ */
709
+ private createContentBasedTools(): MCPTool[] {
710
+ return [
711
+ {
712
+ name: 'specverse_validate_content',
713
+ description: 'Validate SpecVerse specification content directly (no file required)',
714
+ inputSchema: {
715
+ type: 'object',
716
+ properties: {
717
+ content: {
718
+ type: 'string',
719
+ description: 'SpecVerse specification content (.specly format)'
720
+ },
721
+ filename: {
722
+ type: 'string',
723
+ description: 'Optional filename for error reporting (default: temp.specly)'
724
+ },
725
+ verbose: {
726
+ type: 'boolean',
727
+ description: 'Show detailed validation results'
728
+ }
729
+ },
730
+ required: ['content']
731
+ }
732
+ },
733
+ {
734
+ name: 'specverse_infer_content',
735
+ description: 'Generate complete specification from content using AI inference',
736
+ inputSchema: {
737
+ type: 'object',
738
+ properties: {
739
+ content: {
740
+ type: 'string',
741
+ description: 'Minimal SpecVerse specification content (.specly format)'
742
+ },
743
+ filename: {
744
+ type: 'string',
745
+ description: 'Optional filename (default: temp.specly)'
746
+ },
747
+ controllers: {
748
+ type: 'boolean',
749
+ description: 'Generate controllers (default: true)'
750
+ },
751
+ services: {
752
+ type: 'boolean',
753
+ description: 'Generate services (default: true)'
754
+ },
755
+ events: {
756
+ type: 'boolean',
757
+ description: 'Generate events (default: true)'
758
+ },
759
+ views: {
760
+ type: 'boolean',
761
+ description: 'Generate views (default: true)'
762
+ },
763
+ deployment: {
764
+ type: 'boolean',
765
+ description: 'Generate deployment specification (default: false)'
766
+ },
767
+ environment: {
768
+ type: 'string',
769
+ enum: ['development', 'staging', 'production'],
770
+ description: 'Target environment for deployment'
771
+ },
772
+ verbose: {
773
+ type: 'boolean',
774
+ description: 'Show detailed inference process'
775
+ }
776
+ },
777
+ required: ['content']
778
+ }
779
+ },
780
+ {
781
+ name: 'specverse_gen_yaml_content',
782
+ description: 'Generate YAML from SpecVerse specification content',
783
+ inputSchema: {
784
+ type: 'object',
785
+ properties: {
786
+ content: {
787
+ type: 'string',
788
+ description: 'SpecVerse specification content (.specly format)'
789
+ },
790
+ filename: {
791
+ type: 'string',
792
+ description: 'Optional filename (default: temp.specly)'
793
+ }
794
+ },
795
+ required: ['content']
796
+ }
797
+ }
798
+ ];
799
+ }
800
+
801
+ /**
802
+ * Handle content-based commands by creating temporary files
803
+ */
804
+ private async handleContentBasedCommand(toolName: string, args: Record<string, any>): Promise<MCPToolResult> {
805
+ const { content, filename = 'temp.specly', ...otherArgs } = args;
806
+
807
+ if (!content) {
808
+ return {
809
+ content: [{
810
+ type: 'text',
811
+ text: JSON.stringify({
812
+ status: 'error',
813
+ message: 'Content is required for content-based commands',
814
+ timestamp: new Date().toISOString()
815
+ }, null, 2)
816
+ }],
817
+ isError: true
818
+ };
819
+ }
820
+
821
+ // Create temporary directory and file
822
+ let tempDir: string;
823
+ let tempFile: string;
824
+
825
+ try {
826
+ tempDir = mkdtempSync(join(tmpdir(), 'specverse-mcp-'));
827
+ tempFile = join(tempDir, filename);
828
+ writeFileSync(tempFile, content, 'utf8');
829
+
830
+ // Map content tool name to CLI command
831
+ const cliCommand = this.mapContentToolToCommand(toolName);
832
+
833
+ // Execute CLI command with temporary file
834
+ // Note: Most commands expect file as positional argument, not --file flag
835
+ const result = await specverseAPI.executeCliCommand(`${cliCommand} "${tempFile}"`, otherArgs, {
836
+ cliPath: this.cliPath,
837
+ timeout: 60000
838
+ });
839
+
840
+ return {
841
+ content: [{
842
+ type: 'text',
843
+ text: JSON.stringify(result, null, 2)
844
+ }]
845
+ };
846
+
847
+ } catch (error) {
848
+ const errorMessage = error instanceof Error ? error.message : String(error);
849
+
850
+ try {
851
+ const parsedError = JSON.parse(errorMessage);
852
+ return {
853
+ content: [{
854
+ type: 'text',
855
+ text: JSON.stringify(parsedError, null, 2)
856
+ }],
857
+ isError: true
858
+ };
859
+ } catch {
860
+ return {
861
+ content: [{
862
+ type: 'text',
863
+ text: JSON.stringify({
864
+ status: 'error',
865
+ message: 'Content-based command execution failed',
866
+ details: errorMessage,
867
+ timestamp: new Date().toISOString()
868
+ }, null, 2)
869
+ }],
870
+ isError: true
871
+ };
872
+ }
873
+ } finally {
874
+ // Clean up temporary file
875
+ try {
876
+ if (tempFile) unlinkSync(tempFile);
877
+ } catch {
878
+ // Ignore cleanup errors
879
+ }
880
+ }
881
+ }
882
+
883
+ /**
884
+ * Map content-based tool names to CLI commands
885
+ */
886
+ private mapContentToolToCommand(toolName: string): string {
887
+ const mapping: Record<string, string> = {
888
+ 'specverse_validate_content': 'validate',
889
+ 'specverse_infer_content': 'infer',
890
+ 'specverse_gen_yaml_content': 'gen yaml'
891
+ };
892
+
893
+ return mapping[toolName] || toolName.replace(/^specverse_/, '').replace(/_content$/, '').replace(/_/g, ' ');
894
+ }
895
+
896
+ /**
897
+ * Check if we're running in a remote environment where local file creation won't work
898
+ */
899
+ private async isRemoteEnvironment(): Promise<boolean> {
900
+ // Allow explicit override to force local mode
901
+ if (process.env.MCP_FORCE_LOCAL === 'true') {
902
+ return false;
903
+ }
904
+
905
+ // Check for common remote environment indicators
906
+ return (
907
+ // Vercel/Netlify/similar serverless
908
+ process.env.VERCEL === '1' ||
909
+ process.env.NETLIFY === 'true' ||
910
+ process.env.AWS_LAMBDA_FUNCTION_NAME !== undefined ||
911
+
912
+ // Web deployment mode indicators
913
+ process.env.NODE_ENV === 'production' && (
914
+ process.env.PORT !== undefined ||
915
+ process.env.HOST !== undefined
916
+ ) ||
917
+
918
+ // Environment explicitly marked as remote
919
+ process.env.MCP_REMOTE === 'true' ||
920
+
921
+ // Detect if we can't write to current directory (more reliable than just checking root)
922
+ await this.isDirectoryReadOnly()
923
+ );
924
+ }
925
+
926
+ /**
927
+ * Check if we should use remote environment detection specifically for root directory
928
+ * Only triggers if running from root AND no full paths are provided
929
+ */
930
+ private isProblematicRootEnvironment(args: Record<string, any>): boolean {
931
+ if (process.cwd() !== '/') {
932
+ return false; // Not running from root, so no problem
933
+ }
934
+
935
+ // If user provided full paths, it should work fine from root
936
+ const hasFullPaths = (
937
+ (args.name && args.name.startsWith('/')) || // /full/path/project
938
+ (args.file && args.file.startsWith('/')) || // /full/path/file.specly
939
+ (args.output && args.output.startsWith('/')) || // /full/path/output
940
+ (args.directory && args.directory.startsWith('/')) // /full/path/directory
941
+ );
942
+
943
+ if (hasFullPaths) {
944
+ return false; // Full paths work fine from root
945
+ }
946
+
947
+ // Only problematic if we have relative names that would create files in root
948
+ const hasRelativeName = args.name && !args.name.startsWith('/');
949
+
950
+ // Return true only for the actually problematic case
951
+ return hasRelativeName;
952
+ }
953
+
954
+ /**
955
+ * Check if current directory is read-only
956
+ */
957
+ private async isDirectoryReadOnly(): Promise<boolean> {
958
+ try {
959
+ const { writeFileSync, unlinkSync } = await import('fs');
960
+ const testFile = '.mcp-write-test-' + Date.now();
961
+ writeFileSync(testFile, 'test');
962
+ unlinkSync(testFile);
963
+ return false;
964
+ } catch {
965
+ return true;
966
+ }
967
+ }
968
+
969
+ /**
970
+ * Read project files into structured format for direct delivery
971
+ */
972
+ private async readProjectFilesStructured(projectPath: string): Promise<{files: any[], summary: any}> {
973
+ const { readdir, readFile, stat } = await import('fs/promises');
974
+ const { join, relative, extname } = await import('path');
975
+
976
+ const files: any[] = [];
977
+ let totalSize = 0;
978
+ const directories: string[] = [];
979
+
980
+ const readDirectory = async (dirPath: string) => {
981
+ const entries = await readdir(dirPath, { withFileTypes: true });
982
+
983
+ for (const entry of entries) {
984
+ const fullPath = join(dirPath, entry.name);
985
+ const relativePath = relative(projectPath, fullPath);
986
+
987
+ if (entry.isDirectory()) {
988
+ directories.push(relativePath + '/');
989
+ await readDirectory(fullPath);
990
+ } else if (entry.isFile()) {
991
+ try {
992
+ const content = await readFile(fullPath, 'utf8');
993
+ const stats = await stat(fullPath);
994
+ const extension = extname(entry.name).toLowerCase();
995
+
996
+ // Determine file type from extension
997
+ let fileType = 'text';
998
+ if (extension === '.js' || extension === '.ts') fileType = 'javascript';
999
+ else if (extension === '.py') fileType = 'python';
1000
+ else if (extension === '.md') fileType = 'markdown';
1001
+ else if (extension === '.json') fileType = 'json';
1002
+ else if (extension === '.yaml' || extension === '.yml') fileType = 'yaml';
1003
+ else if (extension === '.specly') fileType = 'specverse';
1004
+ else if (extension === '.sh') fileType = 'shell';
1005
+ else if (extension === '.html') fileType = 'html';
1006
+ else if (extension === '.css') fileType = 'css';
1007
+
1008
+ files.push({
1009
+ path: relativePath,
1010
+ content: content,
1011
+ type: fileType,
1012
+ size: stats.size,
1013
+ encoding: 'utf-8'
1014
+ });
1015
+
1016
+ totalSize += stats.size;
1017
+ } catch (error) {
1018
+ console.error(`Failed to read file ${fullPath}:`, error);
1019
+ // Skip files that can't be read
1020
+ }
1021
+ }
1022
+ }
1023
+ };
1024
+
1025
+ await readDirectory(projectPath);
1026
+
1027
+ return {
1028
+ files,
1029
+ summary: {
1030
+ total_files: files.length,
1031
+ total_size: totalSize < 1024 ? `${totalSize}B` :
1032
+ totalSize < 1024 * 1024 ? `${(totalSize / 1024).toFixed(1)}KB` :
1033
+ `${(totalSize / 1024 / 1024).toFixed(2)}MB`,
1034
+ directories: [...new Set(directories)].sort(),
1035
+ file_types: [...new Set(files.map(f => f.type))].sort()
1036
+ }
1037
+ };
1038
+ }
1039
+
1040
+ /**
1041
+ * Package project files into ZIP for remote delivery (DEPRECATED - keeping for fallback)
1042
+ */
1043
+ private async packageProjectFiles(projectPath: string): Promise<{zipData: string, fileName: string, size: number}> {
1044
+ const { execSync } = await import('child_process');
1045
+ const { readFile, unlink } = await import('fs/promises');
1046
+ const { basename, dirname, join } = await import('path');
1047
+ const { tmpdir } = await import('os');
1048
+
1049
+ const projectName = basename(projectPath);
1050
+ const parentDir = dirname(projectPath);
1051
+ const tempZipPath = join(tmpdir(), `${projectName}-${Date.now()}.zip`);
1052
+
1053
+ console.error(`MCP Packaging Debug: Project path: ${projectPath}`);
1054
+ console.error(`MCP Packaging Debug: Project name: ${projectName}`);
1055
+ console.error(`MCP Packaging Debug: Parent dir: ${parentDir}`);
1056
+ console.error(`MCP Packaging Debug: Temp ZIP path: ${tempZipPath}`);
1057
+
1058
+ try {
1059
+ // Create ZIP file using system zip command (available on most systems)
1060
+ const zipCommand = `cd "${parentDir}" && zip -r "${tempZipPath}" "${projectName}"`;
1061
+ console.error(`MCP Packaging Debug: Running command: ${zipCommand}`);
1062
+
1063
+ execSync(zipCommand, {
1064
+ encoding: 'utf8',
1065
+ stdio: 'pipe'
1066
+ });
1067
+
1068
+ console.error(`MCP Packaging Debug: ZIP file created successfully`);
1069
+
1070
+ // Read ZIP file as base64
1071
+ const zipBuffer = await readFile(tempZipPath);
1072
+ console.error(`MCP Packaging Debug: ZIP buffer size: ${zipBuffer.length} bytes`);
1073
+ console.error(`MCP Packaging Debug: ZIP buffer size: ${(zipBuffer.length / 1024 / 1024).toFixed(2)} MB`);
1074
+
1075
+ const zipData = zipBuffer.toString('base64');
1076
+ console.error(`MCP Packaging Debug: Base64 string length: ${zipData.length} chars`);
1077
+
1078
+ // Clean up temp ZIP file
1079
+ await unlink(tempZipPath);
1080
+ console.error(`MCP Packaging Debug: Temp file cleaned up`);
1081
+
1082
+ return {
1083
+ zipData,
1084
+ fileName: `${projectName}.zip`,
1085
+ size: zipBuffer.length
1086
+ };
1087
+ } catch (error) {
1088
+ console.error(`MCP Packaging Debug: ZIP command failed, trying fallback:`, error);
1089
+ // Fallback: try creating ZIP with Node.js if zip command fails
1090
+ return await this.createZipFallback(projectPath);
1091
+ }
1092
+ }
1093
+
1094
+ /**
1095
+ * Fallback ZIP creation using pure Node.js
1096
+ */
1097
+ private async createZipFallback(projectPath: string): Promise<{zipData: string, fileName: string, size: number}> {
1098
+ // Simple ZIP implementation fallback
1099
+ // For now, let's use tar.gz which is more universally available
1100
+ const { execSync } = await import('child_process');
1101
+ const { readFile, unlink } = await import('fs/promises');
1102
+ const { basename, dirname, join } = await import('path');
1103
+ const { tmpdir } = await import('os');
1104
+
1105
+ const projectName = basename(projectPath);
1106
+ const parentDir = dirname(projectPath);
1107
+ const tempTarPath = join(tmpdir(), `${projectName}-${Date.now()}.tar.gz`);
1108
+
1109
+ try {
1110
+ // Create tar.gz file (more universally available than zip)
1111
+ execSync(`cd "${parentDir}" && tar -czf "${tempTarPath}" "${projectName}"`, {
1112
+ encoding: 'utf8',
1113
+ stdio: 'pipe'
1114
+ });
1115
+
1116
+ // Read tar.gz file as base64
1117
+ const tarBuffer = await readFile(tempTarPath);
1118
+ const tarData = tarBuffer.toString('base64');
1119
+
1120
+ // Clean up temp tar file
1121
+ await unlink(tempTarPath);
1122
+
1123
+ return {
1124
+ zipData: tarData,
1125
+ fileName: `${projectName}.tar.gz`,
1126
+ size: tarBuffer.length
1127
+ };
1128
+ } catch (error) {
1129
+ throw new Error(`Failed to create project archive: ${error}`);
1130
+ }
1131
+ }
1132
+
1133
+ /**
1134
+ * Execute init command without --json flag (not supported)
1135
+ * For remote deployments, returns project files as JSON structure
1136
+ */
1137
+ private async executeInitCommand(command: string, args: Record<string, any>): Promise<any> {
1138
+ const { execSync } = await import('child_process');
1139
+
1140
+ // Build command with arguments (excluding --json, --zip, --local, and fullPath which are MCP-only)
1141
+ const argString = Object.entries(args)
1142
+ .filter(([key, value]) =>
1143
+ value !== undefined &&
1144
+ value !== null &&
1145
+ key !== 'zip' && // ZIP is handled by MCP service, not CLI
1146
+ key !== 'local' && // Local is MCP server flag, not CLI flag
1147
+ key !== 'fullPath' && // fullPath is used internally for directory handling
1148
+ key !== 'name' // name is passed as positional argument, not flag
1149
+ )
1150
+ .map(([key, value]) => {
1151
+ if (typeof value === 'boolean') {
1152
+ return value ? `--${key}` : '';
1153
+ } else {
1154
+ return `--${key} "${value}"`;
1155
+ }
1156
+ })
1157
+ .filter(Boolean)
1158
+ .join(' ');
1159
+
1160
+ const baseCommand = this.cliPath === 'specverse' ? 'specverse' : `node ${this.cliPath}`;
1161
+ const fullCommand = `${baseCommand} ${command} ${argString}`.trim();
1162
+
1163
+ // Use fullPath from args if available (contains the complete path), otherwise extract from command
1164
+ const rawName = args.fullPath || command.match(/"([^"]+)"/)?.[1] || args.name || 'project';
1165
+
1166
+ // Handle full path vs relative path
1167
+ let projectName: string;
1168
+ let targetWorkingDir: string;
1169
+
1170
+ if (rawName.startsWith('/')) {
1171
+ // Full absolute path - extract parent directory and project name
1172
+ const { dirname, basename } = await import('path');
1173
+ projectName = basename(rawName);
1174
+ targetWorkingDir = dirname(rawName);
1175
+ } else {
1176
+ // Relative path - use current directory
1177
+ projectName = rawName;
1178
+ targetWorkingDir = process.cwd();
1179
+ }
1180
+
1181
+ const forceZip = args.zip === true;
1182
+ const forceJson = args.json === true;
1183
+
1184
+ console.error(`MCP Init Debug: Working directory: ${process.cwd()}`);
1185
+ console.error(`MCP Init Debug: Target working directory: ${targetWorkingDir}`);
1186
+ console.error(`MCP Init Debug: Raw name: ${rawName}`);
1187
+ console.error(`MCP Init Debug: Project name: ${projectName}`);
1188
+ console.error(`MCP Init Debug: Force ZIP: ${forceZip}`);
1189
+ console.error(`MCP Init Debug: Force JSON: ${forceJson}`);
1190
+ console.error(`MCP Init Debug: Executing command: ${fullCommand}`);
1191
+
1192
+ // Simple decision logic
1193
+ if (forceZip) {
1194
+ console.error(`MCP Init Debug: ZIP requested - will return ZIP file`);
1195
+ return await this.executeInitWithZip(fullCommand, projectName, args);
1196
+ } else if (forceJson) {
1197
+ console.error(`MCP Init Debug: JSON requested - will return JSON structure`);
1198
+ return await this.executeInitWithJson(fullCommand, projectName, args);
1199
+ } else if (await this.canCreateLocalFiles(projectName, targetWorkingDir)) {
1200
+ console.error(`MCP Init Debug: Local filesystem - will create files locally`);
1201
+ return await this.executeInitLocal(fullCommand, projectName, targetWorkingDir);
1202
+ } else {
1203
+ console.error(`MCP Init Debug: Cannot create local files - will return JSON structure`);
1204
+ return await this.executeInitWithJson(fullCommand, projectName, args);
1205
+ }
1206
+ }
1207
+
1208
+ private async canCreateLocalFiles(projectName: string, targetWorkingDir?: string): Promise<boolean> {
1209
+ try {
1210
+ // Use provided target directory, or fall back to old logic for compatibility
1211
+ const targetDir = targetWorkingDir || await (async () => {
1212
+ const cwd = process.cwd();
1213
+
1214
+ if (projectName.startsWith('/')) {
1215
+ // Absolute path - extract parent directory
1216
+ const { dirname } = await import('path');
1217
+ return dirname(projectName);
1218
+ } else {
1219
+ // Relative path - check if current directory is problematic
1220
+ if (cwd === '/') {
1221
+ return null; // Don't create relative paths in root
1222
+ }
1223
+ return cwd;
1224
+ }
1225
+ })();
1226
+
1227
+ // If we couldn't determine a valid target directory, return false
1228
+ if (!targetDir) {
1229
+ return false;
1230
+ }
1231
+
1232
+ // Try to write a test file in the target directory
1233
+ const { writeFileSync, unlinkSync } = await import('fs');
1234
+ const { join } = await import('path');
1235
+ const testFile = join(targetDir, '.mcp-write-test-' + Date.now());
1236
+ writeFileSync(testFile, 'test');
1237
+ unlinkSync(testFile);
1238
+ return true;
1239
+ } catch {
1240
+ return false;
1241
+ }
1242
+ }
1243
+
1244
+ private async executeInitLocal(fullCommand: string, projectName: string, targetWorkingDir?: string): Promise<any> {
1245
+ const { execSync } = await import('child_process');
1246
+ const { join } = await import('path');
1247
+
1248
+ // Use provided target directory or fallback to current directory
1249
+ const workingDir = targetWorkingDir || process.cwd();
1250
+
1251
+ try {
1252
+ const result = execSync(fullCommand, {
1253
+ encoding: 'utf8',
1254
+ timeout: 30000,
1255
+ stdio: 'pipe',
1256
+ cwd: workingDir
1257
+ });
1258
+
1259
+ return {
1260
+ status: 'success',
1261
+ message: `Project '${projectName}' created successfully`,
1262
+ project_path: join(workingDir, projectName),
1263
+ delivery_method: 'local_filesystem',
1264
+ created: true
1265
+ };
1266
+ } catch (error: any) {
1267
+ const errorOutput = error.stdout || error.stderr || error.message;
1268
+ throw new Error(`Failed to create project '${projectName}': ${errorOutput}`);
1269
+ }
1270
+ }
1271
+
1272
+ private async executeInitWithZip(fullCommand: string, projectName: string, args: Record<string, any>): Promise<any> {
1273
+ const { execSync } = await import('child_process');
1274
+ const { mkdtemp, rm } = await import('fs/promises');
1275
+ const { tmpdir } = await import('os');
1276
+ const { join } = await import('path');
1277
+
1278
+ // Create in temp directory
1279
+ const tempDir = await mkdtemp(join(tmpdir(), 'specverse-zip-'));
1280
+
1281
+ try {
1282
+ const result = execSync(fullCommand, {
1283
+ encoding: 'utf8',
1284
+ timeout: 30000,
1285
+ stdio: 'pipe',
1286
+ cwd: tempDir
1287
+ });
1288
+
1289
+ // Package as ZIP
1290
+ const projectPath = join(tempDir, projectName);
1291
+ const zipData = await this.packageProjectFiles(projectPath);
1292
+
1293
+ // Cleanup
1294
+ await rm(tempDir, { recursive: true, force: true });
1295
+
1296
+ return {
1297
+ status: 'success',
1298
+ message: `Project '${projectName}' packaged as ZIP`,
1299
+ delivery_method: 'zip_file',
1300
+ zip_data: zipData.zipData,
1301
+ file_name: zipData.fileName,
1302
+ size: zipData.size
1303
+ };
1304
+ } catch (error: any) {
1305
+ await rm(tempDir, { recursive: true, force: true }).catch(() => {});
1306
+ const errorOutput = error.stdout || error.stderr || error.message;
1307
+ throw new Error(`Failed to create project '${projectName}': ${errorOutput}`);
1308
+ }
1309
+ }
1310
+
1311
+ private async executeInitWithJson(fullCommand: string, projectName: string, args: Record<string, any>): Promise<any> {
1312
+ const { execSync } = await import('child_process');
1313
+ const { mkdtemp, rm } = await import('fs/promises');
1314
+ const { tmpdir } = await import('os');
1315
+ const { join } = await import('path');
1316
+
1317
+ // Create in temp directory
1318
+ const tempDir = await mkdtemp(join(tmpdir(), 'specverse-json-'));
1319
+
1320
+ try {
1321
+ const result = execSync(fullCommand, {
1322
+ encoding: 'utf8',
1323
+ timeout: 30000,
1324
+ stdio: 'pipe',
1325
+ cwd: tempDir
1326
+ });
1327
+
1328
+ // Read files as JSON structure
1329
+ const projectPath = join(tempDir, projectName);
1330
+ const structuredFiles = await this.readProjectFilesStructured(projectPath);
1331
+
1332
+ // Cleanup
1333
+ await rm(tempDir, { recursive: true, force: true });
1334
+
1335
+ return {
1336
+ status: 'success',
1337
+ instruction: 'create_file_attachments_for_each_file_described_in_files',
1338
+ message: `Project '${projectName}' created successfully`,
1339
+ project: projectName,
1340
+ files: structuredFiles.files,
1341
+ summary: structuredFiles.summary,
1342
+ delivery_method: 'json_structure'
1343
+ };
1344
+ } catch (error: any) {
1345
+ await rm(tempDir, { recursive: true, force: true }).catch(() => {});
1346
+ const errorOutput = error.stdout || error.stderr || error.message;
1347
+ throw new Error(`Failed to create project '${projectName}': ${errorOutput}`);
1348
+ }
1349
+ }
1350
+
1351
+ /**
1352
+ * Map MCP tool name back to CLI command
1353
+ */
1354
+ private mapToolNameToCommand(toolName: string): string {
1355
+ // Remove 'specverse_' prefix and convert underscores back to spaces
1356
+ const command = toolName.replace(/^specverse_/, '').replace(/_/g, ' ');
1357
+
1358
+ // Handle special cases
1359
+ if (command.startsWith('ai ')) {
1360
+ return command; // ai commands are already correct
1361
+ }
1362
+
1363
+ return command;
1364
+ }
1365
+
1366
+ /**
1367
+ * Get MCP package version using Node.js built-in package resolution
1368
+ */
1369
+ private async getMCPVersion(): Promise<string> {
1370
+ try {
1371
+ // Method 1: Development mode - look for local package.json first (most reliable)
1372
+ const { readFile } = await import('fs/promises');
1373
+ const { join, dirname } = await import('path');
1374
+ const { fileURLToPath } = await import('url');
1375
+
1376
+ // Get current file location and find project root
1377
+ const __filename = fileURLToPath(import.meta.url);
1378
+ const __dirname = dirname(__filename);
1379
+
1380
+ // In development, package.json should be 2-3 levels up from dist/services/
1381
+ const packagePaths = [
1382
+ join(__dirname, '..', '..', 'package.json'), // dist/services -> root
1383
+ join(__dirname, '..', '..', '..', 'package.json') // dist/target/services -> root
1384
+ ];
1385
+
1386
+ for (const packagePath of packagePaths) {
1387
+ try {
1388
+ const content = await readFile(packagePath, 'utf8');
1389
+ const packageInfo = JSON.parse(content);
1390
+ // Verify this is the MCP package
1391
+ if (packageInfo.name === '@specverse/mcp') {
1392
+ return packageInfo.version;
1393
+ }
1394
+ } catch {
1395
+ continue;
1396
+ }
1397
+ }
1398
+
1399
+ // Method 2: Try npm installed package resolution
1400
+ try {
1401
+ const { createRequire } = await import('module');
1402
+ const require = createRequire(import.meta.url);
1403
+ const packageInfo = require('@specverse/mcp/package.json');
1404
+ return packageInfo.version;
1405
+ } catch {
1406
+ // Method 3: Try import.meta.resolve (newer Node versions)
1407
+ try {
1408
+ const packageJsonUrl = import.meta.resolve('@specverse/mcp/package.json');
1409
+ const content = await readFile(new URL(packageJsonUrl), 'utf8');
1410
+ const packageInfo = JSON.parse(content);
1411
+ return packageInfo.version;
1412
+ } catch {
1413
+ // Fallback to environment variable or unknown
1414
+ return process.env.MCP_VERSION || 'unknown';
1415
+ }
1416
+ }
1417
+ } catch {
1418
+ // Final fallback
1419
+ return process.env.MCP_VERSION || 'unknown';
1420
+ }
1421
+ }
1422
+
1423
+ /**
1424
+ * Execute MCP-specific debug tool
1425
+ */
1426
+ private async executeMCPDebugTool(verbose: boolean): Promise<MCPToolResult> {
1427
+ try {
1428
+ const mcpVersion = await this.getMCPVersion();
1429
+
1430
+ const diagnostics: any = {
1431
+ timestamp: new Date().toISOString(),
1432
+ mcp_server: {
1433
+ version: mcpVersion,
1434
+ mode: 'diagnostic'
1435
+ }
1436
+ };
1437
+
1438
+ // Get SpecVerse installation info
1439
+ try {
1440
+ const { resolvePackageRoot } = specverseAPI;
1441
+ const packageRoot = resolvePackageRoot();
1442
+
1443
+ // Read package.json for version info
1444
+ const { readFile } = await import('fs/promises');
1445
+ const { join } = await import('path');
1446
+ const packageJsonPath = join(packageRoot, 'package.json');
1447
+ const packageContent = await readFile(packageJsonPath, 'utf8');
1448
+ const packageData = JSON.parse(packageContent);
1449
+
1450
+ diagnostics.specverse_installation = {
1451
+ type: 'npm_package',
1452
+ version: packageData.version,
1453
+ location: packageRoot,
1454
+ package_name: packageData.name,
1455
+ status: 'found'
1456
+ };
1457
+ } catch (error) {
1458
+ diagnostics.specverse_installation = {
1459
+ status: 'error',
1460
+ error: error instanceof Error ? error.message : String(error)
1461
+ };
1462
+ }
1463
+
1464
+ // CLI detection
1465
+ diagnostics.cli_detection = {
1466
+ cli_path: this.cliPath,
1467
+ working_directory: this.workingDirectory || process.cwd(),
1468
+ status: this.cliPath ? 'found' : 'not_found'
1469
+ };
1470
+
1471
+ // Health check
1472
+ diagnostics.health_check = {
1473
+ can_import_specverse: !!diagnostics.specverse_installation.version,
1474
+ cli_accessible: !!this.cliPath,
1475
+ capabilities_loaded: !!this.capabilities,
1476
+ overall_status: (!!diagnostics.specverse_installation.version && !!this.cliPath) ? 'healthy' : 'degraded'
1477
+ };
1478
+
1479
+ return {
1480
+ content: [{
1481
+ type: 'text',
1482
+ text: JSON.stringify(diagnostics, null, 2)
1483
+ }]
1484
+ };
1485
+
1486
+ } catch (error) {
1487
+ return {
1488
+ content: [{
1489
+ type: 'text',
1490
+ text: JSON.stringify({
1491
+ status: 'error',
1492
+ message: 'MCP debug tool execution failed',
1493
+ error: error instanceof Error ? error.message : String(error),
1494
+ timestamp: new Date().toISOString()
1495
+ }, null, 2)
1496
+ }],
1497
+ isError: true
1498
+ };
1499
+ }
1500
+ }
1501
+ }