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,744 @@
1
+ /**
2
+ * @fileoverview Rust code extractor for extracting tools from Rust codebases
3
+ * @copyright Copyright (c) 2024-2026 nirholas
4
+ * @license MIT
5
+ */
6
+
7
+ import { ExtractedTool, ParsedDocumentation } from '../types';
8
+
9
+ /**
10
+ * Extracted Rust function information
11
+ */
12
+ interface RustFunction {
13
+ name: string;
14
+ isPublic: boolean;
15
+ isAsync: boolean;
16
+ params: Array<{
17
+ name: string;
18
+ type: string;
19
+ isMutable: boolean;
20
+ isReference: boolean;
21
+ }>;
22
+ returnType: string | null;
23
+ documentation: ParsedDocumentation | null;
24
+ attributes: string[];
25
+ line: number;
26
+ }
27
+
28
+ /**
29
+ * Rust route handler info (for web frameworks)
30
+ */
31
+ interface RustRouteHandler {
32
+ method: string;
33
+ path: string;
34
+ handler: string;
35
+ function: RustFunction | null;
36
+ }
37
+
38
+ /**
39
+ * RustExtractor extracts tools from Rust codebases
40
+ * Supports:
41
+ * - Actix-web route handlers
42
+ * - Axum handlers
43
+ * - Rocket routes
44
+ * - Regular public functions with doc comments
45
+ */
46
+ export class RustExtractor {
47
+ /**
48
+ * Extract tools from Rust code
49
+ */
50
+ async extract(code: string, filename: string): Promise<ExtractedTool[]> {
51
+ const tools: ExtractedTool[] = [];
52
+
53
+ // Extract from web framework routes
54
+ const actixTools = this.extractActixRoutes(code, filename);
55
+ const axumTools = this.extractAxumRoutes(code, filename);
56
+ const rocketTools = this.extractRocketRoutes(code, filename);
57
+
58
+ tools.push(...actixTools, ...axumTools, ...rocketTools);
59
+
60
+ // Extract from public functions with documentation
61
+ const publicFunctions = this.extractPublicFunctions(code, filename);
62
+ tools.push(...publicFunctions);
63
+
64
+ return tools;
65
+ }
66
+
67
+ /**
68
+ * Extract Actix-web route handlers
69
+ * Patterns:
70
+ * - #[get("/path")]
71
+ * - #[post("/path")]
72
+ * - web::resource("/path").route(web::get().to(handler))
73
+ */
74
+ private extractActixRoutes(code: string, filename: string): ExtractedTool[] {
75
+ const tools: ExtractedTool[] = [];
76
+ const lines = code.split('\n');
77
+
78
+ // Pattern for attribute-based routes
79
+ const routeAttrPattern = /#\[(get|post|put|delete|patch|head|options)\s*\(\s*"([^"]+)"\s*(?:,\s*[^)]+)?\)\]/gi;
80
+
81
+ for (let i = 0; i < lines.length; i++) {
82
+ const line = lines[i];
83
+ let match;
84
+
85
+ routeAttrPattern.lastIndex = 0;
86
+ while ((match = routeAttrPattern.exec(line)) !== null) {
87
+ const method = match[1].toUpperCase();
88
+ const path = match[2];
89
+
90
+ // Look for the function definition on the next lines
91
+ const funcInfo = this.findNextFunction(lines, i + 1);
92
+
93
+ if (funcInfo) {
94
+ const toolName = this.generateToolName(method, path, funcInfo.name);
95
+ const description = funcInfo.documentation?.description ||
96
+ `${method} ${path} - ${funcInfo.name}`;
97
+
98
+ tools.push({
99
+ name: toolName,
100
+ description,
101
+ inputSchema: this.buildInputSchema(funcInfo, path),
102
+ source: {
103
+ type: 'code',
104
+ file: filename,
105
+ line: i + 1
106
+ },
107
+ confidence: 0.8,
108
+ confidenceFactors: {
109
+ documentation: funcInfo.documentation ? 0.9 : 0.5,
110
+ types: 0.8,
111
+ examples: funcInfo.documentation?.examples?.length ? 0.8 : 0.3,
112
+ source: 0.9
113
+ }
114
+ });
115
+ }
116
+ }
117
+ }
118
+
119
+ // Pattern for web::scope and web::resource
120
+ const resourcePattern = /web::(resource|scope)\s*\(\s*"([^"]+)"\s*\)/g;
121
+ const routeToPattern = /\.route\s*\(\s*web::(get|post|put|delete|patch)\s*\(\s*\)\s*\.to\s*\(\s*(\w+)\s*\)\s*\)/gi;
122
+
123
+ let resourceMatch;
124
+ while ((resourceMatch = resourcePattern.exec(code)) !== null) {
125
+ const basePath = resourceMatch[2];
126
+ const lineNum = code.substring(0, resourceMatch.index).split('\n').length;
127
+
128
+ // Find route definitions that follow
129
+ const remainingCode = code.substring(resourceMatch.index);
130
+ let routeMatch;
131
+
132
+ while ((routeMatch = routeToPattern.exec(remainingCode)) !== null) {
133
+ const method = routeMatch[1].toUpperCase();
134
+ const handlerName = routeMatch[2];
135
+
136
+ // Try to find the handler function
137
+ const funcInfo = this.findFunctionByName(code, handlerName);
138
+
139
+ tools.push({
140
+ name: this.generateToolName(method, basePath, handlerName),
141
+ description: funcInfo?.documentation?.description || `${method} ${basePath}`,
142
+ inputSchema: funcInfo ? this.buildInputSchema(funcInfo, basePath) : { type: 'object', properties: {}, required: [] },
143
+ source: {
144
+ type: 'code',
145
+ file: filename,
146
+ line: lineNum
147
+ },
148
+ confidence: 0.7
149
+ });
150
+ }
151
+ }
152
+
153
+ return tools;
154
+ }
155
+
156
+ /**
157
+ * Extract Axum route handlers
158
+ * Patterns:
159
+ * - Router::new().route("/path", get(handler))
160
+ * - .route("/path", post(handler))
161
+ */
162
+ private extractAxumRoutes(code: string, filename: string): ExtractedTool[] {
163
+ const tools: ExtractedTool[] = [];
164
+
165
+ // Pattern for .route() calls
166
+ const routePattern = /\.route\s*\(\s*"([^"]+)"\s*,\s*(get|post|put|delete|patch|head|options)\s*\(\s*(\w+)\s*\)/gi;
167
+
168
+ let match;
169
+ while ((match = routePattern.exec(code)) !== null) {
170
+ const path = match[1];
171
+ const method = match[2].toUpperCase();
172
+ const handlerName = match[3];
173
+ const lineNum = code.substring(0, match.index).split('\n').length;
174
+
175
+ const funcInfo = this.findFunctionByName(code, handlerName);
176
+
177
+ tools.push({
178
+ name: this.generateToolName(method, path, handlerName),
179
+ description: funcInfo?.documentation?.description || `${method} ${path}`,
180
+ inputSchema: funcInfo ? this.buildInputSchema(funcInfo, path) : { type: 'object', properties: {}, required: [] },
181
+ source: {
182
+ type: 'code',
183
+ file: filename,
184
+ line: lineNum
185
+ },
186
+ confidence: 0.8
187
+ });
188
+ }
189
+
190
+ // Axum also supports method routing with handler attributes
191
+ const axumAttrPattern = /#\[axum::(debug_handler|handler)]/gi;
192
+
193
+ // Look for #[debug_handler] followed by async fn
194
+ const debugHandlerMatches = code.matchAll(/#\[debug_handler\]\s*(?:pub\s+)?async\s+fn\s+(\w+)/g);
195
+ for (const match of debugHandlerMatches) {
196
+ const handlerName = match[1];
197
+ const lineNum = code.substring(0, match.index!).split('\n').length;
198
+ const funcInfo = this.findFunctionByName(code, handlerName);
199
+
200
+ if (funcInfo) {
201
+ tools.push({
202
+ name: handlerName,
203
+ description: funcInfo.documentation?.description || `Axum handler: ${handlerName}`,
204
+ inputSchema: this.buildInputSchema(funcInfo, ''),
205
+ source: {
206
+ type: 'code',
207
+ file: filename,
208
+ line: lineNum
209
+ },
210
+ confidence: 0.7
211
+ });
212
+ }
213
+ }
214
+
215
+ return tools;
216
+ }
217
+
218
+ /**
219
+ * Extract Rocket route handlers
220
+ * Patterns:
221
+ * - #[get("/path")]
222
+ * - #[post("/path", data = "<input>")]
223
+ */
224
+ private extractRocketRoutes(code: string, filename: string): ExtractedTool[] {
225
+ const tools: ExtractedTool[] = [];
226
+ const lines = code.split('\n');
227
+
228
+ // Rocket uses similar attribute syntax but with more options
229
+ const rocketRoutePattern = /#\[(get|post|put|delete|patch|head|options)\s*\(\s*"([^"]+)"(?:\s*,\s*([^)]+))?\)\]/gi;
230
+
231
+ for (let i = 0; i < lines.length; i++) {
232
+ const line = lines[i];
233
+ let match;
234
+
235
+ rocketRoutePattern.lastIndex = 0;
236
+ while ((match = rocketRoutePattern.exec(line)) !== null) {
237
+ const method = match[1].toUpperCase();
238
+ const path = match[2];
239
+ const options = match[3] || '';
240
+
241
+ // Parse data parameter if present
242
+ const dataMatch = options.match(/data\s*=\s*"<(\w+)>"/);
243
+ const dataParam = dataMatch ? dataMatch[1] : null;
244
+
245
+ // Find the function
246
+ const funcInfo = this.findNextFunction(lines, i + 1);
247
+
248
+ if (funcInfo) {
249
+ tools.push({
250
+ name: this.generateToolName(method, path, funcInfo.name),
251
+ description: funcInfo.documentation?.description || `${method} ${path}`,
252
+ inputSchema: this.buildInputSchema(funcInfo, path, dataParam),
253
+ source: {
254
+ type: 'code',
255
+ file: filename,
256
+ line: i + 1
257
+ },
258
+ confidence: 0.8
259
+ });
260
+ }
261
+ }
262
+ }
263
+
264
+ return tools;
265
+ }
266
+
267
+ /**
268
+ * Extract public functions with doc comments
269
+ */
270
+ private extractPublicFunctions(code: string, filename: string): ExtractedTool[] {
271
+ const tools: ExtractedTool[] = [];
272
+ const lines = code.split('\n');
273
+
274
+ for (let i = 0; i < lines.length; i++) {
275
+ const line = lines[i];
276
+
277
+ // Look for pub fn or pub async fn with preceding doc comments
278
+ if (/^\s*pub\s+(async\s+)?fn\s+\w+/.test(line)) {
279
+ // Check if this function has route attributes (already processed)
280
+ if (i > 0) {
281
+ const prevLine = lines[i - 1];
282
+ if (/#\[(get|post|put|delete|patch|head|options|route)/.test(prevLine)) {
283
+ continue; // Skip, already handled by route extractors
284
+ }
285
+ }
286
+
287
+ const funcInfo = this.parseFunction(lines, i);
288
+ if (funcInfo && funcInfo.documentation) {
289
+ // Only include functions with documentation
290
+ tools.push({
291
+ name: funcInfo.name,
292
+ description: funcInfo.documentation.description || funcInfo.name,
293
+ inputSchema: this.buildInputSchemaFromFunction(funcInfo),
294
+ source: {
295
+ type: 'code',
296
+ file: filename,
297
+ line: i + 1
298
+ },
299
+ confidence: 0.6,
300
+ confidenceFactors: {
301
+ documentation: 0.8,
302
+ types: 0.9,
303
+ examples: funcInfo.documentation.examples?.length ? 0.7 : 0.2,
304
+ source: 0.7
305
+ }
306
+ });
307
+ }
308
+ }
309
+ }
310
+
311
+ return tools;
312
+ }
313
+
314
+ /**
315
+ * Find the next function definition after the given line
316
+ */
317
+ private findNextFunction(lines: string[], startLine: number): RustFunction | null {
318
+ for (let i = startLine; i < Math.min(startLine + 5, lines.length); i++) {
319
+ const line = lines[i];
320
+ if (/^\s*(pub\s+)?(async\s+)?fn\s+\w+/.test(line)) {
321
+ return this.parseFunction(lines, i);
322
+ }
323
+ }
324
+ return null;
325
+ }
326
+
327
+ /**
328
+ * Find a function by name in the code
329
+ */
330
+ private findFunctionByName(code: string, name: string): RustFunction | null {
331
+ const lines = code.split('\n');
332
+ const pattern = new RegExp(`^\\s*(pub\\s+)?(async\\s+)?fn\\s+${name}\\s*[<(]`);
333
+
334
+ for (let i = 0; i < lines.length; i++) {
335
+ if (pattern.test(lines[i])) {
336
+ return this.parseFunction(lines, i);
337
+ }
338
+ }
339
+ return null;
340
+ }
341
+
342
+ /**
343
+ * Parse a Rust function definition
344
+ */
345
+ private parseFunction(lines: string[], lineIndex: number): RustFunction | null {
346
+ const line = lines[lineIndex];
347
+
348
+ // First, try to match single-line function signature
349
+ let funcMatch = line.match(/^\s*(pub\s+)?(async\s+)?fn\s+(\w+)\s*(?:<[^>]*>)?\s*\(([^)]*)\)(?:\s*->\s*(.+?))?(?:\s*(?:where|{))?/);
350
+
351
+ // If no match, try multi-line function signature
352
+ if (!funcMatch) {
353
+ // Get the function name and check for multi-line signature
354
+ const headerMatch = line.match(/^\s*(pub\s+)?(async\s+)?fn\s+(\w+)\s*(?:<[^>]*>)?\s*\(/);
355
+ if (!headerMatch) return null;
356
+
357
+ // Collect lines until we find the closing paren
358
+ let combinedParams = '';
359
+ let returnType: string | undefined;
360
+ let depth = 1;
361
+
362
+ // Get params from first line after the opening paren
363
+ const afterParen = line.substring(line.indexOf('(') + 1);
364
+ combinedParams += afterParen;
365
+
366
+ for (let i = lineIndex + 1; i < lines.length && depth > 0; i++) {
367
+ const currentLine = lines[i];
368
+ for (const char of currentLine) {
369
+ if (char === '(') depth++;
370
+ else if (char === ')') depth--;
371
+ }
372
+
373
+ if (depth > 0) {
374
+ combinedParams += ' ' + currentLine.trim();
375
+ } else {
376
+ // Found the closing paren - extract up to it and check for return type
377
+ const closingIdx = currentLine.indexOf(')');
378
+ combinedParams += ' ' + currentLine.substring(0, closingIdx).trim();
379
+
380
+ // Check for return type
381
+ const afterClose = currentLine.substring(closingIdx + 1);
382
+ const returnMatch = afterClose.match(/^\s*->\s*(.+?)(?:\s*(?:where|{))?$/);
383
+ if (returnMatch) {
384
+ returnType = returnMatch[1].trim();
385
+ }
386
+ break;
387
+ }
388
+ }
389
+
390
+ funcMatch = [
391
+ line,
392
+ headerMatch[1],
393
+ headerMatch[2],
394
+ headerMatch[3],
395
+ combinedParams,
396
+ returnType
397
+ ] as RegExpMatchArray;
398
+ }
399
+
400
+ if (!funcMatch) return null;
401
+
402
+ const [, pubKw, asyncKw, name, paramsStr, returnTypeStr] = funcMatch;
403
+
404
+ // Parse parameters
405
+ const params = this.parseParameters(paramsStr);
406
+
407
+ // Look for doc comments above the function
408
+ const documentation = this.parseDocComments(lines, lineIndex);
409
+
410
+ // Look for attributes
411
+ const attributes = this.parseAttributes(lines, lineIndex);
412
+
413
+ return {
414
+ name,
415
+ isPublic: !!pubKw,
416
+ isAsync: !!asyncKw,
417
+ params,
418
+ returnType: returnTypeStr?.trim() || null,
419
+ documentation,
420
+ attributes,
421
+ line: lineIndex + 1
422
+ };
423
+ }
424
+
425
+ /**
426
+ * Parse function parameters
427
+ */
428
+ private parseParameters(paramsStr: string): RustFunction['params'] {
429
+ const params: RustFunction['params'] = [];
430
+ if (!paramsStr.trim()) return params;
431
+
432
+ // Handle multi-line and complex types
433
+ const paramParts = this.splitParams(paramsStr);
434
+
435
+ for (const part of paramParts) {
436
+ const trimmed = part.trim();
437
+ if (!trimmed || trimmed === 'self' || trimmed === '&self' || trimmed === '&mut self') {
438
+ continue;
439
+ }
440
+
441
+ // Match: name: Type or mut name: Type or &name: Type
442
+ const paramMatch = trimmed.match(/^(&)?(\s*mut\s+)?(\w+)\s*:\s*(.+)$/);
443
+ if (paramMatch) {
444
+ const [, isRef, isMut, name, type] = paramMatch;
445
+ params.push({
446
+ name,
447
+ type: type.trim(),
448
+ isMutable: !!isMut,
449
+ isReference: !!isRef
450
+ });
451
+ }
452
+ }
453
+
454
+ return params;
455
+ }
456
+
457
+ /**
458
+ * Split parameters handling nested generics
459
+ */
460
+ private splitParams(paramsStr: string): string[] {
461
+ const params: string[] = [];
462
+ let current = '';
463
+ let depth = 0;
464
+
465
+ for (const char of paramsStr) {
466
+ if (char === '<' || char === '(' || char === '[' || char === '{') {
467
+ depth++;
468
+ current += char;
469
+ } else if (char === '>' || char === ')' || char === ']' || char === '}') {
470
+ depth--;
471
+ current += char;
472
+ } else if (char === ',' && depth === 0) {
473
+ params.push(current.trim());
474
+ current = '';
475
+ } else {
476
+ current += char;
477
+ }
478
+ }
479
+
480
+ if (current.trim()) {
481
+ params.push(current.trim());
482
+ }
483
+
484
+ return params;
485
+ }
486
+
487
+ /**
488
+ * Parse doc comments (///) above a function
489
+ */
490
+ private parseDocComments(lines: string[], funcLineIndex: number): ParsedDocumentation | null {
491
+ const docLines: string[] = [];
492
+ let i = funcLineIndex - 1;
493
+
494
+ // Skip attributes
495
+ while (i >= 0 && lines[i].trim().startsWith('#[')) {
496
+ i--;
497
+ }
498
+
499
+ // Collect doc comments
500
+ while (i >= 0) {
501
+ const line = lines[i].trim();
502
+ if (line.startsWith('///')) {
503
+ docLines.unshift(line.substring(3).trim());
504
+ i--;
505
+ } else if (line.startsWith('//!') || line === '') {
506
+ i--;
507
+ } else {
508
+ break;
509
+ }
510
+ }
511
+
512
+ if (docLines.length === 0) return null;
513
+
514
+ return this.parseDocumentation(docLines);
515
+ }
516
+
517
+ /**
518
+ * Parse documentation content
519
+ */
520
+ private parseDocumentation(docLines: string[]): ParsedDocumentation {
521
+ const doc: ParsedDocumentation = {
522
+ params: [],
523
+ examples: []
524
+ };
525
+
526
+ let description = '';
527
+ let inExample = false;
528
+ let currentExample = '';
529
+
530
+ for (const line of docLines) {
531
+ // Check for argument documentation
532
+ const argMatch = line.match(/^#?\s*(?:Arguments?|Params?)\s*$/i);
533
+ if (argMatch) continue;
534
+
535
+ const paramMatch = line.match(/^\*?\s*`(\w+)`\s*[-:]?\s*(.+)/);
536
+ if (paramMatch) {
537
+ doc.params.push({
538
+ name: paramMatch[1],
539
+ description: paramMatch[2]
540
+ });
541
+ continue;
542
+ }
543
+
544
+ // Check for examples
545
+ if (line.match(/^#?\s*(?:Example|Examples)\s*$/i)) {
546
+ inExample = true;
547
+ continue;
548
+ }
549
+
550
+ if (line.startsWith('```')) {
551
+ if (inExample && currentExample) {
552
+ doc.examples!.push(currentExample.trim());
553
+ currentExample = '';
554
+ }
555
+ inExample = !inExample;
556
+ continue;
557
+ }
558
+
559
+ if (inExample) {
560
+ currentExample += line + '\n';
561
+ } else if (!line.startsWith('#')) {
562
+ description += (description ? ' ' : '') + line;
563
+ }
564
+ }
565
+
566
+ doc.description = description.trim() || undefined;
567
+ return doc;
568
+ }
569
+
570
+ /**
571
+ * Parse attributes above a function
572
+ */
573
+ private parseAttributes(lines: string[], funcLineIndex: number): string[] {
574
+ const attributes: string[] = [];
575
+ let i = funcLineIndex - 1;
576
+
577
+ while (i >= 0) {
578
+ const line = lines[i].trim();
579
+ if (line.startsWith('#[')) {
580
+ attributes.unshift(line);
581
+ i--;
582
+ } else if (line.startsWith('///') || line === '') {
583
+ i--;
584
+ } else {
585
+ break;
586
+ }
587
+ }
588
+
589
+ return attributes;
590
+ }
591
+
592
+ /**
593
+ * Generate a tool name from HTTP method, path, and handler name
594
+ */
595
+ private generateToolName(method: string, path: string, handlerName: string): string {
596
+ // Convert path to snake_case parts
597
+ const pathParts = path
598
+ .split('/')
599
+ .filter(p => p && !p.startsWith('{') && !p.startsWith('<') && !p.startsWith(':'))
600
+ .map(p => p.replace(/-/g, '_').toLowerCase());
601
+
602
+ if (pathParts.length > 0) {
603
+ return `${method.toLowerCase()}_${pathParts.join('_')}`;
604
+ }
605
+
606
+ return handlerName;
607
+ }
608
+
609
+ /**
610
+ * Build input schema from function info and route path
611
+ */
612
+ private buildInputSchema(
613
+ funcInfo: RustFunction,
614
+ path: string,
615
+ dataParam?: string | null
616
+ ): { type: 'object'; properties: Record<string, any>; required: string[] } {
617
+ const properties: Record<string, any> = {};
618
+ const required: string[] = [];
619
+
620
+ // Extract path parameters
621
+ const pathParams = path.match(/\{(\w+)\}|<(\w+)>|:(\w+)/g) || [];
622
+ for (const param of pathParams) {
623
+ const name = param.replace(/[{}<>:]/g, '');
624
+ properties[name] = {
625
+ type: 'string',
626
+ description: `Path parameter: ${name}`
627
+ };
628
+ required.push(name);
629
+ }
630
+
631
+ // Add function parameters (excluding web framework types)
632
+ for (const param of funcInfo.params) {
633
+ if (this.isWebFrameworkType(param.type)) continue;
634
+ if (pathParams.some(p => p.includes(param.name))) continue;
635
+
636
+ properties[param.name] = {
637
+ type: this.rustTypeToJsonSchema(param.type),
638
+ description: funcInfo.documentation?.params.find(p => p.name === param.name)?.description || param.name
639
+ };
640
+
641
+ // If it's the data parameter or not Option, it's required
642
+ if (param.name === dataParam || !param.type.startsWith('Option<')) {
643
+ required.push(param.name);
644
+ }
645
+ }
646
+
647
+ return { type: 'object', properties, required };
648
+ }
649
+
650
+ /**
651
+ * Build input schema from function only (no route info)
652
+ */
653
+ private buildInputSchemaFromFunction(
654
+ funcInfo: RustFunction
655
+ ): { type: 'object'; properties: Record<string, any>; required: string[] } {
656
+ const properties: Record<string, any> = {};
657
+ const required: string[] = [];
658
+
659
+ for (const param of funcInfo.params) {
660
+ const isOptional = param.type.startsWith('Option<');
661
+
662
+ properties[param.name] = {
663
+ type: this.rustTypeToJsonSchema(param.type),
664
+ description: funcInfo.documentation?.params.find(p => p.name === param.name)?.description || param.name
665
+ };
666
+
667
+ if (!isOptional) {
668
+ required.push(param.name);
669
+ }
670
+ }
671
+
672
+ return { type: 'object', properties, required };
673
+ }
674
+
675
+ /**
676
+ * Check if a type is a web framework type that should be ignored
677
+ */
678
+ private isWebFrameworkType(type: string): boolean {
679
+ const frameworkTypes = [
680
+ 'HttpRequest', 'HttpResponse', 'Request', 'Response',
681
+ 'State', 'Data', 'Query', 'Path', 'Json', 'Form',
682
+ 'Extension', 'Headers', 'Cookies', 'Session',
683
+ 'web::Data', 'web::Path', 'web::Query', 'web::Json',
684
+ 'actix_web::', 'axum::', 'rocket::'
685
+ ];
686
+
687
+ return frameworkTypes.some(ft => type.includes(ft));
688
+ }
689
+
690
+ /**
691
+ * Convert Rust type to JSON Schema type
692
+ */
693
+ private rustTypeToJsonSchema(rustType: string): string {
694
+ const type = rustType.trim();
695
+
696
+ // Handle Option<T>
697
+ if (type.startsWith('Option<')) {
698
+ const inner = type.match(/Option<(.+)>$/);
699
+ if (inner) return this.rustTypeToJsonSchema(inner[1]);
700
+ }
701
+
702
+ // Handle Vec<T>
703
+ if (type.startsWith('Vec<') || type.startsWith('&[') || type.includes('[]')) {
704
+ return 'array';
705
+ }
706
+
707
+ // Handle HashMap, BTreeMap
708
+ if (type.includes('Map<') || type.includes('map<')) {
709
+ return 'object';
710
+ }
711
+
712
+ // Primitive types
713
+ const typeMap: Record<string, string> = {
714
+ 'String': 'string',
715
+ '&str': 'string',
716
+ 'str': 'string',
717
+ 'i8': 'integer',
718
+ 'i16': 'integer',
719
+ 'i32': 'integer',
720
+ 'i64': 'integer',
721
+ 'i128': 'integer',
722
+ 'isize': 'integer',
723
+ 'u8': 'integer',
724
+ 'u16': 'integer',
725
+ 'u32': 'integer',
726
+ 'u64': 'integer',
727
+ 'u128': 'integer',
728
+ 'usize': 'integer',
729
+ 'f32': 'number',
730
+ 'f64': 'number',
731
+ 'bool': 'boolean',
732
+ 'char': 'string'
733
+ };
734
+
735
+ for (const [rust, json] of Object.entries(typeMap)) {
736
+ if (type === rust || type.endsWith(`::${rust}`)) {
737
+ return json;
738
+ }
739
+ }
740
+
741
+ // Default to object for complex types
742
+ return 'object';
743
+ }
744
+ }