glirastes 0.3.0 → 0.3.1

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