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,299 @@
1
+ /**
2
+ * Playground Store Hook - Convenient access to playground state
3
+ * @copyright 2024-2026 nirholas
4
+ * @license MIT
5
+ */
6
+
7
+ 'use client';
8
+
9
+ import { useCallback, useMemo } from 'react';
10
+ import { useRouter } from 'next/navigation';
11
+ import {
12
+ usePlaygroundStore as useStore,
13
+ createPlaygroundError,
14
+ createAnalyticsTracker,
15
+ type PlaygroundState,
16
+ type PlaygroundError,
17
+ type ExecuteToolRequest,
18
+ type ExecuteToolResponse,
19
+ } from '@/lib/playground-store';
20
+ import type { ConversionResult, Tool } from '@/types';
21
+
22
+ export { type PlaygroundState, type PlaygroundError, type ExecuteToolRequest, type ExecuteToolResponse };
23
+
24
+ /**
25
+ * Main hook for accessing playground state and actions
26
+ */
27
+ export function usePlaygroundState() {
28
+ const { state, dispatch, setConversionResult, setError, clearState, generateShareableLink, loadFromUrl, loadFromGist } = useStore();
29
+
30
+ return {
31
+ // State
32
+ generatedCode: state.generatedCode,
33
+ generatedPythonCode: state.generatedPythonCode,
34
+ tools: state.tools,
35
+ repoName: state.repoName,
36
+ repoUrl: state.repoUrl,
37
+ sessionId: state.sessionId,
38
+ lastConversion: state.lastConversion,
39
+ conversionResult: state.conversionResult,
40
+ error: state.error,
41
+ isLoading: state.isLoading,
42
+
43
+ // Computed
44
+ hasCode: !!state.generatedCode,
45
+ toolCount: state.tools.length,
46
+
47
+ // Actions
48
+ setConversionResult,
49
+ setError,
50
+ clearState,
51
+ generateShareableLink,
52
+ loadFromUrl,
53
+ loadFromGist,
54
+
55
+ // Dispatch for advanced use
56
+ dispatch,
57
+ };
58
+ }
59
+
60
+ /**
61
+ * Hook for navigating from conversion to playground
62
+ */
63
+ export function usePlaygroundNavigation() {
64
+ const router = useRouter();
65
+ const { setConversionResult, generateShareableLink } = useStore();
66
+
67
+ const navigateToPlayground = useCallback((result: ConversionResult) => {
68
+ // Store the result first
69
+ setConversionResult(result);
70
+
71
+ // Navigate to playground
72
+ router.push('/playground');
73
+ }, [router, setConversionResult]);
74
+
75
+ const navigateWithCode = useCallback((code: string, name?: string) => {
76
+ // For sharing purposes, encode in URL
77
+ const params = new URLSearchParams();
78
+ try {
79
+ params.set('code', btoa(encodeURIComponent(code)));
80
+ if (name) {
81
+ params.set('name', name);
82
+ }
83
+ router.push(`/playground?${params.toString()}`);
84
+ } catch (error) {
85
+ console.error('Failed to encode code for URL:', error);
86
+ router.push('/playground');
87
+ }
88
+ }, [router]);
89
+
90
+ return {
91
+ navigateToPlayground,
92
+ navigateWithCode,
93
+ generateShareableLink,
94
+ };
95
+ }
96
+
97
+ /**
98
+ * Hook for managing playground errors
99
+ */
100
+ export function usePlaygroundErrors() {
101
+ const { state, setError, dispatch } = useStore();
102
+
103
+ const setSyntaxError = useCallback((message: string, details?: string) => {
104
+ setError(createPlaygroundError('syntax', message, details, false));
105
+ }, [setError]);
106
+
107
+ const setServerError = useCallback((message: string, details?: string) => {
108
+ setError(createPlaygroundError('server', message, details, true));
109
+ }, [setError]);
110
+
111
+ const setExecutionError = useCallback((message: string, details?: string) => {
112
+ setError(createPlaygroundError('execution', message, details, true));
113
+ }, [setError]);
114
+
115
+ const setNetworkError = useCallback((message: string, details?: string) => {
116
+ setError(createPlaygroundError('network', message, details, true));
117
+ }, [setError]);
118
+
119
+ const clearError = useCallback(() => {
120
+ setError(null);
121
+ }, [setError]);
122
+
123
+ const incrementRetry = useCallback(() => {
124
+ dispatch({ type: 'INCREMENT_RETRY' });
125
+ }, [dispatch]);
126
+
127
+ return {
128
+ error: state.error,
129
+ hasError: !!state.error,
130
+ isRecoverable: state.error?.recoverable ?? false,
131
+ retryCount: state.error?.retryCount ?? 0,
132
+ setSyntaxError,
133
+ setServerError,
134
+ setExecutionError,
135
+ setNetworkError,
136
+ clearError,
137
+ incrementRetry,
138
+ };
139
+ }
140
+
141
+ /**
142
+ * Hook for tool execution within the playground
143
+ */
144
+ export function useToolExecution() {
145
+ const { state, dispatch } = useStore();
146
+ const analytics = useMemo(() => createAnalyticsTracker(), []);
147
+
148
+ const executeToolLocally = useCallback(async (
149
+ tool: Tool,
150
+ params: Record<string, unknown>
151
+ ): Promise<ExecuteToolResponse> => {
152
+ if (!state.generatedCode) {
153
+ return {
154
+ success: false,
155
+ error: 'No generated code available',
156
+ sessionId: state.sessionId || '',
157
+ executionTime: 0,
158
+ };
159
+ }
160
+
161
+ const startTime = Date.now();
162
+
163
+ try {
164
+ // Call the API to execute the tool
165
+ const request: ExecuteToolRequest = {
166
+ generatedCode: state.generatedCode,
167
+ toolName: tool.name,
168
+ toolParams: params,
169
+ sessionId: state.sessionId || undefined,
170
+ };
171
+
172
+ const response = await fetch('/api/playground/execute', {
173
+ method: 'POST',
174
+ headers: { 'Content-Type': 'application/json' },
175
+ body: JSON.stringify(request),
176
+ });
177
+
178
+ const executionTime = Date.now() - startTime;
179
+
180
+ if (!response.ok) {
181
+ const errorData = await response.json().catch(() => ({ error: 'Unknown error' }));
182
+ analytics.trackToolExecution(tool.name, false, executionTime);
183
+ return {
184
+ success: false,
185
+ error: errorData.error || `HTTP ${response.status}`,
186
+ sessionId: state.sessionId || '',
187
+ executionTime,
188
+ };
189
+ }
190
+
191
+ const result: ExecuteToolResponse = await response.json();
192
+
193
+ // Update session ID if returned
194
+ if (result.sessionId && result.sessionId !== state.sessionId) {
195
+ dispatch({ type: 'SET_SESSION_ID', payload: result.sessionId });
196
+ }
197
+
198
+ analytics.trackToolExecution(tool.name, result.success, executionTime);
199
+ return result;
200
+ } catch (error) {
201
+ const executionTime = Date.now() - startTime;
202
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
203
+
204
+ analytics.trackToolExecution(tool.name, false, executionTime);
205
+
206
+ return {
207
+ success: false,
208
+ error: errorMessage,
209
+ sessionId: state.sessionId || '',
210
+ executionTime,
211
+ };
212
+ }
213
+ }, [state.generatedCode, state.sessionId, dispatch, analytics]);
214
+
215
+ return {
216
+ executeToolLocally,
217
+ sessionId: state.sessionId,
218
+ hasCode: !!state.generatedCode,
219
+ };
220
+ }
221
+
222
+ /**
223
+ * Hook for analytics tracking
224
+ */
225
+ export function usePlaygroundAnalytics() {
226
+ const analytics = useMemo(() => createAnalyticsTracker(), []);
227
+
228
+ return analytics;
229
+ }
230
+
231
+ /**
232
+ * Hook for sharing playground state
233
+ */
234
+ export function usePlaygroundSharing() {
235
+ const { state, generateShareableLink } = useStore();
236
+ const analytics = useMemo(() => createAnalyticsTracker(), []);
237
+
238
+ const copyShareLink = useCallback(async (): Promise<boolean> => {
239
+ const link = generateShareableLink();
240
+ if (!link) return false;
241
+
242
+ try {
243
+ await navigator.clipboard.writeText(link);
244
+ analytics.trackShare('url');
245
+ return true;
246
+ } catch (error) {
247
+ console.error('Failed to copy share link:', error);
248
+ return false;
249
+ }
250
+ }, [generateShareableLink, analytics]);
251
+
252
+ const createGistAndShare = useCallback(async (token: string): Promise<string | null> => {
253
+ if (!state.generatedCode) return null;
254
+
255
+ try {
256
+ const response = await fetch('https://api.github.com/gists', {
257
+ method: 'POST',
258
+ headers: {
259
+ 'Content-Type': 'application/json',
260
+ 'Authorization': `token ${token}`,
261
+ },
262
+ body: JSON.stringify({
263
+ description: `MCP Server: ${state.repoName || 'Generated'}`,
264
+ public: false,
265
+ files: {
266
+ [`${state.repoName || 'mcp-server'}.ts`]: {
267
+ content: state.generatedCode,
268
+ },
269
+ ...(state.generatedPythonCode ? {
270
+ [`${state.repoName || 'mcp-server'}.py`]: {
271
+ content: state.generatedPythonCode,
272
+ },
273
+ } : {}),
274
+ },
275
+ }),
276
+ });
277
+
278
+ if (!response.ok) {
279
+ throw new Error(`Failed to create Gist: ${response.status}`);
280
+ }
281
+
282
+ const gist = await response.json();
283
+ const shareUrl = `${window.location.origin}/playground?gist=${gist.id}`;
284
+
285
+ analytics.trackShare('gist');
286
+ return shareUrl;
287
+ } catch (error) {
288
+ console.error('Failed to create Gist:', error);
289
+ return null;
290
+ }
291
+ }, [state.generatedCode, state.generatedPythonCode, state.repoName, analytics]);
292
+
293
+ return {
294
+ canShare: !!state.generatedCode,
295
+ copyShareLink,
296
+ createGistAndShare,
297
+ generateShareableLink,
298
+ };
299
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * usePlayground Hook
3
+ * Unified hook that combines all MCP playground hooks with UI state management
4
+ * @copyright 2024-2026 nirholas
5
+ * @license MIT
6
+ */
7
+
8
+ 'use client';
9
+
10
+ import { useState, useMemo, useCallback, useRef, useEffect } from 'react';
11
+ import { useMcpConnection } from './use-mcp-connection';
12
+ import { useMcpTools } from './use-mcp-tools';
13
+ import { useMcpResources } from './use-mcp-resources';
14
+ import { useMcpPrompts } from './use-mcp-prompts';
15
+ import type {
16
+ UsePlaygroundOptions,
17
+ UsePlaygroundReturn,
18
+ PlaygroundTab,
19
+ McpTool,
20
+ McpResource,
21
+ McpPrompt,
22
+ McpCapabilities,
23
+ TransportConfig,
24
+ McpEventEmitter,
25
+ McpEvent,
26
+ ToolExecution,
27
+ ResourceRead,
28
+ PromptExecution,
29
+ } from './types';
30
+ import { createDebugLogger, McpEventEmitter as EventEmitterClass } from './types';
31
+
32
+ // ============================================================================
33
+ // Hook Implementation
34
+ // ============================================================================
35
+
36
+ export function usePlayground(options: UsePlaygroundOptions = {}): UsePlaygroundReturn {
37
+ const {
38
+ debug = false,
39
+ timeout,
40
+ cacheTtl,
41
+ heartbeatInterval,
42
+ onConnect,
43
+ onDisconnect,
44
+ onError,
45
+ } = options;
46
+
47
+ // Create debug logger
48
+ const log = useMemo(
49
+ () => createDebugLogger('usePlayground', { enabled: debug }),
50
+ [debug]
51
+ );
52
+
53
+ // Create shared event emitter
54
+ const eventEmitter = useMemo<McpEventEmitter>(() => {
55
+ const emitter = new EventEmitterClass();
56
+
57
+ // Log all events in debug mode
58
+ if (debug) {
59
+ emitter.subscribe((event: McpEvent) => {
60
+ log.debug(`Event: ${event.type}`, event.data);
61
+ });
62
+ }
63
+
64
+ return emitter;
65
+ }, [debug, log]);
66
+
67
+ // UI State
68
+ const [activeTab, setActiveTab] = useState<PlaygroundTab>('tools');
69
+ const [selectedTool, setSelectedTool] = useState<McpTool | null>(null);
70
+ const [selectedResource, setSelectedResource] = useState<McpResource | null>(null);
71
+ const [selectedPrompt, setSelectedPrompt] = useState<McpPrompt | null>(null);
72
+ const [transportConfig, setTransportConfig] = useState<TransportConfig | null>(null);
73
+
74
+ // Initialize sub-hooks with shared event emitter and debug settings
75
+ const connection = useMcpConnection({
76
+ debug,
77
+ timeout,
78
+ heartbeatInterval,
79
+ eventEmitter,
80
+ });
81
+
82
+ const tools = useMcpTools({
83
+ sessionId: connection.sessionId,
84
+ autoLoad: true,
85
+ debug,
86
+ timeout,
87
+ cacheTtl,
88
+ eventEmitter,
89
+ });
90
+
91
+ const resources = useMcpResources({
92
+ sessionId: connection.sessionId,
93
+ autoLoad: true,
94
+ debug,
95
+ timeout,
96
+ cacheTtl,
97
+ eventEmitter,
98
+ });
99
+
100
+ const prompts = useMcpPrompts({
101
+ sessionId: connection.sessionId,
102
+ autoLoad: true,
103
+ debug,
104
+ timeout,
105
+ cacheTtl,
106
+ eventEmitter,
107
+ });
108
+
109
+ // Subscribe to connection events for callbacks
110
+ useEffect(() => {
111
+ const unsubscribe = eventEmitter.subscribe((event: McpEvent) => {
112
+ switch (event.type) {
113
+ case 'connection:connected':
114
+ log.info('Connected', { sessionId: event.sessionId });
115
+ if (event.sessionId) {
116
+ onConnect?.(event.sessionId);
117
+ }
118
+ break;
119
+ case 'connection:disconnected':
120
+ log.info('Disconnected', { sessionId: event.sessionId });
121
+ onDisconnect?.();
122
+ // Clear selections on disconnect
123
+ setSelectedTool(null);
124
+ setSelectedResource(null);
125
+ setSelectedPrompt(null);
126
+ break;
127
+ case 'connection:error':
128
+ case 'tools:error':
129
+ case 'resources:error':
130
+ case 'prompts:error':
131
+ const errorMsg = (event.data as { error?: string })?.error || 'Unknown error';
132
+ log.error(`Error: ${event.type}`, { error: errorMsg });
133
+ onError?.(new Error(errorMsg));
134
+ break;
135
+ }
136
+ });
137
+
138
+ return unsubscribe;
139
+ }, [eventEmitter, onConnect, onDisconnect, onError, log]);
140
+
141
+ // Computed: is playground ready to use
142
+ const isReady = useMemo(() => {
143
+ return connection.status === 'connected' && connection.sessionId !== null;
144
+ }, [connection.status, connection.sessionId]);
145
+
146
+ // Check if server has a specific capability
147
+ const hasCapability = useCallback(
148
+ (cap: keyof McpCapabilities): boolean => {
149
+ if (!connection.capabilities) return false;
150
+ return !!connection.capabilities[cap];
151
+ },
152
+ [connection.capabilities]
153
+ );
154
+
155
+ return {
156
+ // Connection
157
+ connection,
158
+
159
+ // Data
160
+ tools,
161
+ resources,
162
+ prompts,
163
+
164
+ // UI State
165
+ activeTab,
166
+ setActiveTab,
167
+ selectedTool,
168
+ setSelectedTool,
169
+ selectedResource,
170
+ setSelectedResource,
171
+ selectedPrompt,
172
+ setSelectedPrompt,
173
+
174
+ // Transport Config
175
+ transportConfig,
176
+ setTransportConfig,
177
+
178
+ // Convenience
179
+ isReady,
180
+ hasCapability,
181
+ };
182
+ }
183
+
184
+ export default usePlayground;
@@ -0,0 +1,227 @@
1
+ /**
2
+ * useStreamingConversion Hook - Real-time conversion progress
3
+ * @copyright 2024-2026 nirholas
4
+ * @license MIT
5
+ */
6
+
7
+ 'use client';
8
+
9
+ import { useState, useCallback, useRef } from 'react';
10
+ import type { ConversionResult, ConversionStatus, ApiError } from '@/types';
11
+
12
+ export interface StreamingStep {
13
+ id: string;
14
+ label: string;
15
+ description: string;
16
+ status: 'pending' | 'in-progress' | 'complete' | 'error';
17
+ progress?: number;
18
+ detail?: string;
19
+ }
20
+
21
+ const INITIAL_STEPS: StreamingStep[] = [
22
+ { id: 'validate', label: 'Validating GitHub URL', description: 'Checking repository accessibility', status: 'pending' },
23
+ { id: 'fetch', label: 'Fetching repository', description: 'Downloading repository metadata', status: 'pending' },
24
+ { id: 'classify', label: 'Classifying repository', description: 'Detecting repo type and structure', status: 'pending' },
25
+ { id: 'readme', label: 'Analyzing README', description: 'Extracting documentation and examples', status: 'pending' },
26
+ { id: 'openapi', label: 'Scanning for OpenAPI specs', description: 'Looking for API definitions', status: 'pending' },
27
+ { id: 'code', label: 'Analyzing code', description: 'Extracting functions and patterns', status: 'pending' },
28
+ { id: 'generate-ts', label: 'Generating TypeScript server', description: 'Creating MCP server code', status: 'pending' },
29
+ { id: 'generate-py', label: 'Generating Python server', description: 'Creating Python alternative', status: 'pending' },
30
+ { id: 'configs', label: 'Creating configurations', description: 'Building platform configs', status: 'pending' },
31
+ { id: 'complete', label: 'Conversion complete', description: 'MCP server ready', status: 'pending' },
32
+ ];
33
+
34
+ interface UseStreamingConversionReturn {
35
+ status: ConversionStatus;
36
+ result: ConversionResult | null;
37
+ error: ApiError | null;
38
+ steps: StreamingStep[];
39
+ currentStep: string | null;
40
+ progress: number;
41
+ convert: (url: string) => Promise<void>;
42
+ reset: () => void;
43
+ cancel: () => void;
44
+ }
45
+
46
+ export function useStreamingConversion(): UseStreamingConversionReturn {
47
+ const [status, setStatus] = useState<ConversionStatus>('idle');
48
+ const [result, setResult] = useState<ConversionResult | null>(null);
49
+ const [error, setError] = useState<ApiError | null>(null);
50
+ const [steps, setSteps] = useState<StreamingStep[]>(INITIAL_STEPS);
51
+ const [currentStep, setCurrentStep] = useState<string | null>(null);
52
+ const [progress, setProgress] = useState(0);
53
+ const abortControllerRef = useRef<AbortController | null>(null);
54
+
55
+ const updateStep = useCallback((stepId: string, updates: Partial<StreamingStep>) => {
56
+ setSteps(prev => prev.map(step =>
57
+ step.id === stepId ? { ...step, ...updates } : step
58
+ ));
59
+ }, []);
60
+
61
+ const convert = useCallback(async (url: string) => {
62
+ // Reset state
63
+ setStatus('loading');
64
+ setError(null);
65
+ setResult(null);
66
+ setSteps(INITIAL_STEPS);
67
+ setCurrentStep(null);
68
+ setProgress(0);
69
+
70
+ // Create abort controller
71
+ abortControllerRef.current = new AbortController();
72
+
73
+ try {
74
+ const response = await fetch(`/api/convert/stream?url=${encodeURIComponent(url)}`, {
75
+ signal: abortControllerRef.current.signal,
76
+ });
77
+
78
+ if (!response.ok) {
79
+ const data = await response.json();
80
+ throw new Error(data.error || 'Conversion failed');
81
+ }
82
+
83
+ const reader = response.body?.getReader();
84
+ if (!reader) {
85
+ throw new Error('No response body');
86
+ }
87
+
88
+ const decoder = new TextDecoder();
89
+ let buffer = '';
90
+
91
+ while (true) {
92
+ const { done, value } = await reader.read();
93
+ if (done) break;
94
+
95
+ buffer += decoder.decode(value, { stream: true });
96
+ const lines = buffer.split('\n');
97
+ buffer = lines.pop() || '';
98
+
99
+ for (const line of lines) {
100
+ if (line.startsWith('event: ')) {
101
+ const eventType = line.slice(7);
102
+ const dataLineIndex = lines.indexOf(line) + 1;
103
+ const dataLine = lines[dataLineIndex];
104
+
105
+ if (dataLine?.startsWith('data: ')) {
106
+ const data = JSON.parse(dataLine.slice(6));
107
+
108
+ switch (eventType) {
109
+ case 'progress':
110
+ setCurrentStep(data.step);
111
+ setProgress(data.progress || 0);
112
+ updateStep(data.step, {
113
+ status: data.status === 'complete' ? 'complete' : 'in-progress',
114
+ detail: data.description,
115
+ });
116
+ break;
117
+
118
+ case 'result':
119
+ setResult({
120
+ ...data,
121
+ stats: {
122
+ totalTools: data.tools.length,
123
+ filesAnalyzed: data.sources?.reduce((acc: number, s: { count: number }) => acc + s.count, 0) || 0,
124
+ processingTimeMs: 0,
125
+ cacheHit: false,
126
+ },
127
+ repository: {
128
+ owner: url.split('/')[3] || '',
129
+ name: data.name,
130
+ fullName: `${url.split('/')[3]}/${data.name}`,
131
+ url,
132
+ },
133
+ generatedAt: new Date().toISOString(),
134
+ });
135
+ break;
136
+
137
+ case 'error':
138
+ setError({
139
+ error: data.error,
140
+ code: data.code || 'UNKNOWN_ERROR',
141
+ });
142
+ setStatus('error');
143
+ updateStep(currentStep || 'validate', { status: 'error' });
144
+ return;
145
+
146
+ case 'done':
147
+ setStatus('success');
148
+ setProgress(100);
149
+ break;
150
+ }
151
+ }
152
+ } else if (line.startsWith('data: ')) {
153
+ // Handle data-only lines
154
+ try {
155
+ const data = JSON.parse(line.slice(6));
156
+ if (data.step) {
157
+ setCurrentStep(data.step);
158
+ setProgress(data.progress || 0);
159
+ updateStep(data.step, {
160
+ status: data.status === 'complete' ? 'complete' : 'in-progress',
161
+ detail: data.description,
162
+ });
163
+ }
164
+ if (data.error) {
165
+ setError({
166
+ error: data.error,
167
+ code: data.code || 'UNKNOWN_ERROR',
168
+ });
169
+ setStatus('error');
170
+ return;
171
+ }
172
+ } catch {
173
+ // Ignore parse errors for incomplete data
174
+ }
175
+ }
176
+ }
177
+ }
178
+
179
+ // If we got here without setting success, do it now
180
+ if (status === 'loading') {
181
+ setStatus('success');
182
+ }
183
+
184
+ } catch (err) {
185
+ if (err instanceof Error && err.name === 'AbortError') {
186
+ setStatus('idle');
187
+ return;
188
+ }
189
+
190
+ setError({
191
+ error: err instanceof Error ? err.message : 'Network error',
192
+ code: 'NETWORK_ERROR',
193
+ details: 'Failed to connect to the server.',
194
+ });
195
+ setStatus('error');
196
+ }
197
+ }, [updateStep, currentStep, status]);
198
+
199
+ const reset = useCallback(() => {
200
+ setStatus('idle');
201
+ setResult(null);
202
+ setError(null);
203
+ setSteps(INITIAL_STEPS);
204
+ setCurrentStep(null);
205
+ setProgress(0);
206
+ }, []);
207
+
208
+ const cancel = useCallback(() => {
209
+ if (abortControllerRef.current) {
210
+ abortControllerRef.current.abort();
211
+ abortControllerRef.current = null;
212
+ }
213
+ reset();
214
+ }, [reset]);
215
+
216
+ return {
217
+ status,
218
+ result,
219
+ error,
220
+ steps,
221
+ currentStep,
222
+ progress,
223
+ convert,
224
+ reset,
225
+ cancel,
226
+ };
227
+ }