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,690 @@
1
+ /**
2
+ * Docker Export Component - Generate Dockerfile and docker-compose for MCP servers
3
+ * @copyright 2024-2026 nirholas
4
+ * @license MIT
5
+ */
6
+
7
+ 'use client';
8
+
9
+ import { useState, useMemo, useCallback } from 'react';
10
+ import { motion, AnimatePresence } from 'framer-motion';
11
+ import {
12
+ Container,
13
+ Download,
14
+ Copy,
15
+ Check,
16
+ Settings,
17
+ Code,
18
+ FileText,
19
+ Terminal,
20
+ ChevronDown,
21
+ ChevronUp,
22
+ Play,
23
+ Package,
24
+ Shield,
25
+ Cpu,
26
+ HardDrive,
27
+ Network,
28
+ Eye,
29
+ EyeOff,
30
+ } from 'lucide-react';
31
+ import type { DockerConfig, DockerExportOptions, ConversionResult } from '@/types';
32
+
33
+ interface DockerExportProps {
34
+ result: ConversionResult;
35
+ serverName?: string;
36
+ onExport?: (config: DockerConfig) => void;
37
+ }
38
+
39
+ const BASE_IMAGES = [
40
+ { value: 'node:20-alpine', label: 'Node.js 20 Alpine', size: '~180MB' },
41
+ { value: 'node:20-slim', label: 'Node.js 20 Slim', size: '~240MB' },
42
+ { value: 'node:20', label: 'Node.js 20', size: '~1GB' },
43
+ { value: 'python:3.11-alpine', label: 'Python 3.11 Alpine', size: '~50MB' },
44
+ { value: 'python:3.11-slim', label: 'Python 3.11 Slim', size: '~150MB' },
45
+ { value: 'python:3.11', label: 'Python 3.11', size: '~900MB' },
46
+ ];
47
+
48
+ const DEFAULT_OPTIONS: DockerExportOptions = {
49
+ baseImage: 'node:20-alpine',
50
+ port: 3000,
51
+ exposePorts: [3000],
52
+ envVars: {},
53
+ volumes: [],
54
+ healthCheck: true,
55
+ multiStage: true,
56
+ runAsNonRoot: true,
57
+ labels: true,
58
+ };
59
+
60
+ export default function DockerExport({
61
+ result,
62
+ serverName = 'mcp-server',
63
+ onExport,
64
+ }: DockerExportProps) {
65
+ const [options, setOptions] = useState<DockerExportOptions>(DEFAULT_OPTIONS);
66
+ const [activeTab, setActiveTab] = useState<'dockerfile' | 'compose' | 'env' | 'commands'>('dockerfile');
67
+ const [showAdvanced, setShowAdvanced] = useState(false);
68
+ const [copiedField, setCopiedField] = useState<string | null>(null);
69
+ const [showPreview, setShowPreview] = useState(true);
70
+
71
+ const sanitizedServerName = useMemo(() =>
72
+ serverName.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/--+/g, '-'),
73
+ [serverName]
74
+ );
75
+
76
+ // Generate Dockerfile content
77
+ const dockerfile = useMemo(() => {
78
+ const isNode = options.baseImage.includes('node');
79
+ const isPython = options.baseImage.includes('python');
80
+ const isAlpine = options.baseImage.includes('alpine');
81
+
82
+ let content = `# ${sanitizedServerName} MCP Server
83
+ # Generated by github-to-mcp
84
+ # https://github-to-mcp.dev
85
+
86
+ `;
87
+
88
+ if (options.multiStage && isNode) {
89
+ content += `# Build stage
90
+ FROM ${options.baseImage} AS builder
91
+
92
+ WORKDIR /app
93
+
94
+ # Copy package files
95
+ COPY package*.json ./
96
+
97
+ # Install dependencies
98
+ RUN npm ci --only=production
99
+
100
+ # Copy source files
101
+ COPY . .
102
+
103
+ # Build if needed
104
+ RUN npm run build --if-present
105
+
106
+ # Production stage
107
+ FROM ${options.baseImage} AS production
108
+
109
+ `;
110
+ } else {
111
+ content += `FROM ${options.baseImage}
112
+
113
+ `;
114
+ }
115
+
116
+ if (options.labels) {
117
+ content += `# Labels
118
+ LABEL org.opencontainers.image.title="${sanitizedServerName}"
119
+ LABEL org.opencontainers.image.description="MCP Server with ${result.tools.length} tools"
120
+ LABEL org.opencontainers.image.source="${result.repository.url}"
121
+ LABEL org.opencontainers.image.vendor="github-to-mcp"
122
+
123
+ `;
124
+ }
125
+
126
+ content += `WORKDIR /app
127
+
128
+ `;
129
+
130
+ // Install dependencies for Alpine
131
+ if (isAlpine && !options.multiStage) {
132
+ if (isNode) {
133
+ content += `# Install dependencies
134
+ RUN apk add --no-cache dumb-init
135
+
136
+ `;
137
+ } else if (isPython) {
138
+ content += `# Install dependencies
139
+ RUN apk add --no-cache gcc musl-dev libffi-dev
140
+
141
+ `;
142
+ }
143
+ }
144
+
145
+ // Non-root user
146
+ if (options.runAsNonRoot) {
147
+ if (isAlpine) {
148
+ content += `# Create non-root user
149
+ RUN addgroup -g 1001 -S mcpuser && \\
150
+ adduser -S -D -H -u 1001 -s /sbin/nologin -G mcpuser mcpuser
151
+
152
+ `;
153
+ } else {
154
+ content += `# Create non-root user
155
+ RUN groupadd -g 1001 mcpuser && \\
156
+ useradd -r -u 1001 -g mcpuser mcpuser
157
+
158
+ `;
159
+ }
160
+ }
161
+
162
+ // Copy files
163
+ if (options.multiStage && isNode) {
164
+ content += `# Copy from builder
165
+ COPY --from=builder /app/node_modules ./node_modules
166
+ COPY --from=builder /app/dist ./dist
167
+ COPY --from=builder /app/package.json ./
168
+
169
+ `;
170
+ } else if (isNode) {
171
+ content += `# Copy package files and install
172
+ COPY package*.json ./
173
+ RUN npm ci --only=production
174
+
175
+ # Copy application
176
+ COPY . .
177
+
178
+ `;
179
+ } else if (isPython) {
180
+ content += `# Copy requirements and install
181
+ COPY requirements.txt ./
182
+ RUN pip install --no-cache-dir -r requirements.txt
183
+
184
+ # Copy application
185
+ COPY . .
186
+
187
+ `;
188
+ }
189
+
190
+ // Environment variables
191
+ if (Object.keys(options.envVars).length > 0) {
192
+ content += `# Environment variables\n`;
193
+ Object.entries(options.envVars).forEach(([key, value]) => {
194
+ content += `ENV ${key}=${value}\n`;
195
+ });
196
+ content += '\n';
197
+ }
198
+
199
+ content += `# Set environment
200
+ ENV NODE_ENV=production
201
+ ENV PORT=${options.port}
202
+
203
+ `;
204
+
205
+ // Expose ports
206
+ if (options.exposePorts.length > 0) {
207
+ content += `# Expose ports\n`;
208
+ options.exposePorts.forEach(port => {
209
+ content += `EXPOSE ${port}\n`;
210
+ });
211
+ content += '\n';
212
+ }
213
+
214
+ // Health check
215
+ if (options.healthCheck) {
216
+ content += `# Health check
217
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\
218
+ CMD ${isNode ? 'node -e "require(\'http\').get(\'http://localhost:' + options.port + '/health\', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"' : 'curl -f http://localhost:' + options.port + '/health || exit 1'}
219
+
220
+ `;
221
+ }
222
+
223
+ // Set user
224
+ if (options.runAsNonRoot) {
225
+ content += `# Run as non-root user
226
+ USER mcpuser
227
+
228
+ `;
229
+ }
230
+
231
+ // Entrypoint
232
+ if (isNode) {
233
+ if (isAlpine) {
234
+ content += `# Start server
235
+ ENTRYPOINT ["dumb-init", "--"]
236
+ CMD ["node", "dist/index.js"]
237
+ `;
238
+ } else {
239
+ content += `# Start server
240
+ CMD ["node", "dist/index.js"]
241
+ `;
242
+ }
243
+ } else if (isPython) {
244
+ content += `# Start server
245
+ CMD ["python", "-m", "server"]
246
+ `;
247
+ }
248
+
249
+ return content;
250
+ }, [options, sanitizedServerName, result]);
251
+
252
+ // Generate docker-compose content
253
+ const dockerCompose = useMemo(() => {
254
+ let content = `# ${sanitizedServerName} Docker Compose
255
+ # Generated by github-to-mcp
256
+
257
+ version: '3.8'
258
+
259
+ services:
260
+ ${sanitizedServerName}:
261
+ build:
262
+ context: .
263
+ dockerfile: Dockerfile
264
+ container_name: ${sanitizedServerName}
265
+ restart: unless-stopped
266
+ ports:
267
+ `;
268
+
269
+ options.exposePorts.forEach(port => {
270
+ content += ` - "${port}:${port}"\n`;
271
+ });
272
+
273
+ content += ` environment:
274
+ - NODE_ENV=production
275
+ `;
276
+
277
+ Object.entries(options.envVars).forEach(([key, value]) => {
278
+ content += ` - ${key}=${value}\n`;
279
+ });
280
+
281
+ if (options.volumes.length > 0) {
282
+ content += ` volumes:\n`;
283
+ options.volumes.forEach(vol => {
284
+ content += ` - ${vol}\n`;
285
+ });
286
+ }
287
+
288
+ if (options.healthCheck) {
289
+ content += ` healthcheck:
290
+ test: ["CMD", "curl", "-f", "http://localhost:${options.port}/health"]
291
+ interval: 30s
292
+ timeout: 10s
293
+ retries: 3
294
+ start_period: 10s
295
+ `;
296
+ }
297
+
298
+ content += ` networks:
299
+ - mcp-network
300
+
301
+ networks:
302
+ mcp-network:
303
+ driver: bridge
304
+ `;
305
+
306
+ return content;
307
+ }, [options, sanitizedServerName]);
308
+
309
+ // Generate .env.example content
310
+ const envExample = useMemo(() => {
311
+ let content = `# ${sanitizedServerName} Environment Variables
312
+ # Copy this file to .env and fill in the values
313
+
314
+ # Server Configuration
315
+ PORT=${options.port}
316
+ NODE_ENV=production
317
+
318
+ # API Keys (if needed)
319
+ # OPENAI_API_KEY=sk-...
320
+ # ANTHROPIC_API_KEY=sk-ant-...
321
+
322
+ # Custom Environment Variables
323
+ `;
324
+
325
+ Object.entries(options.envVars).forEach(([key, value]) => {
326
+ content += `${key}=${value}\n`;
327
+ });
328
+
329
+ return content;
330
+ }, [options, sanitizedServerName]);
331
+
332
+ // Generate build/run commands
333
+ const commands = useMemo(() => ({
334
+ build: `docker build -t ${sanitizedServerName}:latest .`,
335
+ run: `docker run -d --name ${sanitizedServerName} -p ${options.port}:${options.port} ${sanitizedServerName}:latest`,
336
+ stop: `docker stop ${sanitizedServerName}`,
337
+ logs: `docker logs -f ${sanitizedServerName}`,
338
+ compose_up: `docker-compose up -d`,
339
+ compose_down: `docker-compose down`,
340
+ compose_logs: `docker-compose logs -f`,
341
+ }), [sanitizedServerName, options.port]);
342
+
343
+ const copyToClipboard = useCallback(async (text: string, field: string) => {
344
+ await navigator.clipboard.writeText(text);
345
+ setCopiedField(field);
346
+ setTimeout(() => setCopiedField(null), 2000);
347
+ }, []);
348
+
349
+ const downloadFile = useCallback((content: string, filename: string) => {
350
+ const blob = new Blob([content], { type: 'text/plain' });
351
+ const url = URL.createObjectURL(blob);
352
+ const a = document.createElement('a');
353
+ a.href = url;
354
+ a.download = filename;
355
+ document.body.appendChild(a);
356
+ a.click();
357
+ document.body.removeChild(a);
358
+ URL.revokeObjectURL(url);
359
+ }, []);
360
+
361
+ const downloadAll = useCallback(() => {
362
+ downloadFile(dockerfile, 'Dockerfile');
363
+ downloadFile(dockerCompose, 'docker-compose.yml');
364
+ downloadFile(envExample, '.env.example');
365
+
366
+ if (onExport) {
367
+ onExport({
368
+ dockerfile,
369
+ dockerCompose,
370
+ envExample,
371
+ buildCommand: commands.build,
372
+ runCommand: commands.run,
373
+ serverName: sanitizedServerName,
374
+ });
375
+ }
376
+ }, [dockerfile, dockerCompose, envExample, commands, downloadFile, onExport, sanitizedServerName]);
377
+
378
+ const TabButton = ({ id, label, icon: Icon }: { id: typeof activeTab; label: string; icon: typeof FileText }) => (
379
+ <button
380
+ onClick={() => setActiveTab(id)}
381
+ className={`flex items-center gap-2 px-4 py-2 text-sm font-medium rounded-lg transition-colors ${
382
+ activeTab === id
383
+ ? 'bg-white text-black'
384
+ : 'text-neutral-400 hover:text-white hover:bg-white/5'
385
+ }`}
386
+ >
387
+ <Icon className="w-4 h-4" />
388
+ {label}
389
+ </button>
390
+ );
391
+
392
+ const CopyButton = ({ text, field }: { text: string; field: string }) => (
393
+ <button
394
+ onClick={() => copyToClipboard(text, field)}
395
+ className="p-2 rounded-lg bg-white/10 hover:bg-white/20 transition-colors"
396
+ title="Copy to clipboard"
397
+ >
398
+ {copiedField === field ? (
399
+ <Check className="w-4 h-4 text-green-400" />
400
+ ) : (
401
+ <Copy className="w-4 h-4" />
402
+ )}
403
+ </button>
404
+ );
405
+
406
+ return (
407
+ <div className="space-y-6">
408
+ {/* Header */}
409
+ <motion.div
410
+ initial={{ opacity: 0, y: 20 }}
411
+ animate={{ opacity: 1, y: 0 }}
412
+ className="flex items-center justify-between"
413
+ >
414
+ <div className="flex items-center gap-3">
415
+ <div className="w-12 h-12 rounded-xl bg-blue-500/10 border border-blue-500/20 flex items-center justify-center">
416
+ <Container className="w-6 h-6 text-blue-400" />
417
+ </div>
418
+ <div>
419
+ <h2 className="text-xl font-semibold text-white">Docker Export</h2>
420
+ <p className="text-sm text-neutral-400">
421
+ Generate production-ready Docker configuration
422
+ </p>
423
+ </div>
424
+ </div>
425
+ <button
426
+ onClick={downloadAll}
427
+ className="flex items-center gap-2 px-4 py-2 bg-white text-black rounded-lg font-medium hover:bg-neutral-200 transition-colors"
428
+ >
429
+ <Download className="w-4 h-4" />
430
+ Download All
431
+ </button>
432
+ </motion.div>
433
+
434
+ {/* Configuration Options */}
435
+ <motion.div
436
+ initial={{ opacity: 0, y: 20 }}
437
+ animate={{ opacity: 1, y: 0 }}
438
+ transition={{ delay: 0.1 }}
439
+ className="rounded-xl border border-neutral-800 bg-neutral-900/50 backdrop-blur-xl overflow-hidden"
440
+ >
441
+ <button
442
+ onClick={() => setShowAdvanced(!showAdvanced)}
443
+ className="w-full p-4 flex items-center justify-between hover:bg-white/5 transition-colors"
444
+ >
445
+ <div className="flex items-center gap-2">
446
+ <Settings className="w-5 h-5 text-neutral-400" />
447
+ <span className="font-medium text-white">Configuration Options</span>
448
+ </div>
449
+ {showAdvanced ? (
450
+ <ChevronUp className="w-5 h-5 text-neutral-400" />
451
+ ) : (
452
+ <ChevronDown className="w-5 h-5 text-neutral-400" />
453
+ )}
454
+ </button>
455
+
456
+ <AnimatePresence>
457
+ {showAdvanced && (
458
+ <motion.div
459
+ initial={{ height: 0, opacity: 0 }}
460
+ animate={{ height: 'auto', opacity: 1 }}
461
+ exit={{ height: 0, opacity: 0 }}
462
+ className="border-t border-neutral-800"
463
+ >
464
+ <div className="p-4 grid grid-cols-1 md:grid-cols-2 gap-4">
465
+ {/* Base Image */}
466
+ <div>
467
+ <label className="block text-sm font-medium text-neutral-300 mb-2">
468
+ <Package className="w-4 h-4 inline mr-1" />
469
+ Base Image
470
+ </label>
471
+ <select
472
+ value={options.baseImage}
473
+ onChange={(e) => setOptions(prev => ({ ...prev, baseImage: e.target.value }))}
474
+ className="w-full p-2 rounded-lg bg-black border border-neutral-700 text-white text-sm focus:outline-none focus:border-white/50"
475
+ >
476
+ {BASE_IMAGES.map(img => (
477
+ <option key={img.value} value={img.value}>
478
+ {img.label} ({img.size})
479
+ </option>
480
+ ))}
481
+ </select>
482
+ </div>
483
+
484
+ {/* Port */}
485
+ <div>
486
+ <label className="block text-sm font-medium text-neutral-300 mb-2">
487
+ <Network className="w-4 h-4 inline mr-1" />
488
+ Port
489
+ </label>
490
+ <input
491
+ type="number"
492
+ value={options.port}
493
+ onChange={(e) => setOptions(prev => ({
494
+ ...prev,
495
+ port: parseInt(e.target.value) || 3000,
496
+ exposePorts: [parseInt(e.target.value) || 3000]
497
+ }))}
498
+ className="w-full p-2 rounded-lg bg-black border border-neutral-700 text-white text-sm focus:outline-none focus:border-white/50"
499
+ min={1}
500
+ max={65535}
501
+ />
502
+ </div>
503
+
504
+ {/* Toggle Options */}
505
+ <div className="md:col-span-2 grid grid-cols-2 md:grid-cols-4 gap-3">
506
+ {[
507
+ { key: 'multiStage', label: 'Multi-stage Build', icon: Cpu },
508
+ { key: 'healthCheck', label: 'Health Check', icon: Shield },
509
+ { key: 'runAsNonRoot', label: 'Non-root User', icon: Shield },
510
+ { key: 'labels', label: 'OCI Labels', icon: FileText },
511
+ ].map(({ key, label, icon: Icon }) => (
512
+ <button
513
+ key={key}
514
+ onClick={() => setOptions(prev => ({ ...prev, [key]: !prev[key as keyof DockerExportOptions] }))}
515
+ className={`flex items-center gap-2 p-3 rounded-lg border transition-colors ${
516
+ options[key as keyof DockerExportOptions]
517
+ ? 'bg-white/10 border-white/30 text-white'
518
+ : 'bg-black/30 border-neutral-700 text-neutral-400'
519
+ }`}
520
+ >
521
+ <Icon className="w-4 h-4" />
522
+ <span className="text-sm">{label}</span>
523
+ </button>
524
+ ))}
525
+ </div>
526
+ </div>
527
+ </motion.div>
528
+ )}
529
+ </AnimatePresence>
530
+ </motion.div>
531
+
532
+ {/* File Tabs */}
533
+ <motion.div
534
+ initial={{ opacity: 0, y: 20 }}
535
+ animate={{ opacity: 1, y: 0 }}
536
+ transition={{ delay: 0.2 }}
537
+ className="rounded-xl border border-neutral-800 bg-neutral-900/50 backdrop-blur-xl overflow-hidden"
538
+ >
539
+ <div className="p-3 border-b border-neutral-800 flex items-center justify-between">
540
+ <div className="flex gap-2">
541
+ <TabButton id="dockerfile" label="Dockerfile" icon={FileText} />
542
+ <TabButton id="compose" label="Compose" icon={HardDrive} />
543
+ <TabButton id="env" label=".env" icon={Settings} />
544
+ <TabButton id="commands" label="Commands" icon={Terminal} />
545
+ </div>
546
+ <button
547
+ onClick={() => setShowPreview(!showPreview)}
548
+ className="p-2 rounded-lg bg-white/10 hover:bg-white/20 transition-colors"
549
+ title={showPreview ? 'Hide preview' : 'Show preview'}
550
+ >
551
+ {showPreview ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
552
+ </button>
553
+ </div>
554
+
555
+ <AnimatePresence mode="wait">
556
+ {showPreview && (
557
+ <motion.div
558
+ key={activeTab}
559
+ initial={{ opacity: 0, y: 10 }}
560
+ animate={{ opacity: 1, y: 0 }}
561
+ exit={{ opacity: 0, y: -10 }}
562
+ className="p-4"
563
+ >
564
+ {activeTab === 'dockerfile' && (
565
+ <div>
566
+ <div className="flex items-center justify-between mb-3">
567
+ <span className="text-sm text-neutral-400 font-mono">Dockerfile</span>
568
+ <div className="flex gap-2">
569
+ <CopyButton text={dockerfile} field="dockerfile" />
570
+ <button
571
+ onClick={() => downloadFile(dockerfile, 'Dockerfile')}
572
+ className="p-2 rounded-lg bg-white/10 hover:bg-white/20 transition-colors"
573
+ title="Download"
574
+ >
575
+ <Download className="w-4 h-4" />
576
+ </button>
577
+ </div>
578
+ </div>
579
+ <pre className="p-4 rounded-lg bg-black border border-neutral-800 overflow-x-auto text-sm font-mono text-neutral-300 max-h-96">
580
+ <code>{dockerfile}</code>
581
+ </pre>
582
+ </div>
583
+ )}
584
+
585
+ {activeTab === 'compose' && (
586
+ <div>
587
+ <div className="flex items-center justify-between mb-3">
588
+ <span className="text-sm text-neutral-400 font-mono">docker-compose.yml</span>
589
+ <div className="flex gap-2">
590
+ <CopyButton text={dockerCompose} field="compose" />
591
+ <button
592
+ onClick={() => downloadFile(dockerCompose, 'docker-compose.yml')}
593
+ className="p-2 rounded-lg bg-white/10 hover:bg-white/20 transition-colors"
594
+ title="Download"
595
+ >
596
+ <Download className="w-4 h-4" />
597
+ </button>
598
+ </div>
599
+ </div>
600
+ <pre className="p-4 rounded-lg bg-black border border-neutral-800 overflow-x-auto text-sm font-mono text-neutral-300 max-h-96">
601
+ <code>{dockerCompose}</code>
602
+ </pre>
603
+ </div>
604
+ )}
605
+
606
+ {activeTab === 'env' && (
607
+ <div>
608
+ <div className="flex items-center justify-between mb-3">
609
+ <span className="text-sm text-neutral-400 font-mono">.env.example</span>
610
+ <div className="flex gap-2">
611
+ <CopyButton text={envExample} field="env" />
612
+ <button
613
+ onClick={() => downloadFile(envExample, '.env.example')}
614
+ className="p-2 rounded-lg bg-white/10 hover:bg-white/20 transition-colors"
615
+ title="Download"
616
+ >
617
+ <Download className="w-4 h-4" />
618
+ </button>
619
+ </div>
620
+ </div>
621
+ <pre className="p-4 rounded-lg bg-black border border-neutral-800 overflow-x-auto text-sm font-mono text-neutral-300 max-h-96">
622
+ <code>{envExample}</code>
623
+ </pre>
624
+ </div>
625
+ )}
626
+
627
+ {activeTab === 'commands' && (
628
+ <div className="space-y-3">
629
+ {Object.entries(commands).map(([key, command]) => (
630
+ <div key={key} className="flex items-center gap-3">
631
+ <span className="text-xs text-neutral-500 w-24 flex-shrink-0">
632
+ {key.replace('_', ' ')}
633
+ </span>
634
+ <code className="flex-1 p-2 rounded bg-black border border-neutral-800 text-sm font-mono text-green-400">
635
+ {command}
636
+ </code>
637
+ <CopyButton text={command} field={key} />
638
+ </div>
639
+ ))}
640
+ </div>
641
+ )}
642
+ </motion.div>
643
+ )}
644
+ </AnimatePresence>
645
+ </motion.div>
646
+
647
+ {/* Quick Start Guide */}
648
+ <motion.div
649
+ initial={{ opacity: 0, y: 20 }}
650
+ animate={{ opacity: 1, y: 0 }}
651
+ transition={{ delay: 0.3 }}
652
+ className="rounded-xl border border-neutral-800 bg-neutral-900/50 backdrop-blur-xl p-4"
653
+ >
654
+ <h3 className="text-sm font-medium text-white mb-3 flex items-center gap-2">
655
+ <Play className="w-4 h-4 text-green-400" />
656
+ Quick Start
657
+ </h3>
658
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
659
+ <div className="flex items-start gap-3">
660
+ <div className="w-6 h-6 rounded-full bg-white/10 flex items-center justify-center text-xs text-white flex-shrink-0">
661
+ 1
662
+ </div>
663
+ <div>
664
+ <div className="text-neutral-300 font-medium">Download files</div>
665
+ <div className="text-neutral-500 text-xs">Click "Download All" button</div>
666
+ </div>
667
+ </div>
668
+ <div className="flex items-start gap-3">
669
+ <div className="w-6 h-6 rounded-full bg-white/10 flex items-center justify-center text-xs text-white flex-shrink-0">
670
+ 2
671
+ </div>
672
+ <div>
673
+ <div className="text-neutral-300 font-medium">Build image</div>
674
+ <div className="text-neutral-500 text-xs font-mono">{commands.build}</div>
675
+ </div>
676
+ </div>
677
+ <div className="flex items-start gap-3">
678
+ <div className="w-6 h-6 rounded-full bg-white/10 flex items-center justify-center text-xs text-white flex-shrink-0">
679
+ 3
680
+ </div>
681
+ <div>
682
+ <div className="text-neutral-300 font-medium">Run container</div>
683
+ <div className="text-neutral-500 text-xs font-mono">{commands.compose_up}</div>
684
+ </div>
685
+ </div>
686
+ </div>
687
+ </motion.div>
688
+ </div>
689
+ );
690
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Docker components barrel export
3
+ * @copyright 2024-2026 nirholas
4
+ * @license MIT
5
+ */
6
+
7
+ export { default as DockerExport } from './DockerExport';