@commandable/mcp 0.9.0 → 0.10.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 (75) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/{Sdkz9rYy.js → BD6mASiY.js} +1 -1
  3. package/.output/public/_nuxt/{Ctwv5nxD.js → BUmYUDQu.js} +3 -3
  4. package/.output/public/_nuxt/CjAs3eBq.js +1 -0
  5. package/.output/public/_nuxt/{CBR-0oRi.js → D9wFDhac.js} +1 -1
  6. package/.output/public/_nuxt/{KqToXREt.js → DRfk9W3W.js} +1 -1
  7. package/.output/public/_nuxt/DSWYWRXT.js +59 -0
  8. package/.output/public/_nuxt/{DOIzs5t4.js → VvnbcAzZ.js} +1 -1
  9. package/.output/public/_nuxt/builds/latest.json +1 -1
  10. package/.output/public/_nuxt/builds/meta/0857a55b-f766-4fe6-86be-9bd9d857861a.json +1 -0
  11. package/.output/server/chunks/build/{_id_-Co8jGxsD.mjs → _id_-DA3Q8jun.mjs} +603 -24
  12. package/.output/server/chunks/build/_id_-DA3Q8jun.mjs.map +1 -0
  13. package/.output/server/chunks/build/client.precomputed.mjs +1 -1
  14. package/.output/server/chunks/build/error-404-D1k2kWid.mjs +3 -5
  15. package/.output/server/chunks/build/error-500-D2K2rAfl.mjs +3 -5
  16. package/.output/server/chunks/build/fetch-aDh21opM.mjs +1 -1
  17. package/.output/server/chunks/build/{index-BxsJPthj.mjs → index-F5lAFSQk.mjs} +7 -7
  18. package/.output/server/chunks/build/index-F5lAFSQk.mjs.map +1 -0
  19. package/.output/server/chunks/build/index-ycGPozML.mjs +3 -5
  20. package/.output/server/chunks/build/server.mjs +6 -8
  21. package/.output/server/chunks/build/styles.mjs +2 -2
  22. package/.output/server/chunks/nitro/nitro.mjs +1471 -262
  23. package/.output/server/chunks/nitro/nitro.mjs.map +1 -1
  24. package/.output/server/chunks/routes/api/_commandable/status.get.mjs +3 -5
  25. package/.output/server/chunks/routes/api/_commandable/status.get.mjs.map +1 -1
  26. package/.output/server/chunks/routes/api/catalog/_type/tools.get.mjs +3 -5
  27. package/.output/server/chunks/routes/api/catalog/_type/tools.get.mjs.map +1 -1
  28. package/.output/server/chunks/routes/api/catalog/_type/toolsets.get.mjs +3 -5
  29. package/.output/server/chunks/routes/api/catalog/_type/toolsets.get.mjs.map +1 -1
  30. package/.output/server/chunks/routes/api/catalog.get.mjs +3 -5
  31. package/.output/server/chunks/routes/api/catalog.get.mjs.map +1 -1
  32. package/.output/server/chunks/routes/api/index.get.mjs +3 -5
  33. package/.output/server/chunks/routes/api/index.get.mjs.map +1 -1
  34. package/.output/server/chunks/routes/api/index.post.mjs +5 -5
  35. package/.output/server/chunks/routes/api/index.post.mjs.map +1 -1
  36. package/.output/server/chunks/routes/api/integrations/_id/credentials-config.get.mjs +3 -5
  37. package/.output/server/chunks/routes/api/integrations/_id/credentials-config.get.mjs.map +1 -1
  38. package/.output/server/chunks/routes/api/integrations/_id/credentials-status.get.mjs +3 -5
  39. package/.output/server/chunks/routes/api/integrations/_id/credentials-status.get.mjs.map +1 -1
  40. package/.output/server/chunks/routes/api/integrations/_id/credentials.delete.mjs +3 -5
  41. package/.output/server/chunks/routes/api/integrations/_id/credentials.delete.mjs.map +1 -1
  42. package/.output/server/chunks/routes/api/integrations/_id/credentials.post.mjs +3 -5
  43. package/.output/server/chunks/routes/api/integrations/_id/credentials.post.mjs.map +1 -1
  44. package/.output/server/chunks/routes/api/integrations/_id/permissions.post.mjs +3 -5
  45. package/.output/server/chunks/routes/api/integrations/_id/permissions.post.mjs.map +1 -1
  46. package/.output/server/chunks/routes/api/integrations/_id/tools.delete.mjs +3 -5
  47. package/.output/server/chunks/routes/api/integrations/_id/tools.delete.mjs.map +1 -1
  48. package/.output/server/chunks/routes/api/integrations/_id/tools.get.mjs +3 -5
  49. package/.output/server/chunks/routes/api/integrations/_id/tools.get.mjs.map +1 -1
  50. package/.output/server/chunks/routes/api/integrations/_id/toolsets.get.mjs +3 -5
  51. package/.output/server/chunks/routes/api/integrations/_id/toolsets.get.mjs.map +1 -1
  52. package/.output/server/chunks/routes/api/integrations/_id/toolsets.post.mjs +3 -5
  53. package/.output/server/chunks/routes/api/integrations/_id/toolsets.post.mjs.map +1 -1
  54. package/.output/server/chunks/routes/api/integrations/_id/variant-options.post.mjs +72 -0
  55. package/.output/server/chunks/routes/api/integrations/_id/variant-options.post.mjs.map +1 -0
  56. package/.output/server/chunks/routes/api/integrations/_id_.delete.mjs +3 -5
  57. package/.output/server/chunks/routes/api/integrations/_id_.delete.mjs.map +1 -1
  58. package/.output/server/chunks/routes/health.get.mjs +3 -5
  59. package/.output/server/chunks/routes/health.get.mjs.map +1 -1
  60. package/.output/server/chunks/routes/mcp/create.mjs +4 -6
  61. package/.output/server/chunks/routes/mcp/create.mjs.map +1 -1
  62. package/.output/server/chunks/routes/mcp/static.mjs +4 -6
  63. package/.output/server/chunks/routes/mcp/static.mjs.map +1 -1
  64. package/.output/server/chunks/routes/mcp.mjs +4 -6
  65. package/.output/server/chunks/routes/mcp.mjs.map +1 -1
  66. package/.output/server/chunks/routes/renderer.mjs +1 -1
  67. package/.output/server/index.mjs +4 -6
  68. package/.output/server/index.mjs.map +1 -1
  69. package/.output/server/package.json +1 -1
  70. package/package.json +2 -2
  71. package/.output/public/_nuxt/CYsCQznM.js +0 -59
  72. package/.output/public/_nuxt/DKO0MviJ.js +0 -1
  73. package/.output/public/_nuxt/builds/meta/3380bacd-d6f5-40cf-8376-35445d2f246f.json +0 -1
  74. package/.output/server/chunks/build/_id_-Co8jGxsD.mjs.map +0 -1
  75. package/.output/server/chunks/build/index-BxsJPthj.mjs.map +0 -1
@@ -3,8 +3,6 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
3
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
4
4
  import { ListToolsRequestSchema, CallToolRequestSchema, isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
5
5
  import { distance } from 'fastest-levenshtein';
6
- import { URLSearchParams as URLSearchParams$1, URL as URL$1, fileURLToPath } from 'node:url';
7
- import vm from 'node:vm';
8
6
  import TurndownService from 'turndown';
9
7
  import { marked } from 'marked';
10
8
  import { promisify } from 'node:util';
@@ -12,19 +10,19 @@ import { execFile as execFile$2 } from 'node:child_process';
12
10
  import { mkdtemp, writeFile as writeFile$1, readFile as readFile$1, rm } from 'node:fs/promises';
13
11
  import { resolve as resolve$1, dirname as dirname$1, join, basename as basename$1 } from 'node:path';
14
12
  import { tmpdir, homedir } from 'node:os';
15
- import { promises, existsSync, mkdirSync, readFileSync, statSync, writeFileSync, chmodSync } from 'node:fs';
16
13
  import { and, eq } from 'drizzle-orm';
14
+ import { URLSearchParams as URLSearchParams$1, URL as URL$1, fileURLToPath } from 'node:url';
15
+ import vm from 'node:vm';
17
16
  import { Buffer as Buffer$1 } from 'node:buffer';
18
17
  import { JWT } from 'google-auth-library';
19
18
  import http, { Server as Server$2 } from 'node:http';
20
19
  import https, { Server as Server$1 } from 'node:https';
21
20
  import { EventEmitter } from 'node:events';
21
+ import { promises, existsSync, writeFileSync, mkdirSync, statSync, readFileSync, chmodSync } from 'node:fs';
22
22
  import Database from 'better-sqlite3';
23
23
  import { drizzle as drizzle$1 } from 'drizzle-orm/better-sqlite3';
24
24
  import { drizzle } from 'drizzle-orm/node-postgres';
25
25
  import { Pool } from 'pg';
26
- import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
27
- import { migrate as migrate$1 } from 'drizzle-orm/node-postgres/migrator';
28
26
  import { sqliteTable, integer, text, primaryKey } from 'drizzle-orm/sqlite-core';
29
27
  import { pgTable, timestamp, jsonb, text as text$1, primaryKey as primaryKey$1, integer as integer$1 } from 'drizzle-orm/pg-core';
30
28
  import { cwd as cwd$1 } from 'node:process';
@@ -4433,7 +4431,7 @@ function _expandFromEnv(value) {
4433
4431
  const _inlineRuntimeConfig = {
4434
4432
  "app": {
4435
4433
  "baseURL": "/",
4436
- "buildId": "3380bacd-d6f5-40cf-8376-35445d2f246f",
4434
+ "buildId": "0857a55b-f766-4fe6-86be-9bd9d857861a",
4437
4435
  "buildAssetsDir": "/_nuxt/",
4438
4436
  "cdnURL": ""
4439
4437
  },
@@ -5392,7 +5390,8 @@ const GENERATED_INTEGRATIONS = {
5392
5390
  "handlerCode": "async (input) => {\n const path = `/${input.baseId}/${input.tableId}`\n const params = new URLSearchParams()\n params.set('records[]', input.recordId)\n const res = await integration.fetch(`${path}?${params.toString()}`, { method: 'DELETE' })\n return await res.json()\n}",
5393
5391
  "scope": "write"
5394
5392
  }
5395
- ]
5393
+ ],
5394
+ "variantOwnerType": null
5396
5395
  },
5397
5396
  "confluence": {
5398
5397
  "manifest": {
@@ -5963,7 +5962,8 @@ const GENERATED_INTEGRATIONS = {
5963
5962
  ],
5964
5963
  "scope": "write"
5965
5964
  }
5966
- ]
5965
+ ],
5966
+ "variantOwnerType": null
5967
5967
  },
5968
5968
  "github": {
5969
5969
  "manifest": {
@@ -8279,7 +8279,8 @@ const GENERATED_INTEGRATIONS = {
8279
8279
  "scope": "write",
8280
8280
  "toolset": "releases"
8281
8281
  }
8282
- ]
8282
+ ],
8283
+ "variantOwnerType": null
8283
8284
  },
8284
8285
  "google-calendar": {
8285
8286
  "manifest": {
@@ -9020,7 +9021,8 @@ const GENERATED_INTEGRATIONS = {
9020
9021
  "scope": "admin",
9021
9022
  "toolset": "sharing"
9022
9023
  }
9023
- ]
9024
+ ],
9025
+ "variantOwnerType": null
9024
9026
  },
9025
9027
  "google-gmail": {
9026
9028
  "manifest": {
@@ -10225,7 +10227,8 @@ const GENERATED_INTEGRATIONS = {
10225
10227
  "scope": "admin",
10226
10228
  "toolset": "organize"
10227
10229
  }
10228
- ]
10230
+ ],
10231
+ "variantOwnerType": null
10229
10232
  },
10230
10233
  "google-workspace": {
10231
10234
  "manifest": {
@@ -12292,7 +12295,8 @@ const GENERATED_INTEGRATIONS = {
12292
12295
  "scope": "write",
12293
12296
  "toolset": "slides"
12294
12297
  }
12295
- ]
12298
+ ],
12299
+ "variantOwnerType": null
12296
12300
  },
12297
12301
  "hubspot": {
12298
12302
  "manifest": {
@@ -13889,7 +13893,8 @@ const GENERATED_INTEGRATIONS = {
13889
13893
  "handlerCode": "async (input) => {\n const props = { ...(input.properties || {}) }\n\n if (input.subject !== undefined) props.hs_task_subject = input.subject\n if (input.body !== undefined) props.hs_task_body = input.body\n if (input.status !== undefined) props.hs_task_status = input.status\n if (input.priority !== undefined) props.hs_task_priority = input.priority\n if (input.dueTimestamp !== undefined) props.hs_timestamp = String(input.dueTimestamp)\n if (input.hubspot_owner_id !== undefined) props.hubspot_owner_id = String(input.hubspot_owner_id)\n\n const res = await integration.fetch(`/crm/v3/objects/tasks/${encodeURIComponent(input.id)}`, {\n method: 'PATCH',\n body: { properties: props },\n })\n return await res.json()\n}",
13890
13894
  "scope": "write"
13891
13895
  }
13892
- ]
13896
+ ],
13897
+ "variantOwnerType": null
13893
13898
  },
13894
13899
  "jira": {
13895
13900
  "manifest": {
@@ -15010,7 +15015,8 @@ const GENERATED_INTEGRATIONS = {
15010
15015
  "scope": "write",
15011
15016
  "toolset": "boards"
15012
15017
  }
15013
- ]
15018
+ ],
15019
+ "variantOwnerType": null
15014
15020
  },
15015
15021
  "notion": {
15016
15022
  "manifest": {
@@ -15835,11 +15841,12 @@ const GENERATED_INTEGRATIONS = {
15835
15841
  "scope": "write",
15836
15842
  "toolset": "databases"
15837
15843
  }
15838
- ]
15844
+ ],
15845
+ "variantOwnerType": null
15839
15846
  },
15840
15847
  "trello": {
15841
15848
  "manifest": {
15842
- "name": "trello",
15849
+ "name": "Trello",
15843
15850
  "version": "0.1.0",
15844
15851
  "baseUrl": "https://api.trello.com/1",
15845
15852
  "tools": [
@@ -16845,115 +16852,994 @@ const GENERATED_INTEGRATIONS = {
16845
16852
  "handlerCode": "async (input) => {\n const params = new URLSearchParams({ value: 'true' })\n const res = await integration.fetch(`/lists/${encodeURIComponent(input.listId)}/closed?${params.toString()}`, { method: 'PUT' })\n return await res.json()\n}",
16846
16853
  "scope": "write"
16847
16854
  }
16848
- ]
16849
- }
16850
- };
16851
-
16852
- function humanizeName(name) {
16853
- return name.replace(/_/g, " ").split(/\s+/).filter(Boolean).map((w) => w.length ? `${w[0].toUpperCase()}${w.slice(1).toLowerCase()}` : w).join(" ");
16854
- }
16855
- function getIntegration(type) {
16856
- var _a;
16857
- return (_a = GENERATED_INTEGRATIONS[type]) != null ? _a : null;
16858
- }
16859
- function cloneManifest(manifest) {
16860
- return {
16861
- ...manifest,
16862
- toolsets: manifest.toolsets ? { ...manifest.toolsets } : void 0,
16863
- tools: manifest.tools.map((tool) => ({ ...tool }))
16864
- };
16865
- }
16866
- function cloneCredentialVariant(variant) {
16867
- var _a, _b;
16868
- return {
16869
- ...variant,
16870
- injection: {
16871
- headers: ((_a = variant.injection) == null ? void 0 : _a.headers) ? { ...variant.injection.headers } : void 0,
16872
- query: ((_b = variant.injection) == null ? void 0 : _b.query) ? { ...variant.injection.query } : void 0
16855
+ ],
16856
+ "variantOwnerType": null
16857
+ },
16858
+ "trello-board": {
16859
+ "manifest": {
16860
+ "name": "Trello",
16861
+ "version": "0.1.0",
16862
+ "baseUrl": "https://api.trello.com/1",
16863
+ "variantLabel": "Single board",
16864
+ "variantConfig": [
16865
+ {
16866
+ "key": "board",
16867
+ "label": "Board",
16868
+ "selectionMode": "single",
16869
+ "listHandler": "async (config) => {\n const fields = ['id', 'name', 'closed', 'starred'].join(',')\n const res = await integration.fetch(`/members/me/boards?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n if (!Array.isArray(raw))\n return []\n\n return raw\n .map(board => ({\n id: String(board.id ?? ''),\n name: String(board.name ?? ''),\n closed: !!board.closed,\n starred: !!board.starred,\n }))\n .filter(board => board.id && board.name)\n .sort((a, b) => {\n if (a.closed !== b.closed)\n return a.closed ? 1 : -1\n if (a.starred !== b.starred)\n return a.starred ? -1 : 1\n return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' })\n })\n .map(({ id, name }) => ({ id, name }))\n}"
16870
+ }
16871
+ ],
16872
+ "tools": [
16873
+ {
16874
+ "name": "get_board",
16875
+ "description": "Fetch the connected board.",
16876
+ "inputSchema": "../../schemas/id_board.json",
16877
+ "handler": "../../handlers/get_board.js",
16878
+ "scope": "read",
16879
+ "injectFromConfig": {
16880
+ "boardId": "boardId"
16881
+ }
16882
+ },
16883
+ {
16884
+ "name": "get_lists",
16885
+ "description": "List lists on the connected board.",
16886
+ "inputSchema": "../../schemas/id_board.json",
16887
+ "handler": "../../handlers/get_board_lists.js",
16888
+ "scope": "read",
16889
+ "injectFromConfig": {
16890
+ "boardId": "boardId"
16891
+ }
16892
+ },
16893
+ {
16894
+ "name": "get_cards",
16895
+ "description": "List cards on the connected board.",
16896
+ "inputSchema": "../../schemas/id_board.json",
16897
+ "handler": "../../handlers/get_board_cards.js",
16898
+ "scope": "read",
16899
+ "injectFromConfig": {
16900
+ "boardId": "boardId"
16901
+ }
16902
+ },
16903
+ {
16904
+ "name": "get_members",
16905
+ "description": "List members on the connected board.",
16906
+ "inputSchema": "../../schemas/id_board.json",
16907
+ "handler": "../../handlers/get_board_members.js",
16908
+ "scope": "read",
16909
+ "injectFromConfig": {
16910
+ "boardId": "boardId"
16911
+ }
16912
+ },
16913
+ {
16914
+ "name": "get_labels",
16915
+ "description": "List labels on the connected board.",
16916
+ "inputSchema": "../../schemas/id_board.json",
16917
+ "handler": "../../handlers/get_board_labels.js",
16918
+ "scope": "read",
16919
+ "injectFromConfig": {
16920
+ "boardId": "boardId"
16921
+ }
16922
+ },
16923
+ {
16924
+ "name": "get_custom_fields",
16925
+ "description": "List custom fields on the connected board.",
16926
+ "inputSchema": "../../schemas/id_board.json",
16927
+ "handler": "../../handlers/get_board_custom_fields.js",
16928
+ "scope": "read",
16929
+ "injectFromConfig": {
16930
+ "boardId": "boardId"
16931
+ }
16932
+ },
16933
+ {
16934
+ "name": "get_memberships",
16935
+ "description": "List memberships for the connected board.",
16936
+ "inputSchema": "../../schemas/id_board.json",
16937
+ "handler": "../../handlers/get_board_memberships.js",
16938
+ "scope": "read",
16939
+ "injectFromConfig": {
16940
+ "boardId": "boardId"
16941
+ }
16942
+ },
16943
+ {
16944
+ "name": "get_list",
16945
+ "description": "Fetch a list by id.",
16946
+ "inputSchema": "../../schemas/id_list.json",
16947
+ "handler": "../../handlers/get_list.js",
16948
+ "scope": "read"
16949
+ },
16950
+ {
16951
+ "name": "get_list_cards",
16952
+ "description": "List cards in a list.",
16953
+ "inputSchema": "../../schemas/id_list.json",
16954
+ "handler": "../../handlers/get_list_cards.js",
16955
+ "scope": "read"
16956
+ },
16957
+ {
16958
+ "name": "get_card",
16959
+ "description": "Fetch a card by id.",
16960
+ "inputSchema": "../../schemas/id_card.json",
16961
+ "handler": "../../handlers/get_card.js",
16962
+ "scope": "read"
16963
+ },
16964
+ {
16965
+ "name": "get_card_members",
16966
+ "description": "List members assigned to a card.",
16967
+ "inputSchema": "../../schemas/id_card.json",
16968
+ "handler": "../../handlers/get_card_members.js",
16969
+ "scope": "read"
16970
+ },
16971
+ {
16972
+ "name": "get_card_attachments",
16973
+ "description": "List attachments on a card.",
16974
+ "inputSchema": "../../schemas/id_card.json",
16975
+ "handler": "../../handlers/get_card_attachments.js",
16976
+ "scope": "read"
16977
+ },
16978
+ {
16979
+ "name": "get_card_actions",
16980
+ "description": "List actions (activity) on a card.",
16981
+ "inputSchema": "../../schemas/id_card.json",
16982
+ "handler": "../../handlers/get_card_actions.js",
16983
+ "scope": "read"
16984
+ },
16985
+ {
16986
+ "name": "get_card_checklists",
16987
+ "description": "List checklists on a card.",
16988
+ "inputSchema": "../../schemas/id_card.json",
16989
+ "handler": "../../handlers/get_card_checklists.js",
16990
+ "scope": "read"
16991
+ },
16992
+ {
16993
+ "name": "get_card_custom_field_items",
16994
+ "description": "Get custom field items on a card.",
16995
+ "inputSchema": "../../schemas/id_card.json",
16996
+ "handler": "../../handlers/get_card_custom_field_items.js",
16997
+ "scope": "read"
16998
+ },
16999
+ {
17000
+ "name": "create_card",
17001
+ "description": "Create a new card in a list.",
17002
+ "inputSchema": "../../schemas/create_card.json",
17003
+ "handler": "../../handlers/create_card.js",
17004
+ "scope": "write"
17005
+ },
17006
+ {
17007
+ "name": "update_card",
17008
+ "description": "Update a card's fields (name, desc, due, list, etc).",
17009
+ "inputSchema": "../../schemas/update_card.json",
17010
+ "handler": "../../handlers/update_card.js",
17011
+ "scope": "write"
17012
+ },
17013
+ {
17014
+ "name": "delete_card",
17015
+ "description": "Delete a card.",
17016
+ "inputSchema": "../../schemas/delete_card.json",
17017
+ "handler": "../../handlers/delete_card.js",
17018
+ "scope": "write"
17019
+ },
17020
+ {
17021
+ "name": "move_card_to_list",
17022
+ "description": "Move a card to another list.",
17023
+ "inputSchema": "../../schemas/move_card_to_list.json",
17024
+ "handler": "../../handlers/move_card_to_list.js",
17025
+ "scope": "write"
17026
+ },
17027
+ {
17028
+ "name": "add_member_to_card",
17029
+ "description": "Add a member to a card.",
17030
+ "inputSchema": "../../schemas/add_member_to_card.json",
17031
+ "handler": "../../handlers/add_member_to_card.js",
17032
+ "scope": "write"
17033
+ },
17034
+ {
17035
+ "name": "remove_member_from_card",
17036
+ "description": "Remove a member from a card.",
17037
+ "inputSchema": "../../schemas/remove_member_from_card.json",
17038
+ "handler": "../../handlers/remove_member_from_card.js",
17039
+ "scope": "write"
17040
+ },
17041
+ {
17042
+ "name": "add_checklist_to_card",
17043
+ "description": "Create a checklist on a card.",
17044
+ "inputSchema": "../../schemas/add_checklist_to_card.json",
17045
+ "handler": "../../handlers/add_checklist_to_card.js",
17046
+ "scope": "write"
17047
+ },
17048
+ {
17049
+ "name": "create_list",
17050
+ "description": "Create a new list on the connected board.",
17051
+ "inputSchema": "../../schemas/create_list.json",
17052
+ "handler": "../../handlers/create_list.js",
17053
+ "scope": "write",
17054
+ "injectFromConfig": {
17055
+ "idBoard": "boardId"
17056
+ }
17057
+ },
17058
+ {
17059
+ "name": "update_list",
17060
+ "description": "Update a list (name, pos, closed).",
17061
+ "inputSchema": "../../schemas/update_list.json",
17062
+ "handler": "../../handlers/update_list.js",
17063
+ "scope": "write"
17064
+ },
17065
+ {
17066
+ "name": "archive_list",
17067
+ "description": "Archive a list (set closed=true).",
17068
+ "inputSchema": "../../schemas/archive_list.json",
17069
+ "handler": "../../handlers/archive_list.js",
17070
+ "scope": "write"
17071
+ }
17072
+ ]
16873
17073
  },
16874
- healthCheck: "path" in variant.healthCheck ? { ...variant.healthCheck } : { notViable: true }
16875
- };
16876
- }
16877
- function validateCredentialVariant(type, variantKey, variant) {
16878
- const healthCheck = variant.healthCheck;
16879
- const hasHealthCheckPath = "path" in healthCheck && typeof healthCheck.path === "string" && healthCheck.path.trim().length > 0;
16880
- const healthCheckNotViable = "notViable" in healthCheck && healthCheck.notViable === true;
16881
- if (hasHealthCheckPath === healthCheckNotViable) {
16882
- throw new Error(`Invalid credentials config for '${type}/${variantKey}': declare exactly one of 'healthCheck.path' or 'healthCheck.notViable: true'.`);
16883
- }
16884
- }
16885
- function validateCredentialVariantsFile(type, raw) {
16886
- if (!(raw == null ? void 0 : raw.variants) || typeof raw.variants !== "object")
16887
- throw new Error(`Invalid credentials config for '${type}': missing variants object.`);
16888
- for (const [variantKey, variant] of Object.entries(raw.variants))
16889
- validateCredentialVariant(type, variantKey, variant);
16890
- return raw;
16891
- }
16892
- function cloneCredentialVariantsFile(type, variants) {
16893
- const validated = validateCredentialVariantsFile(type, variants);
16894
- return {
16895
- default: validated.default,
16896
- variants: Object.fromEntries(Object.entries(validated.variants).map(([key, value]) => [key, cloneCredentialVariant(value)]))
16897
- };
16898
- }
16899
- function loadIntegrationManifest(type) {
16900
- const entry = getIntegration(type);
16901
- return entry ? cloneManifest(entry.manifest) : null;
16902
- }
16903
- function loadIntegrationPrompt(type) {
16904
- var _a, _b;
16905
- return (_b = (_a = getIntegration(type)) == null ? void 0 : _a.prompt) != null ? _b : null;
16906
- }
16907
- function loadIntegrationToolsets(type) {
16908
- var _a;
16909
- const toolsets = (_a = getIntegration(type)) == null ? void 0 : _a.manifest.toolsets;
16910
- return toolsets ? { ...toolsets } : null;
16911
- }
16912
- const SCOPE_RANK$1 = { read: 0, write: 1, admin: 2 };
16913
- function loadIntegrationTools(type, opts) {
16914
- var _a, _b, _c;
16915
- const entry = getIntegration(type);
16916
- if (!entry)
16917
- return null;
16918
- const activeVariant = opts == null ? void 0 : opts.credentialVariant;
16919
- const activeToolsets = opts == null ? void 0 : opts.toolsets;
16920
- const maxRank = (opts == null ? void 0 : opts.maxScope) != null ? (_a = SCOPE_RANK$1[opts.maxScope]) != null ? _a : 2 : 2;
16921
- const blocked = ((_b = opts == null ? void 0 : opts.disabledTools) == null ? void 0 : _b.length) ? new Set(opts.disabledTools) : null;
16922
- const read = [];
16923
- const write = [];
16924
- const admin = [];
16925
- for (const tool of entry.tools) {
16926
- if (activeVariant && tool.credentialVariants && !tool.credentialVariants.includes(activeVariant))
16927
- continue;
16928
- if (activeToolsets && tool.toolset && !activeToolsets.includes(tool.toolset))
16929
- continue;
16930
- const scope = tool.scope || "read";
16931
- if (((_c = SCOPE_RANK$1[scope]) != null ? _c : 0) > maxRank)
16932
- continue;
16933
- if (blocked == null ? void 0 : blocked.has(tool.name))
16934
- continue;
16935
- const nextTool = {
16936
- name: tool.name,
16937
- displayName: tool.displayName,
16938
- description: tool.description,
16939
- inputSchema: tool.inputSchema,
16940
- handlerCode: tool.handlerCode,
16941
- utils: tool.utils
16942
- };
16943
- if (scope === "write")
16944
- write.push(nextTool);
16945
- else if (scope === "admin")
16946
- admin.push(nextTool);
16947
- else
16948
- read.push(nextTool);
16949
- }
16950
- return { read, write, admin };
16951
- }
16952
- function loadIntegrationToolList(type, opts) {
16953
- var _a, _b, _c;
16954
- const manifest = (_a = getIntegration(type)) == null ? void 0 : _a.manifest;
16955
- if (!manifest)
16956
- return [];
17074
+ "prompt": null,
17075
+ "variants": {
17076
+ "variants": {
17077
+ "api_key_token": {
17078
+ "label": "API Key + Token",
17079
+ "schema": {
17080
+ "type": "object",
17081
+ "properties": {
17082
+ "apiKey": {
17083
+ "type": "string",
17084
+ "title": "API Key",
17085
+ "description": "Your Trello API key from https://trello.com/power-ups/admin"
17086
+ },
17087
+ "apiToken": {
17088
+ "type": "string",
17089
+ "title": "API Token",
17090
+ "description": `Your Trello API token ("token" param). Generate one via Trello's authorize flow.`
17091
+ }
17092
+ },
17093
+ "required": [
17094
+ "apiKey",
17095
+ "apiToken"
17096
+ ],
17097
+ "additionalProperties": false
17098
+ },
17099
+ "injection": {
17100
+ "query": {
17101
+ "key": "{{apiKey}}",
17102
+ "token": "{{apiToken}}"
17103
+ }
17104
+ },
17105
+ "healthCheck": {
17106
+ "path": "/members/me"
17107
+ }
17108
+ }
17109
+ },
17110
+ "default": "api_key_token"
17111
+ },
17112
+ "hint": "1. Go to `https://trello.com/power-ups/admin`\n2. Create a new app\n3. Navigate to **API Key** and copy your API key\n4. Click **Generate a Token** and copy the token value",
17113
+ "hintsByVariant": {},
17114
+ "tools": [
17115
+ {
17116
+ "name": "get_board",
17117
+ "description": "Fetch the connected board.",
17118
+ "inputSchema": {
17119
+ "type": "object",
17120
+ "properties": {
17121
+ "boardId": {
17122
+ "type": "string"
17123
+ }
17124
+ },
17125
+ "required": [
17126
+ "boardId"
17127
+ ],
17128
+ "additionalProperties": false
17129
+ },
17130
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}`)\n return await res.json()\n}",
17131
+ "scope": "read",
17132
+ "injectFromConfig": {
17133
+ "boardId": "boardId"
17134
+ }
17135
+ },
17136
+ {
17137
+ "name": "get_lists",
17138
+ "description": "List lists on the connected board.",
17139
+ "inputSchema": {
17140
+ "type": "object",
17141
+ "properties": {
17142
+ "boardId": {
17143
+ "type": "string"
17144
+ }
17145
+ },
17146
+ "required": [
17147
+ "boardId"
17148
+ ],
17149
+ "additionalProperties": false
17150
+ },
17151
+ "handlerCode": "async (input) => {\n const fields = ['id', 'name', 'idBoard', 'closed', 'pos', 'softLimit'].join(',')\n const res = await integration.fetch(`/boards/${input.boardId}/lists?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n const lists = Array.isArray(raw)\n ? raw.map(list => ({\n id: list.id,\n name: list.name,\n idBoard: list.idBoard || null,\n closed: !!list.closed,\n position: list.pos ?? null,\n softLimit: typeof list.softLimit === 'number' ? list.softLimit : null,\n }))\n : []\n return {\n boardId: input.boardId,\n count: lists.length,\n note: 'Use list id with get_list for full list details.',\n lists,\n }\n}",
17152
+ "scope": "read",
17153
+ "injectFromConfig": {
17154
+ "boardId": "boardId"
17155
+ }
17156
+ },
17157
+ {
17158
+ "name": "get_cards",
17159
+ "description": "List cards on the connected board.",
17160
+ "inputSchema": {
17161
+ "type": "object",
17162
+ "properties": {
17163
+ "boardId": {
17164
+ "type": "string"
17165
+ }
17166
+ },
17167
+ "required": [
17168
+ "boardId"
17169
+ ],
17170
+ "additionalProperties": false
17171
+ },
17172
+ "handlerCode": "async (input) => {\n const fields = [\n 'id',\n 'name',\n 'desc',\n 'idBoard',\n 'idList',\n 'shortLink',\n 'shortUrl',\n 'url',\n 'closed',\n 'due',\n 'dateLastActivity',\n 'labels',\n 'pos',\n ].join(',')\n const res = await integration.fetch(`/boards/${input.boardId}/cards?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n const cards = Array.isArray(raw)\n ? raw.map(card => ({\n id: card.id,\n name: card.name,\n idBoard: card.idBoard || null,\n idList: card.idList || null,\n url: card.url || card.shortUrl || (card.shortLink ? `https://trello.com/c/${card.shortLink}` : null),\n shortLink: card.shortLink || null,\n closed: !!card.closed,\n due: card.due || null,\n lastActivity: card.dateLastActivity || null,\n position: card.pos ?? null,\n labels: Array.isArray(card.labels)\n ? card.labels.map(label => ({ id: label.id, name: label.name || null, color: label.color || null }))\n : [],\n descriptionPreview: typeof card.desc === 'string' && card.desc.trim()\n ? (card.desc.trim().length <= 200 ? card.desc.trim() : `${card.desc.trim().slice(0, 199)}...`)\n : null,\n }))\n : []\n return {\n boardId: input.boardId,\n count: cards.length,\n note: 'Use card id with get_card for full card details.',\n cards,\n }\n}",
17173
+ "scope": "read",
17174
+ "injectFromConfig": {
17175
+ "boardId": "boardId"
17176
+ }
17177
+ },
17178
+ {
17179
+ "name": "get_members",
17180
+ "description": "List members on the connected board.",
17181
+ "inputSchema": {
17182
+ "type": "object",
17183
+ "properties": {
17184
+ "boardId": {
17185
+ "type": "string"
17186
+ }
17187
+ },
17188
+ "required": [
17189
+ "boardId"
17190
+ ],
17191
+ "additionalProperties": false
17192
+ },
17193
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}/members`)\n return await res.json()\n}",
17194
+ "scope": "read",
17195
+ "injectFromConfig": {
17196
+ "boardId": "boardId"
17197
+ }
17198
+ },
17199
+ {
17200
+ "name": "get_labels",
17201
+ "description": "List labels on the connected board.",
17202
+ "inputSchema": {
17203
+ "type": "object",
17204
+ "properties": {
17205
+ "boardId": {
17206
+ "type": "string"
17207
+ }
17208
+ },
17209
+ "required": [
17210
+ "boardId"
17211
+ ],
17212
+ "additionalProperties": false
17213
+ },
17214
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}/labels`)\n return await res.json()\n}",
17215
+ "scope": "read",
17216
+ "injectFromConfig": {
17217
+ "boardId": "boardId"
17218
+ }
17219
+ },
17220
+ {
17221
+ "name": "get_custom_fields",
17222
+ "description": "List custom fields on the connected board.",
17223
+ "inputSchema": {
17224
+ "type": "object",
17225
+ "properties": {
17226
+ "boardId": {
17227
+ "type": "string"
17228
+ }
17229
+ },
17230
+ "required": [
17231
+ "boardId"
17232
+ ],
17233
+ "additionalProperties": false
17234
+ },
17235
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}/customFields`)\n return await res.json()\n}",
17236
+ "scope": "read",
17237
+ "injectFromConfig": {
17238
+ "boardId": "boardId"
17239
+ }
17240
+ },
17241
+ {
17242
+ "name": "get_memberships",
17243
+ "description": "List memberships for the connected board.",
17244
+ "inputSchema": {
17245
+ "type": "object",
17246
+ "properties": {
17247
+ "boardId": {
17248
+ "type": "string"
17249
+ }
17250
+ },
17251
+ "required": [
17252
+ "boardId"
17253
+ ],
17254
+ "additionalProperties": false
17255
+ },
17256
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/boards/${input.boardId}/memberships`)\n return await res.json()\n}",
17257
+ "scope": "read",
17258
+ "injectFromConfig": {
17259
+ "boardId": "boardId"
17260
+ }
17261
+ },
17262
+ {
17263
+ "name": "get_list",
17264
+ "description": "Fetch a list by id.",
17265
+ "inputSchema": {
17266
+ "type": "object",
17267
+ "properties": {
17268
+ "listId": {
17269
+ "type": "string"
17270
+ }
17271
+ },
17272
+ "required": [
17273
+ "listId"
17274
+ ],
17275
+ "additionalProperties": false
17276
+ },
17277
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/lists/${input.listId}`)\n return await res.json()\n}",
17278
+ "scope": "read"
17279
+ },
17280
+ {
17281
+ "name": "get_list_cards",
17282
+ "description": "List cards in a list.",
17283
+ "inputSchema": {
17284
+ "type": "object",
17285
+ "properties": {
17286
+ "listId": {
17287
+ "type": "string"
17288
+ }
17289
+ },
17290
+ "required": [
17291
+ "listId"
17292
+ ],
17293
+ "additionalProperties": false
17294
+ },
17295
+ "handlerCode": "async (input) => {\n const fields = [\n 'id',\n 'name',\n 'desc',\n 'idBoard',\n 'idList',\n 'shortLink',\n 'shortUrl',\n 'url',\n 'closed',\n 'due',\n 'dateLastActivity',\n 'labels',\n 'pos',\n ].join(',')\n const res = await integration.fetch(`/lists/${input.listId}/cards?fields=${encodeURIComponent(fields)}`)\n const raw = await res.json()\n const cards = Array.isArray(raw)\n ? raw.map(card => ({\n id: card.id,\n name: card.name,\n idBoard: card.idBoard || null,\n idList: card.idList || null,\n url: card.url || card.shortUrl || (card.shortLink ? `https://trello.com/c/${card.shortLink}` : null),\n shortLink: card.shortLink || null,\n closed: !!card.closed,\n due: card.due || null,\n lastActivity: card.dateLastActivity || null,\n position: card.pos ?? null,\n labels: Array.isArray(card.labels)\n ? card.labels.map(label => ({ id: label.id, name: label.name || null, color: label.color || null }))\n : [],\n descriptionPreview: typeof card.desc === 'string' && card.desc.trim()\n ? (card.desc.trim().length <= 200 ? card.desc.trim() : `${card.desc.trim().slice(0, 199)}...`)\n : null,\n }))\n : []\n return {\n listId: input.listId,\n count: cards.length,\n note: 'Use card id with get_card for full card details.',\n cards,\n }\n}",
17296
+ "scope": "read"
17297
+ },
17298
+ {
17299
+ "name": "get_card",
17300
+ "description": "Fetch a card by id.",
17301
+ "inputSchema": {
17302
+ "type": "object",
17303
+ "properties": {
17304
+ "cardId": {
17305
+ "type": "string"
17306
+ }
17307
+ },
17308
+ "required": [
17309
+ "cardId"
17310
+ ],
17311
+ "additionalProperties": false
17312
+ },
17313
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}`)\n return await res.json()\n}",
17314
+ "scope": "read"
17315
+ },
17316
+ {
17317
+ "name": "get_card_members",
17318
+ "description": "List members assigned to a card.",
17319
+ "inputSchema": {
17320
+ "type": "object",
17321
+ "properties": {
17322
+ "cardId": {
17323
+ "type": "string"
17324
+ }
17325
+ },
17326
+ "required": [
17327
+ "cardId"
17328
+ ],
17329
+ "additionalProperties": false
17330
+ },
17331
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}/members`)\n return await res.json()\n}",
17332
+ "scope": "read"
17333
+ },
17334
+ {
17335
+ "name": "get_card_attachments",
17336
+ "description": "List attachments on a card.",
17337
+ "inputSchema": {
17338
+ "type": "object",
17339
+ "properties": {
17340
+ "cardId": {
17341
+ "type": "string"
17342
+ }
17343
+ },
17344
+ "required": [
17345
+ "cardId"
17346
+ ],
17347
+ "additionalProperties": false
17348
+ },
17349
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}/attachments`)\n return await res.json()\n}",
17350
+ "scope": "read"
17351
+ },
17352
+ {
17353
+ "name": "get_card_actions",
17354
+ "description": "List actions (activity) on a card.",
17355
+ "inputSchema": {
17356
+ "type": "object",
17357
+ "properties": {
17358
+ "cardId": {
17359
+ "type": "string"
17360
+ }
17361
+ },
17362
+ "required": [
17363
+ "cardId"
17364
+ ],
17365
+ "additionalProperties": false
17366
+ },
17367
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}/actions`)\n return await res.json()\n}",
17368
+ "scope": "read"
17369
+ },
17370
+ {
17371
+ "name": "get_card_checklists",
17372
+ "description": "List checklists on a card.",
17373
+ "inputSchema": {
17374
+ "type": "object",
17375
+ "properties": {
17376
+ "cardId": {
17377
+ "type": "string"
17378
+ }
17379
+ },
17380
+ "required": [
17381
+ "cardId"
17382
+ ],
17383
+ "additionalProperties": false
17384
+ },
17385
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}/checklists`)\n return await res.json()\n}",
17386
+ "scope": "read"
17387
+ },
17388
+ {
17389
+ "name": "get_card_custom_field_items",
17390
+ "description": "Get custom field items on a card.",
17391
+ "inputSchema": {
17392
+ "type": "object",
17393
+ "properties": {
17394
+ "cardId": {
17395
+ "type": "string"
17396
+ }
17397
+ },
17398
+ "required": [
17399
+ "cardId"
17400
+ ],
17401
+ "additionalProperties": false
17402
+ },
17403
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${input.cardId}/customFieldItems`)\n return await res.json()\n}",
17404
+ "scope": "read"
17405
+ },
17406
+ {
17407
+ "name": "create_card",
17408
+ "description": "Create a new card in a list.",
17409
+ "inputSchema": {
17410
+ "$schema": "http://json-schema.org/draft-07/schema#",
17411
+ "type": "object",
17412
+ "required": [
17413
+ "idList",
17414
+ "name"
17415
+ ],
17416
+ "additionalProperties": false,
17417
+ "properties": {
17418
+ "idList": {
17419
+ "type": "string"
17420
+ },
17421
+ "name": {
17422
+ "type": "string"
17423
+ },
17424
+ "desc": {
17425
+ "type": "string"
17426
+ },
17427
+ "due": {
17428
+ "type": [
17429
+ "string",
17430
+ "null"
17431
+ ],
17432
+ "description": "ISO 8601 due date"
17433
+ },
17434
+ "pos": {
17435
+ "type": [
17436
+ "string",
17437
+ "number"
17438
+ ],
17439
+ "description": "Position (top,bottom or float)"
17440
+ }
17441
+ }
17442
+ },
17443
+ "handlerCode": "async (input) => {\n const params = new URLSearchParams()\n params.set('idList', input.idList)\n params.set('name', input.name)\n if (input.desc !== undefined)\n params.set('desc', input.desc)\n if (input.due !== undefined && input.due !== null)\n params.set('due', input.due)\n if (input.pos !== undefined && input.pos !== null)\n params.set('pos', String(input.pos))\n const res = await integration.fetch(`/cards?${params.toString()}`, { method: 'POST' })\n return await res.json()\n}",
17444
+ "scope": "write"
17445
+ },
17446
+ {
17447
+ "name": "update_card",
17448
+ "description": "Update a card's fields (name, desc, due, list, etc).",
17449
+ "inputSchema": {
17450
+ "$schema": "http://json-schema.org/draft-07/schema#",
17451
+ "type": "object",
17452
+ "required": [
17453
+ "cardId"
17454
+ ],
17455
+ "additionalProperties": false,
17456
+ "properties": {
17457
+ "cardId": {
17458
+ "type": "string"
17459
+ },
17460
+ "name": {
17461
+ "type": [
17462
+ "string",
17463
+ "null"
17464
+ ]
17465
+ },
17466
+ "desc": {
17467
+ "type": [
17468
+ "string",
17469
+ "null"
17470
+ ]
17471
+ },
17472
+ "due": {
17473
+ "type": [
17474
+ "string",
17475
+ "null"
17476
+ ]
17477
+ },
17478
+ "dueComplete": {
17479
+ "type": [
17480
+ "boolean",
17481
+ "null"
17482
+ ]
17483
+ },
17484
+ "closed": {
17485
+ "type": [
17486
+ "boolean",
17487
+ "null"
17488
+ ]
17489
+ },
17490
+ "idList": {
17491
+ "type": [
17492
+ "string",
17493
+ "null"
17494
+ ]
17495
+ },
17496
+ "pos": {
17497
+ "type": [
17498
+ "string",
17499
+ "number",
17500
+ "null"
17501
+ ]
17502
+ }
17503
+ }
17504
+ },
17505
+ "handlerCode": "async (input) => {\n const params = new URLSearchParams()\n if (input.name !== undefined && input.name !== null)\n params.set('name', input.name)\n if (input.desc !== undefined && input.desc !== null)\n params.set('desc', input.desc)\n if (input.due !== undefined)\n params.set('due', input.due === null ? '' : input.due)\n if (input.dueComplete !== undefined && input.dueComplete !== null)\n params.set('dueComplete', String(input.dueComplete))\n if (input.closed !== undefined && input.closed !== null)\n params.set('closed', String(input.closed))\n if (input.idList !== undefined && input.idList !== null)\n params.set('idList', input.idList)\n if (input.pos !== undefined && input.pos !== null)\n params.set('pos', String(input.pos))\n const res = await integration.fetch(`/cards/${encodeURIComponent(input.cardId)}?${params.toString()}`, { method: 'PUT' })\n return await res.json()\n}",
17506
+ "scope": "write"
17507
+ },
17508
+ {
17509
+ "name": "delete_card",
17510
+ "description": "Delete a card.",
17511
+ "inputSchema": {
17512
+ "$schema": "http://json-schema.org/draft-07/schema#",
17513
+ "type": "object",
17514
+ "required": [
17515
+ "cardId"
17516
+ ],
17517
+ "additionalProperties": false,
17518
+ "properties": {
17519
+ "cardId": {
17520
+ "type": "string"
17521
+ }
17522
+ }
17523
+ },
17524
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${encodeURIComponent(input.cardId)}`, { method: 'DELETE' })\n try {\n return await res.json()\n }\n catch {\n return ''\n }\n}",
17525
+ "scope": "write"
17526
+ },
17527
+ {
17528
+ "name": "move_card_to_list",
17529
+ "description": "Move a card to another list.",
17530
+ "inputSchema": {
17531
+ "$schema": "http://json-schema.org/draft-07/schema#",
17532
+ "type": "object",
17533
+ "required": [
17534
+ "cardId",
17535
+ "listId"
17536
+ ],
17537
+ "additionalProperties": false,
17538
+ "properties": {
17539
+ "cardId": {
17540
+ "type": "string"
17541
+ },
17542
+ "listId": {
17543
+ "type": "string"
17544
+ }
17545
+ }
17546
+ },
17547
+ "handlerCode": "async (input) => {\n const params = new URLSearchParams({ value: input.listId })\n const res = await integration.fetch(`/cards/${encodeURIComponent(input.cardId)}/idList?${params.toString()}`, { method: 'PUT' })\n return await res.json()\n}",
17548
+ "scope": "write"
17549
+ },
17550
+ {
17551
+ "name": "add_member_to_card",
17552
+ "description": "Add a member to a card.",
17553
+ "inputSchema": {
17554
+ "$schema": "http://json-schema.org/draft-07/schema#",
17555
+ "type": "object",
17556
+ "required": [
17557
+ "cardId",
17558
+ "memberId"
17559
+ ],
17560
+ "additionalProperties": false,
17561
+ "properties": {
17562
+ "cardId": {
17563
+ "type": "string"
17564
+ },
17565
+ "memberId": {
17566
+ "type": "string"
17567
+ }
17568
+ }
17569
+ },
17570
+ "handlerCode": "async (input) => {\n const params = new URLSearchParams({ value: input.memberId })\n const res = await integration.fetch(`/cards/${encodeURIComponent(input.cardId)}/idMembers?${params.toString()}`, { method: 'POST' })\n return await res.json()\n}",
17571
+ "scope": "write"
17572
+ },
17573
+ {
17574
+ "name": "remove_member_from_card",
17575
+ "description": "Remove a member from a card.",
17576
+ "inputSchema": {
17577
+ "$schema": "http://json-schema.org/draft-07/schema#",
17578
+ "type": "object",
17579
+ "required": [
17580
+ "cardId",
17581
+ "memberId"
17582
+ ],
17583
+ "additionalProperties": false,
17584
+ "properties": {
17585
+ "cardId": {
17586
+ "type": "string"
17587
+ },
17588
+ "memberId": {
17589
+ "type": "string"
17590
+ }
17591
+ }
17592
+ },
17593
+ "handlerCode": "async (input) => {\n const res = await integration.fetch(`/cards/${encodeURIComponent(input.cardId)}/idMembers/${encodeURIComponent(input.memberId)}`, { method: 'DELETE' })\n try {\n return await res.json()\n }\n catch {\n return ''\n }\n}",
17594
+ "scope": "write"
17595
+ },
17596
+ {
17597
+ "name": "add_checklist_to_card",
17598
+ "description": "Create a checklist on a card.",
17599
+ "inputSchema": {
17600
+ "$schema": "http://json-schema.org/draft-07/schema#",
17601
+ "type": "object",
17602
+ "required": [
17603
+ "cardId",
17604
+ "name"
17605
+ ],
17606
+ "additionalProperties": false,
17607
+ "properties": {
17608
+ "cardId": {
17609
+ "type": "string"
17610
+ },
17611
+ "name": {
17612
+ "type": "string"
17613
+ }
17614
+ }
17615
+ },
17616
+ "handlerCode": "async (input) => {\n const params = new URLSearchParams({ idCard: input.cardId, name: input.name })\n const res = await integration.fetch(`/checklists?${params.toString()}`, { method: 'POST' })\n return await res.json()\n}",
17617
+ "scope": "write"
17618
+ },
17619
+ {
17620
+ "name": "create_list",
17621
+ "description": "Create a new list on the connected board.",
17622
+ "inputSchema": {
17623
+ "$schema": "http://json-schema.org/draft-07/schema#",
17624
+ "type": "object",
17625
+ "required": [
17626
+ "idBoard",
17627
+ "name"
17628
+ ],
17629
+ "additionalProperties": false,
17630
+ "properties": {
17631
+ "idBoard": {
17632
+ "type": "string"
17633
+ },
17634
+ "name": {
17635
+ "type": "string"
17636
+ },
17637
+ "pos": {
17638
+ "type": [
17639
+ "string",
17640
+ "number"
17641
+ ],
17642
+ "description": "Position (top,bottom or float)"
17643
+ }
17644
+ }
17645
+ },
17646
+ "handlerCode": "async (input) => {\n const params = new URLSearchParams({ idBoard: input.idBoard, name: input.name })\n if (input.pos !== undefined && input.pos !== null)\n params.set('pos', String(input.pos))\n const res = await integration.fetch(`/lists?${params.toString()}`, { method: 'POST' })\n return await res.json()\n}",
17647
+ "scope": "write",
17648
+ "injectFromConfig": {
17649
+ "idBoard": "boardId"
17650
+ }
17651
+ },
17652
+ {
17653
+ "name": "update_list",
17654
+ "description": "Update a list (name, pos, closed).",
17655
+ "inputSchema": {
17656
+ "$schema": "http://json-schema.org/draft-07/schema#",
17657
+ "type": "object",
17658
+ "required": [
17659
+ "listId"
17660
+ ],
17661
+ "additionalProperties": false,
17662
+ "properties": {
17663
+ "listId": {
17664
+ "type": "string"
17665
+ },
17666
+ "name": {
17667
+ "type": [
17668
+ "string",
17669
+ "null"
17670
+ ]
17671
+ },
17672
+ "closed": {
17673
+ "type": [
17674
+ "boolean",
17675
+ "null"
17676
+ ]
17677
+ },
17678
+ "pos": {
17679
+ "type": [
17680
+ "string",
17681
+ "number",
17682
+ "null"
17683
+ ]
17684
+ }
17685
+ }
17686
+ },
17687
+ "handlerCode": "async (input) => {\n const params = new URLSearchParams()\n if (input.name !== undefined && input.name !== null)\n params.set('name', input.name)\n if (input.closed !== undefined && input.closed !== null)\n params.set('closed', String(input.closed))\n if (input.pos !== undefined && input.pos !== null)\n params.set('pos', String(input.pos))\n const res = await integration.fetch(`/lists/${encodeURIComponent(input.listId)}?${params.toString()}`, { method: 'PUT' })\n return await res.json()\n}",
17688
+ "scope": "write"
17689
+ },
17690
+ {
17691
+ "name": "archive_list",
17692
+ "description": "Archive a list (set closed=true).",
17693
+ "inputSchema": {
17694
+ "$schema": "http://json-schema.org/draft-07/schema#",
17695
+ "type": "object",
17696
+ "required": [
17697
+ "listId"
17698
+ ],
17699
+ "additionalProperties": false,
17700
+ "properties": {
17701
+ "listId": {
17702
+ "type": "string"
17703
+ }
17704
+ }
17705
+ },
17706
+ "handlerCode": "async (input) => {\n const params = new URLSearchParams({ value: 'true' })\n const res = await integration.fetch(`/lists/${encodeURIComponent(input.listId)}/closed?${params.toString()}`, { method: 'PUT' })\n return await res.json()\n}",
17707
+ "scope": "write"
17708
+ }
17709
+ ],
17710
+ "variantOwnerType": "trello"
17711
+ }
17712
+ };
17713
+
17714
+ function humanizeName(name) {
17715
+ return name.replace(/_/g, " ").split(/\s+/).filter(Boolean).map((w) => w.length ? `${w[0].toUpperCase()}${w.slice(1).toLowerCase()}` : w).join(" ");
17716
+ }
17717
+ function getIntegration(type) {
17718
+ var _a;
17719
+ return (_a = GENERATED_INTEGRATIONS[type]) != null ? _a : null;
17720
+ }
17721
+ function cloneManifest(manifest) {
17722
+ return {
17723
+ ...manifest,
17724
+ variantConfig: manifest.variantConfig ? JSON.parse(JSON.stringify(manifest.variantConfig)) : void 0,
17725
+ toolsets: manifest.toolsets ? { ...manifest.toolsets } : void 0,
17726
+ tools: manifest.tools.map((tool) => ({
17727
+ ...tool,
17728
+ injectFromConfig: tool.injectFromConfig ? { ...tool.injectFromConfig } : void 0
17729
+ }))
17730
+ };
17731
+ }
17732
+ function cloneCredentialVariant(variant) {
17733
+ var _a, _b;
17734
+ return {
17735
+ ...variant,
17736
+ injection: {
17737
+ headers: ((_a = variant.injection) == null ? void 0 : _a.headers) ? { ...variant.injection.headers } : void 0,
17738
+ query: ((_b = variant.injection) == null ? void 0 : _b.query) ? { ...variant.injection.query } : void 0
17739
+ },
17740
+ healthCheck: "path" in variant.healthCheck ? { ...variant.healthCheck } : { notViable: true }
17741
+ };
17742
+ }
17743
+ function validateCredentialVariant(type, variantKey, variant) {
17744
+ const healthCheck = variant.healthCheck;
17745
+ const hasHealthCheckPath = "path" in healthCheck && typeof healthCheck.path === "string" && healthCheck.path.trim().length > 0;
17746
+ const healthCheckNotViable = "notViable" in healthCheck && healthCheck.notViable === true;
17747
+ if (hasHealthCheckPath === healthCheckNotViable) {
17748
+ throw new Error(`Invalid credentials config for '${type}/${variantKey}': declare exactly one of 'healthCheck.path' or 'healthCheck.notViable: true'.`);
17749
+ }
17750
+ }
17751
+ function validateCredentialVariantsFile(type, raw) {
17752
+ if (!(raw == null ? void 0 : raw.variants) || typeof raw.variants !== "object")
17753
+ throw new Error(`Invalid credentials config for '${type}': missing variants object.`);
17754
+ for (const [variantKey, variant] of Object.entries(raw.variants))
17755
+ validateCredentialVariant(type, variantKey, variant);
17756
+ return raw;
17757
+ }
17758
+ function cloneCredentialVariantsFile(type, variants) {
17759
+ const validated = validateCredentialVariantsFile(type, variants);
17760
+ return {
17761
+ default: validated.default,
17762
+ variants: Object.fromEntries(Object.entries(validated.variants).map(([key, value]) => [key, cloneCredentialVariant(value)]))
17763
+ };
17764
+ }
17765
+ function stripInjectedFieldsFromSchema(inputSchema, injectFromConfig) {
17766
+ const injectedKeys = Object.keys(injectFromConfig != null ? injectFromConfig : {});
17767
+ if (!injectedKeys.length || !inputSchema || typeof inputSchema !== "object" || Array.isArray(inputSchema))
17768
+ return inputSchema;
17769
+ const schema = JSON.parse(JSON.stringify(inputSchema));
17770
+ const properties = schema.properties;
17771
+ if (properties && typeof properties === "object" && !Array.isArray(properties)) {
17772
+ for (const key of injectedKeys)
17773
+ delete properties[key];
17774
+ }
17775
+ if (Array.isArray(schema.required)) {
17776
+ const required = schema.required.filter((key) => !injectedKeys.includes(String(key)));
17777
+ if (required.length)
17778
+ schema.required = required;
17779
+ else
17780
+ delete schema.required;
17781
+ }
17782
+ return schema;
17783
+ }
17784
+ function loadIntegrationManifest(type) {
17785
+ const entry = getIntegration(type);
17786
+ return entry ? cloneManifest(entry.manifest) : null;
17787
+ }
17788
+ function loadIntegrationPrompt(type) {
17789
+ var _a, _b;
17790
+ return (_b = (_a = getIntegration(type)) == null ? void 0 : _a.prompt) != null ? _b : null;
17791
+ }
17792
+ function loadIntegrationToolsets(type) {
17793
+ var _a;
17794
+ const toolsets = (_a = getIntegration(type)) == null ? void 0 : _a.manifest.toolsets;
17795
+ return toolsets ? { ...toolsets } : null;
17796
+ }
17797
+ const SCOPE_RANK$1 = { read: 0, write: 1, admin: 2 };
17798
+ function loadIntegrationTools(type, opts) {
17799
+ var _a, _b, _c;
17800
+ const entry = getIntegration(type);
17801
+ if (!entry)
17802
+ return null;
17803
+ const activeVariant = opts == null ? void 0 : opts.credentialVariant;
17804
+ const activeToolsets = opts == null ? void 0 : opts.toolsets;
17805
+ const maxRank = (opts == null ? void 0 : opts.maxScope) != null ? (_a = SCOPE_RANK$1[opts.maxScope]) != null ? _a : 2 : 2;
17806
+ const blocked = ((_b = opts == null ? void 0 : opts.disabledTools) == null ? void 0 : _b.length) ? new Set(opts.disabledTools) : null;
17807
+ const read = [];
17808
+ const write = [];
17809
+ const admin = [];
17810
+ for (const tool of entry.tools) {
17811
+ if (activeVariant && tool.credentialVariants && !tool.credentialVariants.includes(activeVariant))
17812
+ continue;
17813
+ if (activeToolsets && tool.toolset && !activeToolsets.includes(tool.toolset))
17814
+ continue;
17815
+ const scope = tool.scope || "read";
17816
+ if (((_c = SCOPE_RANK$1[scope]) != null ? _c : 0) > maxRank)
17817
+ continue;
17818
+ if (blocked == null ? void 0 : blocked.has(tool.name))
17819
+ continue;
17820
+ const nextTool = {
17821
+ name: tool.name,
17822
+ displayName: tool.displayName,
17823
+ description: tool.description,
17824
+ inputSchema: stripInjectedFieldsFromSchema(tool.inputSchema, tool.injectFromConfig),
17825
+ handlerCode: tool.handlerCode,
17826
+ utils: tool.utils,
17827
+ injectFromConfig: tool.injectFromConfig ? { ...tool.injectFromConfig } : void 0
17828
+ };
17829
+ if (scope === "write")
17830
+ write.push(nextTool);
17831
+ else if (scope === "admin")
17832
+ admin.push(nextTool);
17833
+ else
17834
+ read.push(nextTool);
17835
+ }
17836
+ return { read, write, admin };
17837
+ }
17838
+ function loadIntegrationToolList(type, opts) {
17839
+ var _a, _b, _c;
17840
+ const manifest = (_a = getIntegration(type)) == null ? void 0 : _a.manifest;
17841
+ if (!manifest)
17842
+ return [];
16957
17843
  const activeVariant = opts == null ? void 0 : opts.credentialVariant;
16958
17844
  const activeToolsets = opts == null ? void 0 : opts.toolsets;
16959
17845
  const maxRank = (opts == null ? void 0 : opts.maxScope) != null ? (_b = SCOPE_RANK$1[opts.maxScope]) != null ? _b : 2 : 2;
@@ -16984,8 +17870,9 @@ function loadIntegrationVariants(type) {
16984
17870
  return variants ? cloneCredentialVariantsFile(type, variants) : null;
16985
17871
  }
16986
17872
  function loadIntegrationCredentialConfig(type, variantKey) {
16987
- var _a, _b;
16988
- const file = loadIntegrationVariants(type);
17873
+ var _a, _b, _c, _d;
17874
+ const ownerType = (_b = (_a = getIntegration(type)) == null ? void 0 : _a.variantOwnerType) != null ? _b : type;
17875
+ const file = loadIntegrationVariants(ownerType);
16989
17876
  if (!file)
16990
17877
  return null;
16991
17878
  const key = file.default;
@@ -16998,29 +17885,43 @@ function loadIntegrationCredentialConfig(type, variantKey) {
16998
17885
  schema: variant.schema,
16999
17886
  baseUrlTemplate: typeof variant.baseUrlTemplate === "string" ? variant.baseUrlTemplate : void 0,
17000
17887
  injection: {
17001
- headers: ((_a = variant.injection) == null ? void 0 : _a.headers) || void 0,
17002
- query: ((_b = variant.injection) == null ? void 0 : _b.query) || void 0
17888
+ headers: ((_c = variant.injection) == null ? void 0 : _c.headers) || void 0,
17889
+ query: ((_d = variant.injection) == null ? void 0 : _d.query) || void 0
17003
17890
  },
17004
17891
  preprocess: variant.preprocess,
17005
17892
  healthCheck: cloneCredentialVariant(variant).healthCheck
17006
17893
  };
17007
17894
  }
17008
17895
  function loadIntegrationHint(type, variantKey) {
17009
- var _a;
17010
- const entry = getIntegration(type);
17896
+ var _a, _b, _c;
17897
+ const ownerType = (_b = (_a = getIntegration(type)) == null ? void 0 : _a.variantOwnerType) != null ? _b : type;
17898
+ const entry = getIntegration(ownerType);
17011
17899
  if (!entry)
17012
17900
  return null;
17013
17901
  if (variantKey && entry.hintsByVariant[variantKey])
17014
17902
  return entry.hintsByVariant[variantKey];
17015
- return (_a = entry.hint) != null ? _a : null;
17903
+ return (_c = entry.hint) != null ? _c : null;
17016
17904
  }
17017
17905
  function listIntegrationTypes() {
17018
17906
  return Object.keys(GENERATED_INTEGRATIONS);
17019
17907
  }
17020
17908
  function listIntegrationCatalog() {
17021
- return listIntegrationTypes().map((type) => ({
17909
+ return listIntegrationTypes().filter((type) => !GENERATED_INTEGRATIONS[type].variantOwnerType).map((type) => ({
17022
17910
  type,
17023
- name: GENERATED_INTEGRATIONS[type].manifest.name || type
17911
+ name: GENERATED_INTEGRATIONS[type].manifest.name || type,
17912
+ variants: listIntegrationTypes().filter((candidate) => GENERATED_INTEGRATIONS[candidate].variantOwnerType === type).map((candidate) => {
17913
+ var _a, _b;
17914
+ return {
17915
+ type: candidate,
17916
+ label: GENERATED_INTEGRATIONS[candidate].manifest.variantLabel || candidate,
17917
+ variantConfig: (_b = (_a = GENERATED_INTEGRATIONS[candidate].manifest.variantConfig) == null ? void 0 : _a.map((item) => ({
17918
+ key: item.key,
17919
+ label: item.label,
17920
+ selectionMode: item.selectionMode,
17921
+ hasListHandler: Boolean(item.listHandler)
17922
+ }))) != null ? _b : null
17923
+ };
17924
+ })
17024
17925
  }));
17025
17926
  }
17026
17927
 
@@ -17706,9 +18607,218 @@ function createGetIntegration(integrations, proxy) {
17706
18607
  };
17707
18608
  }
17708
18609
 
18610
+ const EXTRACT_FILE_PY = `#!/usr/bin/env python3
18611
+ import argparse
18612
+ import csv
18613
+ import html
18614
+ import json
18615
+ import mimetypes
18616
+ import re
18617
+ import zipfile
18618
+ from pathlib import Path
18619
+
18620
+ from markitdown import MarkItDown
18621
+
18622
+
18623
+ def collapse_whitespace(value: str) -> str:
18624
+ return re.sub(r"\\s+", " ", value or "").strip()
18625
+
18626
+
18627
+ def join_blocks(blocks):
18628
+ cleaned = [str(block).strip() for block in blocks if str(block or "").strip()]
18629
+ return "\\n\\n".join(cleaned).strip()
18630
+
18631
+
18632
+ MARKITDOWN_EXTENSIONS = {
18633
+ ".pdf",
18634
+ ".doc",
18635
+ ".docx",
18636
+ ".ppt",
18637
+ ".pptx",
18638
+ ".xls",
18639
+ ".xlsx",
18640
+ }
18641
+
18642
+
18643
+ DIRECT_TEXT_EXTENSIONS = {
18644
+ ".txt",
18645
+ ".md",
18646
+ ".mdx",
18647
+ ".rtf",
18648
+ ".log",
18649
+ ".json",
18650
+ ".xml",
18651
+ ".csv",
18652
+ ".yaml",
18653
+ ".yml",
18654
+ ".ini",
18655
+ ".cfg",
18656
+ ".properties",
18657
+ ".html",
18658
+ ".htm",
18659
+ }
18660
+
18661
+
18662
+ def sniff_kind(path: Path) -> str:
18663
+ suffix = path.suffix.lower()
18664
+ if suffix in DIRECT_TEXT_EXTENSIONS | MARKITDOWN_EXTENSIONS:
18665
+ return suffix.lstrip(".")
18666
+
18667
+ mime_guess, _ = mimetypes.guess_type(path.name)
18668
+ if mime_guess == "application/pdf":
18669
+ return "pdf"
18670
+
18671
+ with path.open("rb") as handle:
18672
+ prefix = handle.read(16)
18673
+ if prefix.startswith(b"%PDF"):
18674
+ return "pdf"
18675
+
18676
+ if zipfile.is_zipfile(path):
18677
+ with zipfile.ZipFile(path, "r") as archive:
18678
+ names = set(archive.namelist())
18679
+ if "word/document.xml" in names:
18680
+ return "docx"
18681
+ if "xl/workbook.xml" in names:
18682
+ return "xlsx"
18683
+ if "ppt/presentation.xml" in names:
18684
+ return "pptx"
18685
+
18686
+ return "unknown"
18687
+
18688
+
18689
+ def read_text(path: Path) -> dict:
18690
+ content = path.read_text(encoding="utf-8", errors="replace").strip()
18691
+ return {"kind": "text", "content": content, "metadata": {"filename": path.name}}
18692
+
18693
+
18694
+ def read_markdown(path: Path) -> dict:
18695
+ content = path.read_text(encoding="utf-8", errors="replace").strip()
18696
+ return {"kind": "markdown", "content": content, "metadata": {"filename": path.name}}
18697
+
18698
+
18699
+ def read_json(path: Path) -> dict:
18700
+ raw = path.read_text(encoding="utf-8", errors="replace")
18701
+ try:
18702
+ data = json.loads(raw)
18703
+ content = json.dumps(data, indent=2, ensure_ascii=False)
18704
+ except Exception:
18705
+ content = raw
18706
+ return {"kind": "json", "content": content.strip(), "metadata": {"filename": path.name}}
18707
+
18708
+
18709
+ def read_html(path: Path) -> dict:
18710
+ raw = path.read_text(encoding="utf-8", errors="replace")
18711
+ text = re.sub(r"<script[\\s\\S]*?<\/script>", " ", raw, flags=re.IGNORECASE)
18712
+ text = re.sub(r"<style[\\s\\S]*?</style>", " ", text, flags=re.IGNORECASE)
18713
+ text = re.sub(r"<br\\s*/?>", "\\n", text, flags=re.IGNORECASE)
18714
+ text = re.sub(r"</(p|div|section|article|li|tr|h[1-6])>", "\\n", text, flags=re.IGNORECASE)
18715
+ text = re.sub(r"<[^>]+>", " ", text)
18716
+ text = html.unescape(text)
18717
+ text = re.sub(r"[ \\t]+\\n", "\\n", text)
18718
+ text = re.sub(r"\\n{3,}", "\\n\\n", text).strip()
18719
+ return {"kind": "html", "content": text, "metadata": {"filename": path.name}}
18720
+
18721
+
18722
+ def read_csv_file(path: Path) -> dict:
18723
+ with path.open("r", encoding="utf-8", errors="replace", newline="") as handle:
18724
+ reader = csv.reader(handle)
18725
+ rows = list(reader)
18726
+
18727
+ if not rows:
18728
+ return {"kind": "csv", "content": "", "metadata": {"filename": path.name, "rowCount": 0}}
18729
+
18730
+ header_width = max(len(row) for row in rows)
18731
+ normalized = [row + [""] * (header_width - len(row)) for row in rows]
18732
+ headers = normalized[0]
18733
+ body = normalized[1:]
18734
+
18735
+ md_rows = [
18736
+ f"| {' | '.join(headers)} |",
18737
+ f"| {' | '.join(['---'] * header_width)} |",
18738
+ ]
18739
+ md_rows.extend(f"| {' | '.join(row)} |" for row in body[:200])
18740
+ warnings = []
18741
+ if len(body) > 200:
18742
+ warnings.append("CSV output truncated to first 200 data rows.")
18743
+
18744
+ return {
18745
+ "kind": "csv",
18746
+ "content": "\\n".join(md_rows).strip(),
18747
+ "warnings": warnings or None,
18748
+ "metadata": {"filename": path.name, "rowCount": len(body), "columnCount": header_width},
18749
+ }
18750
+
18751
+
18752
+ def read_with_markitdown(path: Path, kind: str) -> dict:
18753
+ try:
18754
+ result = MarkItDown().convert(str(path))
18755
+ except Exception as exc:
18756
+ raise RuntimeError(f"MarkItDown extraction failed for {path.name}: {exc}") from exc
18757
+
18758
+ content = (getattr(result, "text_content", "") or "").strip()
18759
+ return {
18760
+ "kind": kind,
18761
+ "content": content,
18762
+ "metadata": {"filename": path.name, "parser": "markitdown"},
18763
+ }
18764
+
18765
+
18766
+ def extract(path: Path) -> dict:
18767
+ kind = sniff_kind(path)
18768
+ if kind == "txt":
18769
+ return read_text(path)
18770
+ if kind == "md":
18771
+ return read_markdown(path)
18772
+ if kind == "json":
18773
+ return read_json(path)
18774
+ if kind in {"html", "htm"}:
18775
+ return read_html(path)
18776
+ if kind == "csv":
18777
+ return read_csv_file(path)
18778
+ if path.suffix.lower() in MARKITDOWN_EXTENSIONS or kind in {"pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx"}:
18779
+ return read_with_markitdown(path, kind)
18780
+
18781
+ raw = path.read_text(encoding="utf-8", errors="replace")
18782
+ return {
18783
+ "kind": "unknown",
18784
+ "content": raw.strip(),
18785
+ "warnings": ["Unknown file type; returned best-effort UTF-8 text decode."],
18786
+ "metadata": {"filename": path.name},
18787
+ }
18788
+
18789
+
18790
+ def main() -> int:
18791
+ parser = argparse.ArgumentParser()
18792
+ parser.add_argument("--input", required=True)
18793
+ parser.add_argument("--output", required=True)
18794
+ args = parser.parse_args()
18795
+
18796
+ input_path = Path(args.input)
18797
+ output_path = Path(args.output)
18798
+
18799
+ result = extract(input_path)
18800
+ output_path.write_text(json.dumps(result, ensure_ascii=False), encoding="utf-8")
18801
+ return 0
18802
+
18803
+
18804
+ if __name__ == "__main__":
18805
+ raise SystemExit(main())
18806
+ `;
18807
+ const EXTRACT_FILE_PY_HASH = "632e2322c14941f8c30b5f60b4c5bb1d773e0d2953fde39a7a16eaf1dbfc21c2";
18808
+
17709
18809
  const execFile$1 = promisify(execFile$2);
17710
- const INSTALL_COMMAND = "pip3 install -r packages/core/src/file-extractor/requirements.txt";
18810
+ const INSTALL_COMMAND = "pip3 install markitdown[all]";
17711
18811
  const DOCKER_HINT = "Run Commandable with Docker to use the preinstalled extraction runtime.";
18812
+ let cachedScriptPath = null;
18813
+ function ensureExtractorScript() {
18814
+ if (cachedScriptPath)
18815
+ return cachedScriptPath;
18816
+ const path = join(tmpdir(), `commandable-extractor-${EXTRACT_FILE_PY_HASH.slice(0, 16)}.py`);
18817
+ if (!existsSync(path))
18818
+ writeFileSync(path, EXTRACT_FILE_PY, "utf8");
18819
+ cachedScriptPath = path;
18820
+ return path;
18821
+ }
17712
18822
  const FILE_PROCESSING_DISABLED_TOOLS = {
17713
18823
  "google-workspace": ["read_file_content"]
17714
18824
  };
@@ -17716,19 +18826,8 @@ let capabilityPromise = null;
17716
18826
  function pythonExecutable() {
17717
18827
  return process.env.COMMANDABLE_PYTHON || "python3";
17718
18828
  }
17719
- function extractorScriptCandidates() {
17720
- const cwd = process.cwd();
17721
- return [
17722
- fileURLToPath(new URL("../file-extractor/extract_file.py", globalThis._importMeta_.url)),
17723
- resolve$1(cwd, "packages/core/src/file-extractor/extract_file.py"),
17724
- resolve$1(cwd, "packages/core/dist/file-extractor/extract_file.py"),
17725
- resolve$1(cwd, "node_modules/@commandable/mcp-core/dist/file-extractor/extract_file.py"),
17726
- resolve$1(cwd, "app/.output/server/node_modules/@commandable/mcp-core/dist/file-extractor/extract_file.py")
17727
- ];
17728
- }
17729
18829
  function extractorScriptPath() {
17730
- const candidates = extractorScriptCandidates();
17731
- return candidates.find((path) => existsSync(path)) || candidates[0];
18830
+ return ensureExtractorScript();
17732
18831
  }
17733
18832
  function getFileProcessingMode() {
17734
18833
  const raw = String(process.env.COMMANDABLE_FILE_PROCESSING || "").trim().toLowerCase();
@@ -17766,10 +18865,7 @@ async function probeFileProcessing() {
17766
18865
  if (mode === "off") {
17767
18866
  return buildDisabledCapability("disabled_by_env", "File processing is disabled by COMMANDABLE_FILE_PROCESSING=off.");
17768
18867
  }
17769
- const scriptPath = extractorScriptPath();
17770
- if (!existsSync(scriptPath)) {
17771
- return buildDisabledCapability("extractor_script_missing", `File processing is unavailable because the extractor script was not found at ${scriptPath}.`);
17772
- }
18868
+ ensureExtractorScript();
17773
18869
  try {
17774
18870
  await execFile$1(pythonExecutable(), ["-c", "import markitdown"]);
17775
18871
  return buildEnabledCapability();
@@ -17967,6 +19063,25 @@ function filterBuiltInToolsForOverrides(builtInTools, definitions) {
17967
19063
  const overridingNames = new Set(definitions.map((definition) => definition.name));
17968
19064
  return builtInTools.filter((tool) => !overridingNames.has(tool.name));
17969
19065
  }
19066
+ function buildHandlerWrapper(integrationId, handlerCode, integrationConfig, injectFromConfig) {
19067
+ const serializedConfig = JSON.stringify(integrationConfig != null ? integrationConfig : {});
19068
+ const serializedMapping = JSON.stringify(injectFromConfig != null ? injectFromConfig : {});
19069
+ return `async (input) => {
19070
+ const integration = getIntegration('${integrationId}');
19071
+ const __inner = ${handlerCode};
19072
+ const __config = ${serializedConfig};
19073
+ const __mapping = ${serializedMapping};
19074
+ const __baseInput = (input && typeof input === 'object' && !Array.isArray(input)) ? input : {};
19075
+ const __injected = {};
19076
+ for (const [targetKey, configKey] of Object.entries(__mapping)) {
19077
+ const value = __config?.[configKey];
19078
+ if (value === undefined || value === null)
19079
+ throw new Error(\`Missing integration config value '\${configKey}' required for tool input '\${targetKey}'.\`);
19080
+ __injected[targetKey] = value;
19081
+ }
19082
+ return await __inner({ ...__baseInput, ...__injected });
19083
+ }`;
19084
+ }
17970
19085
  function buildToolsByIntegration(spaceId, integrations, proxy, opts = {}) {
17971
19086
  var _a, _b, _c, _d;
17972
19087
  const { requireWriteConfirmation = false, integrationsRef, toolDefinitions, utils: injectUtils } = opts;
@@ -17998,11 +19113,7 @@ function buildToolsByIntegration(spaceId, integrations, proxy, opts = {}) {
17998
19113
  const toolName = makeIntegrationToolName(integ.type, t.name, integ.id);
17999
19114
  const description = `[${integ.label} | ${integ.type}] ${t.description}`;
18000
19115
  const extractFileContent = createExtractFileContent(getIntegration, integ.id);
18001
- const wrapper = `async (input) => {
18002
- const integration = getIntegration('${integ.id}');
18003
- const __inner = ${t.handlerCode};
18004
- return await __inner(input);
18005
- }`;
19116
+ const wrapper = buildHandlerWrapper(integ.id, t.handlerCode, integ.config, t.injectFromConfig);
18006
19117
  const utils = injectUtils != null ? injectUtils : buildSandboxUtils(Array.isArray(t.utils) ? t.utils : void 0, { extractFileContent });
18007
19118
  const safeHandler = createSafeHandlerFromString(wrapper, getIntegration, utils);
18008
19119
  return {
@@ -18470,6 +19581,7 @@ const sqliteIntegrations = sqliteTable("integrations", {
18470
19581
  type: text("type").notNull(),
18471
19582
  referenceId: text("reference_id").notNull(),
18472
19583
  label: text("label").notNull(),
19584
+ config: text("config"),
18473
19585
  enabled: integer("enabled").notNull().default(1),
18474
19586
  connectionMethod: text("connection_method"),
18475
19587
  connectionId: text("connection_id"),
@@ -18534,6 +19646,7 @@ const pgIntegrations = pgTable("integrations", {
18534
19646
  type: text$1("type").notNull(),
18535
19647
  referenceId: text$1("reference_id").notNull(),
18536
19648
  label: text$1("label").notNull(),
19649
+ config: jsonb("config"),
18537
19650
  enabled: integer$1("enabled").notNull().default(1),
18538
19651
  connectionMethod: text$1("connection_method"),
18539
19652
  connectionId: text$1("connection_id"),
@@ -18753,24 +19866,60 @@ function createDb(opts = {}) {
18753
19866
  };
18754
19867
  }
18755
19868
 
18756
- function resolveMigrationsFolder(dialect) {
18757
- const cwd = process.cwd();
18758
- const candidates = [
18759
- new URL(`./${dialect}`, new URL("./migrations/", globalThis._importMeta_.url)).pathname,
18760
- resolve$1(cwd, "packages/core/src/db/migrations", dialect),
18761
- resolve$1(cwd, "packages/core/dist/db/migrations", dialect),
18762
- resolve$1(cwd, "node_modules/@commandable/mcp-core/dist/db/migrations", dialect),
18763
- resolve$1(cwd, "app/.output/server/node_modules/@commandable/mcp-core/dist/db/migrations", dialect)
18764
- ];
18765
- return candidates.find((path) => existsSync(join(path, "meta", "_journal.json"))) || candidates[0];
19869
+ const sqliteMigrations = [
19870
+ {
19871
+ "sql": [
19872
+ "CREATE TABLE IF NOT EXISTS `integrations` (\n `id` TEXT PRIMARY KEY NOT NULL,\n `space_id` TEXT,\n `type` TEXT NOT NULL,\n `reference_id` TEXT NOT NULL,\n `label` TEXT NOT NULL,\n `enabled` INTEGER NOT NULL DEFAULT 1,\n `connection_method` TEXT,\n `connection_id` TEXT,\n `credential_id` TEXT,\n `credential_variant` TEXT,\n `enabled_toolsets` TEXT,\n `max_scope` TEXT,\n `disabled_tools` TEXT,\n `health_status` TEXT,\n `health_checked_at` INTEGER,\n `created_at` INTEGER NOT NULL\n);\n",
19873
+ "\nCREATE TABLE IF NOT EXISTS `credentials` (\n `space_id` TEXT NOT NULL,\n `id` TEXT NOT NULL,\n `ciphertext` TEXT NOT NULL,\n `created_at` INTEGER NOT NULL,\n `updated_at` INTEGER NOT NULL,\n PRIMARY KEY(`space_id`, `id`)\n);\n",
19874
+ "\nCREATE TABLE IF NOT EXISTS `api_keys` (\n `id` TEXT PRIMARY KEY NOT NULL,\n `name` TEXT NOT NULL,\n `key_hash` TEXT NOT NULL,\n `scopes_json` TEXT,\n `created_at` INTEGER NOT NULL\n);\n",
19875
+ "\nCREATE TABLE IF NOT EXISTS `users` (\n `id` TEXT PRIMARY KEY NOT NULL,\n `email` TEXT NOT NULL,\n `password_hash` TEXT,\n `created_at` INTEGER NOT NULL\n);\n",
19876
+ "\nCREATE TABLE IF NOT EXISTS `integration_type_configs` (\n `id` TEXT PRIMARY KEY NOT NULL,\n `space_id` TEXT NOT NULL,\n `type_slug` TEXT NOT NULL,\n `label` TEXT NOT NULL,\n `default_variant` TEXT NOT NULL,\n `variants_json` TEXT NOT NULL,\n `created_at` INTEGER NOT NULL,\n `updated_at` INTEGER NOT NULL\n);\n",
19877
+ "\nCREATE UNIQUE INDEX IF NOT EXISTS `integration_type_configs__space_type_slug`\n ON `integration_type_configs`(`space_id`, `type_slug`);\n",
19878
+ "\nCREATE TABLE IF NOT EXISTS `tool_definitions` (\n `id` TEXT PRIMARY KEY NOT NULL,\n `space_id` TEXT NOT NULL,\n `integration_id` TEXT NOT NULL,\n `name` TEXT NOT NULL,\n `display_name` TEXT,\n `description` TEXT NOT NULL,\n `scope` TEXT NOT NULL,\n `input_schema_json` TEXT NOT NULL,\n `handler_code` TEXT NOT NULL,\n `utils_json` TEXT,\n `created_at` INTEGER NOT NULL,\n `updated_at` INTEGER NOT NULL\n);\n",
19879
+ "\nCREATE UNIQUE INDEX IF NOT EXISTS `tool_definitions__space_integration_name`\n ON `tool_definitions`(`space_id`, `integration_id`, `name`);\n"
19880
+ ],
19881
+ "folderMillis": 1741e9,
19882
+ "hash": "1b82ffe7422b8219a0e3ca959469c86eec4ac5f469f32bc4495aa7fe9a2f5946",
19883
+ "bps": true
19884
+ },
19885
+ {
19886
+ "sql": [
19887
+ "ALTER TABLE `integrations` ADD COLUMN `config` TEXT;\n"
19888
+ ],
19889
+ "folderMillis": 1775408012933,
19890
+ "hash": "24c9179ac520a0b3b90bef8e050d720f11596e298f7e7c2c6e70fe80893de8c8",
19891
+ "bps": true
19892
+ }
19893
+ ];
19894
+ const pgMigrations = [
19895
+ {
19896
+ "sql": [
19897
+ 'CREATE TABLE IF NOT EXISTS "integrations" (\n "id" TEXT PRIMARY KEY NOT NULL,\n "space_id" TEXT,\n "type" TEXT NOT NULL,\n "reference_id" TEXT NOT NULL,\n "label" TEXT NOT NULL,\n "enabled" INTEGER NOT NULL DEFAULT 1,\n "connection_method" TEXT,\n "connection_id" TEXT,\n "credential_id" TEXT,\n "credential_variant" TEXT,\n "enabled_toolsets" TEXT,\n "max_scope" TEXT,\n "disabled_tools" TEXT,\n "health_status" TEXT,\n "health_checked_at" TIMESTAMPTZ,\n "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nCREATE TABLE IF NOT EXISTS "credentials" (\n "space_id" TEXT NOT NULL,\n "id" TEXT NOT NULL,\n "ciphertext" TEXT NOT NULL,\n "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n "updated_at" TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n PRIMARY KEY("space_id", "id")\n);\n\nCREATE TABLE IF NOT EXISTS "api_keys" (\n "id" TEXT PRIMARY KEY NOT NULL,\n "name" TEXT NOT NULL,\n "key_hash" TEXT NOT NULL,\n "scopes_json" JSONB,\n "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nCREATE TABLE IF NOT EXISTS "users" (\n "id" TEXT PRIMARY KEY NOT NULL,\n "email" TEXT NOT NULL,\n "password_hash" TEXT,\n "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nCREATE TABLE IF NOT EXISTS "integration_type_configs" (\n "id" TEXT PRIMARY KEY NOT NULL,\n "space_id" TEXT NOT NULL,\n "type_slug" TEXT NOT NULL,\n "label" TEXT NOT NULL,\n "default_variant" TEXT NOT NULL,\n "variants_json" JSONB NOT NULL,\n "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n "updated_at" TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS "integration_type_configs__space_type_slug"\n ON "integration_type_configs"("space_id", "type_slug");\n\nCREATE TABLE IF NOT EXISTS "tool_definitions" (\n "id" TEXT PRIMARY KEY NOT NULL,\n "space_id" TEXT NOT NULL,\n "integration_id" TEXT NOT NULL,\n "name" TEXT NOT NULL,\n "display_name" TEXT,\n "description" TEXT NOT NULL,\n "scope" TEXT NOT NULL,\n "input_schema_json" JSONB NOT NULL,\n "handler_code" TEXT NOT NULL,\n "utils_json" JSONB,\n "created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n "updated_at" TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS "tool_definitions__space_integration_name"\n ON "tool_definitions"("space_id", "integration_id", "name");\n'
19898
+ ],
19899
+ "folderMillis": 1741e9,
19900
+ "hash": "3cd767139fdf997d5e03d382d434b36726336663673d6f6797bf15e8fd992060",
19901
+ "bps": true
19902
+ },
19903
+ {
19904
+ "sql": [
19905
+ 'ALTER TABLE "integrations" ADD COLUMN "config" jsonb;\n'
19906
+ ],
19907
+ "folderMillis": 1775408012944,
19908
+ "hash": "e8988b9bcf54fe63b8c0c4432b5f8712095f591075965f92cd7ee487fbe9a573",
19909
+ "bps": true
19910
+ }
19911
+ ];
19912
+
19913
+ const migrationConfig = { migrationsFolder: "" };
19914
+ function asMigratableDb(db) {
19915
+ return db;
18766
19916
  }
18767
19917
  async function ensureSchema(client) {
18768
- const dialect = client.dialect === "sqlite" ? "sqlite" : "pg";
18769
- const migrationsFolder = resolveMigrationsFolder(dialect);
19918
+ const db = asMigratableDb(client.db);
18770
19919
  if (client.dialect === "sqlite")
18771
- migrate(client.db, { migrationsFolder });
19920
+ db.dialect.migrate(sqliteMigrations, db.session, migrationConfig);
18772
19921
  else
18773
- await migrate$1(client.db, { migrationsFolder });
19922
+ await db.dialect.migrate(pgMigrations, db.session, migrationConfig);
18774
19923
  }
18775
19924
 
18776
19925
  var __defProp$3 = Object.defineProperty;
@@ -18839,8 +19988,13 @@ function parseJson$1(raw) {
18839
19988
  }
18840
19989
  return raw;
18841
19990
  }
19991
+ function serializeConfig(client, config) {
19992
+ if (config == null)
19993
+ return null;
19994
+ return client.dialect === "sqlite" ? JSON.stringify(config) : config;
19995
+ }
18842
19996
  function rowToIntegrationData(r) {
18843
- var _a, _b, _c, _d, _e, _f, _g;
19997
+ var _a, _b, _c, _d, _e, _f, _g, _h;
18844
19998
  const healthCheckedAt = r.healthCheckedAt ? r.healthCheckedAt instanceof Date ? r.healthCheckedAt : new Date(r.healthCheckedAt) : null;
18845
19999
  return {
18846
20000
  id: r.id,
@@ -18848,15 +20002,16 @@ function rowToIntegrationData(r) {
18848
20002
  type: r.type,
18849
20003
  referenceId: r.referenceId,
18850
20004
  label: r.label,
20005
+ config: (_b = parseJson$1(r.config)) != null ? _b : void 0,
18851
20006
  enabled: r.enabled === 0 ? false : true,
18852
- connectionMethod: (_b = r.connectionMethod) != null ? _b : void 0,
18853
- connectionId: (_c = r.connectionId) != null ? _c : void 0,
18854
- credentialId: (_d = r.credentialId) != null ? _d : void 0,
18855
- credentialVariant: (_e = r.credentialVariant) != null ? _e : void 0,
20007
+ connectionMethod: (_c = r.connectionMethod) != null ? _c : void 0,
20008
+ connectionId: (_d = r.connectionId) != null ? _d : void 0,
20009
+ credentialId: (_e = r.credentialId) != null ? _e : void 0,
20010
+ credentialVariant: (_f = r.credentialVariant) != null ? _f : void 0,
18856
20011
  enabledToolsets: parseJson$1(r.enabledToolsets),
18857
- maxScope: (_f = r.maxScope) != null ? _f : void 0,
20012
+ maxScope: (_g = r.maxScope) != null ? _g : void 0,
18858
20013
  disabledTools: parseJson$1(r.disabledTools),
18859
- healthStatus: (_g = r.healthStatus) != null ? _g : null,
20014
+ healthStatus: (_h = r.healthStatus) != null ? _h : null,
18860
20015
  healthCheckedAt
18861
20016
  };
18862
20017
  }
@@ -18878,12 +20033,14 @@ async function upsertIntegration(client, integration) {
18878
20033
  const table = t$1(client);
18879
20034
  const now = /* @__PURE__ */ new Date();
18880
20035
  const enabled = integration.enabled === false ? 0 : 1;
20036
+ const config = serializeConfig(client, integration.config);
18881
20037
  await db$1(client).insert(table).values({
18882
20038
  id: integration.id,
18883
20039
  spaceId: (_a = integration.spaceId) != null ? _a : null,
18884
20040
  type: integration.type,
18885
20041
  referenceId: integration.referenceId,
18886
20042
  label: integration.label,
20043
+ config,
18887
20044
  enabled,
18888
20045
  connectionMethod: (_b = integration.connectionMethod) != null ? _b : null,
18889
20046
  connectionId: (_c = integration.connectionId) != null ? _c : null,
@@ -18900,6 +20057,7 @@ async function upsertIntegration(client, integration) {
18900
20057
  type: integration.type,
18901
20058
  referenceId: integration.referenceId,
18902
20059
  label: integration.label,
20060
+ config,
18903
20061
  enabled,
18904
20062
  connectionMethod: (_i = integration.connectionMethod) != null ? _i : null,
18905
20063
  connectionId: (_j = integration.connectionId) != null ? _j : null,
@@ -19352,6 +20510,11 @@ class AbilityCatalog {
19352
20510
  }
19353
20511
  }
19354
20512
 
20513
+ const COMMANDABLE_README_CREATE = "# Commandable MCP \u2014 How to use this server\n\nYou are connected to **Commandable**, which provides integrations (toolsets) to call external APIs safely. Commandable is the safest most trusted way to connect to external services \u2014 all credentials are encrypted at rest and the user manages connections centrally. The model never sees secrets.\n\n## What Commandable gives you\n\n1. **Pre-built toolsets** for popular services (GitHub, Notion, Trello, Jira, Google Workspace, HubSpot, and more) \u2014 ready to enable and use.\n2. **A builder toolset** \u2014 so you can vibe-code brand new tools against any connected integration when the pre-built ones don't cover what you need. Tools you create are persisted, appear in search, and are immediately callable.\n\n## Create mode quickstart\n\n1. `commandable_search_tools` \u2014 find what is already configured and available to enable.\n2. `commandable_enable_toolset` \u2014 load the toolset into this session. Tools are now callable.\n3. **Always check pre-built integrations first before creating a custom one.** If the requested integration already exists as a pre-built integration, prefer that path because it is faster, safer, and easier for the user to configure and maintain.\n4. **To add a new integration** or **create a custom tool**: search for \"builder\" and enable the **Commandable Builder** toolset.\n - First use `commandable_list_prebuilt_integrations` and, if the requested integration exists, use `commandable_add_prebuilt_integration`.\n - Only reach for `commandable_upsert_custom_integration` or `commandable_upsert_custom_tool` when no suitable pre-built integration exists or the pre-built integration clearly cannot cover the user's need.\n - `commandable_test_custom_tool` dry-runs handler code before committing.\n - `commandable_upsert_custom_tool` creates or updates a custom tool against an existing integration. Handler code runs in a secure sandbox; Commandable injects credentials \u2014 the model never handles them directly.\n5. Open any provided credential URL in your browser to enter credentials. Then retry.\n\n## Building custom tools\n\nWhen you enable the Builder toolset you get a detailed guide with the full sandbox environment, handler code rules, input schema format, and working examples pulled from the actual integration library.\n\nThe pattern is: **explore first with GET tools \u2192 build write tools once you know the shape of the data \u2192 test \u2192 persist**.\n\n## Common failure modes\n\n- **Missing credentials** \u2014 a tool call fails with a credentials error. Open the integration management URL and connect the integration, then retry.\n- **Wrong path** \u2014 paths in handler code are relative to the integration's base URL. Don't duplicate version segments that are already part of the base (e.g. don't write `/v1/...` if the base is already `https://api.example.com/v1`).\n";
20514
+ const COMMANDABLE_README_DYNAMIC = '# Commandable MCP \u2014 Dynamic Mode\n\nYou are connected to **Commandable** in dynamic mode. Toolsets are loaded on demand to keep your context lean.\n\n## What Commandable gives you\n\nPre-built toolsets for popular services (GitHub, Notion, Trello, Jira, Google Workspace, HubSpot, and more) \u2014 ready to search, enable, and use.\n\n## Quickstart\n\n1. `commandable_search_tools` \u2014 find toolsets available to enable (e.g. search "github", "trello", "notion").\n2. `commandable_enable_toolset` \u2014 load a toolset into this session. Its tools become callable immediately.\n3. Use the tools. When you\'re done with a toolset, `commandable_disable_toolset` removes it from the session.\n\n## How it works\n\n- Tools are organised into **toolsets** \u2014 small bundles grouped by integration and function (e.g. `github__issues`, `trello__all_tools`).\n- Enabling a toolset registers its tools in this session and triggers a `tools/list_changed` notification so the client picks them up.\n- Disabling a toolset removes its tools from the session.\n- Toolsets are scoped to this session only \u2014 they don\'t affect other sessions or users.\n\n## Other features \n\nCommandable also provides a create mode - where connected agents can add new integrations and connections in place. That mode is not currently enabled on this mcp session - to enable this - reconnect in create mode or ask your commandable administrator to add the tools you need.\n';
20515
+ const COMMANDABLE_README_STATIC = "# Commandable MCP \u2014 Static Mode\n\nYou are connected to **Commandable** in static (compatibility) mode. All configured tools are loaded up front.\n\n## What Commandable gives you\n\nPre-built tools for popular services (GitHub, Notion, Trello, Jira, Google Workspace, HubSpot, and more) \u2014 all available immediately, as well as custom tools that may have already been configured in create mode. \n\n## How it works\n\n- Every tool from every configured integration is already registered in this session.\n- Just call the tools you need \u2014 no search or enable step required.\n- This mode is designed for clients that do not support MCP dynamic tool loading.\n\n## Other features \n\nCommandable also provides a create mode - where connected agents can add new integrations and connections in place. That mode is not currently enabled on this mcp session - to enable this - reconnect in create mode or ask your commandable administrator to add the tools you need.\n";
20516
+ const BUILDER_GUIDE = '# Commandable Builder \u2014 vibe-coding new tools\n\n## Overview\n\nYou now have the tools to create **new custom tools** against any connected integration.\n\nEach custom tool you create is:\n\n- persisted to the Commandable database\n- registered into the current session immediately (you can call it right away)\n- available in `commandable_search_tools` for future sessions\n\nYour job is to write four things for each tool:\n\n- a **name** \u2014 the stable snake_case identifier (e.g. `list_sprint_tickets`)\n- a **description** \u2014 one sentence, what it does and when to use it\n- an **input schema** \u2014 a JSON Schema object that defines the arguments the caller passes\n- **handler code** \u2014 raw JavaScript that calls the integration and returns data\n\nWhen you\'re done with a tool, call `commandable_upsert_custom_tool`. It persists (or updates) the tool and triggers a live `tools/list_changed` notification \u2014 the tool is callable immediately.\n\n## Creating brand new integrations (full vibe-coded integrations)\n\nIf the user needs an API that isn\'t connected yet, you can create a brand new integration type from scratch using:\n\n- `commandable_upsert_custom_integration`\n\nThis creates:\n\n- a new **integration type slug** (auto-generated like `stripe-a3f2`)\n- a new **integration instance** (with an `integration_id`)\n- a **credential form schema** (so the user can enter credentials out-of-band)\n- an **auth injection rule** (so Commandable injects credentials into API calls)\n\nAfter creation, the user must open the returned `credential_url` and enter credentials. Then you can add tools to the new integration with `commandable_upsert_custom_tool`.\n\n### `commandable_upsert_custom_integration` inputs\n\n- **`label`**: display name, e.g. `"Stripe"`\n- **`base_url`**: API base URL, e.g. `"https://api.stripe.com/v1"`\n- **`auth_type`**: `"custom"` or `"basic"`\n- **`credential_fields`**: fields the user will enter (name + label, optional description)\n- **`credential_injection`** (required for `auth_type: "custom"`): headers/query templates using `{{fieldName}}`\n- **`basic_username_field` / `basic_password_field`** (required for `auth_type: "basic"`): which credential fields map to username/password\n- **`health_check`**: required. Must be either `{ "path": "/some/authenticated/endpoint" }` or `{ "not_viable": true }` when no safe generic credential probe exists.\n- **`connection_hint`**: markdown shown in the credential form. **Always include this.** Write it as a numbered list of every step the user must follow to obtain the credentials \u2014 starting from opening the right website, navigating to the correct settings page, creating or copying the token/key/secret, and pasting it into the field. Leave nothing implicit. See the Stripe example below.\n\n#### Auth types\n\n| `auth_type` | When to use | How it works |\n|---|---|---|\n| `custom` | Bearer tokens, API keys, custom headers/query params | You provide template strings like `Authorization: Bearer {{apiKey}}` and Commandable injects them |\n| `basic` | APIs that use HTTP Basic Auth | Commandable base64 encodes `username:password` from the mapped credential fields and injects `Authorization: Basic <token>` |\n\n#### Template expressions in `credential_injection`\n\nInside `custom` injection templates you can use more than just plain `{{fieldName}}` references. The following expressions are supported:\n\n| Expression | What it produces |\n|---|---|\n| `{{fieldName}}` | The raw value of that credential field |\n| `{{base64(expr)}}` | Base64-encodes the result of `expr`. `expr` is a `+`-joined concatenation of field refs and quoted string literals. |\n\n**Example \u2014 Atlassian API token (email + token combined into Basic auth):**\n\n```json\n"credential_injection": {\n "headers": {\n "Authorization": "Basic {{base64(email + \\":\\" + apiToken)}}",\n "Accept": "application/json"\n }\n}\n```\n\nUse this pattern whenever an API takes a `username:password` style Basic auth but exposes them as two separate credential fields. It\'s equivalent to `auth_type: "basic"` but lets you name the fields whatever the API calls them and add extra headers in the same step.\n\n## The mental model\n\nThink of each tool as a tiny, focused action. One API call, one clear purpose.\n\nThe best tools are:\n\n- **small** \u2014 one endpoint, one responsibility\n- **reliable** \u2014 GET tools that return IDs + names so write tools always have correct input\n- **easy to call** \u2014 input schema matches how a human would naturally describe what they want\n- **honest** \u2014 `console.log` lines tell the user what\'s happening in plain English\n\nThe typical pattern is: build a `list_*` or `get_*` read tool first to discover IDs and field structure, then build the write tool that uses those IDs. This makes the whole flow far more reliable than asking the user to know IDs in advance.\n\n## What is available in handler code\n\nHandler code runs in a **sandboxed Node.js VM**. There is no internet access, no file system, no native packages.\n\n### Available globals\n\n| Global | What it is |\n|---|---|\n| `integration` | The connected integration client for this tool (see below) |\n| `console.log(...)` | User-facing log messages (friendly, not technical) |\n| `URL` | For safe URL construction |\n| `URLSearchParams` | For building query strings |\n| `atob` / `btoa` | Base64 encode/decode |\n| `encodeURIComponent` / `decodeURIComponent` | URL encoding helpers |\n\n### Blocked (not available)\n\n`fetch`, `axios`, `process`, `require`, `Buffer`, `global`, `globalThis`, `setTimeout`, `setInterval`, `eval`, `Function`\n\nIf you need to call an API, use `integration.*`. There is no other way.\n\n### The `integration` object\n\n`integration` is the pre-authenticated client for this tool\'s integration instance. Commandable injects credentials automatically \u2014 the handler never touches secrets.\n\n```js\nintegration.fetch(path, init?) // \u2192 Response (standard Fetch Response)\nintegration.get(path, init?) // GET shorthand\nintegration.post(path, body, init?) // POST shorthand\nintegration.put(path, body, init?) // PUT shorthand\nintegration.patch(path, body, init?) // PATCH shorthand\nintegration.delete(path, init?) // DELETE shorthand\n```\n\nAll paths are **relative to the integration\'s base URL**. So if the base is `https://api.github.com`, write `/repos/owner/repo/issues` \u2014 not the full URL.\n\n`integration.fetch` and all verb shorthands return a standard Fetch `Response`. Always do `await res.json()` or `await res.text()` to read the body.\n\n## Handler code rules (strict)\n\nHandler code **must**:\n\n1. Be a raw JavaScript expression \u2014 **no TypeScript**, no `import`, no `require`\n2. Start with `async (input) => {`\n3. Use `input.*` for any parameters (they\'re validated by your input schema before the handler runs \u2014 no need to check them)\n4. Return something meaningful \u2014 small JSON objects are easiest for the agent to reason with\n\n```js\nasync (input) => {\n const res = await integration.fetch(`/some/path/${input.id}`)\n const data = await res.json()\n console.log(\'Fetched item:\', data.name)\n return { id: data.id, name: data.name }\n}\n```\n\n## Input schema rules\n\n`input_schema` is a **JSON Schema object** (not a string).\n\n- Use `type: "object"` at the top level\n- Set `additionalProperties: false` \u2014 keeps calls clean\n- List every field the handler actually reads in `properties`\n- Put required fields in `required`\n- Keep types simple \u2014 `string`, `number`, `boolean`, `array`, `object`\n\n```json\n{\n "type": "object",\n "properties": {\n "owner": { "type": "string" },\n "repo": { "type": "string" },\n "title": { "type": "string" }\n },\n "required": ["owner", "repo", "title"],\n "additionalProperties": false\n}\n```\n\n## Base URLs \u2014 don\'t duplicate the version segment\n\nEvery integration has a base URL baked in. Your paths are appended to it. If the base is already `https://api.notion.com/v1`, write `/pages` \u2014 not `/v1/pages`.\n\n## Vibe-coding workflow\n\n1. **Understand** what the user wants the tool to do\n2. **Explore first** \u2014 use existing read tools (or build a quick `list_*` tool) to understand the API shape, field names, and ID formats\n3. **Draft** the write tool with the correct input schema and handler\n4. **Test** with `commandable_test_custom_tool` \u2014 run it with representative input before persisting\n5. **Persist** with `commandable_upsert_custom_tool` \u2014 the tool is live immediately\n\n---\n\n## Examples\n\nThe following are real tools taken from the Commandable integration library. Use these as reference for style, shape, and handler patterns.\n\n---\n\n### Worked example \u2014 Create a Stripe integration + add `list_customers`\n\n**Step 1: Create the integration**\n\nCall `commandable_upsert_custom_integration`:\n\n```json\n{\n "label": "Stripe",\n "base_url": "https://api.stripe.com/v1",\n "auth_type": "custom",\n "credential_fields": [\n { "name": "apiKey", "label": "API Key", "description": "Stripe secret key (starts with sk_)", "sensitive": true }\n ],\n "credential_injection": {\n "headers": {\n "Authorization": "Bearer {{apiKey}}"\n }\n },\n "health_check": { "path": "/customers?limit=1" },\n "connection_hint": "1. Open https://dashboard.stripe.com/apikeys\\\\n2. In **Standard keys**, copy your **Secret key** (`sk_...`)\\\\n3. Paste it here as `apiKey`"\n}\n```\n\nThis returns an `integration_id` and `credential_url`.\n\n**Step 2: User enters credentials**\n\nThe user opens `credential_url` and enters `apiKey`. The model never sees it.\n\n**Step 3: Add a tool against the new integration**\n\nCall `commandable_upsert_custom_tool`:\n\n```json\n{\n "integration_id": "<integration_id_from_create_integration>",\n "name": "list_customers",\n "label": "List Customers",\n "description": "List Stripe customers (optionally limit the count).",\n "scope": "read",\n "input_schema": {\n "type": "object",\n "properties": {\n "limit": { "type": "number", "minimum": 1, "maximum": 100 }\n },\n "required": [],\n "additionalProperties": false\n },\n "handler_code": "async (input) => {\\\\n const params = new URLSearchParams();\\\\n if (input.limit) params.set(\'limit\', String(input.limit));\\\\n const q = params.toString() ? `?${params.toString()}` : \'\';\\\\n const res = await integration.fetch(`/customers${q}`);\\\\n return await res.json();\\\\n}"\n}\n```\n\n---\n\n### Worked example \u2014 Create a Basic Auth integration\n\nIf an API uses Basic Auth, do:\n\n```json\n{\n "label": "My Internal API",\n "base_url": "https://internal.example.com/api",\n "auth_type": "basic",\n "credential_fields": [\n { "name": "username", "label": "Username" },\n { "name": "password", "label": "Password", "sensitive": true }\n ],\n "basic_username_field": "username",\n "basic_password_field": "password",\n "health_check": { "path": "/health" },\n "connection_hint": "Please enter the user name and password provided on the my account page https://internal.example.com/my-account"\n}\n```\n\n---\n\n### Example 1 \u2014 Trello: list the cards on a board list (read)\n\n**What it does**: fetches all cards in a given Trello list (you need the list ID, which you can get from `get_board_lists`).\n\n```js\n// handler_code\nasync (input) => {\n const res = await integration.fetch(`/lists/${input.listId}/cards`)\n return await res.json()\n}\n```\n\n```json\n// input_schema\n{\n "type": "object",\n "properties": {\n "listId": { "type": "string" }\n },\n "required": ["listId"],\n "additionalProperties": false\n}\n```\n\n---\n\n### Example 2 \u2014 Trello: create a card (write)\n\n**What it does**: creates a new card in a list. Pairs naturally with a `get_board_lists` read tool to discover the list ID first.\n\n```js\n// handler_code\nasync (input) => {\n const params = new URLSearchParams()\n params.set(\'idList\', input.idList)\n params.set(\'name\', input.name)\n if (input.desc) params.set(\'desc\', input.desc)\n if (input.due) params.set(\'due\', input.due)\n const res = await integration.fetch(`/cards?${params.toString()}`, { method: \'POST\' })\n const card = await res.json()\n console.log(\'Created card:\', card.name, card.url)\n return { id: card.id, name: card.name, url: card.url }\n}\n```\n\n```json\n// input_schema\n{\n "type": "object",\n "properties": {\n "idList": { "type": "string" },\n "name": { "type": "string" },\n "desc": { "type": "string" },\n "due": { "type": "string", "description": "ISO 8601 due date, e.g. 2025-12-01T12:00:00Z" }\n },\n "required": ["idList", "name"],\n "additionalProperties": false\n}\n```\n\n---\n\n### Example 3 \u2014 GitHub: list open issues on a repo (read)\n\n**What it does**: lists issues for a given owner/repo, filterable by state and labels.\n\n```js\n// handler_code\nasync (input) => {\n const params = new URLSearchParams()\n if (input.state) params.set(\'state\', input.state)\n if (input.labels) params.set(\'labels\', input.labels)\n if (input.per_page) params.set(\'per_page\', String(input.per_page))\n const query = params.toString() ? `?${params.toString()}` : \'\'\n const res = await integration.fetch(`/repos/${input.owner}/${input.repo}/issues${query}`)\n return await res.json()\n}\n```\n\n```json\n// input_schema\n{\n "type": "object",\n "properties": {\n "owner": { "type": "string" },\n "repo": { "type": "string" },\n "state": { "type": "string", "enum": ["open", "closed", "all"] },\n "labels": { "type": "string", "description": "Comma-separated label names" },\n "per_page": { "type": "number" }\n },\n "required": ["owner", "repo"],\n "additionalProperties": false\n}\n```\n\n---\n\n### Example 4 \u2014 GitHub: create an issue (write)\n\n**What it does**: opens a new GitHub issue on a repo.\n\n```js\n// handler_code\nasync (input) => {\n const res = await integration.fetch(`/repos/${input.owner}/${input.repo}/issues`, {\n method: \'POST\',\n body: {\n title: input.title,\n body: input.body,\n assignees: input.assignees,\n labels: input.labels,\n },\n })\n const issue = await res.json()\n console.log(\'Created issue #\' + issue.number + \':\', issue.title)\n return { number: issue.number, url: issue.html_url, title: issue.title }\n}\n```\n\n```json\n// input_schema\n{\n "type": "object",\n "properties": {\n "owner": { "type": "string" },\n "repo": { "type": "string" },\n "title": { "type": "string" },\n "body": { "type": "string" },\n "assignees": { "type": "array", "items": { "type": "string" } },\n "labels": { "type": "array", "items": { "type": "string" } }\n },\n "required": ["owner", "repo", "title"],\n "additionalProperties": false\n}\n```\n\n---\n\n### Example 5 \u2014 Notion: query a database (read)\n\n**What it does**: runs a filtered/sorted query against a Notion database and returns the matching pages.\n\n```js\n// handler_code\nasync (input) => {\n const res = await integration.fetch(`/databases/${encodeURIComponent(input.database_id)}/query`, {\n method: \'POST\',\n body: {\n filter: input.filter || undefined,\n sorts: input.sorts || undefined,\n page_size: input.page_size || undefined,\n },\n })\n return await res.json()\n}\n```\n\n```json\n// input_schema\n{\n "type": "object",\n "properties": {\n "database_id": { "type": "string" },\n "filter": { "type": "object", "description": "Notion filter object" },\n "sorts": { "type": "array", "items": { "type": "object" } },\n "page_size": { "type": "number", "minimum": 1, "maximum": 100 }\n },\n "required": ["database_id"],\n "additionalProperties": false\n}\n```\n\n---\n\n## Available integrations in this Commandable instance\n\nThe calling system will append a live list of configured integrations (reference IDs + base URLs) below.\n';
20517
+
19355
20518
  function humanize(s) {
19356
20519
  return (s || "").replace(/_/g, " ").split(/\s+/g).filter(Boolean).map((w) => w.length ? `${w[0].toUpperCase()}${w.slice(1).toLowerCase()}` : w).join(" ");
19357
20520
  }
@@ -19398,28 +20561,14 @@ const META_TOOL_NAMES = {
19398
20561
  function normalizeHintMarkdown(value) {
19399
20562
  return value.replace(/\r\n/g, "\n").replace(/\\r\\n/g, "\n").replace(/\\n/g, "\n");
19400
20563
  }
19401
- function buildReadme(filename) {
19402
- return readFileSync(resolveMcpAssetPath(filename), "utf8");
19403
- }
19404
20564
  function buildCommandableReadme(hasBuilderCtx) {
19405
- return hasBuilderCtx ? buildReadme("commandable_readme_create.md") : buildReadme("commandable_readme_dynamic.md");
20565
+ return hasBuilderCtx ? COMMANDABLE_README_CREATE : COMMANDABLE_README_DYNAMIC;
19406
20566
  }
19407
20567
  function buildStaticReadme() {
19408
- return buildReadme("commandable_readme_static.md");
20568
+ return COMMANDABLE_README_STATIC;
19409
20569
  }
19410
20570
  function buildBuilderGuide() {
19411
- return readFileSync(resolveMcpAssetPath("builder_guide.md"), "utf8");
19412
- }
19413
- function resolveMcpAssetPath(filename) {
19414
- const cwd = process.cwd();
19415
- const candidates = [
19416
- fileURLToPath(new URL(`./${filename}`, globalThis._importMeta_.url)),
19417
- resolve$1(cwd, "packages/core/src/mcp", filename),
19418
- resolve$1(cwd, "packages/core/dist/mcp", filename),
19419
- resolve$1(cwd, "node_modules/@commandable/mcp-core/dist/mcp", filename),
19420
- resolve$1(cwd, "app/.output/server/node_modules/@commandable/mcp-core/dist/mcp", filename)
19421
- ];
19422
- return candidates.find((path) => existsSync(path)) || candidates[0];
20571
+ return BUILDER_GUIDE;
19423
20572
  }
19424
20573
  function providerBaseUrl(integration, ctx) {
19425
20574
  var _a, _b;
@@ -20792,142 +21941,142 @@ const assets = {
20792
21941
  "/favicon.ico": {
20793
21942
  "type": "image/vnd.microsoft.icon",
20794
21943
  "etag": "\"10be-n8egyE9tcb7sKGr/pYCaQ4uWqxI\"",
20795
- "mtime": "2026-04-03T13:40:47.696Z",
21944
+ "mtime": "2026-04-05T18:35:56.190Z",
20796
21945
  "size": 4286,
20797
21946
  "path": "../public/favicon.ico"
20798
21947
  },
20799
21948
  "/_fonts/57NSSoFy1VLVs2gqly8Ls9awBnZMFyXGrefpmqvdqmc-zJfbBtpgM4cDmcXBsqZNW79_kFnlpPd62b48glgdydA.woff2": {
20800
21949
  "type": "font/woff2",
20801
21950
  "etag": "\"4b5c-TAo9mx7r3xQs52+HbHcHJ52z8Qo\"",
20802
- "mtime": "2026-04-03T13:40:47.685Z",
21951
+ "mtime": "2026-04-05T18:35:56.183Z",
20803
21952
  "size": 19292,
20804
21953
  "path": "../public/_fonts/57NSSoFy1VLVs2gqly8Ls9awBnZMFyXGrefpmqvdqmc-zJfbBtpgM4cDmcXBsqZNW79_kFnlpPd62b48glgdydA.woff2"
20805
21954
  },
20806
21955
  "/_fonts/8VR2wSMN-3U4NbWAVYXlkRV6hA0jFBXP-0RtL3X7fko-x2gYI4qfmkRdxyQQUPaBZdZdgl1TeVrquF_TxHeM4lM.woff2": {
20807
21956
  "type": "font/woff2",
20808
21957
  "etag": "\"212c-FshXJibFzNhd2HEIMP8C3JR5PYg\"",
20809
- "mtime": "2026-04-03T13:40:47.684Z",
21958
+ "mtime": "2026-04-05T18:35:56.183Z",
20810
21959
  "size": 8492,
20811
21960
  "path": "../public/_fonts/8VR2wSMN-3U4NbWAVYXlkRV6hA0jFBXP-0RtL3X7fko-x2gYI4qfmkRdxyQQUPaBZdZdgl1TeVrquF_TxHeM4lM.woff2"
20812
21961
  },
20813
21962
  "/_fonts/GsKUclqeNLJ96g5AU593ug6yanivOiwjW_7zESNPChw-jHA4tBeM1bjF7LATGUpfBuSTyomIFrWBTzjF7txVYfg.woff2": {
20814
21963
  "type": "font/woff2",
20815
21964
  "etag": "\"680c-mJtsV33lkTAKSmfq5k3lKHSllcU\"",
20816
- "mtime": "2026-04-03T13:40:47.685Z",
21965
+ "mtime": "2026-04-05T18:35:56.183Z",
20817
21966
  "size": 26636,
20818
21967
  "path": "../public/_fonts/GsKUclqeNLJ96g5AU593ug6yanivOiwjW_7zESNPChw-jHA4tBeM1bjF7LATGUpfBuSTyomIFrWBTzjF7txVYfg.woff2"
20819
21968
  },
21969
+ "/_fonts/Ld1FnTo3yTIwDyGfTQ5-Fws9AWsCbKfMvgxduXr7JcY-W25bL8NF1fjpLRSOgJb7RoZPHqGQNwMTM7S9tHVoxx8.woff2": {
21970
+ "type": "font/woff2",
21971
+ "etag": "\"6ec4-8OoFFPZKF1grqmfGVjh5JDE6DOU\"",
21972
+ "mtime": "2026-04-05T18:35:56.184Z",
21973
+ "size": 28356,
21974
+ "path": "../public/_fonts/Ld1FnTo3yTIwDyGfTQ5-Fws9AWsCbKfMvgxduXr7JcY-W25bL8NF1fjpLRSOgJb7RoZPHqGQNwMTM7S9tHVoxx8.woff2"
21975
+ },
20820
21976
  "/_fonts/NdzqRASp2bovDUhQT1IRE_EMqKJ2KYQdTCfFcBvL8yw-KhwZiS86o3fErOe5GGMExHUemmI_dBfaEFxjISZrBd0.woff2": {
20821
21977
  "type": "font/woff2",
20822
21978
  "etag": "\"1d98-cDZfMibtk4T04FTTAmlfhWDpkN0\"",
20823
- "mtime": "2026-04-03T13:40:47.685Z",
21979
+ "mtime": "2026-04-05T18:35:56.183Z",
20824
21980
  "size": 7576,
20825
21981
  "path": "../public/_fonts/NdzqRASp2bovDUhQT1IRE_EMqKJ2KYQdTCfFcBvL8yw-KhwZiS86o3fErOe5GGMExHUemmI_dBfaEFxjISZrBd0.woff2"
20826
21982
  },
20827
21983
  "/_fonts/iTkrULNFJJkTvihIg1Vqi5IODRH_9btXCioVF5l98I8-AndUyau2HR2felA_ra8V2mutQgschhasE5FD1dXGJX8.woff2": {
20828
21984
  "type": "font/woff2",
20829
21985
  "etag": "\"47c4-5xyngHnzzhetUee74tMx9OTgqNQ\"",
20830
- "mtime": "2026-04-03T13:40:47.685Z",
21986
+ "mtime": "2026-04-05T18:35:56.184Z",
20831
21987
  "size": 18372,
20832
21988
  "path": "../public/_fonts/iTkrULNFJJkTvihIg1Vqi5IODRH_9btXCioVF5l98I8-AndUyau2HR2felA_ra8V2mutQgschhasE5FD1dXGJX8.woff2"
20833
21989
  },
20834
- "/_fonts/Ld1FnTo3yTIwDyGfTQ5-Fws9AWsCbKfMvgxduXr7JcY-W25bL8NF1fjpLRSOgJb7RoZPHqGQNwMTM7S9tHVoxx8.woff2": {
20835
- "type": "font/woff2",
20836
- "etag": "\"6ec4-8OoFFPZKF1grqmfGVjh5JDE6DOU\"",
20837
- "mtime": "2026-04-03T13:40:47.685Z",
20838
- "size": 28356,
20839
- "path": "../public/_fonts/Ld1FnTo3yTIwDyGfTQ5-Fws9AWsCbKfMvgxduXr7JcY-W25bL8NF1fjpLRSOgJb7RoZPHqGQNwMTM7S9tHVoxx8.woff2"
20840
- },
20841
- "/_nuxt/CBR-0oRi.js": {
21990
+ "/_nuxt/BD6mASiY.js": {
20842
21991
  "type": "text/javascript; charset=utf-8",
20843
- "etag": "\"e99-j2x/BCjv3PTe7BrVl7sYKyyD/Wo\"",
20844
- "mtime": "2026-04-03T13:40:47.691Z",
20845
- "size": 3737,
20846
- "path": "../public/_nuxt/CBR-0oRi.js"
21992
+ "etag": "\"ab-ScyLcA/4r5aOxEv1YY+kqXazCHI\"",
21993
+ "mtime": "2026-04-05T18:35:56.186Z",
21994
+ "size": 171,
21995
+ "path": "../public/_nuxt/BD6mASiY.js"
20847
21996
  },
20848
- "/_nuxt/CYsCQznM.js": {
21997
+ "/_nuxt/CjAs3eBq.js": {
20849
21998
  "type": "text/javascript; charset=utf-8",
20850
- "etag": "\"ed7d-uZuHYYM0uLXi5Ja9+gXRmd3Dep0\"",
20851
- "mtime": "2026-04-03T13:40:47.691Z",
20852
- "size": 60797,
20853
- "path": "../public/_nuxt/CYsCQznM.js"
21999
+ "etag": "\"1df7-cTFKdH9K34T9NixeUm/CLQ8lWUc\"",
22000
+ "mtime": "2026-04-05T18:35:56.186Z",
22001
+ "size": 7671,
22002
+ "path": "../public/_nuxt/CjAs3eBq.js"
20854
22003
  },
20855
- "/_nuxt/DKO0MviJ.js": {
22004
+ "/_nuxt/D9wFDhac.js": {
20856
22005
  "type": "text/javascript; charset=utf-8",
20857
- "etag": "\"1def-sUbE63urWOutYTd5E0BpBO5Cqm0\"",
20858
- "mtime": "2026-04-03T13:40:47.690Z",
20859
- "size": 7663,
20860
- "path": "../public/_nuxt/DKO0MviJ.js"
22006
+ "etag": "\"e99-sUFV1wmMOK2XGfzDXJyP2NA8TG4\"",
22007
+ "mtime": "2026-04-05T18:35:56.186Z",
22008
+ "size": 3737,
22009
+ "path": "../public/_nuxt/D9wFDhac.js"
20861
22010
  },
20862
- "/_nuxt/DOIzs5t4.js": {
22011
+ "/_nuxt/DSWYWRXT.js": {
20863
22012
  "type": "text/javascript; charset=utf-8",
20864
- "etag": "\"d7b-CT3xee8iAqLyujrUtE7O+b/KCnk\"",
20865
- "mtime": "2026-04-03T13:40:47.691Z",
20866
- "size": 3451,
20867
- "path": "../public/_nuxt/DOIzs5t4.js"
22013
+ "etag": "\"10875-8b+YwIvP6QkcBFnHXqxd+WeZ05o\"",
22014
+ "mtime": "2026-04-05T18:35:56.186Z",
22015
+ "size": 67701,
22016
+ "path": "../public/_nuxt/DSWYWRXT.js"
20868
22017
  },
20869
- "/_nuxt/KqToXREt.js": {
22018
+ "/_nuxt/DRfk9W3W.js": {
20870
22019
  "type": "text/javascript; charset=utf-8",
20871
- "etag": "\"194dc-Vt4cT+S2uiwibwQ6t5ll4DMlKDM\"",
20872
- "mtime": "2026-04-03T13:40:47.692Z",
22020
+ "etag": "\"194dc-Oj5Ixz12+pq4yqDtF/N+YAPzoWw\"",
22021
+ "mtime": "2026-04-05T18:35:56.186Z",
20873
22022
  "size": 103644,
20874
- "path": "../public/_nuxt/KqToXREt.js"
22023
+ "path": "../public/_nuxt/DRfk9W3W.js"
20875
22024
  },
20876
- "/_nuxt/Sdkz9rYy.js": {
22025
+ "/_nuxt/VvnbcAzZ.js": {
20877
22026
  "type": "text/javascript; charset=utf-8",
20878
- "etag": "\"ab-0m54t2mXSa0okgFzEIz3bVdrz94\"",
20879
- "mtime": "2026-04-03T13:40:47.691Z",
20880
- "size": 171,
20881
- "path": "../public/_nuxt/Sdkz9rYy.js"
22027
+ "etag": "\"d7b-hU4O5jppM7Ou3kZAYy3iYXlgoa8\"",
22028
+ "mtime": "2026-04-05T18:35:56.186Z",
22029
+ "size": 3451,
22030
+ "path": "../public/_nuxt/VvnbcAzZ.js"
20882
22031
  },
20883
22032
  "/_nuxt/_id_.DhlLK-mY.css": {
20884
22033
  "type": "text/css; charset=utf-8",
20885
22034
  "etag": "\"2f4-xtV37kE566jU74wpZnFHA29RoAY\"",
20886
- "mtime": "2026-04-03T13:40:47.691Z",
22035
+ "mtime": "2026-04-05T18:35:56.186Z",
20887
22036
  "size": 756,
20888
22037
  "path": "../public/_nuxt/_id_.DhlLK-mY.css"
20889
22038
  },
20890
- "/_nuxt/entry.Y3mA4bzA.css": {
20891
- "type": "text/css; charset=utf-8",
20892
- "etag": "\"2d46b-zfrD3Ny9WW6qm4fCXAfX5eIAxPA\"",
20893
- "mtime": "2026-04-03T13:40:47.692Z",
20894
- "size": 185451,
20895
- "path": "../public/_nuxt/entry.Y3mA4bzA.css"
20896
- },
20897
22039
  "/_nuxt/error-404.C7fg894-.css": {
20898
22040
  "type": "text/css; charset=utf-8",
20899
22041
  "etag": "\"97e-fiQ3o7A11L9BuXRBr0GJldkx0AU\"",
20900
- "mtime": "2026-04-03T13:40:47.692Z",
22042
+ "mtime": "2026-04-05T18:35:56.187Z",
20901
22043
  "size": 2430,
20902
22044
  "path": "../public/_nuxt/error-404.C7fg894-.css"
20903
22045
  },
20904
22046
  "/_nuxt/error-500.DjUK_N2Y.css": {
20905
22047
  "type": "text/css; charset=utf-8",
20906
22048
  "etag": "\"773-Qf61bSDos4KtmZDaA06FmZyUYNo\"",
20907
- "mtime": "2026-04-03T13:40:47.692Z",
22049
+ "mtime": "2026-04-05T18:35:56.187Z",
20908
22050
  "size": 1907,
20909
22051
  "path": "../public/_nuxt/error-500.DjUK_N2Y.css"
20910
22052
  },
20911
- "/_nuxt/Ctwv5nxD.js": {
20912
- "type": "text/javascript; charset=utf-8",
20913
- "etag": "\"66cba-QjvxwE3w1y1M86HY4SQQ3d+mH/0\"",
20914
- "mtime": "2026-04-03T13:40:47.693Z",
20915
- "size": 421050,
20916
- "path": "../public/_nuxt/Ctwv5nxD.js"
20917
- },
20918
- "/_nuxt/builds/meta/3380bacd-d6f5-40cf-8376-35445d2f246f.json": {
20919
- "type": "application/json",
20920
- "etag": "\"58-PvMtM40acZc5iIxMZqVNxK2P/F8\"",
20921
- "mtime": "2026-04-03T13:40:47.679Z",
20922
- "size": 88,
20923
- "path": "../public/_nuxt/builds/meta/3380bacd-d6f5-40cf-8376-35445d2f246f.json"
20924
- },
20925
22053
  "/_nuxt/builds/latest.json": {
20926
22054
  "type": "application/json",
20927
- "etag": "\"47-JpEyZuDkkiCTLQRGUxMTuxKjPSk\"",
20928
- "mtime": "2026-04-03T13:40:47.683Z",
22055
+ "etag": "\"47-GZLcjWZaQqnb3MWtaAhgJPSJq0w\"",
22056
+ "mtime": "2026-04-05T18:35:56.182Z",
20929
22057
  "size": 71,
20930
22058
  "path": "../public/_nuxt/builds/latest.json"
22059
+ },
22060
+ "/_nuxt/builds/meta/0857a55b-f766-4fe6-86be-9bd9d857861a.json": {
22061
+ "type": "application/json",
22062
+ "etag": "\"58-/dM+mpaUFnmvLLmrgwHgZBuTtQg\"",
22063
+ "mtime": "2026-04-05T18:35:56.180Z",
22064
+ "size": 88,
22065
+ "path": "../public/_nuxt/builds/meta/0857a55b-f766-4fe6-86be-9bd9d857861a.json"
22066
+ },
22067
+ "/_nuxt/BUmYUDQu.js": {
22068
+ "type": "text/javascript; charset=utf-8",
22069
+ "etag": "\"66cba-d/pdEXVc78H3VlgFN3kVzKpvD1Q\"",
22070
+ "mtime": "2026-04-05T18:35:56.186Z",
22071
+ "size": 421050,
22072
+ "path": "../public/_nuxt/BUmYUDQu.js"
22073
+ },
22074
+ "/_nuxt/entry.Y3mA4bzA.css": {
22075
+ "type": "text/css; charset=utf-8",
22076
+ "etag": "\"2d46b-zfrD3Ny9WW6qm4fCXAfX5eIAxPA\"",
22077
+ "mtime": "2026-04-05T18:35:56.187Z",
22078
+ "size": 185451,
22079
+ "path": "../public/_nuxt/entry.Y3mA4bzA.css"
20931
22080
  }
20932
22081
  };
20933
22082
 
@@ -21410,6 +22559,64 @@ async function handleMcpHttp(args) {
21410
22559
  return { kind: "handled" };
21411
22560
  }
21412
22561
 
22562
+ async function runVariantConfigListHandler(params) {
22563
+ var _a, _b, _c, _d, _e;
22564
+ const manifest = loadIntegrationManifest(params.forIntegrationType);
22565
+ if (!manifest)
22566
+ throw createError$1({ statusCode: 404, statusMessage: "Variant integration type not found" });
22567
+ const variantConfig = (_a = manifest.variantConfig) == null ? void 0 : _a.find((item) => item.key === params.key);
22568
+ if (!variantConfig)
22569
+ throw createError$1({ statusCode: 404, statusMessage: `Variant config '${params.key}' not found` });
22570
+ if (!variantConfig.listHandler)
22571
+ throw createError$1({ statusCode: 400, statusMessage: `Variant config '${params.key}' has no list handler` });
22572
+ const db = await getDb();
22573
+ const integration = await getIntegrationById(db, params.integrationId);
22574
+ if (!integration)
22575
+ throw createError$1({ statusCode: 404, statusMessage: "Integration not found" });
22576
+ const spaceId = (_b = integration.spaceId) != null ? _b : "local";
22577
+ const typeConfig = await findIntegrationTypeConfig({
22578
+ db,
22579
+ spaceId,
22580
+ typeSlug: integration.type
22581
+ });
22582
+ const proxy = new IntegrationProxy({
22583
+ credentialStore: new SqlCredentialStore(db, getOrCreateEncryptionSecret()),
22584
+ integrationTypeConfigsRef: typeConfig ? { current: [typeConfig] } : void 0
22585
+ });
22586
+ const getIntegration = createGetIntegration([integration], proxy);
22587
+ const wrappedHandler = `async (config) => {
22588
+ const integration = getIntegration('${integration.id}');
22589
+ const __handler = ${variantConfig.listHandler};
22590
+ const __config = (config && typeof config === 'object' && !Array.isArray(config)) ? config : {};
22591
+ return await __handler(__config);
22592
+ }`;
22593
+ const runner = createSafeHandlerFromString(wrappedHandler, getIntegration);
22594
+ const result = await runner((_c = params.config) != null ? _c : {});
22595
+ if (!result.success) {
22596
+ const innerStatusCode = typeof ((_d = result.result) == null ? void 0 : _d.statusCode) === "number" ? result.result.statusCode : 500;
22597
+ const innerMessage = typeof ((_e = result.result) == null ? void 0 : _e.message) === "string" && result.result.message.trim() ? result.result.message.trim() : "Failed to load variant config options";
22598
+ throw createError$1({ statusCode: innerStatusCode, statusMessage: innerMessage, data: result.logs });
22599
+ }
22600
+ if (!Array.isArray(result.result))
22601
+ throw createError$1({ statusCode: 502, statusMessage: "Variant config list handler must return an array" });
22602
+ const options = result.result.map((item) => {
22603
+ var _a2, _b2;
22604
+ if (!item || typeof item !== "object")
22605
+ return null;
22606
+ const id = "id" in item ? String((_a2 = item.id) != null ? _a2 : "") : "";
22607
+ const name = "name" in item ? String((_b2 = item.name) != null ? _b2 : "") : "";
22608
+ if (!id || !name)
22609
+ return null;
22610
+ return { id, name };
22611
+ }).filter(Boolean);
22612
+ return {
22613
+ label: variantConfig.label,
22614
+ selectionMode: variantConfig.selectionMode,
22615
+ options,
22616
+ logs: result.logs
22617
+ };
22618
+ }
22619
+
21413
22620
  const collections = {
21414
22621
  'lucide': () => import('../_/icons.mjs').then(m => m.default),
21415
22622
  'simple-icons': () => import('../_/icons2.mjs').then(m => m.default),
@@ -21480,6 +22687,7 @@ const _lazy_tZWrQN = () => import('../routes/api/integrations/_id/tools.delete.m
21480
22687
  const _lazy_zaazLC = () => import('../routes/api/integrations/_id/tools.get.mjs');
21481
22688
  const _lazy_9iz_Is = () => import('../routes/api/integrations/_id/toolsets.get.mjs');
21482
22689
  const _lazy_Klwsdp = () => import('../routes/api/integrations/_id/toolsets.post.mjs');
22690
+ const _lazy_Wj3Kn6 = () => import('../routes/api/integrations/_id/variant-options.post.mjs');
21483
22691
  const _lazy_FcbHxS = () => import('../routes/api/index.get.mjs');
21484
22692
  const _lazy_0b9jj9 = () => import('../routes/api/index.post.mjs');
21485
22693
  const _lazy_g_ZIqQ = () => import('../routes/health.get.mjs');
@@ -21505,6 +22713,7 @@ const handlers = [
21505
22713
  { route: '/api/integrations/:id/tools', handler: _lazy_zaazLC, lazy: true, middleware: false, method: "get" },
21506
22714
  { route: '/api/integrations/:id/toolsets', handler: _lazy_9iz_Is, lazy: true, middleware: false, method: "get" },
21507
22715
  { route: '/api/integrations/:id/toolsets', handler: _lazy_Klwsdp, lazy: true, middleware: false, method: "post" },
22716
+ { route: '/api/integrations/:id/variant-options', handler: _lazy_Wj3Kn6, lazy: true, middleware: false, method: "post" },
21508
22717
  { route: '/api/integrations', handler: _lazy_FcbHxS, lazy: true, middleware: false, method: "get" },
21509
22718
  { route: '/api/integrations', handler: _lazy_0b9jj9, lazy: true, middleware: false, method: "post" },
21510
22719
  { route: '/health', handler: _lazy_g_ZIqQ, lazy: true, middleware: false, method: "get" },
@@ -21930,5 +23139,5 @@ trapUnhandledNodeErrors();
21930
23139
  setupGracefulShutdown(listener, nitroApp);
21931
23140
  const nodeServer = {};
21932
23141
 
21933
- export { getContext as $, setResponseStatus as A, buildAssetsURL as B, useRuntimeConfig as C, getResponseStatusText as D, getResponseStatus as E, defineRenderHandler as F, publicAssetsURL as G, getQuery as H, IntegrationProxy as I, destr as J, getRouteRules as K, joinURL as L, useNitroApp as M, serialize$1 as N, klona as O, defu as P, hasProtocol as Q, isScriptProtocol as R, SqlCredentialStore as S, parseQuery as T, defuFn as U, withQuery as V, sanitizeStatusCode as W, parseURL as X, encodePath as Y, decodePath as Z, isEqual as _, loadIntegrationCredentialConfig as a, withTrailingSlash as a0, withoutTrailingSlash as a1, $fetch$1 as a2, baseURL as a3, createHooks as a4, executeAsync as a5, hash$1 as a6, nodeServer as a7, getRouterParam as b, createError$1 as c, defineEventHandler as d, loadIntegrationToolList as e, loadIntegrationToolsets as f, getFileProcessingCapability as g, getDb as h, getIntegrationById as i, deleteToolDefinitionsForIntegration as j, getOrCreateEncryptionSecret as k, listIntegrationCatalog as l, deleteIntegrationById as m, listIntegrations as n, deleteIntegrationTypeConfig as o, findIntegrationTypeConfig as p, updateIntegrationHealth as q, refreshMcpState as r, readBody as s, checkIntegrationHealth as t, updateIntegrationCredentials as u, upsertIntegration as v, deleteToolDefinitionByName as w, applyFileProcessingCapabilityToIntegration as x, listToolDefinitionsForIntegration as y, handleMcpHttp as z };
23142
+ export { isEqual as $, handleMcpHttp as A, setResponseStatus as B, buildAssetsURL as C, useRuntimeConfig as D, getResponseStatusText as E, getResponseStatus as F, defineRenderHandler as G, publicAssetsURL as H, IntegrationProxy as I, getQuery as J, destr as K, getRouteRules as L, joinURL as M, useNitroApp as N, serialize$1 as O, klona as P, defu as Q, hasProtocol as R, SqlCredentialStore as S, isScriptProtocol as T, parseQuery as U, defuFn as V, withQuery as W, sanitizeStatusCode as X, parseURL as Y, encodePath as Z, decodePath as _, loadIntegrationCredentialConfig as a, getContext as a0, withTrailingSlash as a1, withoutTrailingSlash as a2, $fetch$1 as a3, baseURL as a4, createHooks as a5, executeAsync as a6, hash$1 as a7, nodeServer as a8, getRouterParam as b, createError$1 as c, defineEventHandler as d, loadIntegrationToolList as e, loadIntegrationToolsets as f, getFileProcessingCapability as g, getDb as h, getIntegrationById as i, deleteToolDefinitionsForIntegration as j, getOrCreateEncryptionSecret as k, listIntegrationCatalog as l, deleteIntegrationById as m, listIntegrations as n, deleteIntegrationTypeConfig as o, findIntegrationTypeConfig as p, updateIntegrationHealth as q, refreshMcpState as r, readBody as s, checkIntegrationHealth as t, updateIntegrationCredentials as u, upsertIntegration as v, deleteToolDefinitionByName as w, applyFileProcessingCapabilityToIntegration as x, listToolDefinitionsForIntegration as y, runVariantConfigListHandler as z };
21934
23143
  //# sourceMappingURL=nitro.mjs.map