@commandable/mcp 0.1.2 → 0.2.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 (282) hide show
  1. package/{dist/app → .output}/nitro.json +1 -1
  2. package/{dist/app/public/_nuxt/-tOYwuj2.js → .output/public/_nuxt/B04gGCnx.js} +3 -3
  3. package/{dist/app/public/_nuxt/D-43HurL.js → .output/public/_nuxt/B2dAlp_u.js} +8 -8
  4. package/.output/public/_nuxt/Ba0BY0O0.js +1 -0
  5. package/.output/public/_nuxt/BvFUCPqA.js +1 -0
  6. package/{dist/app/public/_nuxt/BdctKXor.js → .output/public/_nuxt/Dm_hd4at.js} +1 -1
  7. package/{dist/app/public/_nuxt/BlP7Uu-5.js → .output/public/_nuxt/S2P9sd4n.js} +1 -1
  8. package/.output/public/_nuxt/builds/latest.json +1 -0
  9. package/.output/public/_nuxt/builds/meta/ee5097c4-b785-4b77-92d6-c16a7396d677.json +1 -0
  10. package/{dist/app/public/_nuxt/CsbkV5Bd.js → .output/public/_nuxt/d2XTSFt9.js} +1 -1
  11. package/{dist/app/server/chunks/build/_id_-DBwSV4AY.mjs → .output/server/chunks/build/_id_-Bnxenh08.mjs} +7 -7
  12. package/{dist/app/server/chunks/build/_id_-DBwSV4AY.mjs.map → .output/server/chunks/build/_id_-Bnxenh08.mjs.map} +1 -1
  13. package/{dist/app → .output}/server/chunks/build/client.precomputed.mjs +1 -1
  14. package/{dist/app/server/chunks/build/fetch-ZbqIFhDG.mjs → .output/server/chunks/build/fetch-BmYZnj75.mjs} +58 -6
  15. package/.output/server/chunks/build/fetch-BmYZnj75.mjs.map +1 -0
  16. package/{dist/app/server/chunks/build/index-C8flTcKI.mjs → .output/server/chunks/build/index-CL-Gkd-Y.mjs} +4 -4
  17. package/.output/server/chunks/build/index-CL-Gkd-Y.mjs.map +1 -0
  18. package/{dist/app → .output}/server/chunks/build/server.mjs +3 -3
  19. package/{dist/app → .output}/server/chunks/nitro/nitro.mjs +417 -204
  20. package/.output/server/chunks/nitro/nitro.mjs.map +1 -0
  21. package/{dist/app → .output}/server/chunks/routes/api/index.get.mjs +1 -1
  22. package/{dist/app → .output}/server/chunks/routes/api/index.post.mjs +1 -1
  23. package/{dist/app → .output}/server/chunks/routes/api/integrations/_id/credentials-config.get.mjs +1 -1
  24. package/{dist/app → .output}/server/chunks/routes/api/integrations/_id/credentials-status.get.mjs +1 -1
  25. package/{dist/app → .output}/server/chunks/routes/api/integrations/_id/credentials.delete.mjs +1 -1
  26. package/{dist/app → .output}/server/chunks/routes/api/integrations/_id/credentials.post.mjs +1 -1
  27. package/{dist/app → .output}/server/chunks/routes/api/integrations/_id/permissions.post.mjs +1 -1
  28. package/.output/server/chunks/routes/api/integrations/_id/tools.delete.mjs +51 -0
  29. package/.output/server/chunks/routes/api/integrations/_id/tools.delete.mjs.map +1 -0
  30. package/.output/server/chunks/routes/api/integrations/_id/tools.get.mjs +57 -0
  31. package/.output/server/chunks/routes/api/integrations/_id/tools.get.mjs.map +1 -0
  32. package/.output/server/chunks/routes/api/integrations/_id/toolsets.get.mjs +53 -0
  33. package/.output/server/chunks/routes/api/integrations/_id/toolsets.get.mjs.map +1 -0
  34. package/{dist/app → .output}/server/chunks/routes/api/integrations/_id/toolsets.post.mjs +1 -1
  35. package/.output/server/chunks/routes/api/integrations/_id_.delete.mjs +55 -0
  36. package/.output/server/chunks/routes/api/integrations/_id_.delete.mjs.map +1 -0
  37. package/{dist/app → .output}/server/chunks/routes/mcp/create.mjs +1 -1
  38. package/{dist/app → .output}/server/chunks/routes/mcp.mjs +1 -1
  39. package/{dist/app → .output}/server/chunks/routes/renderer.mjs +1 -1
  40. package/{dist/app → .output}/server/index.mjs +1 -1
  41. package/{dist/app → .output}/server/package.json +2 -2
  42. package/LICENSE +17 -6
  43. package/README.md +32 -32
  44. package/bin/cli.mjs +552 -0
  45. package/bin/commandable-mcp.mjs +8 -0
  46. package/package.json +30 -40
  47. package/dist/app/public/_nuxt/DU1mG77A.js +0 -1
  48. package/dist/app/public/_nuxt/builds/latest.json +0 -1
  49. package/dist/app/public/_nuxt/builds/meta/b13ec2b2-ddd3-4ead-abd4-4fba9dfc0061.json +0 -1
  50. package/dist/app/public/_nuxt/uS7FY2am.js +0 -1
  51. package/dist/app/server/chunks/build/fetch-ZbqIFhDG.mjs.map +0 -1
  52. package/dist/app/server/chunks/build/index-C8flTcKI.mjs.map +0 -1
  53. package/dist/app/server/chunks/nitro/nitro.mjs.map +0 -1
  54. package/dist/app/server/chunks/routes/api/integrations/_id_.delete.mjs +0 -44
  55. package/dist/app/server/chunks/routes/api/integrations/_id_.delete.mjs.map +0 -1
  56. package/dist/app/server/migrations/pg/0000_initial.sql +0 -74
  57. package/dist/app/server/migrations/pg/meta/_journal.json +0 -13
  58. package/dist/app/server/migrations/sqlite/0000_initial.sql +0 -74
  59. package/dist/app/server/migrations/sqlite/meta/_journal.json +0 -13
  60. package/dist/cli/bin.d.ts +0 -3
  61. package/dist/cli/bin.d.ts.map +0 -1
  62. package/dist/cli/bin.js +0 -7
  63. package/dist/cli/bin.js.map +0 -1
  64. package/dist/cli/credentialManager.d.ts +0 -19
  65. package/dist/cli/credentialManager.d.ts.map +0 -1
  66. package/dist/cli/credentialManager.js +0 -82
  67. package/dist/cli/credentialManager.js.map +0 -1
  68. package/dist/cli/index.d.ts +0 -17
  69. package/dist/cli/index.d.ts.map +0 -1
  70. package/dist/cli/index.js +0 -818
  71. package/dist/cli/index.js.map +0 -1
  72. package/dist/cli/setup.d.ts +0 -3
  73. package/dist/cli/setup.d.ts.map +0 -1
  74. package/dist/cli/setup.js +0 -353
  75. package/dist/cli/setup.js.map +0 -1
  76. package/dist/config/configApply.d.ts +0 -16
  77. package/dist/config/configApply.d.ts.map +0 -1
  78. package/dist/config/configApply.js +0 -77
  79. package/dist/config/configApply.js.map +0 -1
  80. package/dist/config/configLoader.d.ts +0 -9
  81. package/dist/config/configLoader.d.ts.map +0 -1
  82. package/dist/config/configLoader.js +0 -75
  83. package/dist/config/configLoader.js.map +0 -1
  84. package/dist/config/configSchema.d.ts +0 -45
  85. package/dist/config/configSchema.d.ts.map +0 -1
  86. package/dist/config/configSchema.js +0 -23
  87. package/dist/config/configSchema.js.map +0 -1
  88. package/dist/crypto/encryption.d.ts +0 -3
  89. package/dist/crypto/encryption.d.ts.map +0 -1
  90. package/dist/crypto/encryption.js +0 -29
  91. package/dist/crypto/encryption.js.map +0 -1
  92. package/dist/db/client.d.ts +0 -24
  93. package/dist/db/client.d.ts.map +0 -1
  94. package/dist/db/client.js +0 -50
  95. package/dist/db/client.js.map +0 -1
  96. package/dist/db/credentialStore.d.ts +0 -15
  97. package/dist/db/credentialStore.d.ts.map +0 -1
  98. package/dist/db/credentialStore.js +0 -56
  99. package/dist/db/credentialStore.js.map +0 -1
  100. package/dist/db/integrationStore.d.ts +0 -12
  101. package/dist/db/integrationStore.d.ts.map +0 -1
  102. package/dist/db/integrationStore.js +0 -111
  103. package/dist/db/integrationStore.js.map +0 -1
  104. package/dist/db/integrationTypeConfigStore.d.ts +0 -6
  105. package/dist/db/integrationTypeConfigStore.d.ts.map +0 -1
  106. package/dist/db/integrationTypeConfigStore.js +0 -94
  107. package/dist/db/integrationTypeConfigStore.js.map +0 -1
  108. package/dist/db/migrate.d.ts +0 -3
  109. package/dist/db/migrate.d.ts.map +0 -1
  110. package/dist/db/migrate.js +0 -11
  111. package/dist/db/migrate.js.map +0 -1
  112. package/dist/db/migrations/pg/0000_initial.sql +0 -74
  113. package/dist/db/migrations/pg/meta/_journal.json +0 -13
  114. package/dist/db/migrations/sqlite/0000_initial.sql +0 -74
  115. package/dist/db/migrations/sqlite/meta/_journal.json +0 -13
  116. package/dist/db/schema.d.ts +0 -1863
  117. package/dist/db/schema.d.ts.map +0 -1
  118. package/dist/db/schema.js +0 -133
  119. package/dist/db/schema.js.map +0 -1
  120. package/dist/db/toolDefinitionStore.d.ts +0 -6
  121. package/dist/db/toolDefinitionStore.d.ts.map +0 -1
  122. package/dist/db/toolDefinitionStore.js +0 -95
  123. package/dist/db/toolDefinitionStore.js.map +0 -1
  124. package/dist/errors/httpError.d.ts +0 -6
  125. package/dist/errors/httpError.d.ts.map +0 -1
  126. package/dist/errors/httpError.js +0 -11
  127. package/dist/errors/httpError.js.map +0 -1
  128. package/dist/index.d.ts +0 -32
  129. package/dist/index.d.ts.map +0 -1
  130. package/dist/index.js +0 -32
  131. package/dist/index.js.map +0 -1
  132. package/dist/integrations/actionsFactory.d.ts +0 -16
  133. package/dist/integrations/actionsFactory.d.ts.map +0 -1
  134. package/dist/integrations/actionsFactory.js +0 -98
  135. package/dist/integrations/actionsFactory.js.map +0 -1
  136. package/dist/integrations/catalog.d.ts +0 -8
  137. package/dist/integrations/catalog.d.ts.map +0 -1
  138. package/dist/integrations/catalog.js +0 -45
  139. package/dist/integrations/catalog.js.map +0 -1
  140. package/dist/integrations/customToolFactory.d.ts +0 -13
  141. package/dist/integrations/customToolFactory.d.ts.map +0 -1
  142. package/dist/integrations/customToolFactory.js +0 -31
  143. package/dist/integrations/customToolFactory.js.map +0 -1
  144. package/dist/integrations/dataLoader.d.ts +0 -3
  145. package/dist/integrations/dataLoader.d.ts.map +0 -1
  146. package/dist/integrations/dataLoader.js +0 -2
  147. package/dist/integrations/dataLoader.js.map +0 -1
  148. package/dist/integrations/fileIntegrationTypeConfigStore.d.ts +0 -7
  149. package/dist/integrations/fileIntegrationTypeConfigStore.d.ts.map +0 -1
  150. package/dist/integrations/fileIntegrationTypeConfigStore.js +0 -34
  151. package/dist/integrations/fileIntegrationTypeConfigStore.js.map +0 -1
  152. package/dist/integrations/getIntegration.d.ts +0 -14
  153. package/dist/integrations/getIntegration.d.ts.map +0 -1
  154. package/dist/integrations/getIntegration.js +0 -30
  155. package/dist/integrations/getIntegration.js.map +0 -1
  156. package/dist/integrations/googleServiceAccount.d.ts +0 -6
  157. package/dist/integrations/googleServiceAccount.d.ts.map +0 -1
  158. package/dist/integrations/googleServiceAccount.js +0 -54
  159. package/dist/integrations/googleServiceAccount.js.map +0 -1
  160. package/dist/integrations/health.d.ts +0 -20
  161. package/dist/integrations/health.d.ts.map +0 -1
  162. package/dist/integrations/health.js +0 -43
  163. package/dist/integrations/health.js.map +0 -1
  164. package/dist/integrations/integrationTypeConfigLookup.d.ts +0 -12
  165. package/dist/integrations/integrationTypeConfigLookup.d.ts.map +0 -1
  166. package/dist/integrations/integrationTypeConfigLookup.js +0 -11
  167. package/dist/integrations/integrationTypeConfigLookup.js.map +0 -1
  168. package/dist/integrations/providerRegistry.d.ts +0 -2
  169. package/dist/integrations/providerRegistry.d.ts.map +0 -1
  170. package/dist/integrations/providerRegistry.js +0 -72
  171. package/dist/integrations/providerRegistry.js.map +0 -1
  172. package/dist/integrations/proxy.d.ts +0 -19
  173. package/dist/integrations/proxy.d.ts.map +0 -1
  174. package/dist/integrations/proxy.js +0 -377
  175. package/dist/integrations/proxy.js.map +0 -1
  176. package/dist/integrations/sandbox.d.ts +0 -8
  177. package/dist/integrations/sandbox.d.ts.map +0 -1
  178. package/dist/integrations/sandbox.js +0 -221
  179. package/dist/integrations/sandbox.js.map +0 -1
  180. package/dist/integrations/sandboxUtils.d.ts +0 -15
  181. package/dist/integrations/sandboxUtils.d.ts.map +0 -1
  182. package/dist/integrations/sandboxUtils.js +0 -489
  183. package/dist/integrations/sandboxUtils.js.map +0 -1
  184. package/dist/integrations/tools.d.ts +0 -3
  185. package/dist/integrations/tools.d.ts.map +0 -1
  186. package/dist/integrations/tools.js +0 -70
  187. package/dist/integrations/tools.js.map +0 -1
  188. package/dist/mcp/abilityCatalog.d.ts +0 -46
  189. package/dist/mcp/abilityCatalog.d.ts.map +0 -1
  190. package/dist/mcp/abilityCatalog.js +0 -275
  191. package/dist/mcp/abilityCatalog.js.map +0 -1
  192. package/dist/mcp/auth.d.ts +0 -18
  193. package/dist/mcp/auth.d.ts.map +0 -1
  194. package/dist/mcp/auth.js +0 -45
  195. package/dist/mcp/auth.js.map +0 -1
  196. package/dist/mcp/builder_guide.md +0 -441
  197. package/dist/mcp/commandable_readme.md +0 -29
  198. package/dist/mcp/handlers.d.ts +0 -21
  199. package/dist/mcp/handlers.d.ts.map +0 -1
  200. package/dist/mcp/handlers.js +0 -86
  201. package/dist/mcp/handlers.js.map +0 -1
  202. package/dist/mcp/metaTools.d.ts +0 -77
  203. package/dist/mcp/metaTools.d.ts.map +0 -1
  204. package/dist/mcp/metaTools.js +0 -753
  205. package/dist/mcp/metaTools.js.map +0 -1
  206. package/dist/mcp/server.d.ts +0 -25
  207. package/dist/mcp/server.d.ts.map +0 -1
  208. package/dist/mcp/server.js +0 -14
  209. package/dist/mcp/server.js.map +0 -1
  210. package/dist/mcp/sessionState.d.ts +0 -18
  211. package/dist/mcp/sessionState.d.ts.map +0 -1
  212. package/dist/mcp/sessionState.js +0 -65
  213. package/dist/mcp/sessionState.js.map +0 -1
  214. package/dist/mcp/toolAdapter.d.ts +0 -34
  215. package/dist/mcp/toolAdapter.d.ts.map +0 -1
  216. package/dist/mcp/toolAdapter.js +0 -24
  217. package/dist/mcp/toolAdapter.js.map +0 -1
  218. package/dist/types.d.ts +0 -92
  219. package/dist/types.d.ts.map +0 -1
  220. package/dist/types.js +0 -2
  221. package/dist/types.js.map +0 -1
  222. package/dist/version.d.ts +0 -2
  223. package/dist/version.d.ts.map +0 -1
  224. package/dist/version.js +0 -7
  225. package/dist/version.js.map +0 -1
  226. /package/{dist/app → .output}/public/_fonts/57NSSoFy1VLVs2gqly8Ls9awBnZMFyXGrefpmqvdqmc-zJfbBtpgM4cDmcXBsqZNW79_kFnlpPd62b48glgdydA.woff2 +0 -0
  227. /package/{dist/app → .output}/public/_fonts/8VR2wSMN-3U4NbWAVYXlkRV6hA0jFBXP-0RtL3X7fko-x2gYI4qfmkRdxyQQUPaBZdZdgl1TeVrquF_TxHeM4lM.woff2 +0 -0
  228. /package/{dist/app → .output}/public/_fonts/GsKUclqeNLJ96g5AU593ug6yanivOiwjW_7zESNPChw-jHA4tBeM1bjF7LATGUpfBuSTyomIFrWBTzjF7txVYfg.woff2 +0 -0
  229. /package/{dist/app → .output}/public/_fonts/Ld1FnTo3yTIwDyGfTQ5-Fws9AWsCbKfMvgxduXr7JcY-W25bL8NF1fjpLRSOgJb7RoZPHqGQNwMTM7S9tHVoxx8.woff2 +0 -0
  230. /package/{dist/app → .output}/public/_fonts/NdzqRASp2bovDUhQT1IRE_EMqKJ2KYQdTCfFcBvL8yw-KhwZiS86o3fErOe5GGMExHUemmI_dBfaEFxjISZrBd0.woff2 +0 -0
  231. /package/{dist/app → .output}/public/_fonts/iTkrULNFJJkTvihIg1Vqi5IODRH_9btXCioVF5l98I8-AndUyau2HR2felA_ra8V2mutQgschhasE5FD1dXGJX8.woff2 +0 -0
  232. /package/{dist/app → .output}/public/_nuxt/_id_.BKAjWkoP.css +0 -0
  233. /package/{dist/app → .output}/public/_nuxt/entry.Y3mA4bzA.css +0 -0
  234. /package/{dist/app → .output}/public/_nuxt/error-404.C7fg894-.css +0 -0
  235. /package/{dist/app → .output}/public/_nuxt/error-500.DjUK_N2Y.css +0 -0
  236. /package/{dist/app → .output}/public/favicon.ico +0 -0
  237. /package/{dist/app → .output}/server/chunks/_/error-500.mjs +0 -0
  238. /package/{dist/app → .output}/server/chunks/_/error-500.mjs.map +0 -0
  239. /package/{dist/app → .output}/server/chunks/_/icons.mjs +0 -0
  240. /package/{dist/app → .output}/server/chunks/_/icons.mjs.map +0 -0
  241. /package/{dist/app → .output}/server/chunks/_/icons2.mjs +0 -0
  242. /package/{dist/app → .output}/server/chunks/_/icons2.mjs.map +0 -0
  243. /package/{dist/app → .output}/server/chunks/build/IntegrationCredentials-styles.CULcCK6_.mjs +0 -0
  244. /package/{dist/app → .output}/server/chunks/build/IntegrationCredentials-styles.CULcCK6_.mjs.map +0 -0
  245. /package/{dist/app → .output}/server/chunks/build/client.precomputed.mjs.map +0 -0
  246. /package/{dist/app → .output}/server/chunks/build/error-404-D2QibUBT.mjs +0 -0
  247. /package/{dist/app → .output}/server/chunks/build/error-404-D2QibUBT.mjs.map +0 -0
  248. /package/{dist/app → .output}/server/chunks/build/error-404-styles.Bvxdxqjk.mjs +0 -0
  249. /package/{dist/app → .output}/server/chunks/build/error-404-styles.Bvxdxqjk.mjs.map +0 -0
  250. /package/{dist/app → .output}/server/chunks/build/error-500-DYvawybF.mjs +0 -0
  251. /package/{dist/app → .output}/server/chunks/build/error-500-DYvawybF.mjs.map +0 -0
  252. /package/{dist/app → .output}/server/chunks/build/error-500-styles.BnYAAXSg.mjs +0 -0
  253. /package/{dist/app → .output}/server/chunks/build/error-500-styles.BnYAAXSg.mjs.map +0 -0
  254. /package/{dist/app → .output}/server/chunks/build/index-5H-nmhph.mjs +0 -0
  255. /package/{dist/app → .output}/server/chunks/build/index-5H-nmhph.mjs.map +0 -0
  256. /package/{dist/app → .output}/server/chunks/build/server.mjs.map +0 -0
  257. /package/{dist/app → .output}/server/chunks/build/styles.mjs +0 -0
  258. /package/{dist/app → .output}/server/chunks/build/styles.mjs.map +0 -0
  259. /package/{dist/app → .output}/server/chunks/routes/api/_commandable/status.get.mjs +0 -0
  260. /package/{dist/app → .output}/server/chunks/routes/api/_commandable/status.get.mjs.map +0 -0
  261. /package/{dist/app → .output}/server/chunks/routes/api/catalog/_type/tools.get.mjs +0 -0
  262. /package/{dist/app → .output}/server/chunks/routes/api/catalog/_type/tools.get.mjs.map +0 -0
  263. /package/{dist/app → .output}/server/chunks/routes/api/catalog/_type/toolsets.get.mjs +0 -0
  264. /package/{dist/app → .output}/server/chunks/routes/api/catalog/_type/toolsets.get.mjs.map +0 -0
  265. /package/{dist/app → .output}/server/chunks/routes/api/catalog.get.mjs +0 -0
  266. /package/{dist/app → .output}/server/chunks/routes/api/catalog.get.mjs.map +0 -0
  267. /package/{dist/app → .output}/server/chunks/routes/api/index.get.mjs.map +0 -0
  268. /package/{dist/app → .output}/server/chunks/routes/api/index.post.mjs.map +0 -0
  269. /package/{dist/app → .output}/server/chunks/routes/api/integrations/_id/credentials-config.get.mjs.map +0 -0
  270. /package/{dist/app → .output}/server/chunks/routes/api/integrations/_id/credentials-status.get.mjs.map +0 -0
  271. /package/{dist/app → .output}/server/chunks/routes/api/integrations/_id/credentials.delete.mjs.map +0 -0
  272. /package/{dist/app → .output}/server/chunks/routes/api/integrations/_id/credentials.post.mjs.map +0 -0
  273. /package/{dist/app → .output}/server/chunks/routes/api/integrations/_id/permissions.post.mjs.map +0 -0
  274. /package/{dist/app → .output}/server/chunks/routes/api/integrations/_id/toolsets.post.mjs.map +0 -0
  275. /package/{dist/app → .output}/server/chunks/routes/health.get.mjs +0 -0
  276. /package/{dist/app → .output}/server/chunks/routes/health.get.mjs.map +0 -0
  277. /package/{dist/app → .output}/server/chunks/routes/mcp/create.mjs.map +0 -0
  278. /package/{dist/app → .output}/server/chunks/routes/mcp.mjs.map +0 -0
  279. /package/{dist/app → .output}/server/chunks/routes/renderer.mjs.map +0 -0
  280. /package/{dist/app → .output}/server/chunks/virtual/_virtual_spa-template.mjs +0 -0
  281. /package/{dist/app → .output}/server/chunks/virtual/_virtual_spa-template.mjs.map +0 -0
  282. /package/{dist/app → .output}/server/index.mjs.map +0 -0
@@ -1,753 +0,0 @@
1
- import { BUILDER_ABILITY_ID } from './abilityCatalog.js';
2
- import { buildMcpToolIndexForIntegrations } from './toolAdapter.js';
3
- import { readFileSync } from 'node:fs';
4
- import { fileURLToPath } from 'node:url';
5
- import crypto from 'node:crypto';
6
- import { listIntegrationCatalog } from '../integrations/catalog.js';
7
- import { getBuiltInIntegrationTypeConfig } from '../integrations/fileIntegrationTypeConfigStore.js';
8
- import { createGetIntegration } from '../integrations/getIntegration.js';
9
- import { loadIntegrationManifest, loadIntegrationPrompt } from '../integrations/dataLoader.js';
10
- import { listIntegrations, upsertIntegration } from '../db/integrationStore.js';
11
- import { PROVIDERS } from '../integrations/providerRegistry.js';
12
- import { createSafeHandlerFromString } from '../integrations/sandbox.js';
13
- import { sanitizeJsonSchema } from '../integrations/tools.js';
14
- import { getToolDefinitionByName, upsertToolDefinition } from '../db/toolDefinitionStore.js';
15
- import { buildExecutableToolFromDefinition } from '../integrations/customToolFactory.js';
16
- import { upsertIntegrationTypeConfig } from '../db/integrationTypeConfigStore.js';
17
- export const META_TOOL_NAMES = {
18
- readme: 'commandable_readme',
19
- searchTools: 'commandable_search_tools',
20
- enableToolset: 'commandable_enable_toolset',
21
- disableToolset: 'commandable_disable_toolset',
22
- listPrebuiltIntegrations: 'commandable_list_prebuilt_integrations',
23
- addPrebuiltIntegration: 'commandable_add_prebuilt_integration',
24
- createCustomIntegration: 'commandable_create_custom_integration',
25
- createCustomTool: 'commandable_create_custom_tool',
26
- testCustomTool: 'commandable_test_custom_tool',
27
- };
28
- function normalizeHintMarkdown(value) {
29
- return value
30
- .replace(/\r\n/g, '\n')
31
- .replace(/\\r\\n/g, '\n')
32
- .replace(/\\n/g, '\n');
33
- }
34
- function buildCommandableReadme() {
35
- const path = fileURLToPath(new URL('./commandable_readme.md', import.meta.url));
36
- return readFileSync(path, 'utf8');
37
- }
38
- function buildBuilderGuide() {
39
- const path = fileURLToPath(new URL('./builder_guide.md', import.meta.url));
40
- return readFileSync(path, 'utf8');
41
- }
42
- function providerBaseUrl(integration) {
43
- const provider = PROVIDERS[integration.type];
44
- const base = provider?.baseUrl;
45
- if (typeof base === 'function') {
46
- try {
47
- return String(base(integration, undefined) || '');
48
- }
49
- catch {
50
- return '(dynamic baseUrl)';
51
- }
52
- }
53
- return String(base || '');
54
- }
55
- function requireBuilderEnabled(sessionState, sessionId, toolName) {
56
- if (!sessionState.isToolActive(sessionId, toolName)) {
57
- throw new Error(`Tool not enabled in this session: ${toolName}. Enable the builder toolset (${BUILDER_ABILITY_ID}) via commandable_search_tools → commandable_enable_toolset first.`);
58
- }
59
- }
60
- export function getMetaToolDefinitions() {
61
- return [
62
- {
63
- name: META_TOOL_NAMES.readme,
64
- description: 'Read this first. Returns a guide explaining how Commandable works and how to discover/add integrations safely.',
65
- inputSchema: { type: 'object', additionalProperties: false, properties: {}, required: [] },
66
- },
67
- {
68
- name: META_TOOL_NAMES.searchTools,
69
- description: `Search available toolsets (integration/toolset bundles) you can enable in this session. Call \`${META_TOOL_NAMES.readme}\` first if you haven't yet.`,
70
- inputSchema: {
71
- type: 'object',
72
- additionalProperties: false,
73
- properties: {
74
- query: { type: 'string', minLength: 1 },
75
- limit: { type: 'number', minimum: 1, maximum: 50 },
76
- },
77
- required: ['query'],
78
- },
79
- },
80
- {
81
- name: META_TOOL_NAMES.enableToolset,
82
- description: `Enable a toolset in the current session, making its tools available. Call \`${META_TOOL_NAMES.readme}\` first if you haven't yet.`,
83
- inputSchema: {
84
- type: 'object',
85
- additionalProperties: false,
86
- properties: {
87
- toolset_id: { type: 'string', minLength: 1 },
88
- },
89
- required: ['toolset_id'],
90
- },
91
- },
92
- {
93
- name: META_TOOL_NAMES.disableToolset,
94
- description: `Disable a toolset from the current session, removing its tools. Call \`${META_TOOL_NAMES.readme}\` first if you haven't yet.`,
95
- inputSchema: {
96
- type: 'object',
97
- additionalProperties: false,
98
- properties: {
99
- toolset_id: { type: 'string', minLength: 1 },
100
- },
101
- required: ['toolset_id'],
102
- },
103
- },
104
- ];
105
- }
106
- export function getBuilderToolDefinitions() {
107
- return [
108
- {
109
- name: META_TOOL_NAMES.listPrebuiltIntegrations,
110
- description: `Builder tool. List available pre-built integrations you can add (from the integration catalog) and show which are already configured.`,
111
- inputSchema: {
112
- type: 'object',
113
- additionalProperties: false,
114
- properties: {
115
- query: { type: 'string' },
116
- limit: { type: 'number', minimum: 1, maximum: 100 },
117
- },
118
- required: [],
119
- },
120
- },
121
- {
122
- name: META_TOOL_NAMES.addPrebuiltIntegration,
123
- description: `Builder tool. Add a pre-built integration from the catalog to this Commandable instance (credentials are entered out-of-band).`,
124
- inputSchema: {
125
- type: 'object',
126
- additionalProperties: false,
127
- properties: {
128
- type: { type: 'string', minLength: 1 },
129
- label: { type: 'string' },
130
- credential_variant: { type: 'string' },
131
- max_scope: { type: 'string', enum: ['read', 'write'] },
132
- enabled_toolsets: { type: 'array', items: { type: 'string' } },
133
- disabled_tools: { type: 'array', items: { type: 'string' } },
134
- },
135
- required: ['type'],
136
- },
137
- },
138
- {
139
- name: META_TOOL_NAMES.createCustomIntegration,
140
- description: 'Builder tool. Create a brand new integration type from scratch (base URL + credential schema + auth injection rules). Returns a credential URL and a new integration_id you can add tools to.',
141
- inputSchema: {
142
- type: 'object',
143
- additionalProperties: false,
144
- properties: {
145
- label: { type: 'string', minLength: 1 },
146
- base_url: { type: 'string', minLength: 1 },
147
- auth_type: { type: 'string', enum: ['basic', 'custom'] },
148
- credential_fields: {
149
- type: 'array',
150
- minItems: 1,
151
- items: {
152
- type: 'object',
153
- additionalProperties: false,
154
- properties: {
155
- name: { type: 'string', minLength: 1 },
156
- label: { type: 'string', minLength: 1 },
157
- description: { type: 'string' },
158
- sensitive: { type: 'boolean' },
159
- },
160
- required: ['name', 'label'],
161
- },
162
- },
163
- credential_injection: {
164
- type: 'object',
165
- additionalProperties: false,
166
- properties: {
167
- headers: { type: 'object', additionalProperties: { type: 'string' } },
168
- query: { type: 'object', additionalProperties: { type: 'string' } },
169
- },
170
- required: [],
171
- },
172
- basic_username_field: { type: 'string' },
173
- basic_password_field: { type: 'string' },
174
- health_check_path: { type: 'string' },
175
- connection_hint: {
176
- type: 'string',
177
- description: 'Markdown shown in the credential form. Must be a numbered list of every step the user needs to follow to obtain the credentials — starting from navigating to the correct web page..',
178
- },
179
- },
180
- required: ['label', 'base_url', 'auth_type', 'credential_fields'],
181
- },
182
- },
183
- {
184
- name: META_TOOL_NAMES.testCustomTool,
185
- description: 'Builder tool. Run a sandboxed tool handler with a test input (does not persist). Use this to iterate before saving a tool.',
186
- inputSchema: {
187
- type: 'object',
188
- additionalProperties: false,
189
- properties: {
190
- integration_id: { type: 'string', minLength: 1 },
191
- handler_code: { type: 'string', minLength: 1 },
192
- input_schema: { type: 'object' },
193
- test_input: { type: 'object' },
194
- },
195
- required: ['integration_id', 'handler_code'],
196
- },
197
- },
198
- {
199
- name: META_TOOL_NAMES.createCustomTool,
200
- description: 'Builder tool. Persist a new custom tool on an existing integration, and register it so it can be used immediately.',
201
- inputSchema: {
202
- type: 'object',
203
- additionalProperties: false,
204
- properties: {
205
- integration_id: { type: 'string', minLength: 1 },
206
- name: { type: 'string', minLength: 1 },
207
- label: { type: 'string' },
208
- description: { type: 'string' },
209
- scope: { type: 'string', enum: ['read', 'write', 'admin'] },
210
- input_schema: { type: 'object' },
211
- handler_code: { type: 'string', minLength: 1 },
212
- },
213
- required: ['integration_id', 'name', 'handler_code'],
214
- },
215
- },
216
- ];
217
- }
218
- export async function handleMetaToolCall(params) {
219
- const { name, args, sessionId, catalog, sessionState, ctx } = params;
220
- if (name === META_TOOL_NAMES.readme) {
221
- return { handled: true, listChanged: false, result: { markdown: buildCommandableReadme() } };
222
- }
223
- if (name === META_TOOL_NAMES.searchTools) {
224
- const query = String(args?.query || '').trim();
225
- const limitRaw = args?.limit;
226
- const limit = typeof limitRaw === 'number' && Number.isFinite(limitRaw) ? Math.max(1, Math.min(50, limitRaw)) : 10;
227
- if (!query)
228
- throw new Error('query is required');
229
- const res = catalog.search(query, limit).map(a => ({
230
- toolset_id: a.id,
231
- label: a.label,
232
- description: a.description,
233
- integration_type: a.integrationtype,
234
- integration_label: a.integrationLabel,
235
- toolset_key: a.toolsetKey || null,
236
- tool_count: a.toolCount,
237
- score: a.score,
238
- }));
239
- return { handled: true, listChanged: false, result: { toolsets: res } };
240
- }
241
- if (name === META_TOOL_NAMES.enableToolset) {
242
- const toolsetId = String(args?.toolset_id || '').trim();
243
- if (!toolsetId)
244
- throw new Error('toolset_id is required');
245
- const ability = catalog.getAbility(toolsetId);
246
- if (!ability)
247
- throw new Error(`Unknown toolset_id: ${toolsetId}`);
248
- const { newTools } = sessionState.loadAbility(sessionId, ability);
249
- const integrationGuide = (() => {
250
- if (ability.id === BUILDER_ABILITY_ID) {
251
- const base = buildBuilderGuide();
252
- const integrations = ctx?.integrationsRef?.current || [];
253
- const lines = integrations.map((i) => {
254
- const baseUrl = providerBaseUrl(i) || '(unknown baseUrl)';
255
- return `- \`${i.referenceId || i.id}\`: ${i.label} (${i.type}), baseUrl: ${baseUrl}`;
256
- }).join('\n');
257
- return `${base}\n\n${lines ? `${lines}\n` : 'No integrations configured yet.\n'}`;
258
- }
259
- try {
260
- return loadIntegrationPrompt(ability.integrationtype);
261
- }
262
- catch {
263
- return null;
264
- }
265
- })();
266
- return {
267
- handled: true,
268
- listChanged: newTools.length > 0,
269
- result: {
270
- loaded: true,
271
- toolset_id: ability.id,
272
- label: ability.label,
273
- tool_count: ability.toolNames.length,
274
- new_tools: newTools,
275
- integration_guide: integrationGuide,
276
- },
277
- };
278
- }
279
- if (name === META_TOOL_NAMES.disableToolset) {
280
- const toolsetId = String(args?.toolset_id || '').trim();
281
- if (!toolsetId)
282
- throw new Error('toolset_id is required');
283
- const ability = catalog.getAbility(toolsetId);
284
- if (!ability)
285
- throw new Error(`Unknown toolset_id: ${toolsetId}`);
286
- const { removedTools } = sessionState.unloadAbility(sessionId, ability);
287
- return {
288
- handled: true,
289
- listChanged: removedTools.length > 0,
290
- result: {
291
- unloaded: true,
292
- toolset_id: ability.id,
293
- label: ability.label,
294
- removed_tools: removedTools,
295
- },
296
- };
297
- }
298
- if (name === META_TOOL_NAMES.listPrebuiltIntegrations) {
299
- requireBuilderEnabled(sessionState, sessionId, META_TOOL_NAMES.listPrebuiltIntegrations);
300
- if (!ctx)
301
- throw new Error('Integration management is not available in this server mode.');
302
- const q = String(args?.query ?? '').trim().toLowerCase();
303
- const limitRaw = args?.limit;
304
- const limit = typeof limitRaw === 'number' && Number.isFinite(limitRaw) ? Math.max(1, Math.min(100, limitRaw)) : 50;
305
- const catalogItems = listIntegrationCatalog();
306
- const configured = await listIntegrations(ctx.db, ctx.spaceId);
307
- const byType = new Map();
308
- for (const it of configured) {
309
- const arr = byType.get(it.type) || [];
310
- arr.push(it);
311
- byType.set(it.type, arr);
312
- }
313
- const items = [];
314
- for (const it of catalogItems) {
315
- if (q) {
316
- const hay = `${it.type} ${it.name}`.toLowerCase();
317
- if (!hay.includes(q))
318
- continue;
319
- }
320
- const instances = byType.get(it.type) || [];
321
- const instanceInfos = await Promise.all(instances.map(async (inst) => {
322
- const hasCreds = inst.connectionMethod === 'credentials' && inst.credentialId
323
- ? await ctx.credentialStore.hasCredentials(ctx.spaceId, inst.credentialId)
324
- : false;
325
- const baseUrl = ctx.credentialSetupBaseUrl ? ctx.credentialSetupBaseUrl.replace(/\/+$/, '') : null;
326
- const credentialUrl = baseUrl && inst.connectionMethod === 'credentials'
327
- ? `${baseUrl}/integrations/${encodeURIComponent(inst.id)}`
328
- : null;
329
- return {
330
- id: inst.id,
331
- label: inst.label,
332
- enabled: inst.enabled !== false,
333
- connection_method: inst.connectionMethod ?? null,
334
- credential_variant: inst.credentialVariant ?? null,
335
- has_credentials: hasCreds,
336
- health_status: inst.healthStatus ?? null,
337
- health_checked_at: inst.healthCheckedAt ? inst.healthCheckedAt.toISOString() : null,
338
- credential_url: credentialUrl,
339
- };
340
- }));
341
- items.push({
342
- type: it.type,
343
- name: it.name,
344
- configured: instances.length > 0,
345
- instances: instanceInfos,
346
- supports_credentials: !!getBuiltInIntegrationTypeConfig(it.type),
347
- });
348
- if (items.length >= limit)
349
- break;
350
- }
351
- return { handled: true, listChanged: false, result: { integrations: items } };
352
- }
353
- if (name === META_TOOL_NAMES.addPrebuiltIntegration) {
354
- requireBuilderEnabled(sessionState, sessionId, META_TOOL_NAMES.addPrebuiltIntegration);
355
- if (!ctx)
356
- throw new Error('Integration management is not available in this server mode.');
357
- const type = String(args?.type || '').trim();
358
- if (!type)
359
- throw new Error('type is required');
360
- const catalogItems = listIntegrationCatalog();
361
- const exists = catalogItems.some(i => i.type === type);
362
- if (!exists)
363
- throw new Error(`Unknown integration type: ${type}`);
364
- const manifest = loadIntegrationManifest(type);
365
- const defaultLabel = (manifest && typeof manifest === 'object' && typeof manifest.name === 'string' && manifest.name.trim().length)
366
- ? manifest.name.trim()
367
- : type;
368
- const id = crypto.randomUUID ? crypto.randomUUID() : crypto.randomBytes(16).toString('hex');
369
- const shortId = id.replace(/[^a-z0-9]/gi, '').slice(0, 8).toLowerCase();
370
- const label = String(args?.label || '').trim() || defaultLabel;
371
- const parseStringArray = (v) => {
372
- if (Array.isArray(v))
373
- return v.map((s) => String(s)).filter(Boolean);
374
- if (typeof v === 'string') {
375
- try {
376
- const p = JSON.parse(v);
377
- return Array.isArray(p) ? p.map((s) => String(s)).filter(Boolean) : undefined;
378
- }
379
- catch {
380
- return undefined;
381
- }
382
- }
383
- return undefined;
384
- };
385
- const enabledToolsets = parseStringArray(args?.enabled_toolsets);
386
- const disabledTools = parseStringArray(args?.disabled_tools);
387
- const maxScope = args?.max_scope === 'read' || args?.max_scope === 'write' ? args.max_scope : undefined;
388
- const credentialVariant = typeof args?.credential_variant === 'string' && args.credential_variant.trim().length
389
- ? args.credential_variant.trim()
390
- : null;
391
- const referenceId = `${type}-${shortId}`;
392
- const integration = {
393
- spaceId: ctx.spaceId,
394
- id,
395
- type,
396
- referenceId,
397
- label,
398
- enabled: true,
399
- enabledToolsets: enabledToolsets?.length ? enabledToolsets : undefined,
400
- maxScope,
401
- disabledTools: disabledTools?.length ? disabledTools : undefined,
402
- credentialVariant,
403
- // mark as credentials-based immediately; values are entered out-of-band via management UI
404
- connectionMethod: 'credentials',
405
- credentialId: `${referenceId}-creds`,
406
- };
407
- await upsertIntegration(ctx.db, integration);
408
- // Refresh mutable integrations ref if present (keeps tool handlers from capturing stale config).
409
- if (ctx.integrationsRef) {
410
- try {
411
- ctx.integrationsRef.current = await listIntegrations(ctx.db, ctx.spaceId);
412
- }
413
- catch { }
414
- }
415
- const typeConfig = getBuiltInIntegrationTypeConfig(type);
416
- const selectedVariantKey = credentialVariant || typeConfig?.defaultVariant || null;
417
- const selectedVariant = selectedVariantKey ? typeConfig?.variants[selectedVariantKey] : null;
418
- const credentialFields = selectedVariant?.credentialSchema && typeof selectedVariant.credentialSchema === 'object'
419
- ? Object.keys(selectedVariant.credentialSchema.properties || {})
420
- : [];
421
- const baseUrl = ctx.credentialSetupBaseUrl ? ctx.credentialSetupBaseUrl.replace(/\/+$/, '') : null;
422
- const managementUrl = baseUrl ? `${baseUrl}/integrations` : null;
423
- const credentialUrl = baseUrl ? `${baseUrl}/integrations/${encodeURIComponent(id)}` : null;
424
- // Dynamic tool registration (create mode): materialize tools for this integration
425
- // and register them into the live tool index + ability catalog.
426
- let registeredTools = 0;
427
- let registeredToolsets = [];
428
- if (ctx.toolIndexRef && ctx.catalogRef) {
429
- const toolIndex = buildMcpToolIndexForIntegrations({
430
- spaceId: ctx.spaceId,
431
- integrations: [integration],
432
- proxy: ctx.proxy,
433
- integrationsRef: ctx.integrationsRef,
434
- });
435
- for (const [toolName, tool] of toolIndex.byName.entries()) {
436
- if (!ctx.toolIndexRef.byName.has(toolName)) {
437
- ctx.toolIndexRef.byName.set(toolName, tool);
438
- registeredTools++;
439
- }
440
- }
441
- if (ctx.toolIndexRef.list) {
442
- for (const t of toolIndex.tools) {
443
- if (!ctx.toolIndexRef.list.find(x => x.name === t.name))
444
- ctx.toolIndexRef.list.push(t);
445
- }
446
- }
447
- const newAbilities = ctx.catalogRef.current.addIntegration(integration);
448
- registeredToolsets = newAbilities.map(a => ({
449
- toolset_id: a.id,
450
- label: a.label,
451
- tool_count: a.toolNames.length,
452
- }));
453
- }
454
- return {
455
- handled: true,
456
- listChanged: false,
457
- result: {
458
- added: true,
459
- integration: {
460
- id,
461
- type,
462
- label,
463
- reference_id: integration.referenceId,
464
- credential_variant: credentialVariant,
465
- },
466
- registered_tools: registeredTools,
467
- toolsets: registeredToolsets,
468
- credentials_needed: !!typeConfig,
469
- management_url: managementUrl,
470
- credential_url: credentialUrl,
471
- credential_fields: credentialFields,
472
- next_steps: credentialUrl
473
- ? ['Open credential_url to enter credentials, then enable a toolset and use tools.']
474
- : ['Start the management UI (create mode) to get a credential URL, then enable a toolset and use tools.'],
475
- },
476
- };
477
- }
478
- if (name === META_TOOL_NAMES.createCustomIntegration) {
479
- requireBuilderEnabled(sessionState, sessionId, META_TOOL_NAMES.createCustomIntegration);
480
- if (!ctx)
481
- throw new Error('Integration management is not available in this server mode.');
482
- if (!ctx.integrationsRef)
483
- throw new Error('integrationsRef is required for builder mode.');
484
- if (!ctx.integrationTypeConfigsRef)
485
- throw new Error('integrationTypeConfigsRef is required for custom integrations.');
486
- const label = String(args?.label || '').trim();
487
- const baseUrl = String(args?.base_url || '').trim();
488
- const authType = (args?.auth_type === 'basic' || args?.auth_type === 'custom') ? String(args.auth_type) : null;
489
- const rawCredFields = args?.credential_fields;
490
- const credentialFields = Array.isArray(rawCredFields)
491
- ? rawCredFields
492
- : (typeof rawCredFields === 'string' ? (() => { try {
493
- const p = JSON.parse(rawCredFields);
494
- return Array.isArray(p) ? p : [];
495
- }
496
- catch {
497
- return [];
498
- } })() : []);
499
- const rawCredInjection = args?.credential_injection;
500
- const credentialInjection = rawCredInjection && typeof rawCredInjection === 'object' && !Array.isArray(rawCredInjection)
501
- ? rawCredInjection
502
- : (typeof rawCredInjection === 'string' ? (() => { try {
503
- const p = JSON.parse(rawCredInjection);
504
- return (p && typeof p === 'object' && !Array.isArray(p)) ? p : null;
505
- }
506
- catch {
507
- return null;
508
- } })() : null);
509
- const basicUsernameField = typeof args?.basic_username_field === 'string' ? args.basic_username_field.trim() : '';
510
- const basicPasswordField = typeof args?.basic_password_field === 'string' ? args.basic_password_field.trim() : '';
511
- const healthCheckPath = typeof args?.health_check_path === 'string' ? args.health_check_path.trim() : '';
512
- const connectionHint = typeof args?.connection_hint === 'string' ? normalizeHintMarkdown(args.connection_hint).trim() : '';
513
- if (!label)
514
- throw new Error('label is required');
515
- if (!baseUrl)
516
- throw new Error('base_url is required');
517
- if (!authType)
518
- throw new Error('auth_type must be basic or custom');
519
- if (!credentialFields.length)
520
- throw new Error('credential_fields is required');
521
- if (authType === 'custom') {
522
- const hasAny = credentialInjection && (credentialInjection.headers || credentialInjection.query);
523
- if (!hasAny)
524
- throw new Error('credential_injection is required when auth_type is custom');
525
- }
526
- else {
527
- if (!basicUsernameField || !basicPasswordField)
528
- throw new Error('basic_username_field and basic_password_field are required when auth_type is basic');
529
- }
530
- const toKebab = (s) => (s || '')
531
- .toLowerCase()
532
- .replace(/[^a-z0-9]+/g, '-')
533
- .replace(/^-+|-+$/g, '')
534
- .slice(0, 32) || 'integration';
535
- const suffix = () => crypto.randomBytes(2).toString('hex');
536
- const existingSlugs = new Set(ctx.integrationTypeConfigsRef.current
537
- .filter(c => c.spaceId === ctx.spaceId)
538
- .map(c => c.typeSlug));
539
- let typeSlug = '';
540
- for (let i = 0; i < 20; i++) {
541
- const candidate = `${toKebab(label)}-${suffix()}`;
542
- if (!existingSlugs.has(candidate)) {
543
- typeSlug = candidate;
544
- break;
545
- }
546
- }
547
- if (!typeSlug)
548
- throw new Error('Failed to generate a unique type slug');
549
- const schemaProps = {};
550
- const required = [];
551
- for (const f of credentialFields) {
552
- const name = String(f?.name || '').trim();
553
- const title = String(f?.label || '').trim();
554
- if (!name || !title)
555
- continue;
556
- const description = typeof f?.description === 'string' ? f.description : undefined;
557
- const sensitive = !!f?.sensitive;
558
- schemaProps[name] = {
559
- type: 'string',
560
- title,
561
- ...(description ? { description } : {}),
562
- ...(sensitive ? { format: 'password' } : {}),
563
- };
564
- required.push(name);
565
- }
566
- if (!Object.keys(schemaProps).length)
567
- throw new Error('credential_fields must include at least one valid field');
568
- const credentialSchema = sanitizeJsonSchema({
569
- type: 'object',
570
- properties: schemaProps,
571
- required,
572
- additionalProperties: false,
573
- });
574
- const id = crypto.randomUUID ? crypto.randomUUID() : crypto.randomBytes(16).toString('hex');
575
- const cfgId = crypto.randomUUID ? crypto.randomUUID() : crypto.randomBytes(16).toString('hex');
576
- const defaultVariantConfig = {
577
- label,
578
- credentialSchema,
579
- auth: authType === 'basic'
580
- ? { kind: 'basic', usernameField: basicUsernameField, passwordField: basicPasswordField }
581
- : { kind: 'template', injection: credentialInjection || {} },
582
- baseUrl,
583
- healthCheck: healthCheckPath ? { path: healthCheckPath } : null,
584
- hintMarkdown: connectionHint || null,
585
- };
586
- const customCfg = {
587
- id: cfgId,
588
- spaceId: ctx.spaceId,
589
- typeSlug,
590
- label,
591
- defaultVariant: 'default',
592
- variants: { default: defaultVariantConfig },
593
- };
594
- await upsertIntegrationTypeConfig(ctx.db, customCfg);
595
- // Keep the proxy cache hot for immediate use (no restart needed).
596
- ctx.integrationTypeConfigsRef.current.push(customCfg);
597
- const shortId = id.replace(/[^a-z0-9]/gi, '').slice(0, 8).toLowerCase();
598
- const referenceId = `${typeSlug}-${shortId}`;
599
- const integration = {
600
- spaceId: ctx.spaceId,
601
- id,
602
- type: typeSlug,
603
- referenceId,
604
- label,
605
- enabled: true,
606
- connectionMethod: 'credentials',
607
- credentialId: `${referenceId}-creds`,
608
- };
609
- await upsertIntegration(ctx.db, integration);
610
- try {
611
- ctx.integrationsRef.current = await listIntegrations(ctx.db, ctx.spaceId);
612
- }
613
- catch { }
614
- const base = ctx.credentialSetupBaseUrl ? ctx.credentialSetupBaseUrl.replace(/\/+$/, '') : null;
615
- const managementUrl = base ? `${base}/integrations` : null;
616
- const credentialUrl = base ? `${base}/integrations/${encodeURIComponent(id)}` : null;
617
- return {
618
- handled: true,
619
- listChanged: false,
620
- result: {
621
- created: true,
622
- integration: {
623
- id,
624
- type: typeSlug,
625
- label,
626
- reference_id: referenceId,
627
- auth_type: authType,
628
- },
629
- management_url: managementUrl,
630
- credential_url: credentialUrl,
631
- next_steps: credentialUrl
632
- ? ['Open credential_url to enter credentials, then create tools with commandable_create_custom_tool.']
633
- : ['Start the management UI (create mode) to get a credential URL, then create tools with commandable_create_custom_tool.'],
634
- },
635
- };
636
- }
637
- if (name === META_TOOL_NAMES.testCustomTool) {
638
- requireBuilderEnabled(sessionState, sessionId, META_TOOL_NAMES.testCustomTool);
639
- if (!ctx)
640
- throw new Error('Tool building is not available in this server mode.');
641
- const integrationId = String(args?.integration_id || '').trim();
642
- const handlerCode = String(args?.handler_code || '').trim();
643
- const inputSchemaRaw = args?.input_schema;
644
- const testInput = (args?.test_input && typeof args.test_input === 'object') ? args.test_input : {};
645
- if (!integrationId)
646
- throw new Error('integration_id is required');
647
- if (!handlerCode)
648
- throw new Error('handler_code is required');
649
- const integration = ctx.integrationsRef?.current?.find(i => i.id === integrationId || i.referenceId === integrationId);
650
- if (!integration)
651
- throw new Error(`Unknown integration_id: ${integrationId}`);
652
- const getIntegration = createGetIntegration(ctx.integrationsRef, ctx.proxy);
653
- const wrapper = `async (input) => {\n const integration = getIntegration('${integration.id}');\n const __inner = ${handlerCode};\n return await __inner(input);\n}`;
654
- const safe = createSafeHandlerFromString(wrapper, getIntegration);
655
- const res = await safe(testInput);
656
- return { handled: true, listChanged: false, result: res };
657
- }
658
- if (name === META_TOOL_NAMES.createCustomTool) {
659
- requireBuilderEnabled(sessionState, sessionId, META_TOOL_NAMES.createCustomTool);
660
- if (!ctx)
661
- throw new Error('Tool building is not available in this server mode.');
662
- const integrationId = String(args?.integration_id || '').trim();
663
- const toolNameRaw = String(args?.name || '').trim();
664
- const label = typeof args?.label === 'string' ? args.label.trim() : '';
665
- const description = typeof args?.description === 'string' ? args.description.trim() : '';
666
- const handlerCode = String(args?.handler_code || '').trim();
667
- const scope = (args?.scope === 'read' || args?.scope === 'write' || args?.scope === 'admin') ? args.scope : 'write';
668
- const inputSchemaObj = (args?.input_schema && typeof args.input_schema === 'object') ? args.input_schema : {
669
- type: 'object',
670
- additionalProperties: true,
671
- };
672
- if (!integrationId)
673
- throw new Error('integration_id is required');
674
- if (!toolNameRaw)
675
- throw new Error('name is required');
676
- if (!handlerCode)
677
- throw new Error('handler_code is required');
678
- if (!/^async\s*\(\s*input\s*\)\s*=>/.test(handlerCode))
679
- throw new Error('handler_code must start with: async (input) => { ... }');
680
- const integration = ctx.integrationsRef?.current?.find(i => i.id === integrationId || i.referenceId === integrationId);
681
- if (!integration)
682
- throw new Error(`Unknown integration_id: ${integrationId}`);
683
- const existing = await getToolDefinitionByName(ctx.db, ctx.spaceId, integration.id, toolNameRaw);
684
- const id = existing?.id || (crypto.randomUUID ? crypto.randomUUID() : crypto.randomBytes(16).toString('hex'));
685
- const inputSchema = sanitizeJsonSchema(inputSchemaObj);
686
- await upsertToolDefinition(ctx.db, {
687
- id,
688
- spaceId: ctx.spaceId,
689
- integrationId: integration.id,
690
- name: toolNameRaw,
691
- displayName: label || null,
692
- description: description || toolNameRaw,
693
- inputSchema,
694
- handlerCode,
695
- scope,
696
- });
697
- // Materialize executable tool and register into the live index.
698
- const executable = buildExecutableToolFromDefinition({
699
- spaceId: ctx.spaceId,
700
- integration,
701
- tool: {
702
- id,
703
- spaceId: ctx.spaceId,
704
- integrationId: integration.id,
705
- name: toolNameRaw,
706
- displayName: label || null,
707
- description: description || toolNameRaw,
708
- inputSchema,
709
- handlerCode,
710
- scope,
711
- },
712
- proxy: ctx.proxy,
713
- integrationsRef: ctx.integrationsRef,
714
- });
715
- if (ctx.toolIndexRef) {
716
- ctx.toolIndexRef.byName.set(executable.name, executable);
717
- if (ctx.toolIndexRef.list && !ctx.toolIndexRef.list.find(t => t.name === executable.name)) {
718
- ctx.toolIndexRef.list.push({
719
- name: executable.name,
720
- description: executable.description,
721
- inputSchema: executable.inputSchema,
722
- });
723
- }
724
- }
725
- let customAbilityId = null;
726
- if (ctx.catalogRef) {
727
- const ability = ctx.catalogRef.current.addCustomTool({ integration, toolName: executable.name });
728
- customAbilityId = ability.id;
729
- // Auto-load the custom tools ability so the newly created tool is immediately callable.
730
- if (sessionId)
731
- sessionState.loadAbility(sessionId, ability);
732
- }
733
- return {
734
- handled: true,
735
- listChanged: true,
736
- result: {
737
- added: true,
738
- tool: {
739
- id,
740
- name: executable.name,
741
- display_name: executable.displayName,
742
- scope,
743
- },
744
- custom_toolset_id: customAbilityId,
745
- next_steps: [
746
- 'Call the newly registered tool by name (it is now enabled in this session).',
747
- ],
748
- },
749
- };
750
- }
751
- return { handled: false };
752
- }
753
- //# sourceMappingURL=metaTools.js.map