glirastes 0.3.0 → 0.3.2

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 (310) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +154 -9
  3. package/codegen/package.json +5 -0
  4. package/dist/cjs/codegen/asset-sync.d.ts +20 -0
  5. package/dist/cjs/codegen/asset-sync.js +28 -0
  6. package/dist/cjs/codegen/coverage.d.ts +66 -0
  7. package/dist/cjs/codegen/coverage.js +408 -0
  8. package/dist/cjs/codegen/endpoint-scanner.d.ts +16 -0
  9. package/dist/cjs/codegen/endpoint-scanner.js +197 -0
  10. package/dist/cjs/codegen/format.d.ts +17 -0
  11. package/dist/cjs/codegen/format.js +34 -0
  12. package/dist/cjs/codegen/fs-utils.d.ts +45 -0
  13. package/dist/cjs/codegen/fs-utils.js +165 -0
  14. package/dist/cjs/codegen/index.d.ts +13 -0
  15. package/dist/cjs/codegen/index.js +33 -0
  16. package/dist/cjs/codegen/mcp-generator.d.ts +50 -0
  17. package/dist/cjs/codegen/mcp-generator.js +803 -0
  18. package/dist/cjs/codegen/module-generator.d.ts +11 -0
  19. package/dist/cjs/codegen/module-generator.js +353 -0
  20. package/dist/cjs/codegen/nestjs-scanner.d.ts +43 -0
  21. package/dist/cjs/codegen/nestjs-scanner.js +241 -0
  22. package/dist/cjs/codegen/output-recommender.d.ts +23 -0
  23. package/dist/cjs/codegen/output-recommender.js +33 -0
  24. package/dist/cjs/codegen/scaffolder.d.ts +36 -0
  25. package/dist/cjs/codegen/scaffolder.js +262 -0
  26. package/dist/cjs/codegen/skill-generator.d.ts +49 -0
  27. package/dist/cjs/codegen/skill-generator.js +967 -0
  28. package/dist/cjs/codegen/types.d.ts +52 -0
  29. package/dist/cjs/codegen/types.js +16 -0
  30. package/dist/cjs/codegen/ui-scanner.d.ts +24 -0
  31. package/dist/cjs/codegen/ui-scanner.js +202 -0
  32. package/dist/cjs/codegen/validator.d.ts +35 -0
  33. package/dist/cjs/codegen/validator.js +292 -0
  34. package/dist/cjs/index.d.ts +1 -0
  35. package/dist/cjs/index.js +23 -0
  36. package/dist/cjs/openapi/index.d.ts +78 -0
  37. package/dist/cjs/openapi/index.js +347 -0
  38. package/dist/cjs/package.json +1 -0
  39. package/dist/cjs/react/audio-worklet-processor.d.ts +16 -0
  40. package/dist/cjs/react/audio-worklet-processor.js +27 -0
  41. package/dist/cjs/react/bridges/rest-session-bridge.d.ts +113 -0
  42. package/dist/cjs/react/bridges/rest-session-bridge.js +209 -0
  43. package/dist/cjs/react/components/ai-chat-panel.d.ts +12 -0
  44. package/dist/cjs/react/components/ai-chat-panel.js +67 -0
  45. package/dist/cjs/react/components/ai-trigger-button.d.ts +2 -0
  46. package/dist/cjs/react/components/ai-trigger-button.js +239 -0
  47. package/dist/cjs/react/components/approval-card.d.ts +9 -0
  48. package/dist/cjs/react/components/approval-card.js +24 -0
  49. package/dist/cjs/react/components/bulk-approval-card.d.ts +9 -0
  50. package/dist/cjs/react/components/bulk-approval-card.js +36 -0
  51. package/dist/cjs/react/components/chat-input.d.ts +10 -0
  52. package/dist/cjs/react/components/chat-input.js +60 -0
  53. package/dist/cjs/react/components/chat-window.d.ts +2 -0
  54. package/dist/cjs/react/components/chat-window.js +134 -0
  55. package/dist/cjs/react/components/confirm-dialog.d.ts +32 -0
  56. package/dist/cjs/react/components/confirm-dialog.js +48 -0
  57. package/dist/cjs/react/components/floating-chat-ui.d.ts +90 -0
  58. package/dist/cjs/react/components/floating-chat-ui.js +163 -0
  59. package/dist/cjs/react/components/mention-chip.d.ts +16 -0
  60. package/dist/cjs/react/components/mention-chip.js +42 -0
  61. package/dist/cjs/react/components/mention-input.d.ts +8 -0
  62. package/dist/cjs/react/components/mention-input.js +117 -0
  63. package/dist/cjs/react/components/message-bubble.d.ts +11 -0
  64. package/dist/cjs/react/components/message-bubble.js +171 -0
  65. package/dist/cjs/react/components/message-list.d.ts +8 -0
  66. package/dist/cjs/react/components/message-list.js +52 -0
  67. package/dist/cjs/react/components/pipeline-timeline.d.ts +7 -0
  68. package/dist/cjs/react/components/pipeline-timeline.js +72 -0
  69. package/dist/cjs/react/components/recording-bar.d.ts +2 -0
  70. package/dist/cjs/react/components/recording-bar.js +81 -0
  71. package/dist/cjs/react/components/recording-controls.d.ts +18 -0
  72. package/dist/cjs/react/components/recording-controls.js +38 -0
  73. package/dist/cjs/react/components/rich-mention-input.d.ts +2 -0
  74. package/dist/cjs/react/components/rich-mention-input.js +571 -0
  75. package/dist/cjs/react/components/session-switcher.d.ts +14 -0
  76. package/dist/cjs/react/components/session-switcher.js +133 -0
  77. package/dist/cjs/react/components/suggestion-bar.d.ts +9 -0
  78. package/dist/cjs/react/components/suggestion-bar.js +47 -0
  79. package/dist/cjs/react/components/suggestion-chip.d.ts +9 -0
  80. package/dist/cjs/react/components/suggestion-chip.js +14 -0
  81. package/dist/cjs/react/components/voice-input-addon.d.ts +13 -0
  82. package/dist/cjs/react/components/voice-input-addon.js +31 -0
  83. package/dist/cjs/react/components/voice-input-button.d.ts +2 -0
  84. package/dist/cjs/react/components/voice-input-button.js +55 -0
  85. package/dist/cjs/react/components/wavesurfer-loader.d.ts +5 -0
  86. package/dist/cjs/react/components/wavesurfer-loader.js +36 -0
  87. package/dist/cjs/react/hooks/use-ai-chat.d.ts +22 -0
  88. package/dist/cjs/react/hooks/use-ai-chat.js +51 -0
  89. package/dist/cjs/react/hooks/use-approvals.d.ts +23 -0
  90. package/dist/cjs/react/hooks/use-approvals.js +63 -0
  91. package/dist/cjs/react/hooks/use-deepgram-transcription.d.ts +2 -0
  92. package/dist/cjs/react/hooks/use-deepgram-transcription.js +329 -0
  93. package/dist/cjs/react/hooks/use-drag-resize-panel.d.ts +48 -0
  94. package/dist/cjs/react/hooks/use-drag-resize-panel.js +308 -0
  95. package/dist/cjs/react/hooks/use-draggable-position.d.ts +25 -0
  96. package/dist/cjs/react/hooks/use-draggable-position.js +134 -0
  97. package/dist/cjs/react/hooks/use-keyboard-shortcut.d.ts +20 -0
  98. package/dist/cjs/react/hooks/use-keyboard-shortcut.js +93 -0
  99. package/dist/cjs/react/hooks/use-mentions.d.ts +23 -0
  100. package/dist/cjs/react/hooks/use-mentions.js +42 -0
  101. package/dist/cjs/react/hooks/use-suggestions.d.ts +22 -0
  102. package/dist/cjs/react/hooks/use-suggestions.js +39 -0
  103. package/dist/cjs/react/index.d.ts +43 -0
  104. package/dist/cjs/react/index.js +111 -0
  105. package/dist/cjs/react/provider/ai-chat-provider.d.ts +45 -0
  106. package/dist/cjs/react/provider/ai-chat-provider.js +1024 -0
  107. package/dist/cjs/react/provider/chat-context.d.ts +84 -0
  108. package/dist/cjs/react/provider/chat-context.js +13 -0
  109. package/dist/cjs/react/template.d.ts +84 -0
  110. package/dist/cjs/react/template.js +90 -0
  111. package/dist/cjs/react/themes.d.ts +24 -0
  112. package/dist/cjs/react/themes.js +273 -0
  113. package/dist/cjs/react/transports/langgraph/index.d.ts +2 -0
  114. package/dist/cjs/react/transports/langgraph/index.js +8 -0
  115. package/dist/cjs/react/transports/langgraph/langgraph-ai-chat.d.ts +62 -0
  116. package/dist/cjs/react/transports/langgraph/langgraph-ai-chat.js +94 -0
  117. package/dist/cjs/react/transports/langgraph.d.ts +71 -0
  118. package/dist/cjs/react/transports/langgraph.js +369 -0
  119. package/dist/cjs/react/transports/vercel/index.d.ts +2 -0
  120. package/dist/cjs/react/transports/vercel/index.js +8 -0
  121. package/dist/cjs/react/transports/vercel/vercel-ai-chat.d.ts +49 -0
  122. package/dist/cjs/react/transports/vercel/vercel-ai-chat.js +81 -0
  123. package/dist/cjs/react/transports/vercel.d.ts +30 -0
  124. package/dist/cjs/react/transports/vercel.js +69 -0
  125. package/dist/cjs/react/types.d.ts +760 -0
  126. package/dist/cjs/react/types.js +2 -0
  127. package/dist/cjs/react/ui.d.ts +73 -0
  128. package/dist/cjs/react/ui.js +183 -0
  129. package/dist/cjs/react/utils/create-approval-description.d.ts +53 -0
  130. package/dist/cjs/react/utils/create-approval-description.js +122 -0
  131. package/dist/cjs/react/utils/create-tool-result-handler.d.ts +90 -0
  132. package/dist/cjs/react/utils/create-tool-result-handler.js +168 -0
  133. package/dist/cjs/react/utils/mention-markup.d.ts +13 -0
  134. package/dist/cjs/react/utils/mention-markup.js +117 -0
  135. package/dist/cjs/react/utils/merge-pipeline-steps.d.ts +19 -0
  136. package/dist/cjs/react/utils/merge-pipeline-steps.js +81 -0
  137. package/dist/cjs/react/utils/sanitize-stored-messages.d.ts +23 -0
  138. package/dist/cjs/react/utils/sanitize-stored-messages.js +52 -0
  139. package/dist/cjs/server/adapters/nestjs/chat/ai-chat-auth.guard.d.ts +10 -0
  140. package/dist/cjs/server/adapters/nestjs/chat/ai-chat-auth.guard.js +42 -0
  141. package/dist/cjs/server/adapters/nestjs/chat/ai-chat-module-options.interface.d.ts +32 -0
  142. package/dist/cjs/server/adapters/nestjs/chat/ai-chat-module-options.interface.js +4 -0
  143. package/dist/cjs/server/adapters/nestjs/chat/ai-chat.controller.d.ts +11 -0
  144. package/dist/cjs/server/adapters/nestjs/chat/ai-chat.controller.js +80 -0
  145. package/dist/cjs/server/adapters/nestjs/chat/ai-chat.module.d.ts +9 -0
  146. package/dist/cjs/server/adapters/nestjs/chat/ai-chat.module.js +119 -0
  147. package/dist/cjs/server/adapters/nestjs/chat/ai-chat.service.d.ts +13 -0
  148. package/dist/cjs/server/adapters/nestjs/chat/ai-chat.service.js +131 -0
  149. package/dist/cjs/server/adapters/nestjs/chat/dto/ai-chat-request.dto.d.ts +7 -0
  150. package/dist/cjs/server/adapters/nestjs/chat/dto/ai-chat-request.dto.js +52 -0
  151. package/dist/cjs/server/adapters/nestjs/chat/dto/chat-message-part.dto.d.ts +19 -0
  152. package/dist/cjs/server/adapters/nestjs/chat/dto/chat-message-part.dto.js +108 -0
  153. package/dist/cjs/server/adapters/nestjs/chat/dto/chat-message.dto.d.ts +8 -0
  154. package/dist/cjs/server/adapters/nestjs/chat/dto/chat-message.dto.js +59 -0
  155. package/dist/cjs/server/adapters/nestjs/chat/dto/index.d.ts +3 -0
  156. package/dist/cjs/server/adapters/nestjs/chat/dto/index.js +9 -0
  157. package/dist/cjs/server/adapters/nestjs/chat/index.d.ts +3 -0
  158. package/dist/cjs/server/adapters/nestjs/chat/index.js +9 -0
  159. package/dist/cjs/server/adapters/nestjs/chat/speech-stream.gateway.d.ts +4 -0
  160. package/dist/cjs/server/adapters/nestjs/chat/speech-stream.gateway.js +73 -0
  161. package/dist/cjs/server/adapters/nestjs/chat/ws-loader.d.ts +5 -0
  162. package/dist/cjs/server/adapters/nestjs/chat/ws-loader.js +72 -0
  163. package/dist/cjs/server/adapters/nestjs/decorators/ai-module.decorator.d.ts +6 -0
  164. package/dist/cjs/server/adapters/nestjs/decorators/ai-module.decorator.js +13 -0
  165. package/dist/cjs/server/adapters/nestjs/decorators/ai-param.decorator.d.ts +5 -0
  166. package/dist/cjs/server/adapters/nestjs/decorators/ai-param.decorator.js +15 -0
  167. package/dist/cjs/server/adapters/nestjs/decorators/ai-tool.decorator.d.ts +6 -0
  168. package/dist/cjs/server/adapters/nestjs/decorators/ai-tool.decorator.js +22 -0
  169. package/dist/cjs/server/adapters/nestjs/decorators/constants.d.ts +4 -0
  170. package/dist/cjs/server/adapters/nestjs/decorators/constants.js +7 -0
  171. package/dist/cjs/server/adapters/nestjs/index.d.ts +14 -0
  172. package/dist/cjs/server/adapters/nestjs/index.js +42 -0
  173. package/dist/cjs/server/adapters/nestjs/metadata.d.ts +39 -0
  174. package/dist/cjs/server/adapters/nestjs/metadata.js +36 -0
  175. package/dist/cjs/server/adapters/nestjs/module/ai-tools-explorer.service.d.ts +36 -0
  176. package/dist/cjs/server/adapters/nestjs/module/ai-tools-explorer.service.js +159 -0
  177. package/dist/cjs/server/adapters/nestjs/module/ai-tools.module.d.ts +37 -0
  178. package/dist/cjs/server/adapters/nestjs/module/ai-tools.module.js +44 -0
  179. package/dist/cjs/server/adapters/nestjs/module/ai-tools.service.d.ts +28 -0
  180. package/dist/cjs/server/adapters/nestjs/module/ai-tools.service.js +41 -0
  181. package/dist/cjs/server/adapters/nestjs/scanner/nestjs-scanner.d.ts +16 -0
  182. package/dist/cjs/server/adapters/nestjs/scanner/nestjs-scanner.js +117 -0
  183. package/dist/cjs/server/adapters/nestjs/scanner/schema-builder.d.ts +26 -0
  184. package/dist/cjs/server/adapters/nestjs/scanner/schema-builder.js +259 -0
  185. package/dist/cjs/server/adapters/nestjs/swagger.d.ts +7 -0
  186. package/dist/cjs/server/adapters/nestjs/swagger.js +39 -0
  187. package/dist/cjs/server/adapters/nextjs/context-helpers.d.ts +22 -0
  188. package/dist/cjs/server/adapters/nextjs/context-helpers.js +60 -0
  189. package/dist/cjs/server/adapters/nextjs/create-ai-chat-handler.d.ts +94 -0
  190. package/dist/cjs/server/adapters/nextjs/create-ai-chat-handler.js +965 -0
  191. package/dist/cjs/server/adapters/nextjs/filter-fallback-error.d.ts +11 -0
  192. package/dist/cjs/server/adapters/nextjs/filter-fallback-error.js +41 -0
  193. package/dist/cjs/server/adapters/nextjs/index.d.ts +8 -0
  194. package/dist/cjs/server/adapters/nextjs/index.js +22 -0
  195. package/dist/cjs/server/adapters/nextjs/prepare-model-messages.d.ts +58 -0
  196. package/dist/cjs/server/adapters/nextjs/prepare-model-messages.js +114 -0
  197. package/dist/cjs/server/adapters/nextjs/sanitize-model-messages.d.ts +64 -0
  198. package/dist/cjs/server/adapters/nextjs/sanitize-model-messages.js +489 -0
  199. package/dist/cjs/server/adapters/nextjs/server-action-helper.d.ts +7 -0
  200. package/dist/cjs/server/adapters/nextjs/server-action-helper.js +40 -0
  201. package/dist/cjs/server/adapters/nextjs/types.d.ts +246 -0
  202. package/dist/cjs/server/adapters/nextjs/types.js +2 -0
  203. package/dist/cjs/server/adapters/nextjs/with-ai-tool.d.ts +9 -0
  204. package/dist/cjs/server/adapters/nextjs/with-ai-tool.js +12 -0
  205. package/dist/cjs/server/core/followup-tool.d.ts +9 -0
  206. package/dist/cjs/server/core/followup-tool.js +82 -0
  207. package/dist/cjs/server/core/index.d.ts +139 -0
  208. package/dist/cjs/server/core/index.js +818 -0
  209. package/dist/cjs/server/core/intent-classifier.d.ts +94 -0
  210. package/dist/cjs/server/core/intent-classifier.js +324 -0
  211. package/dist/cjs/server/core/model-selector.d.ts +12 -0
  212. package/dist/cjs/server/core/model-selector.js +48 -0
  213. package/dist/cjs/server/core/module-router.d.ts +14 -0
  214. package/dist/cjs/server/core/module-router.js +110 -0
  215. package/dist/cjs/server/core/zod-compact.d.ts +18 -0
  216. package/dist/cjs/server/core/zod-compact.js +129 -0
  217. package/dist/cjs/server/index.d.ts +6 -0
  218. package/dist/cjs/server/index.js +28 -0
  219. package/dist/cjs/server/lancer/cache.d.ts +9 -0
  220. package/dist/cjs/server/lancer/cache.js +33 -0
  221. package/dist/cjs/server/lancer/client.d.ts +2 -0
  222. package/dist/cjs/server/lancer/client.js +279 -0
  223. package/dist/cjs/server/lancer/errors.d.ts +13 -0
  224. package/dist/cjs/server/lancer/errors.js +21 -0
  225. package/dist/cjs/server/lancer/index.d.ts +3 -0
  226. package/dist/cjs/server/lancer/index.js +7 -0
  227. package/dist/cjs/server/lancer/telemetry-buffer.d.ts +15 -0
  228. package/dist/cjs/server/lancer/telemetry-buffer.js +64 -0
  229. package/dist/cjs/server/lancer/types.d.ts +201 -0
  230. package/dist/cjs/server/lancer/types.js +5 -0
  231. package/dist/cjs/server/pii-shield/aegis-detector.d.ts +26 -0
  232. package/dist/cjs/server/pii-shield/aegis-detector.js +26 -0
  233. package/dist/cjs/server/pii-shield/create-pii-shield.d.ts +2 -0
  234. package/dist/cjs/server/pii-shield/create-pii-shield.js +191 -0
  235. package/dist/cjs/server/pii-shield/deep-walk.d.ts +1 -0
  236. package/dist/cjs/server/pii-shield/deep-walk.js +19 -0
  237. package/dist/cjs/server/pii-shield/fake-data.d.ts +5 -0
  238. package/dist/cjs/server/pii-shield/fake-data.js +170 -0
  239. package/dist/cjs/server/pii-shield/index.d.ts +4 -0
  240. package/dist/cjs/server/pii-shield/index.js +9 -0
  241. package/dist/cjs/server/pii-shield/leakage.d.ts +1 -0
  242. package/dist/cjs/server/pii-shield/leakage.js +15 -0
  243. package/dist/cjs/server/pii-shield/session-mapping.d.ts +12 -0
  244. package/dist/cjs/server/pii-shield/session-mapping.js +70 -0
  245. package/dist/cjs/server/pipeline.d.ts +26 -0
  246. package/dist/cjs/server/pipeline.js +127 -0
  247. package/dist/cjs/server/testing/approvals.d.ts +11 -0
  248. package/dist/cjs/server/testing/approvals.js +41 -0
  249. package/dist/cjs/server/testing/combination.d.ts +3 -0
  250. package/dist/cjs/server/testing/combination.js +83 -0
  251. package/dist/cjs/server/testing/create-test-suite.d.ts +29 -0
  252. package/dist/cjs/server/testing/create-test-suite.js +81 -0
  253. package/dist/cjs/server/testing/edge-cases.d.ts +8 -0
  254. package/dist/cjs/server/testing/edge-cases.js +277 -0
  255. package/dist/cjs/server/testing/guardrails.d.ts +14 -0
  256. package/dist/cjs/server/testing/guardrails.js +152 -0
  257. package/dist/cjs/server/testing/helpers.d.ts +14 -0
  258. package/dist/cjs/server/testing/helpers.js +119 -0
  259. package/dist/cjs/server/testing/index.d.ts +12 -0
  260. package/dist/cjs/server/testing/index.js +37 -0
  261. package/dist/cjs/server/testing/mock-executor.d.ts +8 -0
  262. package/dist/cjs/server/testing/mock-executor.js +40 -0
  263. package/dist/cjs/server/testing/regression.d.ts +7 -0
  264. package/dist/cjs/server/testing/regression.js +27 -0
  265. package/dist/cjs/server/testing/routing.d.ts +12 -0
  266. package/dist/cjs/server/testing/routing.js +63 -0
  267. package/dist/cjs/server/testing/schema-consistency.d.ts +6 -0
  268. package/dist/cjs/server/testing/schema-consistency.js +56 -0
  269. package/dist/cjs/server/testing/smoke.d.ts +11 -0
  270. package/dist/cjs/server/testing/smoke.js +64 -0
  271. package/dist/cjs/server/testing/types.d.ts +156 -0
  272. package/dist/cjs/server/testing/types.js +2 -0
  273. package/dist/cjs/types.d.ts +696 -0
  274. package/dist/cjs/types.js +91 -0
  275. package/dist/cli/commands/install-skills.d.ts +17 -0
  276. package/dist/cli/commands/install-skills.js +185 -0
  277. package/dist/cli/commands/install-skills.js.map +1 -0
  278. package/dist/cli/index.js +25 -0
  279. package/dist/cli/index.js.map +1 -1
  280. package/dist/react/components/ai-trigger-button.js +4 -6
  281. package/dist/react/components/ai-trigger-button.js.map +1 -1
  282. package/dist/react/components/recording-bar.js +4 -6
  283. package/dist/react/components/recording-bar.js.map +1 -1
  284. package/dist/react/components/wavesurfer-loader.d.ts +5 -0
  285. package/dist/react/components/wavesurfer-loader.js +34 -0
  286. package/dist/react/components/wavesurfer-loader.js.map +1 -0
  287. package/dist/server/adapters/nestjs/chat/ai-chat.module.d.ts +1 -1
  288. package/dist/server/adapters/nestjs/chat/ai-chat.module.js +3 -2
  289. package/dist/server/adapters/nestjs/chat/ai-chat.module.js.map +1 -1
  290. package/dist/server/adapters/nestjs/chat/speech-stream.gateway.d.ts +1 -1
  291. package/dist/server/adapters/nestjs/chat/speech-stream.gateway.js +10 -8
  292. package/dist/server/adapters/nestjs/chat/speech-stream.gateway.js.map +1 -1
  293. package/dist/server/adapters/nestjs/chat/ws-loader.d.ts +5 -0
  294. package/dist/server/adapters/nestjs/chat/ws-loader.js +37 -0
  295. package/dist/server/adapters/nestjs/chat/ws-loader.js.map +1 -0
  296. package/openapi/package.json +5 -0
  297. package/package.json +59 -16
  298. package/react/langgraph/package.json +5 -0
  299. package/react/package.json +5 -0
  300. package/react/vercel/package.json +5 -0
  301. package/server/nestjs/package.json +5 -0
  302. package/server/nextjs/package.json +5 -0
  303. package/server/package.json +5 -0
  304. package/server/testing/package.json +5 -0
  305. package/skills/README.md +107 -0
  306. package/skills/building-glirastes-chat-ui/SKILL.md +378 -0
  307. package/skills/integrating-glirastes-nestjs/SKILL.md +346 -0
  308. package/skills/integrating-glirastes-nextjs/SKILL.md +312 -0
  309. package/skills/integrating-glirastes-nextjs-with-nestjs-backend/SKILL.md +359 -0
  310. package/skills/maintaining-glirastes-tools/SKILL.md +467 -0
@@ -0,0 +1,803 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateMcpServer = generateMcpServer;
4
+ const fs_utils_js_1 = require("./fs-utils.js");
5
+ const endpoint_scanner_js_1 = require("./endpoint-scanner.js");
6
+ const ui_scanner_js_1 = require("./ui-scanner.js");
7
+ const types_js_1 = require("./types.js");
8
+ /**
9
+ * Extract tool information from a source file for MCP generation.
10
+ * Parses defineEndpointTool / defineUiTool blocks via regex.
11
+ */
12
+ async function extractSkillTools(absolutePath) {
13
+ const content = await (0, fs_utils_js_1.readFileSafe)(absolutePath);
14
+ const tools = [];
15
+ // Match endpoint tool blocks
16
+ const endpointBlocks = (0, fs_utils_js_1.extractBalancedBlocks)(content, /define(?:Ai)?EndpointTool\(\s*/);
17
+ for (const block of endpointBlocks) {
18
+ const tool = parseToolBlock(block, 'endpoint');
19
+ if (tool)
20
+ tools.push(tool);
21
+ }
22
+ // Match UI tool blocks (they don't have method/path, so we synthesize POST + /api/ui/{toolName})
23
+ const uiBlocks = (0, fs_utils_js_1.extractBalancedBlocks)(content, /define(?:Ai)?UiTool\(\s*/);
24
+ for (const block of uiBlocks) {
25
+ const tool = parseToolBlock(block, 'ui');
26
+ if (tool)
27
+ tools.push(tool);
28
+ }
29
+ return tools;
30
+ }
31
+ function parseToolBlock(block, kind) {
32
+ const toolNameMatch = block.match(/toolName\s*:\s*['"`]([^'"`]+)['"`]/);
33
+ if (!toolNameMatch)
34
+ return null;
35
+ // Match description — handle backtick templates (multiline) and regular quotes
36
+ const descMatch = block.match(/description\s*:\s*`([^`]+)`/) ??
37
+ block.match(/description\s*:\s*['"]([^'"]+)['"]/);
38
+ const methodMatch = block.match(/method\s*:\s*['"`]([^'"`]+)['"`]/);
39
+ const pathMatch = block.match(/path\s*:\s*['"`]([^'"`]+)['"`]/);
40
+ const moduleMatch = block.match(/module\s*:\s*['"`]([^'"`]+)['"`]/);
41
+ const approvalMatch = block.match(/needsApproval\s*:\s*(true|false)/);
42
+ // Extract allowedRoles
43
+ const rolesMatch = block.match(/allowedRoles\s*:\s*\[([^\]]*)\]/);
44
+ let allowedRoles;
45
+ if (rolesMatch) {
46
+ allowedRoles = rolesMatch[1]
47
+ .match(/['"`]([^'"`]+)['"`]/g)
48
+ ?.map((s) => s.replace(/['"`]/g, ''));
49
+ }
50
+ // Extract input fields from z.object({...})
51
+ const inputFields = extractZodFields(block, 'inputSchema');
52
+ const outputFields = extractZodFields(block, 'outputSchema');
53
+ const toolName = toolNameMatch[1];
54
+ return {
55
+ toolName,
56
+ description: descMatch?.[1] ?? `${toolName} tool`,
57
+ method: methodMatch?.[1] ?? (kind === 'ui' ? 'POST' : 'GET'),
58
+ path: pathMatch?.[1] ?? (kind === 'ui' ? `/api/ui/${toolName}` : `/api/${toolName}`),
59
+ module: moduleMatch?.[1],
60
+ allowedRoles,
61
+ needsApproval: approvalMatch ? approvalMatch[1] === 'true' : undefined,
62
+ inputFields,
63
+ outputFields,
64
+ };
65
+ }
66
+ /**
67
+ * Extract field names and approximate types from a Zod schema block.
68
+ */
69
+ function extractZodFields(block, schemaKey) {
70
+ const fields = [];
71
+ // Find the schema block: inputSchema: z.object({...})
72
+ const schemaPattern = new RegExp(`${schemaKey}\\s*:\\s*z\\.object\\(\\s*\\{([\\s\\S]*?)\\}\\s*\\)`);
73
+ const schemaMatch = block.match(schemaPattern);
74
+ if (!schemaMatch)
75
+ return fields;
76
+ const schemaContent = schemaMatch[1];
77
+ // Match field definitions: fieldName: z.string(), fieldName: z.number().optional(), etc.
78
+ const fieldPattern = /(\w+)\s*:\s*z\.(\w+)\((.*?)\)((?:\.\w+\([^)]*\))*)/g;
79
+ let fieldMatch;
80
+ while ((fieldMatch = fieldPattern.exec(schemaContent)) !== null) {
81
+ const name = fieldMatch[1];
82
+ const zodType = fieldMatch[2];
83
+ const chainedMethods = fieldMatch[4] ?? '';
84
+ const isOptional = chainedMethods.includes('.optional()');
85
+ const descriptionMatch = chainedMethods.match(/\.describe\(\s*['"`]([^'"`]+)['"`]\s*\)/);
86
+ const typeMap = {
87
+ string: 'string',
88
+ number: 'number',
89
+ boolean: 'boolean',
90
+ date: 'string (ISO date)',
91
+ enum: 'string (enum)',
92
+ array: 'array',
93
+ object: 'object',
94
+ uuid: 'string (UUID)',
95
+ };
96
+ fields.push({
97
+ name,
98
+ type: typeMap[zodType] ?? zodType,
99
+ required: !isOptional,
100
+ description: descriptionMatch?.[1],
101
+ });
102
+ }
103
+ return fields;
104
+ }
105
+ // ============================================================================
106
+ // MCP Server Code Generation
107
+ // ============================================================================
108
+ /**
109
+ * Map extracted Zod type strings to Zod builder calls for generated code.
110
+ */
111
+ function zodTypeToCode(field) {
112
+ const typeMap = {
113
+ 'string': 'z.string()',
114
+ 'number': 'z.number()',
115
+ 'boolean': 'z.boolean()',
116
+ 'string (ISO date)': 'z.string()',
117
+ 'string (enum)': 'z.string()',
118
+ 'string (UUID)': 'z.string()',
119
+ 'array': 'z.array(z.string())',
120
+ 'object': 'z.record(z.string())',
121
+ };
122
+ let code = typeMap[field.type] ?? 'z.string()';
123
+ if (field.description) {
124
+ code += `.describe(${JSON.stringify(field.description)})`;
125
+ }
126
+ if (!field.required) {
127
+ code += '.optional()';
128
+ }
129
+ return code;
130
+ }
131
+ /**
132
+ * Generate the Zod schema object literal for a tool's input fields.
133
+ */
134
+ function generateZodSchema(fields) {
135
+ if (fields.length === 0)
136
+ return '{}';
137
+ const entries = fields.map((f) => ` ${f.name}: ${zodTypeToCode(f)},`);
138
+ return `{\n${entries.join('\n')}\n }`;
139
+ }
140
+ /**
141
+ * Generate a single MCP tool registration block.
142
+ */
143
+ function generateToolRegistration(tool, baseUrl) {
144
+ const schema = generateZodSchema(tool.inputFields);
145
+ const httpMethod = tool.method;
146
+ const fullPath = `${baseUrl}${tool.path}`;
147
+ // Build the fetch call based on HTTP method
148
+ const hasBody = httpMethod !== 'GET' && httpMethod !== 'DELETE';
149
+ const fetchOptions = hasBody
150
+ ? `{
151
+ method: '${httpMethod}',
152
+ headers: { ...authHeaders(), 'Content-Type': 'application/json' },
153
+ body: JSON.stringify(params),
154
+ }`
155
+ : `{
156
+ method: '${httpMethod}',
157
+ headers: authHeaders(),
158
+ }`;
159
+ // Build URL — substitute path params like :id with params.id
160
+ const pathParams = tool.path.match(/:(\w+)/g);
161
+ let urlExpr;
162
+ if (pathParams) {
163
+ const paramNames = pathParams.map((p) => p.slice(1));
164
+ let urlTemplate = fullPath;
165
+ for (const param of paramNames) {
166
+ urlTemplate = urlTemplate.replace(`:${param}`, `\${params.${param}}`);
167
+ }
168
+ urlExpr = `\`${urlTemplate}\``;
169
+ }
170
+ else {
171
+ urlExpr = `'${fullPath}'`;
172
+ }
173
+ return `server.tool(
174
+ '${tool.toolName}',
175
+ ${JSON.stringify(tool.description)},
176
+ ${schema},
177
+ async (params) => {
178
+ const response = await fetch(${urlExpr}, ${fetchOptions});
179
+ const data = await response.json();
180
+
181
+ if (!response.ok) {
182
+ return {
183
+ content: [{ type: 'text', text: \`Error \${response.status}: \${JSON.stringify(data)}\` }],
184
+ isError: true,
185
+ };
186
+ }
187
+
188
+ return {
189
+ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
190
+ };
191
+ },
192
+ );`;
193
+ }
194
+ /**
195
+ * Shorten a description to max ~180 chars, English, first sentence only.
196
+ */
197
+ function shortenDescription(desc) {
198
+ // Take first sentence only
199
+ const first = desc.split(/\n/)[0].replace(/\s+/g, ' ').trim();
200
+ // Truncate to 180 chars
201
+ if (first.length <= 180)
202
+ return first;
203
+ return first.slice(0, 177) + '...';
204
+ }
205
+ /**
206
+ * Build the tool registry as a JSON structure for the layered server.
207
+ */
208
+ function buildToolRegistry(tools, baseUrl) {
209
+ const entries = tools.map(t => {
210
+ const params = {};
211
+ for (const f of t.inputFields) {
212
+ const typeStr = f.type === 'array' ? 'string[]' :
213
+ f.type === 'object' ? 'object' :
214
+ f.type.startsWith('string') ? 'string' :
215
+ f.type;
216
+ params[f.name] = `${typeStr}${f.required ? '' : '?'}`;
217
+ }
218
+ return ` {
219
+ name: ${JSON.stringify(t.toolName)},
220
+ description: ${JSON.stringify(shortenDescription(t.description))},
221
+ method: ${JSON.stringify(t.method)},
222
+ path: ${JSON.stringify(t.path)},
223
+ module: ${JSON.stringify(t.module ?? 'general')},
224
+ params: ${JSON.stringify(params)},
225
+ }`;
226
+ });
227
+ return `[\n${entries.join(',\n')}\n]`;
228
+ }
229
+ /**
230
+ * Generate the server.ts file content using layered tool design.
231
+ *
232
+ * Instead of registering 93 individual tools (which costs ~74K tokens),
233
+ * this generates 3 meta-tools:
234
+ * - search_tools: Find tools by keyword (returns name + description only)
235
+ * - describe_tool: Get full schema for a specific tool
236
+ * - call_tool: Execute a tool with parameters
237
+ *
238
+ * This reduces token cost from ~74K to ~3K (96% reduction).
239
+ */
240
+ function generateServerFile(config, tools) {
241
+ const slug = slugify(config.appName);
242
+ const registry = buildToolRegistry(tools, config.baseUrl);
243
+ return `// Generated MCP Server for ${config.appName}
244
+ // Auto-generated by glirastes
245
+ // Layered design: 3 meta-tools instead of ${tools.length} flat tools (~96% token reduction)
246
+
247
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
248
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
249
+ import { z } from 'zod';
250
+ import { authHeaders } from './auth.js';
251
+
252
+ const BASE_URL = process.env.BASE_URL ?? '${config.baseUrl}';
253
+
254
+ const server = new McpServer({
255
+ name: '${slug}',
256
+ version: '${config.version ?? '1.0.0'}',
257
+ });
258
+
259
+ // Tool registry — ${tools.length} tools across ${new Set(tools.map(t => t.module ?? 'general')).size} modules
260
+ const TOOLS: Array<{
261
+ name: string;
262
+ description: string;
263
+ method: string;
264
+ path: string;
265
+ module: string;
266
+ params: Record<string, string>;
267
+ }> = ${registry};
268
+
269
+ // --- Meta-tool 1: Search tools by keyword ---
270
+ server.tool(
271
+ 'search_tools',
272
+ 'Find available API tools by keyword or module name. Returns matching tool names with descriptions.',
273
+ {
274
+ query: z.string().describe('Keyword to search in tool names and descriptions'),
275
+ module: z.string().optional().describe('Filter by module name'),
276
+ limit: z.number().optional().describe('Max results (default 10)'),
277
+ },
278
+ async (params) => {
279
+ const q = params.query.toLowerCase();
280
+ const limit = params.limit ?? 10;
281
+ const matches = TOOLS
282
+ .filter(t => {
283
+ if (params.module && t.module !== params.module) return false;
284
+ return t.name.includes(q) || t.description.toLowerCase().includes(q) || t.module.includes(q);
285
+ })
286
+ .slice(0, limit)
287
+ .map(t => ({ name: t.name, description: t.description, module: t.module, method: t.method }));
288
+
289
+ return {
290
+ content: [{ type: 'text', text: JSON.stringify({ matches, total: matches.length, modules: [...new Set(TOOLS.map(t => t.module))] }, null, 2) }],
291
+ };
292
+ },
293
+ );
294
+
295
+ // --- Meta-tool 2: Describe a specific tool ---
296
+ server.tool(
297
+ 'describe_tool',
298
+ 'Get full details and parameter schema for a specific tool by name.',
299
+ {
300
+ name: z.string().describe('Exact tool name from search_tools results'),
301
+ },
302
+ async (params) => {
303
+ const tool = TOOLS.find(t => t.name === params.name);
304
+ if (!tool) {
305
+ return { content: [{ type: 'text', text: \`Tool "\${params.name}" not found. Use search_tools to find available tools.\` }], isError: true };
306
+ }
307
+ return {
308
+ content: [{ type: 'text', text: JSON.stringify(tool, null, 2) }],
309
+ };
310
+ },
311
+ );
312
+
313
+ // --- Meta-tool 3: Execute a tool ---
314
+ server.tool(
315
+ 'call_tool',
316
+ 'Execute an API tool by name with the given parameters.',
317
+ {
318
+ name: z.string().describe('Tool name to execute'),
319
+ params: z.record(z.unknown()).optional().describe('Tool parameters as key-value pairs'),
320
+ },
321
+ async (args) => {
322
+ const tool = TOOLS.find(t => t.name === args.name);
323
+ if (!tool) {
324
+ return { content: [{ type: 'text', text: \`Tool "\${args.name}" not found.\` }], isError: true };
325
+ }
326
+
327
+ const toolParams = args.params ?? {};
328
+
329
+ // Build URL — substitute path params like :id
330
+ let url = \`\${BASE_URL}\${tool.path}\`;
331
+ const pathParams = tool.path.match(/:([\\w]+)/g);
332
+ if (pathParams) {
333
+ for (const p of pathParams) {
334
+ const key = p.slice(1);
335
+ const val = toolParams[key];
336
+ if (val !== undefined) {
337
+ url = url.replace(p, String(val));
338
+ delete toolParams[key];
339
+ }
340
+ }
341
+ }
342
+
343
+ // Build query string for GET requests with remaining params
344
+ if (tool.method === 'GET' && Object.keys(toolParams).length > 0) {
345
+ const qs = new URLSearchParams();
346
+ for (const [k, v] of Object.entries(toolParams)) {
347
+ if (v !== undefined && v !== null) qs.set(k, String(v));
348
+ }
349
+ url += \`?\${qs.toString()}\`;
350
+ }
351
+
352
+ const hasBody = tool.method !== 'GET' && tool.method !== 'DELETE';
353
+ const fetchOpts: RequestInit = {
354
+ method: tool.method,
355
+ headers: hasBody
356
+ ? { ...authHeaders(), 'Content-Type': 'application/json' }
357
+ : authHeaders(),
358
+ };
359
+ if (hasBody && Object.keys(toolParams).length > 0) {
360
+ fetchOpts.body = JSON.stringify(toolParams);
361
+ }
362
+
363
+ try {
364
+ const response = await fetch(url, fetchOpts);
365
+ const data = await response.json();
366
+
367
+ if (!response.ok) {
368
+ return {
369
+ content: [{ type: 'text', text: \`Error \${response.status}: \${JSON.stringify(data)}\` }],
370
+ isError: true,
371
+ };
372
+ }
373
+
374
+ return {
375
+ content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
376
+ };
377
+ } catch (err) {
378
+ return {
379
+ content: [{ type: 'text', text: \`Request failed: \${err instanceof Error ? err.message : String(err)}\` }],
380
+ isError: true,
381
+ };
382
+ }
383
+ },
384
+ );
385
+
386
+ async function main() {
387
+ const transport = new StdioServerTransport();
388
+ await server.connect(transport);
389
+ }
390
+
391
+ main().catch(console.error);
392
+ `;
393
+ }
394
+ /**
395
+ * Generate the auth.ts helper file content.
396
+ */
397
+ function generateAuthFile(auth) {
398
+ switch (auth.type) {
399
+ case 'bearer':
400
+ return `// Auth helper for ${auth.type} authentication
401
+ // Auto-generated by glirastes — do not edit manually.
402
+
403
+ const TOKEN = process.env.${auth.tokenEnvVar};
404
+
405
+ if (!TOKEN) {
406
+ console.error('Missing environment variable: ${auth.tokenEnvVar}');
407
+ process.exit(1);
408
+ }
409
+
410
+ /**
411
+ * Returns authorization headers for API requests.
412
+ */
413
+ export function authHeaders(): Record<string, string> {
414
+ return {
415
+ Authorization: \`Bearer \${TOKEN}\`,
416
+ };
417
+ }
418
+ `;
419
+ case 'api-key':
420
+ return `// Auth helper for API key authentication
421
+ // Auto-generated by glirastes — do not edit manually.
422
+
423
+ const API_KEY = process.env.${auth.keyEnvVar};
424
+
425
+ if (!API_KEY) {
426
+ console.error('Missing environment variable: ${auth.keyEnvVar}');
427
+ process.exit(1);
428
+ }
429
+
430
+ /**
431
+ * Returns authorization headers for API requests.
432
+ */
433
+ export function authHeaders(): Record<string, string> {
434
+ return {
435
+ '${auth.headerName}': API_KEY!,
436
+ };
437
+ }
438
+ `;
439
+ case 'oauth2':
440
+ return `// Auth helper for OAuth 2.0 Client Credentials authentication
441
+ // Auto-generated by glirastes — do not edit manually.
442
+
443
+ const CLIENT_ID = process.env.${auth.clientIdEnvVar};
444
+ const CLIENT_SECRET = process.env.${auth.clientSecretEnvVar};
445
+ const TOKEN_URL = '${auth.tokenUrl}';
446
+ ${auth.scopes ? `const SCOPES = '${auth.scopes.join(' ')}';` : ''}
447
+
448
+ if (!CLIENT_ID || !CLIENT_SECRET) {
449
+ console.error('Missing environment variables: ${auth.clientIdEnvVar}, ${auth.clientSecretEnvVar}');
450
+ process.exit(1);
451
+ }
452
+
453
+ let cachedToken: string | null = null;
454
+ let tokenExpiresAt = 0;
455
+
456
+ /**
457
+ * Obtain an access token via the OAuth 2.0 Client Credentials flow.
458
+ */
459
+ async function getToken(): Promise<string> {
460
+ if (cachedToken && Date.now() < tokenExpiresAt) {
461
+ return cachedToken;
462
+ }
463
+
464
+ const body = new URLSearchParams({
465
+ grant_type: 'client_credentials',
466
+ client_id: CLIENT_ID!,
467
+ client_secret: CLIENT_SECRET!,
468
+ ${auth.scopes ? 'scope: SCOPES,' : ''}
469
+ });
470
+
471
+ const response = await fetch(TOKEN_URL, {
472
+ method: 'POST',
473
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
474
+ body: body.toString(),
475
+ });
476
+
477
+ if (!response.ok) {
478
+ throw new Error(\`OAuth token request failed: \${response.status}\`);
479
+ }
480
+
481
+ const data = (await response.json()) as { access_token: string; expires_in?: number };
482
+ cachedToken = data.access_token;
483
+ // Refresh 60s before expiry
484
+ tokenExpiresAt = Date.now() + ((data.expires_in ?? 3600) - 60) * 1000;
485
+ return cachedToken;
486
+ }
487
+
488
+ /**
489
+ * Returns authorization headers for API requests.
490
+ */
491
+ export function authHeaders(): Record<string, string> {
492
+ // For OAuth2, we need async token fetch — but MCP tool handlers are async,
493
+ // so we cache the token synchronously after first fetch.
494
+ if (!cachedToken) {
495
+ throw new Error('Call ensureAuth() before making requests');
496
+ }
497
+ return {
498
+ Authorization: \`Bearer \${cachedToken}\`,
499
+ };
500
+ }
501
+
502
+ /**
503
+ * Ensure a valid token is available. Call once at startup.
504
+ */
505
+ export async function ensureAuth(): Promise<void> {
506
+ await getToken();
507
+ }
508
+ `;
509
+ case 'cookie':
510
+ return `// Auth helper for cookie-based authentication
511
+ // Auto-generated by glirastes — do not edit manually.
512
+
513
+ let sessionCookie: string | null = null;
514
+
515
+ /**
516
+ * Set the session cookie obtained from login.
517
+ */
518
+ export function setSessionCookie(cookie: string): void {
519
+ sessionCookie = cookie;
520
+ }
521
+
522
+ /**
523
+ * Returns authorization headers for API requests.
524
+ */
525
+ export function authHeaders(): Record<string, string> {
526
+ if (!sessionCookie) {
527
+ return {};
528
+ }
529
+ return {
530
+ Cookie: sessionCookie,
531
+ };
532
+ }
533
+ `;
534
+ }
535
+ }
536
+ /**
537
+ * Generate the types.ts file content with Zod schemas.
538
+ */
539
+ function generateTypesFile(tools) {
540
+ const lines = [
541
+ '// Re-exported Zod schemas for MCP tool inputs/outputs',
542
+ '// Auto-generated by glirastes — do not edit manually.',
543
+ '',
544
+ "import { z } from 'zod';",
545
+ '',
546
+ ];
547
+ for (const tool of tools) {
548
+ if (tool.inputFields.length > 0) {
549
+ const schemaName = `${camelCase(tool.toolName)}InputSchema`;
550
+ lines.push(`export const ${schemaName} = z.object({`);
551
+ for (const field of tool.inputFields) {
552
+ lines.push(` ${field.name}: ${zodTypeToCode(field)},`);
553
+ }
554
+ lines.push('});');
555
+ lines.push(`export type ${pascalCase(tool.toolName)}Input = z.infer<typeof ${schemaName}>;`);
556
+ lines.push('');
557
+ }
558
+ if (tool.outputFields.length > 0) {
559
+ const schemaName = `${camelCase(tool.toolName)}OutputSchema`;
560
+ lines.push(`export const ${schemaName} = z.object({`);
561
+ for (const field of tool.outputFields) {
562
+ const typeMap = {
563
+ 'string': 'z.string()',
564
+ 'number': 'z.number()',
565
+ 'boolean': 'z.boolean()',
566
+ };
567
+ lines.push(` ${field.name}: ${typeMap[field.type] ?? 'z.string()'},`);
568
+ }
569
+ lines.push('});');
570
+ lines.push(`export type ${pascalCase(tool.toolName)}Output = z.infer<typeof ${schemaName}>;`);
571
+ lines.push('');
572
+ }
573
+ }
574
+ return lines.join('\n');
575
+ }
576
+ /**
577
+ * Generate the package.json file content.
578
+ */
579
+ function generatePackageJson(config) {
580
+ const slug = slugify(config.appName);
581
+ const pkg = {
582
+ name: `${slug}-mcp-server`,
583
+ version: config.version ?? '1.0.0',
584
+ description: `MCP server for ${config.appName}`,
585
+ type: 'module',
586
+ main: 'dist/server.js',
587
+ scripts: {
588
+ build: 'tsc',
589
+ start: 'node dist/server.js',
590
+ dev: 'tsx server.ts',
591
+ },
592
+ dependencies: {
593
+ '@modelcontextprotocol/sdk': '^1.12.1',
594
+ zod: '^3.24.0',
595
+ },
596
+ devDependencies: {
597
+ tsx: '^4.19.0',
598
+ typescript: '^5.7.0',
599
+ },
600
+ };
601
+ return JSON.stringify(pkg, null, 2) + '\n';
602
+ }
603
+ /**
604
+ * Generate the tsconfig.json file content.
605
+ */
606
+ function generateTsConfig() {
607
+ const config = {
608
+ compilerOptions: {
609
+ target: 'ES2022',
610
+ module: 'Node16',
611
+ moduleResolution: 'Node16',
612
+ outDir: './dist',
613
+ rootDir: '.',
614
+ strict: true,
615
+ esModuleInterop: true,
616
+ skipLibCheck: true,
617
+ declaration: true,
618
+ },
619
+ include: ['*.ts'],
620
+ exclude: ['node_modules', 'dist'],
621
+ };
622
+ return JSON.stringify(config, null, 2) + '\n';
623
+ }
624
+ /**
625
+ * Generate the README.md file content.
626
+ */
627
+ function generateReadme(config, tools) {
628
+ const slug = slugify(config.appName);
629
+ // Group tools by module
630
+ const byModule = new Map();
631
+ for (const tool of tools) {
632
+ const mod = tool.module ?? 'general';
633
+ if (!byModule.has(mod))
634
+ byModule.set(mod, []);
635
+ byModule.get(mod).push(tool);
636
+ }
637
+ const lines = [];
638
+ lines.push(`# ${config.appName} MCP Server`);
639
+ lines.push('');
640
+ lines.push(`Auto-generated [Model Context Protocol](https://modelcontextprotocol.io/) server for the ${config.appName} platform API.`);
641
+ lines.push('');
642
+ lines.push(`**Tools:** ${tools.length} | **Modules:** ${byModule.size} | **Transport:** stdio`);
643
+ lines.push('');
644
+ // Setup
645
+ lines.push('## Setup');
646
+ lines.push('');
647
+ lines.push('```bash');
648
+ lines.push('npm install');
649
+ lines.push('npm run build');
650
+ lines.push('```');
651
+ lines.push('');
652
+ // Auth environment
653
+ lines.push('## Authentication');
654
+ lines.push('');
655
+ lines.push(generateAuthReadmeSection(config.auth));
656
+ lines.push('');
657
+ // Usage with Claude Desktop
658
+ lines.push('## Usage with Claude Desktop');
659
+ lines.push('');
660
+ lines.push('Add to your Claude Desktop configuration (`claude_desktop_config.json`):');
661
+ lines.push('');
662
+ lines.push('```json');
663
+ lines.push(JSON.stringify({
664
+ mcpServers: {
665
+ [slug]: {
666
+ command: 'node',
667
+ args: ['dist/server.js'],
668
+ cwd: `/path/to/${slug}-mcp-server`,
669
+ },
670
+ },
671
+ }, null, 2));
672
+ lines.push('```');
673
+ lines.push('');
674
+ // Usage with Claude Code
675
+ lines.push('## Usage with Claude Code');
676
+ lines.push('');
677
+ lines.push('```bash');
678
+ lines.push(`claude mcp add ${slug} node dist/server.js`);
679
+ lines.push('```');
680
+ lines.push('');
681
+ // Available tools
682
+ lines.push('## Available Tools');
683
+ lines.push('');
684
+ for (const [moduleName, moduleTools] of byModule) {
685
+ lines.push(`### ${moduleName}`);
686
+ lines.push('');
687
+ lines.push('| Tool | Method | Path | Description |');
688
+ lines.push('|------|--------|------|-------------|');
689
+ for (const tool of moduleTools) {
690
+ lines.push(`| \`${tool.toolName}\` | ${tool.method} | \`${tool.path}\` | ${tool.description} |`);
691
+ }
692
+ lines.push('');
693
+ }
694
+ // Development
695
+ lines.push('## Development');
696
+ lines.push('');
697
+ lines.push('```bash');
698
+ lines.push('# Run in development mode');
699
+ lines.push('npm run dev');
700
+ lines.push('');
701
+ lines.push('# Build for production');
702
+ lines.push('npm run build');
703
+ lines.push('npm start');
704
+ lines.push('```');
705
+ lines.push('');
706
+ return lines.join('\n');
707
+ }
708
+ /**
709
+ * Generate auth section for README based on auth strategy.
710
+ */
711
+ function generateAuthReadmeSection(auth) {
712
+ switch (auth.type) {
713
+ case 'bearer':
714
+ return `Set the \`${auth.tokenEnvVar}\` environment variable:\n\n\`\`\`bash\nexport ${auth.tokenEnvVar}="your-token-here"\n\`\`\``;
715
+ case 'api-key':
716
+ return `Set the \`${auth.keyEnvVar}\` environment variable:\n\n\`\`\`bash\nexport ${auth.keyEnvVar}="your-api-key-here"\n\`\`\``;
717
+ case 'oauth2':
718
+ return `Set the OAuth 2.0 credentials:\n\n\`\`\`bash\nexport ${auth.clientIdEnvVar}="your-client-id"\nexport ${auth.clientSecretEnvVar}="your-client-secret"\n\`\`\``;
719
+ case 'cookie':
720
+ return 'This server uses cookie-based authentication. The session cookie must be set programmatically after login.';
721
+ }
722
+ }
723
+ /**
724
+ * Generate an MCP server project from discovered tool definitions.
725
+ *
726
+ * Scans the project for endpoint and UI tool definitions and produces
727
+ * a complete MCP server project as in-memory file contents. The caller
728
+ * is responsible for writing the files to disk.
729
+ *
730
+ * The generated server uses stdio transport and registers one MCP tool
731
+ * per discovered endpoint/UI tool, grouped by module.
732
+ */
733
+ async function generateMcpServer(options) {
734
+ const opts = (0, types_js_1.resolveDefaults)(options);
735
+ const outputDir = options.mcpOutputDir ?? 'mcp-server';
736
+ // Scan all tool files
737
+ const endpointScan = await (0, endpoint_scanner_js_1.scanEndpointTools)(options);
738
+ const uiScan = await (0, ui_scanner_js_1.scanUiTools)(options);
739
+ // Extract tool metadata from all discovered files
740
+ const allTools = [];
741
+ for (const file of [...endpointScan.files, ...uiScan.files]) {
742
+ const tools = await extractSkillTools(file.absolutePath);
743
+ allTools.push(...tools);
744
+ }
745
+ // Collect module names
746
+ const moduleSet = new Set(allTools.map((t) => t.module ?? 'general'));
747
+ const modulesUsed = Array.from(moduleSet).sort();
748
+ // Generate all file contents
749
+ const files = [
750
+ {
751
+ path: `${outputDir}/server.ts`,
752
+ content: generateServerFile(options.skillConfig, allTools),
753
+ },
754
+ {
755
+ path: `${outputDir}/auth.ts`,
756
+ content: generateAuthFile(options.skillConfig.auth),
757
+ },
758
+ {
759
+ path: `${outputDir}/types.ts`,
760
+ content: generateTypesFile(allTools),
761
+ },
762
+ {
763
+ path: `${outputDir}/package.json`,
764
+ content: generatePackageJson(options.skillConfig),
765
+ },
766
+ {
767
+ path: `${outputDir}/tsconfig.json`,
768
+ content: generateTsConfig(),
769
+ },
770
+ {
771
+ path: `${outputDir}/README.md`,
772
+ content: generateReadme(options.skillConfig, allTools),
773
+ },
774
+ ];
775
+ if (!opts.quiet) {
776
+ console.log(`\u2713 Generated MCP server: ${allTools.length} tools across ${modulesUsed.length} modules`);
777
+ for (const file of files) {
778
+ console.log(` - ${file.path}`);
779
+ }
780
+ }
781
+ return {
782
+ files,
783
+ toolCount: allTools.length,
784
+ modulesUsed,
785
+ tools: allTools,
786
+ };
787
+ }
788
+ // ============================================================================
789
+ // String Utilities
790
+ // ============================================================================
791
+ function slugify(s) {
792
+ return s
793
+ .toLowerCase()
794
+ .replace(/[^a-z0-9]+/g, '-')
795
+ .replace(/^-|-$/g, '');
796
+ }
797
+ function camelCase(s) {
798
+ return s.replace(/[-_](\w)/g, (_, c) => c.toUpperCase());
799
+ }
800
+ function pascalCase(s) {
801
+ const cc = camelCase(s);
802
+ return cc.charAt(0).toUpperCase() + cc.slice(1);
803
+ }