glirastes 0.1.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 (424) hide show
  1. package/CHANGELOG.md +468 -0
  2. package/README.md +651 -0
  3. package/dist/cli/bin.d.ts +2 -0
  4. package/dist/cli/bin.js +34 -0
  5. package/dist/cli/bin.js.map +1 -0
  6. package/dist/cli/commands/check-upgrade.d.ts +15 -0
  7. package/dist/cli/commands/check-upgrade.js +138 -0
  8. package/dist/cli/commands/check-upgrade.js.map +1 -0
  9. package/dist/cli/commands/test.d.ts +8 -0
  10. package/dist/cli/commands/test.js +76 -0
  11. package/dist/cli/commands/test.js.map +1 -0
  12. package/dist/cli/index.d.ts +1 -0
  13. package/dist/cli/index.js +609 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/cli/utils/changelog-parser.d.ts +13 -0
  16. package/dist/cli/utils/changelog-parser.js +89 -0
  17. package/dist/cli/utils/changelog-parser.js.map +1 -0
  18. package/dist/cli/utils/commit-parser.d.ts +8 -0
  19. package/dist/cli/utils/commit-parser.js +23 -0
  20. package/dist/cli/utils/commit-parser.js.map +1 -0
  21. package/dist/cli/utils/gap-detector.d.ts +14 -0
  22. package/dist/cli/utils/gap-detector.js +65 -0
  23. package/dist/cli/utils/gap-detector.js.map +1 -0
  24. package/dist/cli/utils/get-cli-version.d.ts +2 -0
  25. package/dist/cli/utils/get-cli-version.js +10 -0
  26. package/dist/cli/utils/get-cli-version.js.map +1 -0
  27. package/dist/codegen/asset-sync.d.ts +20 -0
  28. package/dist/codegen/asset-sync.js +26 -0
  29. package/dist/codegen/asset-sync.js.map +1 -0
  30. package/dist/codegen/coverage.d.ts +66 -0
  31. package/dist/codegen/coverage.js +372 -0
  32. package/dist/codegen/coverage.js.map +1 -0
  33. package/dist/codegen/endpoint-scanner.d.ts +16 -0
  34. package/dist/codegen/endpoint-scanner.js +161 -0
  35. package/dist/codegen/endpoint-scanner.js.map +1 -0
  36. package/dist/codegen/format.d.ts +17 -0
  37. package/dist/codegen/format.js +28 -0
  38. package/dist/codegen/format.js.map +1 -0
  39. package/dist/codegen/fs-utils.d.ts +45 -0
  40. package/dist/codegen/fs-utils.js +155 -0
  41. package/dist/codegen/fs-utils.js.map +1 -0
  42. package/dist/codegen/index.d.ts +13 -0
  43. package/dist/codegen/index.js +13 -0
  44. package/dist/codegen/index.js.map +1 -0
  45. package/dist/codegen/mcp-generator.d.ts +50 -0
  46. package/dist/codegen/mcp-generator.js +801 -0
  47. package/dist/codegen/mcp-generator.js.map +1 -0
  48. package/dist/codegen/module-generator.d.ts +11 -0
  49. package/dist/codegen/module-generator.js +351 -0
  50. package/dist/codegen/module-generator.js.map +1 -0
  51. package/dist/codegen/nestjs-scanner.d.ts +43 -0
  52. package/dist/codegen/nestjs-scanner.js +239 -0
  53. package/dist/codegen/nestjs-scanner.js.map +1 -0
  54. package/dist/codegen/output-recommender.d.ts +23 -0
  55. package/dist/codegen/output-recommender.js +31 -0
  56. package/dist/codegen/output-recommender.js.map +1 -0
  57. package/dist/codegen/scaffolder.d.ts +36 -0
  58. package/dist/codegen/scaffolder.js +259 -0
  59. package/dist/codegen/scaffolder.js.map +1 -0
  60. package/dist/codegen/skill-generator.d.ts +49 -0
  61. package/dist/codegen/skill-generator.js +965 -0
  62. package/dist/codegen/skill-generator.js.map +1 -0
  63. package/dist/codegen/types.d.ts +52 -0
  64. package/dist/codegen/types.js +14 -0
  65. package/dist/codegen/types.js.map +1 -0
  66. package/dist/codegen/ui-scanner.d.ts +24 -0
  67. package/dist/codegen/ui-scanner.js +197 -0
  68. package/dist/codegen/ui-scanner.js.map +1 -0
  69. package/dist/codegen/validator.d.ts +35 -0
  70. package/dist/codegen/validator.js +256 -0
  71. package/dist/codegen/validator.js.map +1 -0
  72. package/dist/openapi/demo-generate.d.ts +1 -0
  73. package/dist/openapi/demo-generate.js +15 -0
  74. package/dist/openapi/demo-generate.js.map +1 -0
  75. package/dist/openapi/index.d.ts +78 -0
  76. package/dist/openapi/index.js +341 -0
  77. package/dist/openapi/index.js.map +1 -0
  78. package/dist/react/audio-worklet-processor.d.ts +9 -0
  79. package/dist/react/audio-worklet-processor.js +28 -0
  80. package/dist/react/audio-worklet-processor.js.map +1 -0
  81. package/dist/react/bridges/rest-session-bridge.d.ts +113 -0
  82. package/dist/react/bridges/rest-session-bridge.js +207 -0
  83. package/dist/react/bridges/rest-session-bridge.js.map +1 -0
  84. package/dist/react/components/ai-chat-panel.d.ts +12 -0
  85. package/dist/react/components/ai-chat-panel.js +65 -0
  86. package/dist/react/components/ai-chat-panel.js.map +1 -0
  87. package/dist/react/components/ai-trigger-button.d.ts +2 -0
  88. package/dist/react/components/ai-trigger-button.js +239 -0
  89. package/dist/react/components/ai-trigger-button.js.map +1 -0
  90. package/dist/react/components/approval-card.d.ts +9 -0
  91. package/dist/react/components/approval-card.js +22 -0
  92. package/dist/react/components/approval-card.js.map +1 -0
  93. package/dist/react/components/bulk-approval-card.d.ts +9 -0
  94. package/dist/react/components/bulk-approval-card.js +34 -0
  95. package/dist/react/components/bulk-approval-card.js.map +1 -0
  96. package/dist/react/components/chat-input.d.ts +10 -0
  97. package/dist/react/components/chat-input.js +58 -0
  98. package/dist/react/components/chat-input.js.map +1 -0
  99. package/dist/react/components/chat-window.d.ts +2 -0
  100. package/dist/react/components/chat-window.js +132 -0
  101. package/dist/react/components/chat-window.js.map +1 -0
  102. package/dist/react/components/confirm-dialog.d.ts +32 -0
  103. package/dist/react/components/confirm-dialog.js +46 -0
  104. package/dist/react/components/confirm-dialog.js.map +1 -0
  105. package/dist/react/components/floating-chat-ui.d.ts +84 -0
  106. package/dist/react/components/floating-chat-ui.js +161 -0
  107. package/dist/react/components/floating-chat-ui.js.map +1 -0
  108. package/dist/react/components/mention-chip.d.ts +16 -0
  109. package/dist/react/components/mention-chip.js +39 -0
  110. package/dist/react/components/mention-chip.js.map +1 -0
  111. package/dist/react/components/mention-input.d.ts +8 -0
  112. package/dist/react/components/mention-input.js +115 -0
  113. package/dist/react/components/mention-input.js.map +1 -0
  114. package/dist/react/components/message-bubble.d.ts +11 -0
  115. package/dist/react/components/message-bubble.js +123 -0
  116. package/dist/react/components/message-bubble.js.map +1 -0
  117. package/dist/react/components/message-list.d.ts +8 -0
  118. package/dist/react/components/message-list.js +50 -0
  119. package/dist/react/components/message-list.js.map +1 -0
  120. package/dist/react/components/pipeline-timeline.d.ts +7 -0
  121. package/dist/react/components/pipeline-timeline.js +70 -0
  122. package/dist/react/components/pipeline-timeline.js.map +1 -0
  123. package/dist/react/components/recording-bar.d.ts +2 -0
  124. package/dist/react/components/recording-bar.js +81 -0
  125. package/dist/react/components/recording-bar.js.map +1 -0
  126. package/dist/react/components/recording-controls.d.ts +18 -0
  127. package/dist/react/components/recording-controls.js +35 -0
  128. package/dist/react/components/recording-controls.js.map +1 -0
  129. package/dist/react/components/rich-mention-input.d.ts +2 -0
  130. package/dist/react/components/rich-mention-input.js +569 -0
  131. package/dist/react/components/rich-mention-input.js.map +1 -0
  132. package/dist/react/components/session-switcher.d.ts +14 -0
  133. package/dist/react/components/session-switcher.js +131 -0
  134. package/dist/react/components/session-switcher.js.map +1 -0
  135. package/dist/react/components/suggestion-bar.d.ts +9 -0
  136. package/dist/react/components/suggestion-bar.js +45 -0
  137. package/dist/react/components/suggestion-bar.js.map +1 -0
  138. package/dist/react/components/suggestion-chip.d.ts +9 -0
  139. package/dist/react/components/suggestion-chip.js +12 -0
  140. package/dist/react/components/suggestion-chip.js.map +1 -0
  141. package/dist/react/components/voice-input-addon.d.ts +13 -0
  142. package/dist/react/components/voice-input-addon.js +29 -0
  143. package/dist/react/components/voice-input-addon.js.map +1 -0
  144. package/dist/react/components/voice-input-button.d.ts +2 -0
  145. package/dist/react/components/voice-input-button.js +53 -0
  146. package/dist/react/components/voice-input-button.js.map +1 -0
  147. package/dist/react/hooks/use-ai-chat.d.ts +22 -0
  148. package/dist/react/hooks/use-ai-chat.js +49 -0
  149. package/dist/react/hooks/use-ai-chat.js.map +1 -0
  150. package/dist/react/hooks/use-approvals.d.ts +23 -0
  151. package/dist/react/hooks/use-approvals.js +61 -0
  152. package/dist/react/hooks/use-approvals.js.map +1 -0
  153. package/dist/react/hooks/use-deepgram-transcription.d.ts +2 -0
  154. package/dist/react/hooks/use-deepgram-transcription.js +327 -0
  155. package/dist/react/hooks/use-deepgram-transcription.js.map +1 -0
  156. package/dist/react/hooks/use-drag-resize-panel.d.ts +48 -0
  157. package/dist/react/hooks/use-drag-resize-panel.js +306 -0
  158. package/dist/react/hooks/use-drag-resize-panel.js.map +1 -0
  159. package/dist/react/hooks/use-draggable-position.d.ts +25 -0
  160. package/dist/react/hooks/use-draggable-position.js +132 -0
  161. package/dist/react/hooks/use-draggable-position.js.map +1 -0
  162. package/dist/react/hooks/use-keyboard-shortcut.d.ts +20 -0
  163. package/dist/react/hooks/use-keyboard-shortcut.js +91 -0
  164. package/dist/react/hooks/use-keyboard-shortcut.js.map +1 -0
  165. package/dist/react/hooks/use-mentions.d.ts +23 -0
  166. package/dist/react/hooks/use-mentions.js +40 -0
  167. package/dist/react/hooks/use-mentions.js.map +1 -0
  168. package/dist/react/hooks/use-suggestions.d.ts +22 -0
  169. package/dist/react/hooks/use-suggestions.js +37 -0
  170. package/dist/react/hooks/use-suggestions.js.map +1 -0
  171. package/dist/react/index.d.ts +43 -0
  172. package/dist/react/index.js +53 -0
  173. package/dist/react/index.js.map +1 -0
  174. package/dist/react/provider/ai-chat-provider.d.ts +45 -0
  175. package/dist/react/provider/ai-chat-provider.js +1021 -0
  176. package/dist/react/provider/ai-chat-provider.js.map +1 -0
  177. package/dist/react/provider/chat-context.d.ts +84 -0
  178. package/dist/react/provider/chat-context.js +10 -0
  179. package/dist/react/provider/chat-context.js.map +1 -0
  180. package/dist/react/styles.css +897 -0
  181. package/dist/react/template.d.ts +84 -0
  182. package/dist/react/template.js +83 -0
  183. package/dist/react/template.js.map +1 -0
  184. package/dist/react/themes.d.ts +24 -0
  185. package/dist/react/themes.js +269 -0
  186. package/dist/react/themes.js.map +1 -0
  187. package/dist/react/transports/langgraph/index.d.ts +2 -0
  188. package/dist/react/transports/langgraph/index.js +3 -0
  189. package/dist/react/transports/langgraph/index.js.map +1 -0
  190. package/dist/react/transports/langgraph/langgraph-ai-chat.d.ts +62 -0
  191. package/dist/react/transports/langgraph/langgraph-ai-chat.js +92 -0
  192. package/dist/react/transports/langgraph/langgraph-ai-chat.js.map +1 -0
  193. package/dist/react/transports/langgraph.d.ts +71 -0
  194. package/dist/react/transports/langgraph.js +366 -0
  195. package/dist/react/transports/langgraph.js.map +1 -0
  196. package/dist/react/transports/vercel/index.d.ts +2 -0
  197. package/dist/react/transports/vercel/index.js +3 -0
  198. package/dist/react/transports/vercel/index.js.map +1 -0
  199. package/dist/react/transports/vercel/vercel-ai-chat.d.ts +49 -0
  200. package/dist/react/transports/vercel/vercel-ai-chat.js +79 -0
  201. package/dist/react/transports/vercel/vercel-ai-chat.js.map +1 -0
  202. package/dist/react/transports/vercel.d.ts +30 -0
  203. package/dist/react/transports/vercel.js +67 -0
  204. package/dist/react/transports/vercel.js.map +1 -0
  205. package/dist/react/types.d.ts +750 -0
  206. package/dist/react/types.js +2 -0
  207. package/dist/react/types.js.map +1 -0
  208. package/dist/react/ui.d.ts +73 -0
  209. package/dist/react/ui.js +170 -0
  210. package/dist/react/ui.js.map +1 -0
  211. package/dist/react/utils/create-approval-description.d.ts +53 -0
  212. package/dist/react/utils/create-approval-description.js +120 -0
  213. package/dist/react/utils/create-approval-description.js.map +1 -0
  214. package/dist/react/utils/create-tool-result-handler.d.ts +90 -0
  215. package/dist/react/utils/create-tool-result-handler.js +166 -0
  216. package/dist/react/utils/create-tool-result-handler.js.map +1 -0
  217. package/dist/react/utils/mention-markup.d.ts +13 -0
  218. package/dist/react/utils/mention-markup.js +111 -0
  219. package/dist/react/utils/mention-markup.js.map +1 -0
  220. package/dist/react/utils/merge-pipeline-steps.d.ts +19 -0
  221. package/dist/react/utils/merge-pipeline-steps.js +79 -0
  222. package/dist/react/utils/merge-pipeline-steps.js.map +1 -0
  223. package/dist/react/utils/sanitize-stored-messages.d.ts +23 -0
  224. package/dist/react/utils/sanitize-stored-messages.js +50 -0
  225. package/dist/react/utils/sanitize-stored-messages.js.map +1 -0
  226. package/dist/server/adapters/nestjs/chat/ai-chat-auth.guard.d.ts +10 -0
  227. package/dist/server/adapters/nestjs/chat/ai-chat-auth.guard.js +40 -0
  228. package/dist/server/adapters/nestjs/chat/ai-chat-auth.guard.js.map +1 -0
  229. package/dist/server/adapters/nestjs/chat/ai-chat-module-options.interface.d.ts +32 -0
  230. package/dist/server/adapters/nestjs/chat/ai-chat-module-options.interface.js +2 -0
  231. package/dist/server/adapters/nestjs/chat/ai-chat-module-options.interface.js.map +1 -0
  232. package/dist/server/adapters/nestjs/chat/ai-chat.controller.d.ts +11 -0
  233. package/dist/server/adapters/nestjs/chat/ai-chat.controller.js +78 -0
  234. package/dist/server/adapters/nestjs/chat/ai-chat.controller.js.map +1 -0
  235. package/dist/server/adapters/nestjs/chat/ai-chat.module.d.ts +9 -0
  236. package/dist/server/adapters/nestjs/chat/ai-chat.module.js +116 -0
  237. package/dist/server/adapters/nestjs/chat/ai-chat.module.js.map +1 -0
  238. package/dist/server/adapters/nestjs/chat/ai-chat.service.d.ts +13 -0
  239. package/dist/server/adapters/nestjs/chat/ai-chat.service.js +129 -0
  240. package/dist/server/adapters/nestjs/chat/ai-chat.service.js.map +1 -0
  241. package/dist/server/adapters/nestjs/chat/dto/ai-chat-request.dto.d.ts +7 -0
  242. package/dist/server/adapters/nestjs/chat/dto/ai-chat-request.dto.js +49 -0
  243. package/dist/server/adapters/nestjs/chat/dto/ai-chat-request.dto.js.map +1 -0
  244. package/dist/server/adapters/nestjs/chat/dto/chat-message-part.dto.d.ts +19 -0
  245. package/dist/server/adapters/nestjs/chat/dto/chat-message-part.dto.js +105 -0
  246. package/dist/server/adapters/nestjs/chat/dto/chat-message-part.dto.js.map +1 -0
  247. package/dist/server/adapters/nestjs/chat/dto/chat-message.dto.d.ts +8 -0
  248. package/dist/server/adapters/nestjs/chat/dto/chat-message.dto.js +56 -0
  249. package/dist/server/adapters/nestjs/chat/dto/chat-message.dto.js.map +1 -0
  250. package/dist/server/adapters/nestjs/chat/dto/index.d.ts +3 -0
  251. package/dist/server/adapters/nestjs/chat/dto/index.js +4 -0
  252. package/dist/server/adapters/nestjs/chat/dto/index.js.map +1 -0
  253. package/dist/server/adapters/nestjs/chat/index.d.ts +3 -0
  254. package/dist/server/adapters/nestjs/chat/index.js +3 -0
  255. package/dist/server/adapters/nestjs/chat/index.js.map +1 -0
  256. package/dist/server/adapters/nestjs/chat/speech-stream.gateway.d.ts +4 -0
  257. package/dist/server/adapters/nestjs/chat/speech-stream.gateway.js +69 -0
  258. package/dist/server/adapters/nestjs/chat/speech-stream.gateway.js.map +1 -0
  259. package/dist/server/adapters/nestjs/decorators/ai-module.decorator.d.ts +6 -0
  260. package/dist/server/adapters/nestjs/decorators/ai-module.decorator.js +11 -0
  261. package/dist/server/adapters/nestjs/decorators/ai-module.decorator.js.map +1 -0
  262. package/dist/server/adapters/nestjs/decorators/ai-param.decorator.d.ts +5 -0
  263. package/dist/server/adapters/nestjs/decorators/ai-param.decorator.js +13 -0
  264. package/dist/server/adapters/nestjs/decorators/ai-param.decorator.js.map +1 -0
  265. package/dist/server/adapters/nestjs/decorators/ai-tool.decorator.d.ts +6 -0
  266. package/dist/server/adapters/nestjs/decorators/ai-tool.decorator.js +20 -0
  267. package/dist/server/adapters/nestjs/decorators/ai-tool.decorator.js.map +1 -0
  268. package/dist/server/adapters/nestjs/decorators/constants.d.ts +4 -0
  269. package/dist/server/adapters/nestjs/decorators/constants.js +5 -0
  270. package/dist/server/adapters/nestjs/decorators/constants.js.map +1 -0
  271. package/dist/server/adapters/nestjs/index.d.ts +14 -0
  272. package/dist/server/adapters/nestjs/index.js +20 -0
  273. package/dist/server/adapters/nestjs/index.js.map +1 -0
  274. package/dist/server/adapters/nestjs/metadata.d.ts +39 -0
  275. package/dist/server/adapters/nestjs/metadata.js +30 -0
  276. package/dist/server/adapters/nestjs/metadata.js.map +1 -0
  277. package/dist/server/adapters/nestjs/module/ai-tools-explorer.service.d.ts +36 -0
  278. package/dist/server/adapters/nestjs/module/ai-tools-explorer.service.js +156 -0
  279. package/dist/server/adapters/nestjs/module/ai-tools-explorer.service.js.map +1 -0
  280. package/dist/server/adapters/nestjs/module/ai-tools.module.d.ts +37 -0
  281. package/dist/server/adapters/nestjs/module/ai-tools.module.js +42 -0
  282. package/dist/server/adapters/nestjs/module/ai-tools.module.js.map +1 -0
  283. package/dist/server/adapters/nestjs/module/ai-tools.service.d.ts +28 -0
  284. package/dist/server/adapters/nestjs/module/ai-tools.service.js +38 -0
  285. package/dist/server/adapters/nestjs/module/ai-tools.service.js.map +1 -0
  286. package/dist/server/adapters/nestjs/scanner/nestjs-scanner.d.ts +16 -0
  287. package/dist/server/adapters/nestjs/scanner/nestjs-scanner.js +115 -0
  288. package/dist/server/adapters/nestjs/scanner/nestjs-scanner.js.map +1 -0
  289. package/dist/server/adapters/nestjs/scanner/schema-builder.d.ts +26 -0
  290. package/dist/server/adapters/nestjs/scanner/schema-builder.js +255 -0
  291. package/dist/server/adapters/nestjs/scanner/schema-builder.js.map +1 -0
  292. package/dist/server/adapters/nestjs/swagger.d.ts +7 -0
  293. package/dist/server/adapters/nestjs/swagger.js +37 -0
  294. package/dist/server/adapters/nestjs/swagger.js.map +1 -0
  295. package/dist/server/adapters/nextjs/context-helpers.d.ts +22 -0
  296. package/dist/server/adapters/nextjs/context-helpers.js +55 -0
  297. package/dist/server/adapters/nextjs/context-helpers.js.map +1 -0
  298. package/dist/server/adapters/nextjs/create-ai-chat-handler.d.ts +78 -0
  299. package/dist/server/adapters/nextjs/create-ai-chat-handler.js +950 -0
  300. package/dist/server/adapters/nextjs/create-ai-chat-handler.js.map +1 -0
  301. package/dist/server/adapters/nextjs/index.d.ts +8 -0
  302. package/dist/server/adapters/nextjs/index.js +9 -0
  303. package/dist/server/adapters/nextjs/index.js.map +1 -0
  304. package/dist/server/adapters/nextjs/prepare-model-messages.d.ts +58 -0
  305. package/dist/server/adapters/nextjs/prepare-model-messages.js +111 -0
  306. package/dist/server/adapters/nextjs/prepare-model-messages.js.map +1 -0
  307. package/dist/server/adapters/nextjs/sanitize-model-messages.d.ts +64 -0
  308. package/dist/server/adapters/nextjs/sanitize-model-messages.js +487 -0
  309. package/dist/server/adapters/nextjs/sanitize-model-messages.js.map +1 -0
  310. package/dist/server/adapters/nextjs/server-action-helper.d.ts +7 -0
  311. package/dist/server/adapters/nextjs/server-action-helper.js +38 -0
  312. package/dist/server/adapters/nextjs/server-action-helper.js.map +1 -0
  313. package/dist/server/adapters/nextjs/types.d.ts +246 -0
  314. package/dist/server/adapters/nextjs/types.js +2 -0
  315. package/dist/server/adapters/nextjs/types.js.map +1 -0
  316. package/dist/server/adapters/nextjs/with-ai-tool.d.ts +9 -0
  317. package/dist/server/adapters/nextjs/with-ai-tool.js +10 -0
  318. package/dist/server/adapters/nextjs/with-ai-tool.js.map +1 -0
  319. package/dist/server/core/followup-tool.d.ts +9 -0
  320. package/dist/server/core/followup-tool.js +80 -0
  321. package/dist/server/core/followup-tool.js.map +1 -0
  322. package/dist/server/core/index.d.ts +139 -0
  323. package/dist/server/core/index.js +787 -0
  324. package/dist/server/core/index.js.map +1 -0
  325. package/dist/server/core/intent-classifier.d.ts +94 -0
  326. package/dist/server/core/intent-classifier.js +314 -0
  327. package/dist/server/core/intent-classifier.js.map +1 -0
  328. package/dist/server/core/model-selector.d.ts +12 -0
  329. package/dist/server/core/model-selector.js +45 -0
  330. package/dist/server/core/model-selector.js.map +1 -0
  331. package/dist/server/core/module-router.d.ts +14 -0
  332. package/dist/server/core/module-router.js +107 -0
  333. package/dist/server/core/module-router.js.map +1 -0
  334. package/dist/server/core/zod-compact.d.ts +18 -0
  335. package/dist/server/core/zod-compact.js +127 -0
  336. package/dist/server/core/zod-compact.js.map +1 -0
  337. package/dist/server/index.d.ts +5 -0
  338. package/dist/server/index.js +8 -0
  339. package/dist/server/index.js.map +1 -0
  340. package/dist/server/lancer/cache.d.ts +9 -0
  341. package/dist/server/lancer/cache.js +30 -0
  342. package/dist/server/lancer/cache.js.map +1 -0
  343. package/dist/server/lancer/client.d.ts +2 -0
  344. package/dist/server/lancer/client.js +277 -0
  345. package/dist/server/lancer/client.js.map +1 -0
  346. package/dist/server/lancer/errors.d.ts +13 -0
  347. package/dist/server/lancer/errors.js +18 -0
  348. package/dist/server/lancer/errors.js.map +1 -0
  349. package/dist/server/lancer/index.d.ts +3 -0
  350. package/dist/server/lancer/index.js +3 -0
  351. package/dist/server/lancer/index.js.map +1 -0
  352. package/dist/server/lancer/telemetry-buffer.d.ts +15 -0
  353. package/dist/server/lancer/telemetry-buffer.js +61 -0
  354. package/dist/server/lancer/telemetry-buffer.js.map +1 -0
  355. package/dist/server/lancer/types.d.ts +201 -0
  356. package/dist/server/lancer/types.js +5 -0
  357. package/dist/server/lancer/types.js.map +1 -0
  358. package/dist/server/pii-shield/aegis-detector.d.ts +26 -0
  359. package/dist/server/pii-shield/aegis-detector.js +24 -0
  360. package/dist/server/pii-shield/aegis-detector.js.map +1 -0
  361. package/dist/server/pii-shield/create-pii-shield.d.ts +2 -0
  362. package/dist/server/pii-shield/create-pii-shield.js +189 -0
  363. package/dist/server/pii-shield/create-pii-shield.js.map +1 -0
  364. package/dist/server/pii-shield/deep-walk.d.ts +1 -0
  365. package/dist/server/pii-shield/deep-walk.js +17 -0
  366. package/dist/server/pii-shield/deep-walk.js.map +1 -0
  367. package/dist/server/pii-shield/fake-data.d.ts +5 -0
  368. package/dist/server/pii-shield/fake-data.js +168 -0
  369. package/dist/server/pii-shield/fake-data.js.map +1 -0
  370. package/dist/server/pii-shield/index.d.ts +4 -0
  371. package/dist/server/pii-shield/index.js +5 -0
  372. package/dist/server/pii-shield/index.js.map +1 -0
  373. package/dist/server/pii-shield/leakage.d.ts +1 -0
  374. package/dist/server/pii-shield/leakage.js +13 -0
  375. package/dist/server/pii-shield/leakage.js.map +1 -0
  376. package/dist/server/pii-shield/session-mapping.d.ts +12 -0
  377. package/dist/server/pii-shield/session-mapping.js +68 -0
  378. package/dist/server/pii-shield/session-mapping.js.map +1 -0
  379. package/dist/server/pipeline.d.ts +26 -0
  380. package/dist/server/pipeline.js +125 -0
  381. package/dist/server/pipeline.js.map +1 -0
  382. package/dist/server/testing/approvals.d.ts +11 -0
  383. package/dist/server/testing/approvals.js +39 -0
  384. package/dist/server/testing/approvals.js.map +1 -0
  385. package/dist/server/testing/combination.d.ts +3 -0
  386. package/dist/server/testing/combination.js +81 -0
  387. package/dist/server/testing/combination.js.map +1 -0
  388. package/dist/server/testing/create-test-suite.d.ts +29 -0
  389. package/dist/server/testing/create-test-suite.js +79 -0
  390. package/dist/server/testing/create-test-suite.js.map +1 -0
  391. package/dist/server/testing/edge-cases.d.ts +8 -0
  392. package/dist/server/testing/edge-cases.js +275 -0
  393. package/dist/server/testing/edge-cases.js.map +1 -0
  394. package/dist/server/testing/guardrails.d.ts +14 -0
  395. package/dist/server/testing/guardrails.js +150 -0
  396. package/dist/server/testing/guardrails.js.map +1 -0
  397. package/dist/server/testing/helpers.d.ts +14 -0
  398. package/dist/server/testing/helpers.js +114 -0
  399. package/dist/server/testing/helpers.js.map +1 -0
  400. package/dist/server/testing/index.d.ts +12 -0
  401. package/dist/server/testing/index.js +21 -0
  402. package/dist/server/testing/index.js.map +1 -0
  403. package/dist/server/testing/mock-executor.d.ts +8 -0
  404. package/dist/server/testing/mock-executor.js +38 -0
  405. package/dist/server/testing/mock-executor.js.map +1 -0
  406. package/dist/server/testing/regression.d.ts +7 -0
  407. package/dist/server/testing/regression.js +25 -0
  408. package/dist/server/testing/regression.js.map +1 -0
  409. package/dist/server/testing/routing.d.ts +12 -0
  410. package/dist/server/testing/routing.js +61 -0
  411. package/dist/server/testing/routing.js.map +1 -0
  412. package/dist/server/testing/schema-consistency.d.ts +6 -0
  413. package/dist/server/testing/schema-consistency.js +54 -0
  414. package/dist/server/testing/schema-consistency.js.map +1 -0
  415. package/dist/server/testing/smoke.d.ts +11 -0
  416. package/dist/server/testing/smoke.js +62 -0
  417. package/dist/server/testing/smoke.js.map +1 -0
  418. package/dist/server/testing/types.d.ts +156 -0
  419. package/dist/server/testing/types.js +2 -0
  420. package/dist/server/testing/types.js.map +1 -0
  421. package/dist/types.d.ts +696 -0
  422. package/dist/types.js +84 -0
  423. package/dist/types.js.map +1 -0
  424. package/package.json +187 -0
@@ -0,0 +1,965 @@
1
+ import { writeFile, mkdir } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { readFileSafe, extractBalancedBlocks } from './fs-utils.js';
4
+ import { scanEndpointTools } from './endpoint-scanner.js';
5
+ import { scanUiTools } from './ui-scanner.js';
6
+ import { resolveDefaults } from './types.js';
7
+ /**
8
+ * Extract tool information from a source file for skill generation.
9
+ * Parses defineEndpointTool / defineUiTool blocks via regex.
10
+ */
11
+ async function extractSkillTools(absolutePath) {
12
+ const content = await readFileSafe(absolutePath);
13
+ const tools = [];
14
+ // Match endpoint tool blocks
15
+ const endpointBlocks = extractBalancedBlocks(content, /define(?:Ai)?EndpointTool\(\s*/);
16
+ for (const block of endpointBlocks) {
17
+ const tool = parseToolBlock(block, 'endpoint');
18
+ if (tool)
19
+ tools.push(tool);
20
+ }
21
+ // Match UI tool blocks (they don't have method/path, so we synthesize POST + /api/ui/{toolName})
22
+ const uiBlocks = extractBalancedBlocks(content, /define(?:Ai)?UiTool\(\s*/);
23
+ for (const block of uiBlocks) {
24
+ const tool = parseToolBlock(block, 'ui');
25
+ if (tool)
26
+ tools.push(tool);
27
+ }
28
+ return tools;
29
+ }
30
+ function parseToolBlock(block, kind) {
31
+ const toolNameMatch = block.match(/toolName\s*:\s*['"`]([^'"`]+)['"`]/);
32
+ if (!toolNameMatch)
33
+ return null;
34
+ // Match description — handle backtick templates (multiline) and regular quotes
35
+ const descMatch = block.match(/description\s*:\s*`([^`]+)`/) ??
36
+ block.match(/description\s*:\s*['"]([^'"]+)['"]/);
37
+ const methodMatch = block.match(/method\s*:\s*['"`]([^'"`]+)['"`]/);
38
+ const pathMatch = block.match(/path\s*:\s*['"`]([^'"`]+)['"`]/);
39
+ const moduleMatch = block.match(/module\s*:\s*['"`]([^'"`]+)['"`]/);
40
+ const approvalMatch = block.match(/needsApproval\s*:\s*(true|false)/);
41
+ // Extract allowedRoles
42
+ const rolesMatch = block.match(/allowedRoles\s*:\s*\[([^\]]*)\]/);
43
+ let allowedRoles;
44
+ if (rolesMatch) {
45
+ allowedRoles = rolesMatch[1]
46
+ .match(/['"`]([^'"`]+)['"`]/g)
47
+ ?.map((s) => s.replace(/['"`]/g, ''));
48
+ }
49
+ // Extract input fields from z.object({...})
50
+ const inputFields = extractZodFields(block, 'inputSchema');
51
+ const outputFields = extractZodFields(block, 'outputSchema');
52
+ const toolName = toolNameMatch[1];
53
+ return {
54
+ toolName,
55
+ description: descMatch?.[1] ?? `${toolName} tool`,
56
+ method: methodMatch?.[1] ?? (kind === 'ui' ? 'POST' : 'GET'),
57
+ path: pathMatch?.[1] ?? (kind === 'ui' ? `/api/ui/${toolName}` : `/api/${toolName}`),
58
+ module: moduleMatch?.[1],
59
+ allowedRoles,
60
+ needsApproval: approvalMatch ? approvalMatch[1] === 'true' : undefined,
61
+ inputFields,
62
+ outputFields,
63
+ };
64
+ }
65
+ /**
66
+ * Extract field names and approximate types from a Zod schema block.
67
+ */
68
+ function extractZodFields(block, schemaKey) {
69
+ const fields = [];
70
+ // Find the schema block: inputSchema: z.object({...})
71
+ const schemaPattern = new RegExp(`${schemaKey}\\s*:\\s*z\\.object\\(\\s*\\{([\\s\\S]*?)\\}\\s*\\)`);
72
+ const schemaMatch = block.match(schemaPattern);
73
+ if (!schemaMatch)
74
+ return fields;
75
+ const schemaContent = schemaMatch[1];
76
+ // Match field definitions: fieldName: z.string(), fieldName: z.number().optional(), etc.
77
+ const fieldPattern = /(\w+)\s*:\s*z\.(\w+)\((.*?)\)((?:\.\w+\([^)]*\))*)/g;
78
+ let fieldMatch;
79
+ while ((fieldMatch = fieldPattern.exec(schemaContent)) !== null) {
80
+ const name = fieldMatch[1];
81
+ const zodType = fieldMatch[2];
82
+ const chainedMethods = fieldMatch[4] ?? '';
83
+ const isOptional = chainedMethods.includes('.optional()');
84
+ const descriptionMatch = chainedMethods.match(/\.describe\(\s*['"`]([^'"`]+)['"`]\s*\)/);
85
+ const typeMap = {
86
+ string: 'string',
87
+ number: 'number',
88
+ boolean: 'boolean',
89
+ date: 'string (ISO date)',
90
+ enum: 'string (enum)',
91
+ array: 'array',
92
+ object: 'object',
93
+ uuid: 'string (UUID)',
94
+ };
95
+ fields.push({
96
+ name,
97
+ type: typeMap[zodType] ?? zodType,
98
+ required: !isOptional,
99
+ description: descriptionMatch?.[1],
100
+ });
101
+ }
102
+ return fields;
103
+ }
104
+ // ============================================================================
105
+ // Markdown Skill Generation (Claude Code format)
106
+ // ============================================================================
107
+ /**
108
+ * Compact tool reference for module files.
109
+ * ~40% fewer lines than the original toolToMarkdown.
110
+ */
111
+ function toolToCompactMarkdown(tool) {
112
+ const lines = [];
113
+ lines.push(`### ${tool.toolName} — \`${tool.method} ${tool.path}\``);
114
+ lines.push(tool.description);
115
+ const meta = [];
116
+ if (tool.allowedRoles?.length)
117
+ meta.push(`Roles: ${tool.allowedRoles.join(', ')}`);
118
+ if (tool.needsApproval)
119
+ meta.push('Requires approval');
120
+ if (meta.length)
121
+ lines.push(meta.join(' | '));
122
+ if (tool.inputFields.length > 0) {
123
+ lines.push('');
124
+ lines.push('| Param | Type | Req | Description |');
125
+ lines.push('|-------|------|-----|-------------|');
126
+ for (const f of tool.inputFields) {
127
+ lines.push(`| ${f.name} | ${f.type} | ${f.required ? 'yes' : '-'} | ${f.description ?? ''} |`);
128
+ }
129
+ }
130
+ if (tool.outputFields.length > 0) {
131
+ lines.push('');
132
+ lines.push('**Response:**');
133
+ for (const field of tool.outputFields) {
134
+ lines.push(`- \`${field.name}\`: ${field.type}`);
135
+ }
136
+ }
137
+ lines.push('');
138
+ return lines.join('\n');
139
+ }
140
+ /**
141
+ * Original verbose tool markdown (kept for monolithic fallback).
142
+ */
143
+ function toolToMarkdown(tool, baseUrl) {
144
+ const lines = [];
145
+ lines.push(`### \`${tool.toolName}\``);
146
+ lines.push('');
147
+ lines.push(tool.description);
148
+ lines.push('');
149
+ lines.push(`- **Method:** \`${tool.method}\``);
150
+ lines.push(`- **Endpoint:** \`${baseUrl}${tool.path}\``);
151
+ if (tool.module) {
152
+ lines.push(`- **Module:** ${tool.module}`);
153
+ }
154
+ if (tool.needsApproval) {
155
+ lines.push(`- **Requires approval:** yes`);
156
+ }
157
+ if (tool.allowedRoles?.length) {
158
+ lines.push(`- **Allowed roles:** ${tool.allowedRoles.join(', ')}`);
159
+ }
160
+ if (tool.inputFields.length > 0) {
161
+ lines.push('');
162
+ lines.push('**Parameters:**');
163
+ lines.push('');
164
+ lines.push('| Name | Type | Required | Description |');
165
+ lines.push('|------|------|----------|-------------|');
166
+ for (const field of tool.inputFields) {
167
+ lines.push(`| \`${field.name}\` | ${field.type} | ${field.required ? 'yes' : 'no'} | ${field.description ?? ''} |`);
168
+ }
169
+ }
170
+ if (tool.outputFields.length > 0) {
171
+ lines.push('');
172
+ lines.push('**Response fields:**');
173
+ lines.push('');
174
+ for (const field of tool.outputFields) {
175
+ lines.push(`- \`${field.name}\`: ${field.type}`);
176
+ }
177
+ }
178
+ lines.push('');
179
+ return lines.join('\n');
180
+ }
181
+ /**
182
+ * Build a CSO-optimized description for the router SKILL.md.
183
+ * Lists concrete capabilities the user might ask about.
184
+ */
185
+ function buildRouterDescription(config, byModule) {
186
+ const capabilities = [];
187
+ for (const [moduleName, moduleTools] of byModule) {
188
+ const label = moduleName.replace(/_/g, ' ');
189
+ const verbs = moduleTools
190
+ .slice(0, 3)
191
+ .map((t) => t.toolName.replace(/_/g, ' '))
192
+ .join(', ');
193
+ capabilities.push(`${label} (${verbs})`);
194
+ }
195
+ const authHint = config.auth.type === 'bearer'
196
+ ? `Requires ${config.auth.tokenEnvVar} env var.`
197
+ : config.auth.type === 'api-key'
198
+ ? `Requires ${config.auth.keyEnvVar} env var.`
199
+ : '';
200
+ // Extract user-facing action verbs from tool names for CSO
201
+ const actionVerbs = new Set();
202
+ for (const [, moduleTools] of byModule) {
203
+ for (const t of moduleTools) {
204
+ const verb = t.toolName.split('_')[0];
205
+ if (['list', 'get', 'create', 'update', 'delete', 'assign', 'sync', 'navigate', 'open', 'bulk'].includes(verb)) {
206
+ actionVerbs.add(verb);
207
+ }
208
+ }
209
+ }
210
+ const parts = [
211
+ `Manages ${capabilities.map(c => c.split(' (')[0]).join(', ')} in ${config.appName}.`,
212
+ `Use when user asks to ${Array.from(actionVerbs).slice(0, 6).join('/')} data.`,
213
+ `Covers: ${capabilities.join('; ')}.`,
214
+ authHint,
215
+ config.description ?? '',
216
+ ].filter(Boolean);
217
+ return parts.join(' ').slice(0, 1024);
218
+ }
219
+ /**
220
+ * Build a CSO-optimized description for a module file.
221
+ */
222
+ function buildModuleDescription(config, moduleName, moduleTools) {
223
+ const readCount = moduleTools.filter((t) => t.method === 'GET').length;
224
+ const writeCount = moduleTools.length - readCount;
225
+ const label = moduleName.replace(/_/g, ' ');
226
+ const verbs = moduleTools.map((t) => t.toolName.replace(/_/g, ' ')).join(', ');
227
+ const typeSummary = [
228
+ readCount > 0 ? `${readCount} read` : '',
229
+ writeCount > 0 ? `${writeCount} write` : '',
230
+ ].filter(Boolean).join(', ');
231
+ return `${label} module for ${config.appName} API. Use when: ${verbs}. ${typeSummary} endpoint${moduleTools.length !== 1 ? 's' : ''}.`.slice(0, 1024);
232
+ }
233
+ /**
234
+ * Generate the router SKILL.md that links to per-module files.
235
+ */
236
+ function generateRouterSkill(config, tools, byModule) {
237
+ const lines = [];
238
+ const slug = slugify(config.appName);
239
+ const readTools = tools.filter((t) => t.method === 'GET');
240
+ const writeTools = tools.filter((t) => t.method !== 'GET');
241
+ // Collect all module keywords for triggers
242
+ const allKeywords = [];
243
+ for (const [moduleName, moduleTools] of byModule) {
244
+ allKeywords.push(moduleName.replace(/_/g, ' '));
245
+ for (const t of moduleTools) {
246
+ allKeywords.push(t.toolName.replace(/_/g, ' '));
247
+ }
248
+ }
249
+ const description = buildRouterDescription(config, byModule);
250
+ // ── YAML Frontmatter ──
251
+ lines.push('---');
252
+ lines.push(`name: managing-${slug}`);
253
+ lines.push(`description: ${description}`);
254
+ lines.push(`compatibility: Requires curl and jq. Needs network access to ${config.baseUrl}.`);
255
+ lines.push(`allowed-tools: "Bash(curl:*) Bash(jq:*)"`);
256
+ lines.push('---');
257
+ lines.push('');
258
+ // ── Title & Overview ──
259
+ lines.push(`# ${config.appName} API`);
260
+ lines.push('');
261
+ lines.push(`**${tools.length} tools** (${readTools.length} read, ${writeTools.length} write) across **${byModule.size} module(s)**.`);
262
+ lines.push('');
263
+ lines.push(`**Base URL:** \`${config.baseUrl}\``);
264
+ lines.push('');
265
+ // ── Authentication ──
266
+ lines.push('## Authentication');
267
+ lines.push('');
268
+ lines.push(generateAuthInstructions(config.auth));
269
+ lines.push('');
270
+ // ── Module Overview Table ──
271
+ lines.push('## Modules');
272
+ lines.push('');
273
+ lines.push('| Module | Tools | Read | Write | Key tools |');
274
+ lines.push('|--------|-------|------|-------|-----------|');
275
+ for (const [moduleName, moduleTools] of byModule) {
276
+ const modSlug = moduleName.replace(/_/g, '-');
277
+ const readCount = moduleTools.filter((t) => t.method === 'GET').length;
278
+ const writeCount = moduleTools.length - readCount;
279
+ const keyTools = moduleTools.slice(0, 3).map((t) => `\`${t.toolName}\``).join(', ');
280
+ lines.push(`| [${moduleName}](${modSlug}.md) | ${moduleTools.length} | ${readCount} | ${writeCount} | ${keyTools} |`);
281
+ }
282
+ lines.push('');
283
+ // ── Request Format ──
284
+ lines.push('## Making Requests');
285
+ lines.push('');
286
+ lines.push('```bash');
287
+ lines.push(`# GET request (read operations)`);
288
+ lines.push(`curl -s -H "Authorization: Bearer $TOKEN" \\`);
289
+ lines.push(` "${config.baseUrl}/api/<path>" | jq .`);
290
+ lines.push('');
291
+ lines.push(`# POST/PATCH/PUT request (write operations)`);
292
+ lines.push(`curl -s -X POST -H "Authorization: Bearer $TOKEN" \\`);
293
+ lines.push(` -H "Content-Type: application/json" \\`);
294
+ lines.push(` -d '{"key": "value"}' \\`);
295
+ lines.push(` "${config.baseUrl}/api/<path>" | jq .`);
296
+ lines.push('```');
297
+ lines.push('');
298
+ // ── Destructive Action Warning ──
299
+ if (writeTools.length > 0) {
300
+ lines.push('## Write Operations');
301
+ lines.push('');
302
+ lines.push('Before executing write operations (POST, PATCH, PUT, DELETE):');
303
+ lines.push('');
304
+ lines.push('1. Show the user what data will be modified');
305
+ lines.push('2. If `needsApproval` is marked for the tool, **always ask for confirmation**');
306
+ lines.push('3. After a successful write, report what changed');
307
+ lines.push('');
308
+ }
309
+ // ── Troubleshooting ──
310
+ lines.push('## Troubleshooting');
311
+ lines.push('');
312
+ lines.push('### Error: 401 Unauthorized');
313
+ lines.push('Cause: Token is missing, expired, or invalid.');
314
+ lines.push('Solution: Re-authenticate and obtain a fresh token (see Authentication).');
315
+ lines.push('');
316
+ lines.push('### Error: 403 Forbidden');
317
+ lines.push('Cause: The current user role does not have permission for this tool.');
318
+ lines.push('Solution: Check the `allowedRoles` for the tool and verify the user has the required role.');
319
+ lines.push('');
320
+ lines.push('### Error: 422 Validation Error');
321
+ lines.push('Cause: Request body does not match the expected schema.');
322
+ lines.push('Solution: Check the parameter table for the tool and ensure all required fields are provided with correct types.');
323
+ lines.push('');
324
+ return lines.join('\n');
325
+ }
326
+ /**
327
+ * Generate a per-module skill file with compact tool references.
328
+ */
329
+ function generateModuleSkill(config, moduleName, moduleTools) {
330
+ const lines = [];
331
+ const slug = slugify(config.appName);
332
+ const modSlug = moduleName.replace(/_/g, '-');
333
+ const description = buildModuleDescription(config, moduleName, moduleTools);
334
+ const readTools = moduleTools.filter((t) => t.method === 'GET');
335
+ const writeTools = moduleTools.filter((t) => t.method !== 'GET');
336
+ // ── YAML Frontmatter ──
337
+ lines.push('---');
338
+ lines.push(`name: ${slug}-api-${modSlug}`);
339
+ lines.push(`description: ${description}`);
340
+ lines.push('---');
341
+ lines.push('');
342
+ // ── Title ──
343
+ const label = moduleName.replace(/_/g, ' ');
344
+ lines.push(`# ${label}`);
345
+ lines.push('');
346
+ lines.push(`${moduleTools.length} tools (${readTools.length} read, ${writeTools.length} write) | Base URL: \`${config.baseUrl}\``);
347
+ lines.push('');
348
+ // ── Tool Reference ──
349
+ lines.push('## Tools');
350
+ lines.push('');
351
+ for (const tool of moduleTools) {
352
+ lines.push(toolToCompactMarkdown(tool));
353
+ }
354
+ // ── Examples ──
355
+ const exampleReadTool = readTools[0];
356
+ const exampleWriteTool = writeTools[0];
357
+ if (exampleReadTool || exampleWriteTool) {
358
+ lines.push('## Examples');
359
+ lines.push('');
360
+ if (exampleReadTool) {
361
+ lines.push(`### Read: ${exampleReadTool.toolName.replace(/_/g, ' ')}`);
362
+ lines.push('');
363
+ lines.push('```bash');
364
+ lines.push(`curl -s -H "Authorization: Bearer $TOKEN" \\`);
365
+ lines.push(` "${config.baseUrl}${exampleReadTool.path}" | jq .`);
366
+ lines.push('```');
367
+ lines.push('');
368
+ }
369
+ if (exampleWriteTool) {
370
+ const bodyFields = exampleWriteTool.inputFields
371
+ .filter((f) => f.required)
372
+ .map((f) => `"${f.name}": "<value>"`)
373
+ .join(', ');
374
+ lines.push(`### Write: ${exampleWriteTool.toolName.replace(/_/g, ' ')}`);
375
+ lines.push('');
376
+ lines.push('```bash');
377
+ lines.push(`curl -s -X ${exampleWriteTool.method} -H "Authorization: Bearer $TOKEN" \\`);
378
+ lines.push(` -H "Content-Type: application/json" \\`);
379
+ lines.push(` -d '{${bodyFields}}' \\`);
380
+ lines.push(` "${config.baseUrl}${exampleWriteTool.path}" | jq .`);
381
+ lines.push('```');
382
+ lines.push('');
383
+ }
384
+ }
385
+ return lines.join('\n');
386
+ }
387
+ /**
388
+ * Generate modular skill files: one router SKILL.md + one file per module.
389
+ * Returns an array of { relativePath, content } for the caller to write.
390
+ */
391
+ function generateModularSkills(config, tools) {
392
+ const files = [];
393
+ // Group tools by module
394
+ const byModule = new Map();
395
+ for (const tool of tools) {
396
+ const mod = tool.module ?? 'general';
397
+ if (!byModule.has(mod))
398
+ byModule.set(mod, []);
399
+ byModule.get(mod).push(tool);
400
+ }
401
+ // Generate router SKILL.md
402
+ files.push({
403
+ relativePath: 'SKILL.md',
404
+ content: generateRouterSkill(config, tools, byModule),
405
+ });
406
+ // Generate per-module files
407
+ for (const [moduleName, moduleTools] of byModule) {
408
+ const modSlug = moduleName.replace(/_/g, '-');
409
+ files.push({
410
+ relativePath: `${modSlug}.md`,
411
+ content: generateModuleSkill(config, moduleName, moduleTools),
412
+ });
413
+ }
414
+ return files;
415
+ }
416
+ /**
417
+ * Generate a single monolithic SKILL.md (legacy fallback).
418
+ * Renamed from the original generateMarkdownSkill.
419
+ */
420
+ function generateMonolithicSkill(config, tools) {
421
+ const lines = [];
422
+ const slug = slugify(config.appName);
423
+ // Group tools by module (needed for multiple sections)
424
+ const byModule = new Map();
425
+ for (const tool of tools) {
426
+ const mod = tool.module ?? 'general';
427
+ if (!byModule.has(mod))
428
+ byModule.set(mod, []);
429
+ byModule.get(mod).push(tool);
430
+ }
431
+ const moduleNames = Array.from(byModule.keys());
432
+ const readTools = tools.filter((t) => t.method === 'GET');
433
+ const writeTools = tools.filter((t) => t.method !== 'GET');
434
+ // ── YAML Frontmatter (Anthropic spec: name + description required) ──
435
+ // description: what it does + when to use it + trigger phrases (max 1024 chars)
436
+ const triggerPhrases = moduleNames.slice(0, 4).map((m) => m.replace(/_/g, ' ')).join(', ');
437
+ const descriptionParts = [
438
+ `Interact with the ${config.appName} platform API.`,
439
+ `Use when the user wants to query or modify data via ${config.appName},`,
440
+ `mentions ${triggerPhrases},`,
441
+ `or asks to call the ${config.appName} API.`,
442
+ config.description ? config.description : '',
443
+ ].filter(Boolean);
444
+ const description = descriptionParts.join(' ').slice(0, 1024);
445
+ lines.push('---');
446
+ lines.push(`name: ${slug}-api`);
447
+ lines.push(`description: ${description}`);
448
+ if (config.version) {
449
+ lines.push(`metadata:`);
450
+ lines.push(` version: ${config.version}`);
451
+ lines.push(` author: auto-generated by glirastes`);
452
+ lines.push(` category: platform-api`);
453
+ }
454
+ lines.push(`compatibility: Requires curl and jq. Needs network access to ${config.baseUrl}.`);
455
+ lines.push(`allowed-tools: "Bash(curl:*) Bash(jq:*)"`);
456
+ lines.push('---');
457
+ lines.push('');
458
+ // ── Title & Overview ──
459
+ lines.push(`# ${config.appName} API`);
460
+ lines.push('');
461
+ lines.push(`This skill gives you access to the ${config.appName} platform API.`);
462
+ lines.push(`It exposes **${tools.length} tools** (${readTools.length} read, ${writeTools.length} write) across **${byModule.size} module(s)**.`);
463
+ lines.push('');
464
+ lines.push(`**Base URL:** \`${config.baseUrl}\``);
465
+ lines.push('');
466
+ // ── Instructions ──
467
+ lines.push('## Instructions');
468
+ lines.push('');
469
+ // Step 1: Authentication
470
+ lines.push('### Step 1: Authenticate');
471
+ lines.push('');
472
+ lines.push(generateAuthInstructions(config.auth));
473
+ lines.push('');
474
+ // Step 2: Choose the right tool
475
+ lines.push('### Step 2: Choose the right tool');
476
+ lines.push('');
477
+ lines.push('Select a tool based on the user\'s intent:');
478
+ lines.push('');
479
+ for (const [moduleName, moduleTools] of byModule) {
480
+ const readCount = moduleTools.filter((t) => t.method === 'GET').length;
481
+ const writeCount = moduleTools.length - readCount;
482
+ lines.push(`- **${moduleName}**: ${moduleTools.map((t) => `\`${t.toolName}\``).join(', ')} (${readCount} read, ${writeCount} write)`);
483
+ }
484
+ lines.push('');
485
+ // Step 3: Make the request
486
+ lines.push('### Step 3: Make the request');
487
+ lines.push('');
488
+ lines.push('```bash');
489
+ lines.push(`# GET request (read operations)`);
490
+ lines.push(`curl -s -H "Authorization: Bearer $TOKEN" \\`);
491
+ lines.push(` "${config.baseUrl}/api/<path>" | jq .`);
492
+ lines.push('');
493
+ lines.push(`# POST/PATCH/PUT request (write operations)`);
494
+ lines.push(`curl -s -X POST -H "Authorization: Bearer $TOKEN" \\`);
495
+ lines.push(` -H "Content-Type: application/json" \\`);
496
+ lines.push(` -d '{"key": "value"}' \\`);
497
+ lines.push(` "${config.baseUrl}/api/<path>" | jq .`);
498
+ lines.push('```');
499
+ lines.push('');
500
+ // Step 4: Confirm destructive actions
501
+ if (writeTools.length > 0) {
502
+ lines.push('### Step 4: Confirm destructive actions');
503
+ lines.push('');
504
+ lines.push('Before executing write operations (POST, PATCH, PUT, DELETE):');
505
+ lines.push('');
506
+ lines.push('1. Show the user what data will be modified');
507
+ lines.push('2. If `needsApproval` is marked for the tool, **always ask for confirmation**');
508
+ lines.push('3. After a successful write, report what changed');
509
+ lines.push('');
510
+ }
511
+ // ── Tool Reference (grouped by module) ──
512
+ lines.push('## Tool Reference');
513
+ lines.push('');
514
+ for (const [moduleName, moduleTools] of byModule) {
515
+ lines.push(`### Module: ${moduleName}`);
516
+ lines.push('');
517
+ for (const tool of moduleTools) {
518
+ lines.push(toolToMarkdown(tool, config.baseUrl));
519
+ }
520
+ }
521
+ // ── Examples ──
522
+ lines.push('## Examples');
523
+ lines.push('');
524
+ // Auto-generate examples from actual tools
525
+ const exampleReadTool = readTools[0];
526
+ const exampleWriteTool = writeTools[0];
527
+ if (exampleReadTool) {
528
+ lines.push(`### Example 1: Read data`);
529
+ lines.push('');
530
+ lines.push(`User says: "Show me the ${exampleReadTool.toolName.replace(/_/g, ' ').replace(/^(list|get) /, '')}"`);
531
+ lines.push('');
532
+ lines.push('Actions:');
533
+ lines.push(`1. Authenticate with the API`);
534
+ lines.push(`2. Call \`${exampleReadTool.method} ${config.baseUrl}${exampleReadTool.path}\``);
535
+ lines.push(`3. Format and display results to the user`);
536
+ lines.push('');
537
+ lines.push('```bash');
538
+ lines.push(`curl -s -H "Authorization: Bearer $TOKEN" \\`);
539
+ lines.push(` "${config.baseUrl}${exampleReadTool.path}" | jq .`);
540
+ lines.push('```');
541
+ lines.push('');
542
+ }
543
+ if (exampleWriteTool) {
544
+ lines.push(`### Example 2: Write data`);
545
+ lines.push('');
546
+ lines.push(`User says: "${exampleWriteTool.toolName.replace(/_/g, ' ')}"`);
547
+ lines.push('');
548
+ lines.push('Actions:');
549
+ lines.push(`1. Authenticate with the API`);
550
+ lines.push(`2. Confirm the action with the user${exampleWriteTool.needsApproval ? ' (requires approval)' : ''}`);
551
+ const bodyFields = exampleWriteTool.inputFields
552
+ .filter((f) => f.required)
553
+ .map((f) => `"${f.name}": "<value>"`)
554
+ .join(', ');
555
+ lines.push(`3. Call \`${exampleWriteTool.method} ${config.baseUrl}${exampleWriteTool.path}\` with body \`{${bodyFields}}\``);
556
+ lines.push(`4. Report the result`);
557
+ lines.push('');
558
+ }
559
+ // ── Troubleshooting ──
560
+ lines.push('## Troubleshooting');
561
+ lines.push('');
562
+ lines.push('### Error: 401 Unauthorized');
563
+ lines.push('Cause: Token is missing, expired, or invalid.');
564
+ lines.push('Solution: Re-authenticate and obtain a fresh token (see Step 1).');
565
+ lines.push('');
566
+ lines.push('### Error: 403 Forbidden');
567
+ lines.push('Cause: The current user role does not have permission for this tool.');
568
+ lines.push('Solution: Check the `allowedRoles` for the tool and verify the user has the required role.');
569
+ lines.push('');
570
+ lines.push('### Error: 422 Validation Error');
571
+ lines.push('Cause: Request body does not match the expected schema.');
572
+ lines.push('Solution: Check the parameter table for the tool and ensure all required fields are provided with correct types.');
573
+ lines.push('');
574
+ return lines.join('\n');
575
+ }
576
+ /**
577
+ * Generate auth instructions in a step-by-step format (for the Instructions section).
578
+ */
579
+ function generateAuthInstructions(auth) {
580
+ switch (auth.type) {
581
+ case 'bearer':
582
+ return [
583
+ `This API uses **Bearer token** authentication.`,
584
+ ``,
585
+ `\`\`\`bash`,
586
+ `# Ensure the token is available`,
587
+ `TOKEN="\$${auth.tokenEnvVar}"`,
588
+ ``,
589
+ `# Every request must include:`,
590
+ `# -H "Authorization: Bearer $TOKEN"`,
591
+ `\`\`\``,
592
+ ``,
593
+ `Expected result: Requests return 200. If you get 401, the token is missing or expired.`,
594
+ auth.description ? `\n${auth.description}` : '',
595
+ ].join('\n');
596
+ case 'api-key':
597
+ return [
598
+ `This API uses **API key** authentication via the \`${auth.headerName}\` header.`,
599
+ ``,
600
+ `\`\`\`bash`,
601
+ `API_KEY="\$${auth.keyEnvVar}"`,
602
+ ``,
603
+ `# Every request must include:`,
604
+ `# -H "${auth.headerName}: $API_KEY"`,
605
+ `\`\`\``,
606
+ ``,
607
+ `Expected result: Requests return 200. If you get 401, the API key is invalid.`,
608
+ auth.description ? `\n${auth.description}` : '',
609
+ ].join('\n');
610
+ case 'oauth2':
611
+ return [
612
+ `This API uses **OAuth 2.0 Client Credentials** flow.`,
613
+ ``,
614
+ `\`\`\`bash`,
615
+ `# 1. Obtain access token`,
616
+ `TOKEN=$(curl -s -X POST ${auth.tokenUrl} \\`,
617
+ ` -d "grant_type=client_credentials" \\`,
618
+ ` -d "client_id=\$${auth.clientIdEnvVar}" \\`,
619
+ ` -d "client_secret=\$${auth.clientSecretEnvVar}"${auth.scopes ? ` \\\n -d "scope=${auth.scopes.join(' ')}"` : ''} \\`,
620
+ ` | jq -r '.access_token')`,
621
+ ``,
622
+ `# 2. Verify token was obtained`,
623
+ `[ -n "$TOKEN" ] && echo "Auth OK" || echo "Auth FAILED"`,
624
+ `\`\`\``,
625
+ ``,
626
+ `Expected result: "Auth OK". If "Auth FAILED", check client credentials.`,
627
+ auth.description ? `\n${auth.description}` : '',
628
+ ].join('\n');
629
+ case 'cookie':
630
+ return [
631
+ `This API uses **cookie-based** session authentication.`,
632
+ `The agent must first authenticate via the login endpoint and pass cookies in subsequent requests.`,
633
+ ``,
634
+ `\`\`\`bash`,
635
+ `# Store cookies from login`,
636
+ `curl -s -c cookies.txt -X POST <login-url> \\`,
637
+ ` -H "Content-Type: application/json" \\`,
638
+ ` -d '{"username": "...", "password": "..."}'`,
639
+ ``,
640
+ `# Use cookies in subsequent requests`,
641
+ `curl -s -b cookies.txt <api-url>`,
642
+ `\`\`\``,
643
+ auth.description ? `\n${auth.description}` : '',
644
+ ].join('\n');
645
+ }
646
+ }
647
+ // ============================================================================
648
+ // JSON Manifest Generation (machine-readable for Codex / Agent SDK)
649
+ // ============================================================================
650
+ function toolToJsonSchema(tool) {
651
+ const parameters = {
652
+ type: 'object',
653
+ properties: {},
654
+ required: [],
655
+ };
656
+ for (const field of tool.inputFields) {
657
+ const typeMap = {
658
+ string: 'string',
659
+ number: 'number',
660
+ boolean: 'boolean',
661
+ 'string (ISO date)': 'string',
662
+ 'string (enum)': 'string',
663
+ 'string (UUID)': 'string',
664
+ array: 'array',
665
+ object: 'object',
666
+ };
667
+ const prop = {
668
+ type: typeMap[field.type] ?? 'string',
669
+ };
670
+ if (field.description)
671
+ prop.description = field.description;
672
+ if (field.type === 'string (UUID)')
673
+ prop.format = 'uuid';
674
+ if (field.type === 'string (ISO date)')
675
+ prop.format = 'date-time';
676
+ parameters.properties[field.name] = prop;
677
+ if (field.required) {
678
+ parameters.required.push(field.name);
679
+ }
680
+ }
681
+ const result = {
682
+ name: tool.toolName,
683
+ description: tool.description,
684
+ method: tool.method,
685
+ path: tool.path,
686
+ parameters,
687
+ };
688
+ if (tool.outputFields.length > 0) {
689
+ const response = {
690
+ type: 'object',
691
+ properties: {},
692
+ };
693
+ for (const field of tool.outputFields) {
694
+ response.properties[field.name] = {
695
+ type: field.type === 'number' ? 'number' : 'string',
696
+ };
697
+ }
698
+ result.response = response;
699
+ }
700
+ if (tool.needsApproval)
701
+ result.needsApproval = true;
702
+ return result;
703
+ }
704
+ function generateJsonManifest(config, tools) {
705
+ const modules = {};
706
+ for (const tool of tools) {
707
+ const mod = tool.module ?? 'general';
708
+ if (!modules[mod])
709
+ modules[mod] = [];
710
+ modules[mod].push(tool.toolName);
711
+ }
712
+ return {
713
+ name: `${slugify(config.appName)}-api`,
714
+ description: config.description ?? `Agent skill for ${config.appName} platform API`,
715
+ version: config.version,
716
+ baseUrl: config.baseUrl,
717
+ auth: config.auth,
718
+ tools: tools.map(toolToJsonSchema),
719
+ modules,
720
+ };
721
+ }
722
+ // ============================================================================
723
+ // Optimize Meta-Skill Template
724
+ // ============================================================================
725
+ /**
726
+ * Generate the "optimize-generated-skills" meta-skill SKILL.md.
727
+ * This skill teaches a coding agent how to review and upgrade the
728
+ * auto-generated API skills to production quality.
729
+ *
730
+ * Replaces {APP_NAME} with the actual app name slug.
731
+ */
732
+ function generateOptimizeSkillTemplate(appName) {
733
+ const slug = slugify(appName);
734
+ return `---
735
+ name: optimize-generated-skills
736
+ description: Use after running \`glirastes generate-skills\` to review and improve auto-generated API skill files. Covers frontmatter CSO, token efficiency, description quality, parameter completeness, and adding domain context the generator cannot infer.
737
+ ---
738
+
739
+ # Optimize Generated Skills
740
+
741
+ ## Overview
742
+
743
+ Auto-generated skills from \`glirastes generate-skills\` are structurally correct but lack domain context, workflow knowledge, and CSO polish. This skill guides you through reviewing and upgrading them to production quality.
744
+
745
+ **Target:** The generated skill at \`./${slug}-api/SKILL.md\` and its module files.
746
+
747
+ ## When to Use
748
+
749
+ - Right after running \`glirastes generate-skills\`
750
+ - When an agent struggles to find or use the generated skill correctly
751
+ - When adding new tools and regenerating (review diff, preserve manual additions)
752
+
753
+ ## Review Process
754
+
755
+ Work through each step in order. After each step, re-read the file to verify changes.
756
+
757
+ ### Step 1: Router SKILL.md
758
+
759
+ Open \`./${slug}-api/SKILL.md\` and check:
760
+
761
+ **Frontmatter:**
762
+ - \`description\` starts with "Use when..." (not "Interact with..." or "Tool for...")
763
+ - Includes searchable keywords: module names, key tool names, error codes (401, 403, 422)
764
+ - Under 500 characters; no workflow summary (CSO: triggers only, never process)
765
+ - \`allowed-tools\` matches what the agent actually needs (curl, jq, etc.)
766
+
767
+ **Body:**
768
+ - Module table is accurate (tool counts, key tools)
769
+ - Auth section has correct env var names
770
+ - Total line count < 100
771
+
772
+ ### Step 2: Module Files
773
+
774
+ For each \`<module>.md\` in \`./${slug}-api/\`:
775
+
776
+ **Descriptions:**
777
+ - Replace generic "Tool for X" with actionable descriptions
778
+ - Include WHEN to use: \`"Use to look up user UUIDs before assigning tasks"\`
779
+ - Include WHAT it returns: \`"Returns list with IDs, titles, status"\`
780
+ - Add LLM hints for mutations: \`"IMPORTANT: ask for title first"\`, \`"DO NOT invent IDs"\`
781
+
782
+ **Parameter tables:**
783
+ - Every required field has a description (not blank)
784
+ - Types match actual API behavior (e.g., \`string (UUID)\` not just \`string\`)
785
+ - Optional fields explain when to use them
786
+
787
+ **Language consistency:**
788
+ - All descriptions in one language (all English OR all German, not mixed)
789
+ - If the consumer app's UI language differs from English, match it
790
+
791
+ **Line count:**
792
+ - Each module file < 500 lines
793
+ - If over 500: split into sub-modules or compress rarely-used tools into a summary table
794
+
795
+ ### Step 3: Token Efficiency
796
+
797
+ **Router:** Should be < 100 lines. If longer:
798
+ - Move troubleshooting to a separate \`troubleshooting.md\` (only if > 3 error patterns)
799
+ - Keep auth and module table inline
800
+
801
+ **Module files:** Compress where possible:
802
+ - Collapse tools with identical parameter shapes into a single entry with variants
803
+ - Remove empty "Response" sections
804
+ - Use \`--help\` references instead of documenting every optional param
805
+
806
+ **Rarely-used tools:** If a module has > 15 tools:
807
+ - Move rarely-used ones to an "Additional Tools" section at the bottom
808
+ - Keep the top 5-8 most common tools prominent
809
+
810
+ ### Step 4: Domain Context
811
+
812
+ This is the highest-value step. Add knowledge the generator cannot infer:
813
+
814
+ **Business rules:**
815
+ \`\`\`markdown
816
+ ## Business Rules
817
+ - Tasks can only be assigned to members of the same group
818
+ - Deleting a group reassigns all tasks to "unassigned"
819
+ - Holiday calendar entries require admin role
820
+ \`\`\`
821
+
822
+ **Common workflows:**
823
+ \`\`\`markdown
824
+ ## Common Workflows
825
+
826
+ ### Move a task to another group
827
+ 1. \`list_groups\` to get target group ID
828
+ 2. \`update_task\` with new \`groupId\`
829
+ Note: task keeps its assignee only if assignee is in the target group.
830
+ \`\`\`
831
+
832
+ **Error recovery:**
833
+ \`\`\`markdown
834
+ ## Error Recovery
835
+ - 409 Conflict on task update: re-fetch the task (optimistic locking)
836
+ - 422 on create with assigneeId: the user UUID is wrong, use \`find_user\` first
837
+ \`\`\`
838
+
839
+ **Cross-module references:**
840
+ \`\`\`markdown
841
+ <!-- In task-mutation.md -->
842
+ **Prerequisite:** Use \`find_user\` (in [group-management](group-management.md)) to resolve user names to UUIDs before assigning.
843
+ \`\`\`
844
+
845
+ ### Step 5: Verify
846
+
847
+ Run through this checklist and fix any remaining issues:
848
+
849
+ \`\`\`
850
+ - [ ] Router SKILL.md < 100 lines
851
+ - [ ] Each module file < 500 lines
852
+ - [ ] All descriptions are specific (no "Tool for X" patterns)
853
+ - [ ] Language is consistent per file
854
+ - [ ] Parameter descriptions filled in for required fields
855
+ - [ ] Common workflows documented (at least 2)
856
+ - [ ] Error codes and symptoms in frontmatter keywords
857
+ - [ ] Cross-references between related modules
858
+ - [ ] Business rules section added where applicable
859
+ - [ ] Auth env var name matches actual .env
860
+ \`\`\`
861
+
862
+ ## After Optimization
863
+
864
+ - Commit the optimized files (they live in \`.claude/skills/generated/\`)
865
+ - Note: re-running \`glirastes generate-skills\` will overwrite your changes
866
+ - To preserve manual additions across regeneration, consider moving domain context to a separate file (e.g., \`${slug}-api/domain-context.md\`) and referencing it from the module files
867
+
868
+ ## Anti-Patterns
869
+
870
+ | Pattern | Fix |
871
+ |---------|-----|
872
+ | "Tool for creating items" | "Create a new item. Ask for title first. Returns the created item with its UUID." |
873
+ | Empty parameter descriptions | Fill in what the parameter does and any constraints |
874
+ | Mixed English/German in one file | Pick one language, be consistent |
875
+ | 800-line module file | Split by sub-domain or compress rarely-used tools |
876
+ | Workflow in frontmatter description | Move to body; description = triggers only |
877
+ | Duplicated auth instructions in modules | Reference router SKILL.md instead |
878
+ `;
879
+ }
880
+ /**
881
+ * Generate agent skill files from discovered tool definitions.
882
+ *
883
+ * Scans the project for endpoint and UI tool definitions and produces:
884
+ * - Modular Markdown skill files (one router SKILL.md + one file per module)
885
+ * - A JSON manifest (machine-readable for Codex / Agent SDK)
886
+ *
887
+ * Both formats contain the full tool catalog with auth instructions,
888
+ * enabling autonomous agents to interact with the platform API.
889
+ */
890
+ export async function generateAgentSkills(options) {
891
+ const opts = resolveDefaults(options);
892
+ const formats = options.formats ?? ['markdown', 'json'];
893
+ const outputDir = options.skillOutputDir
894
+ ? join(opts.rootDir, options.skillOutputDir)
895
+ : join(opts.rootDir, '.claude', 'skills', 'generated');
896
+ // Scan all tool files
897
+ const endpointScan = await scanEndpointTools(options);
898
+ const uiScan = await scanUiTools(options);
899
+ // Extract tool metadata from all discovered files
900
+ const allTools = [];
901
+ for (const file of [...endpointScan.files, ...uiScan.files]) {
902
+ const tools = await extractSkillTools(file.absolutePath);
903
+ allTools.push(...tools);
904
+ }
905
+ // Count modules
906
+ const moduleSet = new Set(allTools.map((t) => t.module ?? 'general'));
907
+ await mkdir(outputDir, { recursive: true });
908
+ const result = {
909
+ toolCount: allTools.length,
910
+ moduleCount: moduleSet.size,
911
+ tools: allTools,
912
+ };
913
+ // Generate modular Markdown skills — one router + one file per module:
914
+ // .claude/skills/generated/<app>-api/SKILL.md (router)
915
+ // .claude/skills/generated/<app>-api/<module>.md (per module)
916
+ if (formats.includes('markdown')) {
917
+ const skillFiles = generateModularSkills(options.skillConfig, allTools);
918
+ const skillFolderName = `${slugify(options.skillConfig.appName)}-api`;
919
+ const skillDir = join(outputDir, skillFolderName);
920
+ await mkdir(skillDir, { recursive: true });
921
+ const writtenPaths = [];
922
+ for (const file of skillFiles) {
923
+ const filePath = join(skillDir, file.relativePath);
924
+ await writeFile(filePath, file.content, 'utf-8');
925
+ writtenPaths.push(filePath);
926
+ }
927
+ // markdownPath points to the router SKILL.md for backward compat
928
+ result.markdownPath = join(skillDir, 'SKILL.md');
929
+ result.markdownPaths = writtenPaths;
930
+ // Generate optimize meta-skill alongside the API skill
931
+ const optimizeDir = join(outputDir, 'optimize-generated-skills');
932
+ await mkdir(optimizeDir, { recursive: true });
933
+ const optimizeContent = generateOptimizeSkillTemplate(options.skillConfig.appName);
934
+ const optimizePath = join(optimizeDir, 'SKILL.md');
935
+ await writeFile(optimizePath, optimizeContent, 'utf-8');
936
+ writtenPaths.push(optimizePath);
937
+ if (!opts.quiet) {
938
+ console.log(`\u2713 Generated skill (Markdown, modular): ${writtenPaths.length} files in ${skillDir}`);
939
+ for (const p of writtenPaths) {
940
+ console.log(` - ${p}`);
941
+ }
942
+ }
943
+ }
944
+ // Generate JSON manifest
945
+ if (formats.includes('json')) {
946
+ const manifest = generateJsonManifest(options.skillConfig, allTools);
947
+ const jsonPath = join(outputDir, `${slugify(options.skillConfig.appName)}-api.skill.json`);
948
+ await writeFile(jsonPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
949
+ result.jsonPath = jsonPath;
950
+ if (!opts.quiet) {
951
+ console.log(`\u2713 Generated skill (JSON): ${jsonPath}`);
952
+ }
953
+ }
954
+ if (!opts.quiet) {
955
+ console.log(` ${allTools.length} tools across ${moduleSet.size} modules`);
956
+ }
957
+ return result;
958
+ }
959
+ function slugify(s) {
960
+ return s
961
+ .toLowerCase()
962
+ .replace(/[^a-z0-9]+/g, '-')
963
+ .replace(/^-|-$/g, '');
964
+ }
965
+ //# sourceMappingURL=skill-generator.js.map