github-to-mcp-monorepo 1.0.0

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 (388) hide show
  1. package/.env.example +8 -0
  2. package/.github/CODEOWNERS +6 -0
  3. package/.husky/pre-commit +1 -0
  4. package/.nvmrc +1 -0
  5. package/.prettierignore +5 -0
  6. package/.prettierrc +7 -0
  7. package/.vscode/settings.json +4 -0
  8. package/ARCHITECTURE.md +1429 -0
  9. package/CHANGELOG.md +167 -0
  10. package/CONTRIBUTING.md +327 -0
  11. package/LICENSE +201 -0
  12. package/README.md +1028 -0
  13. package/SECURITY.md +248 -0
  14. package/VISUAL_GUIDE.md +437 -0
  15. package/apps/vscode/IMPLEMENTATION.md +480 -0
  16. package/apps/vscode/README.md +248 -0
  17. package/apps/vscode/package.json +381 -0
  18. package/apps/vscode/resources/icon.png +0 -0
  19. package/apps/vscode/resources/icon.svg +5 -0
  20. package/apps/vscode/src/commands/browseRegistry.ts +211 -0
  21. package/apps/vscode/src/commands/configureClaudeDesktop.ts +332 -0
  22. package/apps/vscode/src/commands/convert.ts +82 -0
  23. package/apps/vscode/src/commands/convertCurrentRepo.ts +109 -0
  24. package/apps/vscode/src/commands/convertFromUrl.ts +138 -0
  25. package/apps/vscode/src/commands/index.ts +121 -0
  26. package/apps/vscode/src/commands/validate.ts +197 -0
  27. package/apps/vscode/src/extension.ts +464 -0
  28. package/apps/vscode/src/global.d.ts +36 -0
  29. package/apps/vscode/src/test/extension.test.ts +73 -0
  30. package/apps/vscode/src/utils/file-generator.ts +529 -0
  31. package/apps/vscode/src/utils/github-api.ts +335 -0
  32. package/apps/vscode/src/utils/index.ts +29 -0
  33. package/apps/vscode/src/utils/mcp-config.ts +334 -0
  34. package/apps/vscode/src/utils/storage.ts +87 -0
  35. package/apps/vscode/src/views/McpServersTreeView.ts +160 -0
  36. package/apps/vscode/src/views/OutputChannelView.ts +195 -0
  37. package/apps/vscode/src/views/StatusBarItem.ts +251 -0
  38. package/apps/vscode/src/views/ToolsExplorerView.ts +314 -0
  39. package/apps/vscode/src/views/historyProvider.ts +75 -0
  40. package/apps/vscode/src/views/index.ts +12 -0
  41. package/apps/vscode/src/views/resultsPanel.ts +330 -0
  42. package/apps/vscode/src/webviews/ConversionPanel.ts +350 -0
  43. package/apps/vscode/src/webviews/ToolDetailsPanel.ts +448 -0
  44. package/apps/vscode/src/webviews/index.ts +9 -0
  45. package/apps/vscode/src/webviews/webview-ui/styles.ts +492 -0
  46. package/apps/vscode/tsconfig.json +20 -0
  47. package/apps/web/PLAYGROUND_GUIDE.md +499 -0
  48. package/apps/web/README.md +505 -0
  49. package/apps/web/app/api/convert/route.ts +100 -0
  50. package/apps/web/app/api/convert/stream/route.ts +198 -0
  51. package/apps/web/app/api/deploy/route.ts +157 -0
  52. package/apps/web/app/api/edge/route.ts +308 -0
  53. package/apps/web/app/api/export-docker/route.ts +284 -0
  54. package/apps/web/app/api/generate-openapi/route.ts +119 -0
  55. package/apps/web/app/api/mcp/[serverId]/route.ts +263 -0
  56. package/apps/web/app/api/playground/connect/route.ts +143 -0
  57. package/apps/web/app/api/playground/disconnect/route.ts +78 -0
  58. package/apps/web/app/api/playground/execute/route.ts +135 -0
  59. package/apps/web/app/api/playground/sessions/route.ts +103 -0
  60. package/apps/web/app/api/playground/tools/route.ts +117 -0
  61. package/apps/web/app/api/playground/v2/connect/route.ts +96 -0
  62. package/apps/web/app/api/playground/v2/disconnect/route.ts +88 -0
  63. package/apps/web/app/api/playground/v2/health/route.ts +80 -0
  64. package/apps/web/app/api/playground/v2/prompts/route.ts +160 -0
  65. package/apps/web/app/api/playground/v2/resources/route.ts +159 -0
  66. package/apps/web/app/api/playground/v2/sessions/route.ts +184 -0
  67. package/apps/web/app/api/playground/v2/tools/route.ts +167 -0
  68. package/apps/web/app/api/stream/route.ts +232 -0
  69. package/apps/web/app/batch/BatchConvertClient.tsx +190 -0
  70. package/apps/web/app/batch/page.tsx +37 -0
  71. package/apps/web/app/convert/page.tsx +269 -0
  72. package/apps/web/app/dashboard/page.tsx +380 -0
  73. package/apps/web/app/globals.css +622 -0
  74. package/apps/web/app/layout.tsx +120 -0
  75. package/apps/web/app/manifest.ts +31 -0
  76. package/apps/web/app/opengraph-image.tsx +112 -0
  77. package/apps/web/app/page.old.tsx +924 -0
  78. package/apps/web/app/page.tsx +77 -0
  79. package/apps/web/app/playground/page.tsx +306 -0
  80. package/apps/web/app/playground/v2/error.tsx +163 -0
  81. package/apps/web/app/playground/v2/layout.tsx +58 -0
  82. package/apps/web/app/playground/v2/loading.tsx +152 -0
  83. package/apps/web/app/playground/v2/page.tsx +644 -0
  84. package/apps/web/app/playground/v2/providers.tsx +214 -0
  85. package/apps/web/app/playground/v2/use-shortcuts.ts +209 -0
  86. package/apps/web/app/playground/v2/use-url-state.ts +296 -0
  87. package/apps/web/app/providers.tsx +22 -0
  88. package/apps/web/app/sitemap.ts +32 -0
  89. package/apps/web/app/twitter-image.tsx +112 -0
  90. package/apps/web/components/BranchSelector.tsx +401 -0
  91. package/apps/web/components/ClaudeConfigExport.tsx +226 -0
  92. package/apps/web/components/Features.tsx +84 -0
  93. package/apps/web/components/Footer.tsx +119 -0
  94. package/apps/web/components/GenerationProgress.tsx +248 -0
  95. package/apps/web/components/GithubUrlInput.tsx +483 -0
  96. package/apps/web/components/Header.tsx +175 -0
  97. package/apps/web/components/Hero.tsx +117 -0
  98. package/apps/web/components/HowItWorks.tsx +119 -0
  99. package/apps/web/components/InstallBanner.tsx +158 -0
  100. package/apps/web/components/Logo.tsx +116 -0
  101. package/apps/web/components/ParticleBackground.tsx +105 -0
  102. package/apps/web/components/Playground.tsx +472 -0
  103. package/apps/web/components/PlaygroundToolTester.tsx +410 -0
  104. package/apps/web/components/ProductCards.tsx +179 -0
  105. package/apps/web/components/SplitView.tsx +194 -0
  106. package/apps/web/components/ToolFilter.tsx +260 -0
  107. package/apps/web/components/ToolList.tsx +325 -0
  108. package/apps/web/components/batch/BatchConvert.tsx +785 -0
  109. package/apps/web/components/batch/index.ts +7 -0
  110. package/apps/web/components/convert/ConfigTabs.tsx +230 -0
  111. package/apps/web/components/convert/ConversionResult.tsx +482 -0
  112. package/apps/web/components/convert/InlinePlayground.tsx +259 -0
  113. package/apps/web/components/convert/LoadingSteps.tsx +311 -0
  114. package/apps/web/components/convert/OneClickInstall.tsx +224 -0
  115. package/apps/web/components/convert/ToolCard.tsx +189 -0
  116. package/apps/web/components/convert/TryInPlayground.tsx +242 -0
  117. package/apps/web/components/convert/index.ts +12 -0
  118. package/apps/web/components/deploy/DeployButton.tsx +369 -0
  119. package/apps/web/components/deploy/index.ts +7 -0
  120. package/apps/web/components/docker/DockerExport.tsx +690 -0
  121. package/apps/web/components/docker/index.ts +7 -0
  122. package/apps/web/components/install/OneClickInstall.tsx +676 -0
  123. package/apps/web/components/install/index.ts +7 -0
  124. package/apps/web/components/playground/CapabilityTabs.tsx +150 -0
  125. package/apps/web/components/playground/ConnectionStatusV2.tsx +322 -0
  126. package/apps/web/components/playground/EmptyStates.tsx +305 -0
  127. package/apps/web/components/playground/ExecutionLog.tsx +260 -0
  128. package/apps/web/components/playground/ExecutionLogV2.tsx +378 -0
  129. package/apps/web/components/playground/JsonViewer.tsx +388 -0
  130. package/apps/web/components/playground/PlaygroundLayout.tsx +244 -0
  131. package/apps/web/components/playground/PromptsPanel.tsx +385 -0
  132. package/apps/web/components/playground/ResourcesPanel.tsx +378 -0
  133. package/apps/web/components/playground/SchemaForm.tsx +477 -0
  134. package/apps/web/components/playground/ServerStatus.tsx +151 -0
  135. package/apps/web/components/playground/ShareButton.tsx +239 -0
  136. package/apps/web/components/playground/ToolsPanel.tsx +309 -0
  137. package/apps/web/components/playground/TransportConfigurator.tsx +563 -0
  138. package/apps/web/components/playground/index.ts +74 -0
  139. package/apps/web/components/playground/types.ts +202 -0
  140. package/apps/web/components/streaming/StreamingProgress.tsx +441 -0
  141. package/apps/web/components/streaming/index.ts +7 -0
  142. package/apps/web/components/ui/badge.tsx +42 -0
  143. package/apps/web/components/ui/button.tsx +88 -0
  144. package/apps/web/components/ui/card.tsx +75 -0
  145. package/apps/web/components/ui/code-block.tsx +122 -0
  146. package/apps/web/components/ui/index.ts +12 -0
  147. package/apps/web/components/ui/input.tsx +55 -0
  148. package/apps/web/components/ui/tabs.tsx +61 -0
  149. package/apps/web/hooks/index.ts +85 -0
  150. package/apps/web/hooks/types.ts +1173 -0
  151. package/apps/web/hooks/use-conversion.ts +133 -0
  152. package/apps/web/hooks/use-execution-history.ts +376 -0
  153. package/apps/web/hooks/use-generation-progress.ts +147 -0
  154. package/apps/web/hooks/use-local-storage.ts +88 -0
  155. package/apps/web/hooks/use-mcp-client.ts +623 -0
  156. package/apps/web/hooks/use-mcp-connection.ts +500 -0
  157. package/apps/web/hooks/use-mcp-execution.ts +282 -0
  158. package/apps/web/hooks/use-mcp-prompts.ts +441 -0
  159. package/apps/web/hooks/use-mcp-resources.ts +430 -0
  160. package/apps/web/hooks/use-mcp-tools.ts +540 -0
  161. package/apps/web/hooks/use-playground-store.ts +299 -0
  162. package/apps/web/hooks/use-playground.ts +184 -0
  163. package/apps/web/hooks/use-streaming-conversion.ts +227 -0
  164. package/apps/web/hooks/useBatchConversion.ts +271 -0
  165. package/apps/web/hooks/useDockerConfig.ts +161 -0
  166. package/apps/web/hooks/usePlatformDetection.ts +80 -0
  167. package/apps/web/hooks/useStreaming.ts +199 -0
  168. package/apps/web/lib/api/errors.ts +386 -0
  169. package/apps/web/lib/api/index.ts +137 -0
  170. package/apps/web/lib/api/logger.ts +187 -0
  171. package/apps/web/lib/api/middleware.ts +364 -0
  172. package/apps/web/lib/api/openapi.ts +977 -0
  173. package/apps/web/lib/api/session-manager.ts +594 -0
  174. package/apps/web/lib/api/types.ts +433 -0
  175. package/apps/web/lib/api/validation.ts +523 -0
  176. package/apps/web/lib/constants.ts +114 -0
  177. package/apps/web/lib/mcp/client.ts +1137 -0
  178. package/apps/web/lib/mcp/events.ts +651 -0
  179. package/apps/web/lib/mcp/index.ts +347 -0
  180. package/apps/web/lib/mcp/logger.ts +428 -0
  181. package/apps/web/lib/mcp/metrics.ts +703 -0
  182. package/apps/web/lib/mcp/retry.ts +616 -0
  183. package/apps/web/lib/mcp/session-manager.ts +779 -0
  184. package/apps/web/lib/mcp/transports.ts +988 -0
  185. package/apps/web/lib/mcp/types.ts +594 -0
  186. package/apps/web/lib/mcp-client-enhanced.ts +871 -0
  187. package/apps/web/lib/mcp-client.ts +778 -0
  188. package/apps/web/lib/mcp-errors.ts +489 -0
  189. package/apps/web/lib/mcp-sandbox.ts +593 -0
  190. package/apps/web/lib/mcp-testing.ts +428 -0
  191. package/apps/web/lib/mcp-types.ts +448 -0
  192. package/apps/web/lib/playground-store.tsx +1147 -0
  193. package/apps/web/lib/utils.ts +439 -0
  194. package/apps/web/next-env.d.ts +5 -0
  195. package/apps/web/next.config.js +23 -0
  196. package/apps/web/package.json +55 -0
  197. package/apps/web/postcss.config.js +6 -0
  198. package/apps/web/public/.well-known/ai-plugin.json +17 -0
  199. package/apps/web/public/logo.svg +6 -0
  200. package/apps/web/public/robots.txt +22 -0
  201. package/apps/web/public/schema.json +27 -0
  202. package/apps/web/tailwind.config.js +26 -0
  203. package/apps/web/tailwind.config.ts +123 -0
  204. package/apps/web/tsconfig.json +20 -0
  205. package/apps/web/types/deploy.ts +139 -0
  206. package/apps/web/types/index.ts +247 -0
  207. package/apps/web/vercel.json +39 -0
  208. package/eslint.config.mjs +23 -0
  209. package/llms.txt +102 -0
  210. package/mkdocs/docs/api/core.md +318 -0
  211. package/mkdocs/docs/api/index.md +128 -0
  212. package/mkdocs/docs/api/mcp-server.md +301 -0
  213. package/mkdocs/docs/api/openapi-parser.md +254 -0
  214. package/mkdocs/docs/assets/logo.svg +7 -0
  215. package/mkdocs/docs/changelog.md +118 -0
  216. package/mkdocs/docs/cli/generate.md +148 -0
  217. package/mkdocs/docs/cli/index.md +52 -0
  218. package/mkdocs/docs/cli/inspect.md +164 -0
  219. package/mkdocs/docs/cli/serve.md +136 -0
  220. package/mkdocs/docs/concepts/classification.md +254 -0
  221. package/mkdocs/docs/concepts/how-it-works.md +299 -0
  222. package/mkdocs/docs/concepts/index.md +77 -0
  223. package/mkdocs/docs/concepts/mcp-protocol.md +362 -0
  224. package/mkdocs/docs/concepts/tool-types.md +382 -0
  225. package/mkdocs/docs/contributing/architecture.md +262 -0
  226. package/mkdocs/docs/contributing/development.md +245 -0
  227. package/mkdocs/docs/contributing/index.md +73 -0
  228. package/mkdocs/docs/contributing/testing.md +320 -0
  229. package/mkdocs/docs/getting-started/configuration.md +235 -0
  230. package/mkdocs/docs/getting-started/index.md +54 -0
  231. package/mkdocs/docs/getting-started/installation.md +145 -0
  232. package/mkdocs/docs/getting-started/quickstart.md +160 -0
  233. package/mkdocs/docs/guides/batch.md +375 -0
  234. package/mkdocs/docs/guides/claude-desktop.md +227 -0
  235. package/mkdocs/docs/guides/cursor.md +188 -0
  236. package/mkdocs/docs/guides/custom-tools.md +367 -0
  237. package/mkdocs/docs/guides/index.md +78 -0
  238. package/mkdocs/docs/guides/private-repos.md +221 -0
  239. package/mkdocs/docs/guides/vscode.md +247 -0
  240. package/mkdocs/docs/index.md +175 -0
  241. package/mkdocs/docs/reference/config.md +223 -0
  242. package/mkdocs/docs/reference/env.md +192 -0
  243. package/mkdocs/docs/reference/index.md +102 -0
  244. package/mkdocs/docs/reference/tools.md +309 -0
  245. package/mkdocs/docs/stylesheets/extra.css +231 -0
  246. package/mkdocs/mkdocs.yml +204 -0
  247. package/mkdocs/overrides/.gitkeep +1 -0
  248. package/mkdocs/overrides/main.html +7 -0
  249. package/mkdocs/python-deps.txt +7 -0
  250. package/mkdocs/vercel.json +11 -0
  251. package/package.json +63 -0
  252. package/packages/core/package.json +61 -0
  253. package/packages/core/src/__tests__/bitbucket-client.test.ts +366 -0
  254. package/packages/core/src/__tests__/cli.test.ts +235 -0
  255. package/packages/core/src/__tests__/code-extractor.test.ts +378 -0
  256. package/packages/core/src/__tests__/docker-generator.test.ts +255 -0
  257. package/packages/core/src/__tests__/github-client.test.ts +390 -0
  258. package/packages/core/src/__tests__/gitlab-client.test.ts +319 -0
  259. package/packages/core/src/__tests__/go-extractor.test.ts +351 -0
  260. package/packages/core/src/__tests__/graphql-extractor.test.ts +330 -0
  261. package/packages/core/src/__tests__/java-extractor.test.ts +497 -0
  262. package/packages/core/src/__tests__/plugins.test.ts +467 -0
  263. package/packages/core/src/__tests__/readme-extractor.test.ts +258 -0
  264. package/packages/core/src/__tests__/redis-cache.test.ts +307 -0
  265. package/packages/core/src/__tests__/rust-extractor.test.ts +252 -0
  266. package/packages/core/src/__tests__/streaming.test.ts +251 -0
  267. package/packages/core/src/additional-extractors.ts +333 -0
  268. package/packages/core/src/cache/cache-interface.ts +179 -0
  269. package/packages/core/src/cache/index.ts +210 -0
  270. package/packages/core/src/cache/redis-cache.ts +291 -0
  271. package/packages/core/src/cache/upstash-cache.ts +379 -0
  272. package/packages/core/src/cache.ts +251 -0
  273. package/packages/core/src/cli.ts +822 -0
  274. package/packages/core/src/code-extractor.ts +696 -0
  275. package/packages/core/src/docker-generator.ts +470 -0
  276. package/packages/core/src/edge-compatible.ts +491 -0
  277. package/packages/core/src/extractors/go-extractor.ts +791 -0
  278. package/packages/core/src/extractors/index.ts +9 -0
  279. package/packages/core/src/extractors/java-extractor.ts +937 -0
  280. package/packages/core/src/extractors/rust-extractor.ts +744 -0
  281. package/packages/core/src/github-client.ts +319 -0
  282. package/packages/core/src/go-generator.ts +356 -0
  283. package/packages/core/src/graphql-extractor.ts +358 -0
  284. package/packages/core/src/index.ts +797 -0
  285. package/packages/core/src/langchain-exporter.ts +617 -0
  286. package/packages/core/src/language-parsers.ts +1114 -0
  287. package/packages/core/src/mcp-introspector.ts +279 -0
  288. package/packages/core/src/monorepo-detector.ts +378 -0
  289. package/packages/core/src/plugins/index.ts +370 -0
  290. package/packages/core/src/plugins/registry.ts +404 -0
  291. package/packages/core/src/plugins/types.ts +215 -0
  292. package/packages/core/src/providers/base-provider.ts +246 -0
  293. package/packages/core/src/providers/bitbucket-client.ts +464 -0
  294. package/packages/core/src/providers/gitlab-client.ts +388 -0
  295. package/packages/core/src/providers/index.ts +176 -0
  296. package/packages/core/src/python-generator.ts +260 -0
  297. package/packages/core/src/queue/index.ts +100 -0
  298. package/packages/core/src/queue/memory-queue.ts +445 -0
  299. package/packages/core/src/queue/redis-queue.ts +578 -0
  300. package/packages/core/src/queue/types.ts +251 -0
  301. package/packages/core/src/readme-extractor.ts +409 -0
  302. package/packages/core/src/schema-generator.ts +638 -0
  303. package/packages/core/src/streaming.ts +999 -0
  304. package/packages/core/src/types.ts +289 -0
  305. package/packages/core/tsconfig.json +9 -0
  306. package/packages/core/tsup.config.ts +25 -0
  307. package/packages/mcp-server/README.md +297 -0
  308. package/packages/mcp-server/package.json +55 -0
  309. package/packages/mcp-server/src/__tests__/mcp-server.test.ts +177 -0
  310. package/packages/mcp-server/src/__tests__/tools.test.ts +217 -0
  311. package/packages/mcp-server/src/index.ts +1206 -0
  312. package/packages/mcp-server/src/prompts/index.ts +601 -0
  313. package/packages/mcp-server/src/tools/export-docker.ts +362 -0
  314. package/packages/mcp-server/src/tools/generate-openapi.ts +162 -0
  315. package/packages/mcp-server/src/tools/monitor-mcp-server.ts +448 -0
  316. package/packages/mcp-server/src/tools/stream-convert.ts +398 -0
  317. package/packages/mcp-server/src/tools/test-mcp-tool.ts +531 -0
  318. package/packages/mcp-server/tsconfig.json +12 -0
  319. package/packages/mcp-server/tsup.config.ts +14 -0
  320. package/packages/openapi-parser/package-lock.json +3028 -0
  321. package/packages/openapi-parser/package.json +41 -0
  322. package/packages/openapi-parser/src/analyzer.ts +700 -0
  323. package/packages/openapi-parser/src/asyncapi-parser.ts +475 -0
  324. package/packages/openapi-parser/src/cli.ts +302 -0
  325. package/packages/openapi-parser/src/generator.ts +570 -0
  326. package/packages/openapi-parser/src/generators/express-analyzer.ts +649 -0
  327. package/packages/openapi-parser/src/generators/fastapi-analyzer.ts +960 -0
  328. package/packages/openapi-parser/src/generators/index.ts +200 -0
  329. package/packages/openapi-parser/src/generators/nextjs-analyzer.ts +768 -0
  330. package/packages/openapi-parser/src/generators/openapi-builder.ts +527 -0
  331. package/packages/openapi-parser/src/generators/types.ts +298 -0
  332. package/packages/openapi-parser/src/graphql-parser.ts +462 -0
  333. package/packages/openapi-parser/src/grpc-parser.ts +649 -0
  334. package/packages/openapi-parser/src/har-parser.ts +723 -0
  335. package/packages/openapi-parser/src/index.ts +635 -0
  336. package/packages/openapi-parser/src/insomnia-parser.ts +614 -0
  337. package/packages/openapi-parser/src/parser.ts +231 -0
  338. package/packages/openapi-parser/src/postman-parser.ts +611 -0
  339. package/packages/openapi-parser/src/ref-resolver.ts +313 -0
  340. package/packages/openapi-parser/src/transformer.ts +459 -0
  341. package/packages/openapi-parser/tests/generators/express.test.ts +209 -0
  342. package/packages/openapi-parser/tests/generators/fastapi.test.ts +236 -0
  343. package/packages/openapi-parser/tests/generators/nextjs.test.ts +273 -0
  344. package/packages/openapi-parser/tests/parsers.test.ts +847 -0
  345. package/packages/openapi-parser/tsconfig.json +9 -0
  346. package/packages/openapi-parser/tsup.config.ts +11 -0
  347. package/packages/registry/package.json +59 -0
  348. package/packages/registry/src/cli.ts +456 -0
  349. package/packages/registry/src/index.ts +44 -0
  350. package/packages/registry/src/popular/github.json +47 -0
  351. package/packages/registry/src/popular/index.ts +55 -0
  352. package/packages/registry/src/popular/linear.json +42 -0
  353. package/packages/registry/src/popular/notion.json +42 -0
  354. package/packages/registry/src/popular/openai.json +40 -0
  355. package/packages/registry/src/popular/resend.json +38 -0
  356. package/packages/registry/src/popular/slack.json +42 -0
  357. package/packages/registry/src/popular/stripe.json +163 -0
  358. package/packages/registry/src/popular/supabase.json +42 -0
  359. package/packages/registry/src/popular/twilio.json +40 -0
  360. package/packages/registry/src/popular/vercel.json +40 -0
  361. package/packages/registry/src/registry.ts +492 -0
  362. package/packages/registry/src/storage.ts +334 -0
  363. package/packages/registry/src/types.ts +275 -0
  364. package/packages/registry/src/updater.ts +208 -0
  365. package/packages/registry/tsconfig.json +10 -0
  366. package/packages/registry/tsup.config.ts +11 -0
  367. package/pnpm-workspace.yaml +3 -0
  368. package/scripts/build-docs.sh +16 -0
  369. package/server.json +9 -0
  370. package/templates/Dockerfile.python.template +60 -0
  371. package/templates/Dockerfile.typescript.template +60 -0
  372. package/templates/docker-compose.template.yml +68 -0
  373. package/tests/fixtures/express-app/index.js +34 -0
  374. package/tests/fixtures/express-app/routes/posts.js +43 -0
  375. package/tests/fixtures/express-app/routes/users.js +58 -0
  376. package/tests/fixtures/fastapi-app/main.py +125 -0
  377. package/tests/fixtures/fastapi-app/routes/admin.py +42 -0
  378. package/tests/fixtures/graphql/simple-schema.graphql +65 -0
  379. package/tests/fixtures/mocks/github-api-responses.json +63 -0
  380. package/tests/fixtures/nextjs-app/app/api/posts/route.ts +55 -0
  381. package/tests/fixtures/nextjs-app/app/api/users/[id]/route.ts +63 -0
  382. package/tests/fixtures/nextjs-app/app/api/users/route.ts +44 -0
  383. package/tests/fixtures/nextjs-app/pages/api/health.ts +28 -0
  384. package/tests/fixtures/openapi/petstore.yaml +179 -0
  385. package/tests/integration/langchain-export.test.ts +405 -0
  386. package/tests/integration/openapi-conversion.test.ts +221 -0
  387. package/tsconfig.json +18 -0
  388. package/vitest.config.ts +32 -0
@@ -0,0 +1,644 @@
1
+ /**
2
+ * Playground V2 Page - Full-featured MCP playground with transport configuration
3
+ * @copyright 2024-2026 nirholas
4
+ * @license MIT
5
+ */
6
+
7
+ 'use client';
8
+
9
+ import { Suspense, useEffect, useCallback, useMemo, useState, useRef } from 'react';
10
+ import { motion, AnimatePresence } from 'framer-motion';
11
+ import {
12
+ Terminal,
13
+ ArrowLeft,
14
+ History,
15
+ Settings,
16
+ X,
17
+ } from 'lucide-react';
18
+ import Link from 'next/link';
19
+
20
+ import Header from '@/components/Header';
21
+ import Footer from '@/components/Footer';
22
+ import ParticleBackground from '@/components/ParticleBackground';
23
+ import { Button } from '@/components/ui/button';
24
+
25
+ // Playground components
26
+ import {
27
+ TransportConfigurator,
28
+ ConnectionStatusV2 as ConnectionStatus,
29
+ CapabilityTabs,
30
+ ToolsPanel,
31
+ ResourcesPanel,
32
+ PromptsPanel,
33
+ ExecutionLogV2 as ExecutionLog,
34
+ EmptyStates,
35
+ FirstTimeGuide,
36
+ ShareButton,
37
+ } from '@/components/playground';
38
+
39
+ // Hooks
40
+ import { usePlayground, useExecutionHistory } from '@/hooks';
41
+ import type { TransportConfig as HooksTransportConfig, McpTool, McpResource, McpPrompt, PlaygroundTab } from '@/hooks/types';
42
+ import type { TransportConfig as ComponentTransportConfig, LogEntry } from '@/components/playground/types';
43
+
44
+ // Local hooks
45
+ import { useUrlState } from './use-url-state';
46
+ import { useShortcuts } from './use-shortcuts';
47
+
48
+ // ============================================================================
49
+ // Type Definitions for Playground
50
+ // We use 'any' assertions to bridge the gap between hook types and component types
51
+ // since they are structurally compatible but TypeScript sees them as different
52
+ // ============================================================================
53
+
54
+ /* eslint-disable @typescript-eslint/no-explicit-any */
55
+ type AnyTool = any;
56
+ type AnyResource = any;
57
+ type AnyPrompt = any;
58
+ type AnyCapabilities = any;
59
+ /* eslint-enable @typescript-eslint/no-explicit-any */
60
+
61
+ // ============================================================================
62
+ // Type Adapters
63
+ // ============================================================================
64
+
65
+ /**
66
+ * Convert hook TransportConfig to component TransportConfig
67
+ */
68
+ function toComponentTransport(config: HooksTransportConfig | null): ComponentTransportConfig | null {
69
+ if (!config) return null;
70
+
71
+ switch (config.type) {
72
+ case 'stdio':
73
+ return {
74
+ type: 'stdio',
75
+ command: config.command,
76
+ args: config.args,
77
+ env: config.env,
78
+ };
79
+ case 'sse':
80
+ case 'http':
81
+ return {
82
+ type: 'sse',
83
+ url: config.url,
84
+ headers: config.headers,
85
+ };
86
+ case 'websocket':
87
+ return {
88
+ type: 'streamable-http',
89
+ url: config.url,
90
+ headers: config.headers,
91
+ };
92
+ default:
93
+ return null;
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Convert component TransportConfig to hook TransportConfig
99
+ */
100
+ function toHooksTransport(config: ComponentTransportConfig): HooksTransportConfig {
101
+ switch (config.type) {
102
+ case 'stdio':
103
+ return {
104
+ type: 'stdio',
105
+ command: config.command,
106
+ args: config.args,
107
+ env: config.env,
108
+ };
109
+ case 'sse':
110
+ return {
111
+ type: 'sse',
112
+ url: config.url,
113
+ headers: config.headers,
114
+ };
115
+ case 'streamable-http':
116
+ return {
117
+ type: 'http',
118
+ url: config.url,
119
+ headers: config.headers,
120
+ };
121
+ }
122
+ }
123
+
124
+ // ============================================================================
125
+ // Main Page Component
126
+ // ============================================================================
127
+
128
+ function PlaygroundV2Content() {
129
+ // Initialize playground hook
130
+ const playground = usePlayground();
131
+
132
+ // Execution history
133
+ const executionHistory = useExecutionHistory({ persist: true });
134
+
135
+ // URL state sync
136
+ useUrlState({
137
+ transportConfig: playground.transportConfig,
138
+ setTransportConfig: playground.setTransportConfig,
139
+ activeTab: playground.activeTab,
140
+ setActiveTab: playground.setActiveTab,
141
+ selectedToolName: playground.selectedTool?.name,
142
+ tools: playground.tools.tools,
143
+ setSelectedTool: playground.setSelectedTool,
144
+ });
145
+
146
+ // Local state
147
+ const [showSettings, setShowSettings] = useState(false);
148
+ const [showHistory, setShowHistory] = useState(false);
149
+ const [showFirstTimeGuide, setShowFirstTimeGuide] = useState(false);
150
+ const searchInputRef = useRef<HTMLInputElement>(null);
151
+
152
+ // Check if first time user
153
+ useEffect(() => {
154
+ if (typeof window !== 'undefined') {
155
+ const hasVisited = localStorage.getItem('mcp-playground-v2-visited');
156
+ if (!hasVisited) {
157
+ setShowFirstTimeGuide(true);
158
+ localStorage.setItem('mcp-playground-v2-visited', 'true');
159
+ }
160
+ }
161
+ }, []);
162
+
163
+ // Keyboard shortcuts
164
+ const executeSelectedTool = useCallback(() => {
165
+ if (playground.selectedTool && playground.activeTab === 'tools') {
166
+ // Trigger execute via the ToolsPanel
167
+ // This is handled by the panel itself
168
+ }
169
+ }, [playground.selectedTool, playground.activeTab]);
170
+
171
+ const focusSearch = useCallback(() => {
172
+ searchInputRef.current?.focus();
173
+ }, []);
174
+
175
+ const clearSelection = useCallback(() => {
176
+ playground.setSelectedTool(null);
177
+ playground.setSelectedResource(null);
178
+ playground.setSelectedPrompt(null);
179
+ }, [playground]);
180
+
181
+ const copyLastResult = useCallback(() => {
182
+ const lastEntry = executionHistory.history[0];
183
+ if (lastEntry?.result) {
184
+ navigator.clipboard.writeText(JSON.stringify(lastEntry.result, null, 2));
185
+ }
186
+ }, [executionHistory.history]);
187
+
188
+ useShortcuts({
189
+ onExecute: executeSelectedTool,
190
+ onFocusSearch: focusSearch,
191
+ onSwitchToTab: (tab: 1 | 2 | 3) => {
192
+ if (tab === 1) playground.setActiveTab('tools');
193
+ else if (tab === 2) playground.setActiveTab('resources');
194
+ else if (tab === 3) playground.setActiveTab('prompts');
195
+ },
196
+ onClearSelection: clearSelection,
197
+ onCopyLastResult: copyLastResult,
198
+ enabled: true,
199
+ });
200
+
201
+ // Connection handlers
202
+ const handleConnect = useCallback(() => {
203
+ if (playground.transportConfig) {
204
+ playground.connection.connect(toHooksTransport(playground.transportConfig as unknown as ComponentTransportConfig));
205
+ }
206
+ }, [playground.transportConfig, playground.connection]);
207
+
208
+ const handleDisconnect = useCallback(() => {
209
+ playground.connection.disconnect();
210
+ }, [playground.connection]);
211
+
212
+ // Transport config change handler
213
+ const handleTransportChange = useCallback((config: ComponentTransportConfig) => {
214
+ playground.setTransportConfig(toHooksTransport(config));
215
+ }, [playground]);
216
+
217
+ // Tool execution handler - uses tool name to avoid type incompatibility
218
+ const handleToolExecute = useCallback((toolName: string, params: Record<string, unknown>) => {
219
+ playground.tools.executeTool(toolName, params);
220
+ }, [playground.tools]);
221
+
222
+ // Wrapper for ToolsPanel that adapts the type
223
+ const handleToolsPanelExecute = useCallback((tool: { name: string }, params: Record<string, unknown>) => {
224
+ handleToolExecute(tool.name, params);
225
+ }, [handleToolExecute]);
226
+
227
+ // Resource read handler
228
+ const handleResourceRead = useCallback((uri: string) => {
229
+ playground.resources.readResource(uri);
230
+ }, [playground.resources]);
231
+
232
+ // Prompt execute handler
233
+ const handlePromptExecute = useCallback((name: string, args?: Record<string, string>) => {
234
+ playground.prompts.getPrompt(name, args);
235
+ }, [playground.prompts]);
236
+
237
+ // Convert execution history to log entries
238
+ const logEntries = useMemo((): LogEntry[] => {
239
+ return executionHistory.history.map((entry, index) => ({
240
+ id: entry.id || `log-${index}`,
241
+ type: entry.success ? 'success' as const : 'error' as const,
242
+ message: `${entry.type}: ${entry.name}`,
243
+ timestamp: entry.timestamp,
244
+ data: entry.result || entry.error,
245
+ }));
246
+ }, [executionHistory.history]);
247
+
248
+ // Counts for capability tabs
249
+ const counts = useMemo(() => ({
250
+ tools: playground.tools.tools.length,
251
+ resources: playground.resources.resources.length,
252
+ prompts: playground.prompts.prompts.length,
253
+ }), [playground.tools.tools.length, playground.resources.resources.length, playground.prompts.prompts.length]);
254
+
255
+ // Last tool execution
256
+ const lastToolExecution = playground.tools.executions[0];
257
+ const toolLastResult = lastToolExecution?.result;
258
+ const toolLastError = lastToolExecution?.error;
259
+ const isToolExecuting = lastToolExecution?.status === 'pending' || lastToolExecution?.status === 'running';
260
+
261
+ // Last resource read
262
+ const lastResourceRead = playground.resources.reads[0];
263
+ const resourceLastContents = lastResourceRead?.contents;
264
+ const resourceLastError = lastResourceRead?.error;
265
+ const isResourceReading = lastResourceRead?.status === 'pending' || lastResourceRead?.status === 'loading';
266
+
267
+ // Last prompt execution
268
+ const lastPromptExecution = playground.prompts.executions[0];
269
+ const promptLastMessages = lastPromptExecution?.messages;
270
+ const promptLastError = lastPromptExecution?.error;
271
+ const isPromptExecuting = lastPromptExecution?.status === 'pending' || lastPromptExecution?.status === 'loading';
272
+
273
+ // Determine page state
274
+ const isConnected = playground.connection.status === 'connected';
275
+ const isConnecting = playground.connection.status === 'connecting';
276
+ const hasError = playground.connection.status === 'error';
277
+
278
+ return (
279
+ <main id="main-content" className="relative min-h-screen flex flex-col bg-black">
280
+ <ParticleBackground />
281
+ <Header />
282
+
283
+ <div className="container mx-auto px-4 pt-24 pb-8 flex-1 flex flex-col">
284
+ {/* Back link and actions */}
285
+ <motion.div
286
+ initial={{ opacity: 0, x: -20 }}
287
+ animate={{ opacity: 1, x: 0 }}
288
+ className="mb-6 flex items-center justify-between"
289
+ >
290
+ <Link
291
+ href="/"
292
+ className="inline-flex items-center gap-2 text-sm text-neutral-400 hover:text-white transition-colors"
293
+ >
294
+ <ArrowLeft className="w-4 h-4" />
295
+ Back to Home
296
+ </Link>
297
+
298
+ <div className="flex items-center gap-2">
299
+ <Button
300
+ onClick={() => setShowHistory(!showHistory)}
301
+ variant="outline"
302
+ size="sm"
303
+ className="gap-2"
304
+ >
305
+ <History className="w-4 h-4" />
306
+ <span className="hidden sm:inline">History</span>
307
+ </Button>
308
+ <ShareButton
309
+ transportConfig={toComponentTransport(playground.transportConfig)}
310
+ activeTab={playground.activeTab}
311
+ selectedToolName={playground.selectedTool?.name}
312
+ />
313
+ </div>
314
+ </motion.div>
315
+
316
+ {/* Page header */}
317
+ <motion.div
318
+ initial={{ opacity: 0, y: 20 }}
319
+ animate={{ opacity: 1, y: 0 }}
320
+ className="text-center mb-8"
321
+ >
322
+ <div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-white/5 border border-neutral-800 mb-6">
323
+ <Terminal className="w-4 h-4 text-white" />
324
+ <span className="text-sm font-medium text-neutral-400">
325
+ MCP <span className="text-white font-semibold">Playground</span>
326
+ </span>
327
+ <span className="ml-2 px-2 py-0.5 text-xs bg-green-500/20 text-green-400 rounded-full">
328
+ v2
329
+ </span>
330
+ </div>
331
+
332
+ <h1 className="text-4xl md:text-5xl font-bold text-white mb-4">
333
+ Interactive MCP Testing
334
+ </h1>
335
+ <p className="text-lg text-neutral-400 max-w-2xl mx-auto">
336
+ Connect to any MCP server and test tools, resources, and prompts interactively.
337
+ </p>
338
+ </motion.div>
339
+
340
+ {/* First time guide modal */}
341
+ <AnimatePresence>
342
+ {showFirstTimeGuide && (
343
+ <motion.div
344
+ initial={{ opacity: 0 }}
345
+ animate={{ opacity: 1 }}
346
+ exit={{ opacity: 0 }}
347
+ className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/80 backdrop-blur-sm"
348
+ onClick={() => setShowFirstTimeGuide(false)}
349
+ >
350
+ <motion.div
351
+ initial={{ scale: 0.95, opacity: 0 }}
352
+ animate={{ scale: 1, opacity: 1 }}
353
+ exit={{ scale: 0.95, opacity: 0 }}
354
+ className="relative max-w-2xl w-full max-h-[80vh] overflow-y-auto bg-neutral-900 border border-neutral-800 rounded-xl"
355
+ onClick={(e) => e.stopPropagation()}
356
+ >
357
+ <button
358
+ onClick={() => setShowFirstTimeGuide(false)}
359
+ className="absolute top-4 right-4 text-neutral-400 hover:text-white"
360
+ >
361
+ <X className="w-5 h-5" />
362
+ </button>
363
+ <FirstTimeGuide onGetStarted={() => setShowFirstTimeGuide(false)} />
364
+ </motion.div>
365
+ </motion.div>
366
+ )}
367
+ </AnimatePresence>
368
+
369
+ {/* Main content area with optional sidebar */}
370
+ <div className="flex-1 flex flex-col lg:flex-row gap-6">
371
+ {/* Main panel */}
372
+ <div className="flex-1 flex flex-col gap-6 min-w-0">
373
+ {/* Connection Section */}
374
+ <motion.section
375
+ initial={{ opacity: 0, y: 20 }}
376
+ animate={{ opacity: 1, y: 0 }}
377
+ transition={{ delay: 0.1 }}
378
+ className="p-4 md:p-6 rounded-2xl border border-neutral-800 bg-neutral-900/50 backdrop-blur-xl"
379
+ >
380
+ <div className="flex flex-col gap-4">
381
+ <TransportConfigurator
382
+ value={toComponentTransport(playground.transportConfig)}
383
+ onChange={handleTransportChange}
384
+ disabled={isConnected || isConnecting}
385
+ />
386
+ <ConnectionStatus
387
+ status={playground.connection.status}
388
+ sessionId={playground.connection.sessionId}
389
+ serverInfo={playground.connection.serverInfo}
390
+ capabilities={playground.connection.capabilities as AnyCapabilities}
391
+ error={playground.connection.error}
392
+ onConnect={handleConnect}
393
+ onDisconnect={handleDisconnect}
394
+ onDismissError={playground.connection.clearError}
395
+ />
396
+ </div>
397
+ </motion.section>
398
+
399
+ {/* Capabilities Section */}
400
+ {isConnected ? (
401
+ <motion.section
402
+ initial={{ opacity: 0, y: 20 }}
403
+ animate={{ opacity: 1, y: 0 }}
404
+ transition={{ delay: 0.2 }}
405
+ className="flex-1 flex flex-col min-h-[400px] md:min-h-[500px] rounded-2xl border border-neutral-800 bg-neutral-900/50 backdrop-blur-xl overflow-hidden"
406
+ >
407
+ {/* Tabs */}
408
+ <div className="p-3 md:p-4 border-b border-neutral-800">
409
+ <CapabilityTabs
410
+ activeTab={playground.activeTab}
411
+ onTabChange={playground.setActiveTab}
412
+ capabilities={playground.connection.capabilities as AnyCapabilities}
413
+ counts={counts}
414
+ />
415
+ </div>
416
+
417
+ {/* Tab Content */}
418
+ <div className="flex-1 overflow-hidden">
419
+ <AnimatePresence mode="wait">
420
+ {playground.activeTab === 'tools' && (
421
+ <motion.div
422
+ key="tools"
423
+ initial={{ opacity: 0, x: -10 }}
424
+ animate={{ opacity: 1, x: 0 }}
425
+ exit={{ opacity: 0, x: 10 }}
426
+ className="h-full"
427
+ >
428
+ {playground.tools.tools.length > 0 ? (
429
+ <ToolsPanel
430
+ tools={playground.tools.tools as AnyTool[]}
431
+ selectedTool={playground.selectedTool as AnyTool}
432
+ onSelectTool={(tool: AnyTool) => playground.setSelectedTool(tool)}
433
+ onExecute={handleToolsPanelExecute}
434
+ isExecuting={isToolExecuting}
435
+ lastResult={toolLastResult}
436
+ lastError={toolLastError}
437
+ />
438
+ ) : (
439
+ <EmptyStates type="no-tools" />
440
+ )}
441
+ </motion.div>
442
+ )}
443
+
444
+ {playground.activeTab === 'resources' && (
445
+ <motion.div
446
+ key="resources"
447
+ initial={{ opacity: 0, x: -10 }}
448
+ animate={{ opacity: 1, x: 0 }}
449
+ exit={{ opacity: 0, x: 10 }}
450
+ className="h-full"
451
+ >
452
+ {playground.resources.resources.length > 0 ? (
453
+ <ResourcesPanel
454
+ resources={playground.resources.resources as AnyResource[]}
455
+ selectedResource={playground.selectedResource as AnyResource}
456
+ onSelectResource={(res: AnyResource) => playground.setSelectedResource(res)}
457
+ onRead={handleResourceRead}
458
+ isReading={isResourceReading}
459
+ lastContents={resourceLastContents as any}
460
+ lastError={resourceLastError}
461
+ />
462
+ ) : (
463
+ <EmptyStates type="no-resources" />
464
+ )}
465
+ </motion.div>
466
+ )}
467
+
468
+ {playground.activeTab === 'prompts' && (
469
+ <motion.div
470
+ key="prompts"
471
+ initial={{ opacity: 0, x: -10 }}
472
+ animate={{ opacity: 1, x: 0 }}
473
+ exit={{ opacity: 0, x: 10 }}
474
+ className="h-full"
475
+ >
476
+ {playground.prompts.prompts.length > 0 ? (
477
+ <PromptsPanel
478
+ prompts={playground.prompts.prompts as AnyPrompt[]}
479
+ selectedPrompt={playground.selectedPrompt as AnyPrompt}
480
+ onSelectPrompt={(prompt: AnyPrompt) => playground.setSelectedPrompt(prompt)}
481
+ onExecute={handlePromptExecute}
482
+ isExecuting={isPromptExecuting}
483
+ lastMessages={promptLastMessages as any}
484
+ lastError={promptLastError}
485
+ />
486
+ ) : (
487
+ <EmptyStates type="no-prompts" />
488
+ )}
489
+ </motion.div>
490
+ )}
491
+ </AnimatePresence>
492
+ </div>
493
+ </motion.section>
494
+ ) : (
495
+ <motion.section
496
+ initial={{ opacity: 0, y: 20 }}
497
+ animate={{ opacity: 1, y: 0 }}
498
+ transition={{ delay: 0.2 }}
499
+ className="flex-1 flex items-center justify-center min-h-[400px] rounded-2xl border border-neutral-800 bg-neutral-900/50 backdrop-blur-xl"
500
+ >
501
+ <EmptyStates
502
+ type="not-connected"
503
+ onAction={playground.transportConfig ? handleConnect : undefined}
504
+ />
505
+ </motion.section>
506
+ )}
507
+ </div>
508
+
509
+ {/* History sidebar - desktop */}
510
+ <AnimatePresence>
511
+ {showHistory && (
512
+ <motion.aside
513
+ initial={{ opacity: 0, x: 20 }}
514
+ animate={{ opacity: 1, x: 0 }}
515
+ exit={{ opacity: 0, x: 20 }}
516
+ className="hidden lg:block w-80 flex-shrink-0"
517
+ >
518
+ <div className="sticky top-24 rounded-2xl border border-neutral-800 bg-neutral-900/50 backdrop-blur-xl overflow-hidden">
519
+ <div className="p-4 border-b border-neutral-800 flex items-center justify-between">
520
+ <h3 className="font-semibold text-white flex items-center gap-2">
521
+ <History className="w-4 h-4" />
522
+ Execution History
523
+ </h3>
524
+ <Button
525
+ onClick={executionHistory.clear}
526
+ variant="ghost"
527
+ size="sm"
528
+ className="text-neutral-400 hover:text-white"
529
+ >
530
+ Clear
531
+ </Button>
532
+ </div>
533
+ <ExecutionLog
534
+ entries={logEntries}
535
+ maxHeight={500}
536
+ onClear={executionHistory.clear}
537
+ />
538
+ </div>
539
+ </motion.aside>
540
+ )}
541
+ </AnimatePresence>
542
+ </div>
543
+
544
+ {/* Mobile history panel */}
545
+ <AnimatePresence>
546
+ {showHistory && (
547
+ <motion.div
548
+ initial={{ opacity: 0, y: 20 }}
549
+ animate={{ opacity: 1, y: 0 }}
550
+ exit={{ opacity: 0, y: 20 }}
551
+ className="lg:hidden mt-6"
552
+ >
553
+ <div className="rounded-2xl border border-neutral-800 bg-neutral-900/50 backdrop-blur-xl overflow-hidden">
554
+ <div className="p-4 border-b border-neutral-800 flex items-center justify-between">
555
+ <h3 className="font-semibold text-white flex items-center gap-2">
556
+ <History className="w-4 h-4" />
557
+ Execution History
558
+ </h3>
559
+ <div className="flex items-center gap-2">
560
+ <Button
561
+ onClick={executionHistory.clear}
562
+ variant="ghost"
563
+ size="sm"
564
+ className="text-neutral-400 hover:text-white"
565
+ >
566
+ Clear
567
+ </Button>
568
+ <Button
569
+ onClick={() => setShowHistory(false)}
570
+ variant="ghost"
571
+ size="sm"
572
+ >
573
+ <X className="w-4 h-4" />
574
+ </Button>
575
+ </div>
576
+ </div>
577
+ <ExecutionLog
578
+ entries={logEntries}
579
+ maxHeight={300}
580
+ onClear={executionHistory.clear}
581
+ />
582
+ </div>
583
+ </motion.div>
584
+ )}
585
+ </AnimatePresence>
586
+ </div>
587
+
588
+ <Footer />
589
+ </main>
590
+ );
591
+ }
592
+
593
+ // ============================================================================
594
+ // Page Export
595
+ // ============================================================================
596
+
597
+ export default function PlaygroundV2Page() {
598
+ return (
599
+ <Suspense fallback={<PlaygroundSkeleton />}>
600
+ <PlaygroundV2Content />
601
+ </Suspense>
602
+ );
603
+ }
604
+
605
+ // ============================================================================
606
+ // Skeleton Component
607
+ // ============================================================================
608
+
609
+ function PlaygroundSkeleton() {
610
+ return (
611
+ <main className="relative min-h-screen flex flex-col bg-black">
612
+ <div className="container mx-auto px-4 pt-24 pb-8 flex-1">
613
+ {/* Header skeleton */}
614
+ <div className="text-center mb-8">
615
+ <div className="h-8 w-48 bg-neutral-800 rounded-full mx-auto mb-6 animate-pulse" />
616
+ <div className="h-12 w-96 bg-neutral-800 rounded mx-auto mb-4 animate-pulse" />
617
+ <div className="h-6 w-80 bg-neutral-800 rounded mx-auto animate-pulse" />
618
+ </div>
619
+
620
+ {/* Connection section skeleton */}
621
+ <div className="p-6 rounded-2xl border border-neutral-800 bg-neutral-900/50 mb-6">
622
+ <div className="flex flex-col lg:flex-row gap-6">
623
+ <div className="flex-1 space-y-4">
624
+ <div className="h-10 bg-neutral-800 rounded animate-pulse" />
625
+ <div className="h-10 bg-neutral-800 rounded animate-pulse" />
626
+ </div>
627
+ <div className="lg:w-80 h-32 bg-neutral-800 rounded animate-pulse" />
628
+ </div>
629
+ </div>
630
+
631
+ {/* Main content skeleton */}
632
+ <div className="min-h-[500px] rounded-2xl border border-neutral-800 bg-neutral-900/50 p-6">
633
+ <div className="h-10 w-64 bg-neutral-800 rounded mb-6 animate-pulse" />
634
+ <div className="grid grid-cols-2 gap-4">
635
+ <div className="h-24 bg-neutral-800 rounded animate-pulse" />
636
+ <div className="h-24 bg-neutral-800 rounded animate-pulse" />
637
+ <div className="h-24 bg-neutral-800 rounded animate-pulse" />
638
+ <div className="h-24 bg-neutral-800 rounded animate-pulse" />
639
+ </div>
640
+ </div>
641
+ </div>
642
+ </main>
643
+ );
644
+ }