callman-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/LICENSE +21 -0
  3. package/README.md +203 -0
  4. package/dist/client/api.d.ts +109 -0
  5. package/dist/client/api.d.ts.map +1 -0
  6. package/dist/client/api.js +180 -0
  7. package/dist/client/api.js.map +1 -0
  8. package/dist/client/errors.d.ts +27 -0
  9. package/dist/client/errors.d.ts.map +1 -0
  10. package/dist/client/errors.js +98 -0
  11. package/dist/client/errors.js.map +1 -0
  12. package/dist/client/http.d.ts +34 -0
  13. package/dist/client/http.d.ts.map +1 -0
  14. package/dist/client/http.js +121 -0
  15. package/dist/client/http.js.map +1 -0
  16. package/dist/client/types.d.ts +327 -0
  17. package/dist/client/types.d.ts.map +1 -0
  18. package/dist/client/types.js +5 -0
  19. package/dist/client/types.js.map +1 -0
  20. package/dist/config.d.ts +20 -0
  21. package/dist/config.d.ts.map +1 -0
  22. package/dist/config.js +69 -0
  23. package/dist/config.js.map +1 -0
  24. package/dist/context.d.ts +35 -0
  25. package/dist/context.d.ts.map +1 -0
  26. package/dist/context.js +91 -0
  27. package/dist/context.js.map +1 -0
  28. package/dist/domain/diagram/build.d.ts +260 -0
  29. package/dist/domain/diagram/build.d.ts.map +1 -0
  30. package/dist/domain/diagram/build.js +160 -0
  31. package/dist/domain/diagram/build.js.map +1 -0
  32. package/dist/domain/diagram/layout.d.ts +17 -0
  33. package/dist/domain/diagram/layout.d.ts.map +1 -0
  34. package/dist/domain/diagram/layout.js +61 -0
  35. package/dist/domain/diagram/layout.js.map +1 -0
  36. package/dist/domain/diagram/patch.d.ts +330 -0
  37. package/dist/domain/diagram/patch.d.ts.map +1 -0
  38. package/dist/domain/diagram/patch.js +176 -0
  39. package/dist/domain/diagram/patch.js.map +1 -0
  40. package/dist/domain/diagram/summarize.d.ts +41 -0
  41. package/dist/domain/diagram/summarize.d.ts.map +1 -0
  42. package/dist/domain/diagram/summarize.js +47 -0
  43. package/dist/domain/diagram/summarize.js.map +1 -0
  44. package/dist/domain/importDetect.d.ts +6 -0
  45. package/dist/domain/importDetect.d.ts.map +1 -0
  46. package/dist/domain/importDetect.js +32 -0
  47. package/dist/domain/importDetect.js.map +1 -0
  48. package/dist/domain/requestShape.d.ts +796 -0
  49. package/dist/domain/requestShape.d.ts.map +1 -0
  50. package/dist/domain/requestShape.js +250 -0
  51. package/dist/domain/requestShape.js.map +1 -0
  52. package/dist/domain/resolve.d.ts +30 -0
  53. package/dist/domain/resolve.d.ts.map +1 -0
  54. package/dist/domain/resolve.js +56 -0
  55. package/dist/domain/resolve.js.map +1 -0
  56. package/dist/domain/scenario/build.d.ts +270 -0
  57. package/dist/domain/scenario/build.d.ts.map +1 -0
  58. package/dist/domain/scenario/build.js +135 -0
  59. package/dist/domain/scenario/build.js.map +1 -0
  60. package/dist/domain/scenario/summarize.d.ts +206 -0
  61. package/dist/domain/scenario/summarize.d.ts.map +1 -0
  62. package/dist/domain/scenario/summarize.js +138 -0
  63. package/dist/domain/scenario/summarize.js.map +1 -0
  64. package/dist/index.d.ts +3 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +142 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/lib/cache.d.ts +12 -0
  69. package/dist/lib/cache.d.ts.map +1 -0
  70. package/dist/lib/cache.js +40 -0
  71. package/dist/lib/cache.js.map +1 -0
  72. package/dist/lib/ids.d.ts +5 -0
  73. package/dist/lib/ids.d.ts.map +1 -0
  74. package/dist/lib/ids.js +19 -0
  75. package/dist/lib/ids.js.map +1 -0
  76. package/dist/lib/log.d.ts +10 -0
  77. package/dist/lib/log.d.ts.map +1 -0
  78. package/dist/lib/log.js +25 -0
  79. package/dist/lib/log.js.map +1 -0
  80. package/dist/lib/mask.d.ts +24 -0
  81. package/dist/lib/mask.d.ts.map +1 -0
  82. package/dist/lib/mask.js +63 -0
  83. package/dist/lib/mask.js.map +1 -0
  84. package/dist/lib/pagination.d.ts +21 -0
  85. package/dist/lib/pagination.d.ts.map +1 -0
  86. package/dist/lib/pagination.js +40 -0
  87. package/dist/lib/pagination.js.map +1 -0
  88. package/dist/lib/truncate.d.ts +25 -0
  89. package/dist/lib/truncate.d.ts.map +1 -0
  90. package/dist/lib/truncate.js +45 -0
  91. package/dist/lib/truncate.js.map +1 -0
  92. package/dist/main.d.ts +9 -0
  93. package/dist/main.d.ts.map +1 -0
  94. package/dist/main.js +12 -0
  95. package/dist/main.js.map +1 -0
  96. package/dist/prompts/index.d.ts +4 -0
  97. package/dist/prompts/index.d.ts.map +1 -0
  98. package/dist/prompts/index.js +72 -0
  99. package/dist/prompts/index.js.map +1 -0
  100. package/dist/resources/docs/diagramSchema.d.ts +2 -0
  101. package/dist/resources/docs/diagramSchema.d.ts.map +1 -0
  102. package/dist/resources/docs/diagramSchema.js +65 -0
  103. package/dist/resources/docs/diagramSchema.js.map +1 -0
  104. package/dist/resources/docs/overview.d.ts +2 -0
  105. package/dist/resources/docs/overview.d.ts.map +1 -0
  106. package/dist/resources/docs/overview.js +46 -0
  107. package/dist/resources/docs/overview.js.map +1 -0
  108. package/dist/resources/docs/requestSchema.d.ts +2 -0
  109. package/dist/resources/docs/requestSchema.d.ts.map +1 -0
  110. package/dist/resources/docs/requestSchema.js +70 -0
  111. package/dist/resources/docs/requestSchema.js.map +1 -0
  112. package/dist/resources/generated/aiPacks.d.ts +3 -0
  113. package/dist/resources/generated/aiPacks.d.ts.map +1 -0
  114. package/dist/resources/generated/aiPacks.js +11 -0
  115. package/dist/resources/generated/aiPacks.js.map +1 -0
  116. package/dist/resources/index.d.ts +4 -0
  117. package/dist/resources/index.d.ts.map +1 -0
  118. package/dist/resources/index.js +114 -0
  119. package/dist/resources/index.js.map +1 -0
  120. package/dist/run/executeCollection.d.ts +19 -0
  121. package/dist/run/executeCollection.d.ts.map +1 -0
  122. package/dist/run/executeCollection.js +89 -0
  123. package/dist/run/executeCollection.js.map +1 -0
  124. package/dist/run/loadBundle.d.ts +9 -0
  125. package/dist/run/loadBundle.d.ts.map +1 -0
  126. package/dist/run/loadBundle.js +242 -0
  127. package/dist/run/loadBundle.js.map +1 -0
  128. package/dist/run/resolveTemplate.d.ts +2 -0
  129. package/dist/run/resolveTemplate.d.ts.map +1 -0
  130. package/dist/run/resolveTemplate.js +12 -0
  131. package/dist/run/resolveTemplate.js.map +1 -0
  132. package/dist/run/summarize.d.ts +73 -0
  133. package/dist/run/summarize.d.ts.map +1 -0
  134. package/dist/run/summarize.js +69 -0
  135. package/dist/run/summarize.js.map +1 -0
  136. package/dist/run/types.d.ts +46 -0
  137. package/dist/run/types.d.ts.map +1 -0
  138. package/dist/run/types.js +2 -0
  139. package/dist/run/types.js.map +1 -0
  140. package/dist/server.d.ts +23 -0
  141. package/dist/server.d.ts.map +1 -0
  142. package/dist/server.js +25 -0
  143. package/dist/server.js.map +1 -0
  144. package/dist/tools/catalog.d.ts +18 -0
  145. package/dist/tools/catalog.d.ts.map +1 -0
  146. package/dist/tools/catalog.js +66 -0
  147. package/dist/tools/catalog.js.map +1 -0
  148. package/dist/tools/collections.d.ts +4 -0
  149. package/dist/tools/collections.d.ts.map +1 -0
  150. package/dist/tools/collections.js +201 -0
  151. package/dist/tools/collections.js.map +1 -0
  152. package/dist/tools/diagrams.d.ts +4 -0
  153. package/dist/tools/diagrams.d.ts.map +1 -0
  154. package/dist/tools/diagrams.js +226 -0
  155. package/dist/tools/diagrams.js.map +1 -0
  156. package/dist/tools/environments.d.ts +4 -0
  157. package/dist/tools/environments.d.ts.map +1 -0
  158. package/dist/tools/environments.js +150 -0
  159. package/dist/tools/environments.js.map +1 -0
  160. package/dist/tools/import.d.ts +6 -0
  161. package/dist/tools/import.d.ts.map +1 -0
  162. package/dist/tools/import.js +144 -0
  163. package/dist/tools/import.js.map +1 -0
  164. package/dist/tools/index.d.ts +5 -0
  165. package/dist/tools/index.d.ts.map +1 -0
  166. package/dist/tools/index.js +26 -0
  167. package/dist/tools/index.js.map +1 -0
  168. package/dist/tools/lookups.d.ts +33 -0
  169. package/dist/tools/lookups.d.ts.map +1 -0
  170. package/dist/tools/lookups.js +132 -0
  171. package/dist/tools/lookups.js.map +1 -0
  172. package/dist/tools/meta.d.ts +4 -0
  173. package/dist/tools/meta.d.ts.map +1 -0
  174. package/dist/tools/meta.js +78 -0
  175. package/dist/tools/meta.js.map +1 -0
  176. package/dist/tools/requests.d.ts +4 -0
  177. package/dist/tools/requests.d.ts.map +1 -0
  178. package/dist/tools/requests.js +247 -0
  179. package/dist/tools/requests.js.map +1 -0
  180. package/dist/tools/run.d.ts +4 -0
  181. package/dist/tools/run.d.ts.map +1 -0
  182. package/dist/tools/run.js +167 -0
  183. package/dist/tools/run.js.map +1 -0
  184. package/dist/tools/scenarios.d.ts +4 -0
  185. package/dist/tools/scenarios.d.ts.map +1 -0
  186. package/dist/tools/scenarios.js +242 -0
  187. package/dist/tools/scenarios.js.map +1 -0
  188. package/dist/tools/shared.d.ts +20 -0
  189. package/dist/tools/shared.d.ts.map +1 -0
  190. package/dist/tools/shared.js +74 -0
  191. package/dist/tools/shared.js.map +1 -0
  192. package/dist/tools/workspaces.d.ts +4 -0
  193. package/dist/tools/workspaces.d.ts.map +1 -0
  194. package/dist/tools/workspaces.js +80 -0
  195. package/dist/tools/workspaces.js.map +1 -0
  196. package/dist-cjs/client/api.js +183 -0
  197. package/dist-cjs/client/errors.js +104 -0
  198. package/dist-cjs/client/http.js +124 -0
  199. package/dist-cjs/client/types.js +5 -0
  200. package/dist-cjs/config.js +73 -0
  201. package/dist-cjs/context.js +94 -0
  202. package/dist-cjs/domain/diagram/build.js +164 -0
  203. package/dist-cjs/domain/diagram/layout.js +98 -0
  204. package/dist-cjs/domain/diagram/patch.js +179 -0
  205. package/dist-cjs/domain/diagram/summarize.js +52 -0
  206. package/dist-cjs/domain/importDetect.js +40 -0
  207. package/dist-cjs/domain/requestShape.js +260 -0
  208. package/dist-cjs/domain/resolve.js +63 -0
  209. package/dist-cjs/domain/scenario/build.js +140 -0
  210. package/dist-cjs/domain/scenario/summarize.js +144 -0
  211. package/dist-cjs/lib/cache.js +43 -0
  212. package/dist-cjs/lib/ids.js +24 -0
  213. package/dist-cjs/lib/log.js +28 -0
  214. package/dist-cjs/lib/mask.js +72 -0
  215. package/dist-cjs/lib/pagination.js +48 -0
  216. package/dist-cjs/lib/truncate.js +52 -0
  217. package/dist-cjs/main.js +31 -0
  218. package/dist-cjs/package.json +3 -0
  219. package/dist-cjs/prompts/index.js +75 -0
  220. package/dist-cjs/resources/docs/diagramSchema.js +67 -0
  221. package/dist-cjs/resources/docs/overview.js +48 -0
  222. package/dist-cjs/resources/docs/requestSchema.js +72 -0
  223. package/dist-cjs/resources/generated/aiPacks.js +13 -0
  224. package/dist-cjs/resources/index.js +117 -0
  225. package/dist-cjs/run/executeCollection.js +93 -0
  226. package/dist-cjs/run/loadBundle.js +246 -0
  227. package/dist-cjs/run/resolveTemplate.js +15 -0
  228. package/dist-cjs/run/summarize.js +73 -0
  229. package/dist-cjs/run/types.js +2 -0
  230. package/dist-cjs/server.js +28 -0
  231. package/dist-cjs/tools/catalog.js +69 -0
  232. package/dist-cjs/tools/collections.js +204 -0
  233. package/dist-cjs/tools/diagrams.js +229 -0
  234. package/dist-cjs/tools/environments.js +153 -0
  235. package/dist-cjs/tools/import.js +147 -0
  236. package/dist-cjs/tools/index.js +31 -0
  237. package/dist-cjs/tools/lookups.js +149 -0
  238. package/dist-cjs/tools/meta.js +81 -0
  239. package/dist-cjs/tools/requests.js +250 -0
  240. package/dist-cjs/tools/run.js +203 -0
  241. package/dist-cjs/tools/scenarios.js +245 -0
  242. package/dist-cjs/tools/shared.js +81 -0
  243. package/dist-cjs/tools/workspaces.js +83 -0
  244. package/package.json +80 -0
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AI_PACKS = exports.AI_PACKS_CORE_VERSION = void 0;
4
+ // GENERATED by scripts/build-static-resources.mjs from callman-core@1.28.0 ai-packs — do not edit.
5
+ exports.AI_PACKS_CORE_VERSION = "1.28.0";
6
+ exports.AI_PACKS = {
7
+ "db-queries": "<!-- GENERATED FILE — do not edit by hand. Source: callman_core (npm run ai:packs). -->\n\n# Callman data access from scripts (`pm.db.query` / `pm.redis.command`)\n\n`pm.db.query({ connectionId, query })` — ALWAYS `await`. `query` is coerced to a string, `{{tokens}}` are resolved, then dispatched by the connection's type. `connectionId` may be omitted to use the request's configured DB connection. IMPORTANT: `pm.db.query` does NOT accept a `params`/bind array — inline values (quote strings) or use `{{env.X}}` tokens; SQL placeholders like `$1` or `?` are NOT bound.\n\n## MongoDB\n`query` MUST be a JSON STRING of a command object (use `JSON.stringify`), NOT a `db.coll.find(...)` shell string. The match key is `filter` (a top-level `query` key is rejected).\n\n```js\nconst body = pm.response.json();\nconst res = await pm.db.query({\n connectionId: \"…\",\n query: JSON.stringify({\n collection: \"users\",\n operation: \"findOne\", // find | findOne | aggregate | countDocuments | insertOne | insertMany | updateOne | updateMany | deleteOne | deleteMany | findOneAndUpdate | findOneAndReplace | findOneAndDelete\n filter: { email: body.data.user.email },\n }),\n});\npm.expect(res.rowCount).to.be.above(0); // existence check\n```\n\nPer-operation fields: `find`/`findOne` use `filter` (+ optional `projection`,`sort`,`limit`,`skip`); `aggregate` uses `pipeline` (array); `insertOne` uses `document`, `insertMany` uses `documents`; `updateOne`/`updateMany`/`findOneAndUpdate` use `filter`+`update` (Mongo update operators, e.g. `{ $set: { … } }`); `deleteOne`/`deleteMany` use `filter`; `findOneAndUpdate`/`findOneAndReplace` accept `returnDocument: \"before\"|\"after\"`. A 24-hex string in a filter is auto-coerced to ObjectId (or use `{ \"$oid\": \"…\" }`). Rows are in `res.rows`; write ops surface counts in `res.rowCount`.\n\n## PostgreSQL / MySQL / Oracle (SQL)\n`query` is plain SQL text. Because `pm.db.query` binds no params, inline the value and quote strings yourself (or use a `{{token}}`):\n\n```js\nconst email = pm.response.json().data.user.email;\nconst res = await pm.db.query({\n connectionId: \"…\",\n query: `SELECT id FROM users WHERE email = '${email}'`,\n});\npm.expect(res.rowCount).to.be.above(0);\n```\n\nNotes: a trailing `;` is stripped (except Oracle PL/SQL blocks, which keep it). **Oracle** returns column names UPPERCASE — read `res.rows[0].EMAIL`, not `.email`. `res.rowCount` is the row count for SELECT and the affected-row count for INSERT/UPDATE/DELETE.\n\n## SQL Server (mssql)\nSingle statement per query; a trailing `;` is stripped; `GO` batch separators are REJECTED (client-tool syntax, not T-SQL). Positional params bind as named inputs: `params[0]` → `@p1`, `params[1]` → `@p2`… (scenario db node only — `pm.db.query` has no params).\n\n```sql\nSELECT TOP 1 id, amount FROM dbo.orders WHERE customer_id = @p1 ORDER BY created_at DESC\n```\n\n## Redis (`pm.redis.command`)\n`command` is a single string. Supported commands: **GET, SET, DEL, EXISTS, TTL, HGET, HSET, HGETALL, HDEL, LPUSH, RPUSH, LRANGE, LLEN, SADD, SMEMBERS, SISMEMBER, INCR, DECR, INCRBY, EXPIRE, PERSIST, TYPE, ZADD, ZRANGE, ZSCORE, SCAN**. Quote a value that contains spaces.\n\nStructured replies land in `res.result` as real values: `HGETALL` → object, `LRANGE`/`SMEMBERS`/`ZRANGE` → array, `EXISTS`/`SISMEMBER`/`EXPIRE`/`PERSIST` → boolean; `res.resultText` is the stringified form. `SCAN pattern [count]` is Callman-managed: the cursor loop runs internally (capped at 1000 keys / 100 iterations) and returns `{ keys, count, truncated }` — no raw cursors.\n\n```js\nconst res = await pm.redis.command({ connectionId: \"…\", command: `GET session:${id}` });\npm.expect(res.success).to.be.true;\n// res.result / res.resultText hold the value; res.commandName, res.key are set.\n```\n",
8
+ "diagram-components": "<!-- GENERATED FILE — do not edit by hand. Source: callman_core (npm run ai:packs). -->\n\n# Diagram components and edge notation\n\nA diagram node's `type` MUST be one of the keys below (`callman-core` `DIAGRAM_COMPONENT_CATALOG`). Sizes are the defaults the studio uses; `container` types hold children via `parentId`.\n\n## Edge notation\n\n| Semantic | Meaning | Style tuple |\n| --- | --- | --- |\n| `sync` | Request / response call | dashed=false, strokeWidth=1.5 |\n| `async` | Fire-and-forget, event or callback | dashed=true, dashPattern=\"6 4\", strokeWidth=1.5 |\n| `fallback` | Retry, fallback or optional path | dashed=true, dashPattern=\"1 3\", strokeWidth=1.25 |\n| `bus` | Message bus or stream | dashed=false, strokeWidth=3 |\n\n## Generic (`generic`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `line` | Line | 160×0 | connector, edge, link |\n| `arrow` | Arrow | 160×0 | connector, directed, link |\n| `line.dashed` | Dashed Line | 160×0 | dotted, connector |\n| `rect` | Rectangle | 140×64 | box, card |\n| `square` | Square | 90×90 | |\n| `ellipse` | Ellipse | 140×64 | oval |\n| `circle` | Circle | 90×90 | |\n| `diamond` | Diamond | 140×64 | rhombus |\n| `triangle` | Triangle | 140×64 | |\n| `hexagon` | Hexagon | 140×64 | |\n| `pentagon` | Pentagon | 140×64 | |\n| `octagon` | Octagon | 140×64 | |\n| `parallelogram` | Parallelogram | 140×64 | |\n| `trapezoid` | Trapezoid | 140×64 | |\n| `cylinder` | Cylinder | 140×64 | can, tube |\n| `cloud-shape` | Cloud | 140×64 | |\n| `callout` | Callout | 140×64 | speech, bubble |\n| `text` | Text | 120×36 | |\n| `sticky` | Sticky note | 140×100 | postit, comment |\n| `card` | Card | 140×64 | |\n| `frame` | Frame / Container (container) | 220×160 | group, container, boundary |\n| `pool.horizontal` | Pool (horizontal) (swimlane) | 360×220 | swimlane, lane, container, subsystem |\n| `pool.vertical` | Pool (vertical) (swimlane) | 220×360 | swimlane, lane, container, subsystem |\n| `image` | Image | 140×64 | picture |\n\n## Flowchart (`flowchart`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `flow.process` | Process | 140×64 | step, action |\n| `flow.alt-process` | Alternate Process | 140×64 | |\n| `flow.decision` | Decision | 140×100 | if, branch |\n| `flow.terminator` | Start / End | 130×56 | terminator, begin, stop |\n| `flow.data` | Data (I/O) | 140×64 | input, output, io |\n| `flow.document` | Document | 140×64 | |\n| `flow.multi-document` | Multi-Document | 140×64 | |\n| `flow.predefined` | Predefined Process | 140×64 | subroutine |\n| `flow.manual-input` | Manual Input | 140×64 | |\n| `flow.manual-op` | Manual Operation | 140×64 | |\n| `flow.preparation` | Preparation | 140×64 | |\n| `flow.stored-data` | Stored Data | 140×64 | |\n| `flow.database` | Database | 140×64 | db, store |\n| `flow.display` | Display | 140×64 | |\n| `flow.delay` | Delay | 140×64 | |\n| `flow.merge` | Merge | 140×64 | |\n| `flow.or` | Or | 140×64 | |\n| `flow.connector` | On-page Connector | 48×48 | |\n| `flow.off-page` | Off-page Connector | 140×64 | |\n| `flow.annotation` | Annotation | 140×64 | |\n\n## UML (`uml`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `uml.class` | Class | 140×64 | entity |\n| `uml.abstract` | Abstract Class | 140×64 | |\n| `uml.interface` | Interface | 140×64 | |\n| `uml.enum` | Enum | 140×64 | |\n| `uml.object` | Object | 140×64 | |\n| `uml.package` | Package | 140×64 | |\n| `uml.component` | Component | 140×64 | |\n| `uml.node` | Node / Deployment | 140×64 | |\n| `uml.actor` | Actor | 60×100 | user, role |\n| `uml.usecase` | Use Case | 140×64 | |\n| `uml.boundary` | Boundary | 140×64 | |\n| `uml.control` | Control | 140×64 | |\n| `uml.entity` | Entity | 140×64 | |\n| `uml.state` | State | 140×64 | |\n| `uml.initial` | Initial State | 36×36 | |\n| `uml.final` | Final State | 40×40 | |\n| `uml.decision` | Decision | 60×60 | |\n| `uml.note` | Note / Comment | 140×64 | comment |\n\n## ERD (`erd`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `erd.entity` | Entity | 140×64 | table |\n| `erd.weak-entity` | Weak Entity | 140×64 | |\n| `erd.attribute` | Attribute | 140×64 | |\n| `erd.key-attribute` | Key Attribute | 140×64 | pk, primary key |\n| `erd.multivalued` | Multivalued Attribute | 140×64 | |\n| `erd.derived` | Derived Attribute | 140×64 | |\n| `erd.relationship` | Relationship | 140×64 | |\n| `erd.identifying` | Identifying Relationship | 140×64 | |\n\n## Architecture (`networking`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `net.user` | User / Client | 60×100 | client, person |\n| `net.admin` | Admin | 60×100 | |\n| `net.browser` | Browser | 140×64 | |\n| `net.mobile` | Mobile Device | 90×130 | phone |\n| `net.desktop` | Desktop | 140×64 | |\n| `net.iot` | IoT Device | 140×64 | |\n| `net.server` | Server | 140×64 | |\n| `net.service` | Service | 140×64 | microservice |\n| `net.monolith` | Monolith | 140×64 | |\n| `net.api-gateway` | API Gateway | 140×64 | api, gateway |\n| `net.load-balancer` | Load Balancer | 140×64 | lb |\n| `net.reverse-proxy` | Reverse Proxy | 140×64 | proxy |\n| `net.firewall` | Firewall | 140×64 | waf |\n| `net.router` | Router | 140×64 | |\n| `net.switch` | Switch | 140×64 | |\n| `net.dns` | DNS | 140×64 | |\n| `net.cdn` | CDN | 140×64 | edge |\n| `net.cache` | Cache | 140×64 | |\n| `net.queue` | Queue | 140×64 | mq |\n| `net.websocket` | Web Socket | 140×64 | ws |\n| `net.rest` | REST endpoint | 140×64 | http, api |\n| `net.internet` | Internet / Cloud | 140×64 | wan |\n| `net.datacenter` | Datacenter | 140×64 | |\n| `net.container` | Container | 140×64 | |\n| `net.pod` | Pod | 140×64 | |\n| `net.vm` | Virtual Machine | 140×64 | vm |\n\n## Databases (`database`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `db.postgres` | PostgreSQL | 176×56 | postgres, pg |\n| `db.mysql` | MySQL | 176×56 | |\n| `db.mariadb` | MariaDB | 176×56 | |\n| `db.mongodb` | MongoDB | 176×56 | mongo |\n| `db.redis` | Redis | 176×56 | |\n| `db.sqlite` | SQLite | 176×56 | |\n| `db.mssql` | MS SQL Server | 176×56 | sqlserver, mssql |\n| `db.oracle` | Oracle | 176×56 | |\n| `db.cassandra` | Cassandra | 176×56 | |\n| `db.elasticsearch` | Elasticsearch | 176×56 | elastic, es |\n| `db.neo4j` | Neo4j | 176×56 | graph |\n| `db.couchdb` | CouchDB | 176×56 | couch |\n| `db.couchbase` | Couchbase | 176×56 | |\n| `db.clickhouse` | ClickHouse | 176×56 | |\n| `db.cockroachdb` | CockroachDB | 176×56 | cockroach |\n| `db.influxdb` | InfluxDB | 176×56 | influx, tsdb |\n| `db.snowflake` | Snowflake | 176×56 | |\n| `db.supabase` | Supabase | 176×56 | |\n\n## Messaging (`messaging`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `mq.kafka` | Apache Kafka | 176×56 | kafka |\n| `mq.rabbitmq` | RabbitMQ | 176×56 | rabbit, amqp |\n| `mq.nats` | NATS | 176×56 | |\n| `mq.pulsar` | Apache Pulsar | 176×56 | pulsar |\n| `mq.mqtt` | MQTT | 176×56 | |\n| `mq.pubsub` | Pub/Sub | 176×56 | pubsub |\n| `mq.activemq` | ActiveMQ | 176×56 | jms |\n\n## Languages (`language`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `lang.node` | Node.js | 176×56 | node, js runtime |\n| `lang.python` | Python | 176×56 | py |\n| `lang.java` | Java | 176×56 | jvm |\n| `lang.go` | Go | 176×56 | golang |\n| `lang.rust` | Rust | 176×56 | |\n| `lang.dotnet` | C# / .NET | 176×56 | csharp, c# |\n| `lang.typescript` | TypeScript | 176×56 | ts |\n| `lang.javascript` | JavaScript | 176×56 | js |\n| `lang.ruby` | Ruby | 176×56 | |\n| `lang.php` | PHP | 176×56 | |\n| `lang.kotlin` | Kotlin | 176×56 | |\n| `lang.swift` | Swift | 176×56 | |\n| `lang.scala` | Scala | 176×56 | |\n| `lang.elixir` | Elixir | 176×56 | |\n| `lang.cpp` | C++ | 176×56 | cpp |\n\n## Frameworks (`framework`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `fw.express` | Express | 176×56 | |\n| `fw.nestjs` | NestJS | 176×56 | nest |\n| `fw.spring` | Spring Boot | 176×56 | spring |\n| `fw.django` | Django | 176×56 | |\n| `fw.flask` | Flask | 176×56 | |\n| `fw.fastapi` | FastAPI | 176×56 | |\n| `fw.rails` | Rails | 176×56 | ruby on rails |\n| `fw.laravel` | Laravel | 176×56 | |\n| `fw.dotnet` | .NET | 176×56 | |\n| `fw.react` | React | 176×56 | |\n| `fw.vue` | Vue | 176×56 | vuejs |\n| `fw.angular` | Angular | 176×56 | |\n| `fw.next` | Next.js | 176×56 | nextjs |\n| `fw.nuxt` | Nuxt | 176×56 | nuxtjs |\n| `fw.svelte` | Svelte | 176×56 | sveltekit |\n| `fw.electron` | Electron | 176×56 | |\n| `fw.tailwind` | Tailwind | 176×56 | tailwindcss |\n| `fw.graphql` | GraphQL | 176×56 | |\n\n## DevOps / CI-CD (`devops`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `ops.docker` | Docker | 176×56 | |\n| `ops.k8s` | Kubernetes | 176×56 | k8s |\n| `ops.nginx` | Nginx | 176×56 | |\n| `ops.haproxy` | HAProxy | 176×56 | lb |\n| `ops.traefik` | Traefik | 176×56 | traefik |\n| `ops.terraform` | Terraform | 176×56 | iac |\n| `ops.ansible` | Ansible | 176×56 | |\n| `ops.jenkins` | Jenkins | 176×56 | ci |\n| `ops.gha` | GitHub Actions | 176×56 | ci, actions |\n| `ops.gitlab` | GitLab CI | 176×56 | ci |\n| `ops.argocd` | ArgoCD | 176×56 | gitops |\n| `ops.helm` | Helm | 176×56 | |\n| `ops.istio` | Istio | 176×56 | service mesh |\n| `ops.envoy` | Envoy | 176×56 | proxy |\n| `ops.consul` | Consul | 176×56 | |\n| `ops.vault` | Vault | 176×56 | secrets |\n| `ops.pm2` | PM2 | 176×56 | |\n| `ops.maven` | Maven | 176×56 | build |\n\n## Auth / Identity (`auth`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `auth.oidc` | OpenID Connect | 176×56 | oidc |\n| `auth.jwt` | JWT | 176×56 | token |\n| `auth.keycloak` | Keycloak | 176×56 | |\n| `auth.auth0` | Auth0 | 176×56 | |\n| `auth.okta` | Okta | 176×56 | |\n| `auth.firebase` | Firebase Auth | 176×56 | firebase |\n| `auth.oauth` | OAuth 2.0 | 176×56 | oauth |\n| `auth.saml` | SAML | 176×56 | |\n| `auth.ldap` | LDAP | 176×56 | |\n\n## Observability (`observability`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `obs.prometheus` | Prometheus | 176×56 | metrics |\n| `obs.grafana` | Grafana | 176×56 | dashboard |\n| `obs.datadog` | Datadog | 176×56 | |\n| `obs.sentry` | Sentry | 176×56 | errors |\n| `obs.elasticsearch` | Elasticsearch | 176×56 | elk |\n| `obs.logstash` | Logstash | 176×56 | elk |\n| `obs.kibana` | Kibana | 176×56 | elk |\n| `obs.jaeger` | Jaeger | 176×56 | tracing |\n| `obs.otel` | OpenTelemetry | 176×56 | otel, tracing |\n| `obs.newrelic` | New Relic | 176×56 | |\n\n## AWS (`aws`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `aws.ec2` | EC2 | 176×56 | aws |\n| `aws.lambda` | Lambda | 176×56 | aws |\n| `aws.s3` | S3 | 176×56 | aws |\n| `aws.ebs` | EBS | 176×56 | aws |\n| `aws.efs` | EFS | 176×56 | aws |\n| `aws.rds` | RDS | 176×56 | aws |\n| `aws.aurora` | Aurora | 176×56 | aws |\n| `aws.dynamodb` | DynamoDB | 176×56 | aws |\n| `aws.elasticache` | ElastiCache | 176×56 | aws |\n| `aws.redshift` | Redshift | 176×56 | aws |\n| `aws.vpc` | VPC | 176×56 | aws |\n| `aws.subnet` | Subnet | 176×56 | aws |\n| `aws.internet-gateway` | Internet Gateway | 176×56 | aws |\n| `aws.nat-gateway` | NAT Gateway | 176×56 | aws |\n| `aws.elb` | ELB | 176×56 | aws |\n| `aws.alb` | ALB | 176×56 | aws |\n| `aws.nlb` | NLB | 176×56 | aws |\n| `aws.api-gateway` | API Gateway | 176×56 | aws |\n| `aws.cloudfront` | CloudFront | 176×56 | aws |\n| `aws.route-53` | Route 53 | 176×56 | aws |\n| `aws.sqs` | SQS | 176×56 | aws |\n| `aws.sns` | SNS | 176×56 | aws |\n| `aws.eventbridge` | EventBridge | 176×56 | aws |\n| `aws.kinesis` | Kinesis | 176×56 | aws |\n| `aws.step-functions` | Step Functions | 176×56 | aws |\n| `aws.ecs` | ECS | 176×56 | aws |\n| `aws.eks` | EKS | 176×56 | aws |\n| `aws.fargate` | Fargate | 176×56 | aws |\n| `aws.ecr` | ECR | 176×56 | aws |\n| `aws.iam` | IAM | 176×56 | aws |\n| `aws.cognito` | Cognito | 176×56 | aws |\n| `aws.secrets-manager` | Secrets Manager | 176×56 | aws |\n| `aws.kms` | KMS | 176×56 | aws |\n| `aws.cloudwatch` | CloudWatch | 176×56 | aws |\n| `aws.cloudtrail` | CloudTrail | 176×56 | aws |\n| `aws.glue` | Glue | 176×56 | aws |\n| `aws.athena` | Athena | 176×56 | aws |\n| `aws.sagemaker` | SageMaker | 176×56 | aws |\n| `aws.appsync` | AppSync | 176×56 | aws |\n| `aws.amplify` | Amplify | 176×56 | aws |\n\n## Azure (`azure`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `azure.virtual-machine` | Virtual Machine | 176×56 | azure |\n| `azure.vm-scale-set` | VM Scale Set | 176×56 | azure |\n| `azure.app-service` | App Service | 176×56 | azure |\n| `azure.functions` | Functions | 176×56 | azure |\n| `azure.container-instances` | Container Instances | 176×56 | azure |\n| `azure.aks` | AKS | 176×56 | azure |\n| `azure.container-registry` | Container Registry | 176×56 | azure |\n| `azure.blob-storage` | Blob Storage | 176×56 | azure |\n| `azure.files` | Files | 176×56 | azure |\n| `azure.disk` | Disk | 176×56 | azure |\n| `azure.sql-database` | SQL Database | 176×56 | azure |\n| `azure.cosmos-db` | Cosmos DB | 176×56 | azure |\n| `azure.cache-for-redis` | Cache for Redis | 176×56 | azure |\n| `azure.synapse` | Synapse | 176×56 | azure |\n| `azure.virtual-network` | Virtual Network | 176×56 | azure |\n| `azure.load-balancer` | Load Balancer | 176×56 | azure |\n| `azure.application-gateway` | Application Gateway | 176×56 | azure |\n| `azure.front-door` | Front Door | 176×56 | azure |\n| `azure.service-bus` | Service Bus | 176×56 | azure |\n| `azure.event-hub` | Event Hub | 176×56 | azure |\n| `azure.event-grid` | Event Grid | 176×56 | azure |\n| `azure.key-vault` | Key Vault | 176×56 | azure |\n| `azure.entra-id` | Entra ID | 176×56 | azure |\n| `azure.monitor` | Monitor | 176×56 | azure |\n| `azure.application-insights` | Application Insights | 176×56 | azure |\n| `azure.logic-apps` | Logic Apps | 176×56 | azure |\n| `azure.api-management` | API Management | 176×56 | azure |\n\n## GCP (`gcp`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `gcp.compute-engine` | Compute Engine | 176×56 | gcp, google |\n| `gcp.app-engine` | App Engine | 176×56 | gcp, google |\n| `gcp.cloud-functions` | Cloud Functions | 176×56 | gcp, google |\n| `gcp.cloud-run` | Cloud Run | 176×56 | gcp, google |\n| `gcp.gke` | GKE | 176×56 | gcp, google |\n| `gcp.artifact-registry` | Artifact Registry | 176×56 | gcp, google |\n| `gcp.cloud-storage` | Cloud Storage | 176×56 | gcp, google |\n| `gcp.persistent-disk` | Persistent Disk | 176×56 | gcp, google |\n| `gcp.cloud-sql` | Cloud SQL | 176×56 | gcp, google |\n| `gcp.cloud-spanner` | Cloud Spanner | 176×56 | gcp, google |\n| `gcp.firestore` | Firestore | 176×56 | gcp, google |\n| `gcp.bigtable` | Bigtable | 176×56 | gcp, google |\n| `gcp.bigquery` | BigQuery | 176×56 | gcp, google |\n| `gcp.memorystore` | Memorystore | 176×56 | gcp, google |\n| `gcp.vpc` | VPC | 176×56 | gcp, google |\n| `gcp.cloud-load-balancing` | Cloud Load Balancing | 176×56 | gcp, google |\n| `gcp.cloud-cdn` | Cloud CDN | 176×56 | gcp, google |\n| `gcp.cloud-dns` | Cloud DNS | 176×56 | gcp, google |\n| `gcp.pub-sub` | Pub/Sub | 176×56 | gcp, google |\n| `gcp.dataflow` | Dataflow | 176×56 | gcp, google |\n| `gcp.cloud-tasks` | Cloud Tasks | 176×56 | gcp, google |\n| `gcp.iam` | IAM | 176×56 | gcp, google |\n| `gcp.secret-manager` | Secret Manager | 176×56 | gcp, google |\n| `gcp.cloud-kms` | Cloud KMS | 176×56 | gcp, google |\n| `gcp.cloud-monitoring` | Cloud Monitoring | 176×56 | gcp, google |\n| `gcp.vertex-ai` | Vertex AI | 176×56 | gcp, google |\n",
9
+ "feature-policy": "<!-- GENERATED FILE — do not edit by hand. Source: callman_core (npm run ai:packs). -->\n\n# Script feature policy\n\nSome `pm.*` features can be disabled per execution context (ScriptFeaturePolicy). A disabled feature evaluates to `undefined` at top level; inside `pm.test` callbacks it throws so the test reports SKIPPED instead of failing.\n\nCapability-gated members:\n\n## database\n\n- `pm.db.query({ connectionId, query })`\n- `pm.db.pre`\n- `pm.db.post`\n\n## kafka\n\n- `pm.kafka.event()`\n- `pm.kafka.messages()`\n\n## redis\n\n- `pm.redis.command({ connectionId, command })`\n- `pm.redis.get(key)`\n- `pm.redis.results.pre`\n- `pm.redis.results.post`\n\nGeneration guidance: prefer declared pre/post queries and `pm.db.query` only when the user explicitly asks for database work; never assume kafka/redis capabilities exist unless the task mentions them.\n",
10
+ "pm-api": "<!-- GENERATED FILE — do not edit by hand. Source: callman_core (npm run ai:packs). -->\n\n# Callman `pm.*` scripting API\n\nScripts are plain JavaScript (top-level `await` allowed). Use ONLY the API below — anything else (fetch, require, process, Buffer, ...) is blocked by the sandbox.\n\n## pm.test\n\nRegister a named test. The callback's assertion failures mark the test failed without aborting the script.\n\n- `pm.test(name, fn)` — Runs fn (sync or async); pass/fail lands in the run's test results.\n\n## pm.expect\n\nChai-style assertions plus Jest-style matchers.\n\n- `pm.expect(value)` — Assertion chain. Equality: .to.equal(x) (identity), .to.eql(x) / .to.deep.equal(x) / .toEqual(x) (deep). Existence: .to.exist, .toBeDefined(), .toBeNull(). Strings/arrays: .to.include(x) / .toContain(x), .oneOf([..]). Numbers: .toBeGreaterThan / .toBeLessThan / .to.be.above(n) / .to.be.below(n). Types: .to.be.a('string'|'number'|...). Negation: .to.not.<...> / .not.<matcher>. Properties: .to.have.property('name', value?).\n- `pm.expect.fail(message?)` — Fails the surrounding test immediately.\n\n## pm.environment\n\nActive environment variables (alias: pm.env). Writes are scoped to the run and surface as variable mutations.\n\n- `pm.environment.get(key)` — Read a variable (string or undefined).\n- `pm.environment.set(key, value)` — Write a variable for subsequent steps.\n- `pm.environment.unset(key)` — Remove a variable.\n- `pm.environment.has(key)` — true when the key exists.\n- `pm.environment.clear()` — Remove every variable in the scope.\n- `pm.environment.toObject()` — Plain { key: value } snapshot.\n- `pm.environment.replaceIn(template)` — Resolve {{tokens}} inside a string.\n- `pm.environment.name` — Active environment's name.\n\n## pm.globals\n\nWorkspace-level global variables. Same surface as pm.environment.\n\n- `pm.globals.get(key)` — Read a global.\n- `pm.globals.set(key, value)` — Write a global for the run.\n- `pm.globals.unset(key)` — Remove a global.\n- `pm.globals.has(key)` — true when the key exists.\n- `pm.globals.clear()` — Remove every global in the scope.\n- `pm.globals.toObject()` — Plain snapshot.\n- `pm.globals.replaceIn(template)` — Resolve {{tokens}} inside a string.\n\n## pm.collectionVariables\n\nCollection-scoped variables that survive across requests within one collection run iteration.\n\n- `pm.collectionVariables.get(key)` — Read a collection variable.\n- `pm.collectionVariables.set(key, value)` — Write; persists across the iteration.\n- `pm.collectionVariables.unset(key)` — Remove a collection variable.\n- `pm.collectionVariables.has(key)` — true when the key exists.\n- `pm.collectionVariables.clear()` — Remove all collection variables.\n- `pm.collectionVariables.toObject()` — Plain snapshot.\n- `pm.collectionVariables.replaceIn(template)` — Resolve {{tokens}}.\n\n## pm.variables\n\nLayered read across all scopes (per-iteration > environment > globals) plus template resolution.\n\n- `pm.variables.get(key)` — Read through the precedence chain.\n- `pm.variables.set(key, value)` — Write to the run-local layer.\n- `pm.variables.unset(key)` — Remove from the run-local layer.\n- `pm.variables.has(key)` — true when any layer has the key.\n- `pm.variables.toObject()` — Merged snapshot.\n- `pm.variables.replaceIn(template)` — Resolve {{tokens}} in a string.\n- `pm.variables.resolve(template)` — Like replaceIn, but also resolves scenario node-output references.\n\n## pm.request\n\nThe outgoing request. Mutations only have effect in pre-request scripts (the call has not fired yet).\n\n- `pm.request.url` — Resolved URL string.\n- `pm.request.method` — HTTP method.\n- `pm.request.body` — Body snapshot (mode + content).\n- `pm.request.headers` — HeaderList: .all() .get(name) .has(name) .add({key,value}) .upsert({key,value}) .remove(name) .idx(i).\n- `pm.request.query` — Query params as a HeaderList.\n- `pm.request.getHeader(name)` — Read one header value.\n- `pm.request.setHeader(name, value)` — Set/replace a header. _(stages: pre-request, scenario-script)_\n- `pm.request.unsetHeader(name)` — Remove a header. _(stages: pre-request, scenario-script)_\n- `pm.request.getQueryParam(name)` — Read one query param.\n- `pm.request.setQueryParam(name, value)` — Set/replace a query param. _(stages: pre-request, scenario-script)_\n- `pm.request.unsetQueryParam(name)` — Remove a query param. _(stages: pre-request, scenario-script)_\n- `pm.request.setUrl(url)` — Replace the URL. _(stages: pre-request, scenario-script)_\n- `pm.request.setMethod(method)` — Replace the method. _(stages: pre-request, scenario-script)_\n- `pm.request.setRawBody(value)` — Replace the raw body (string or object → JSON). _(stages: pre-request, scenario-script)_\n\n## pm.response\n\nThe received response. Not available in pre-request scripts.\n\n- `pm.response.code` — Status code (number). _(stages: post-response, tests, scenario-script)_\n- `pm.response.status` — Status code (number, alias). _(stages: post-response, tests, scenario-script)_\n- `pm.response.statusText` — Status text. _(stages: post-response, tests, scenario-script)_\n- `pm.response.json()` — Parsed JSON body — call once into a const (`const body = pm.response.json()`); throws on non-JSON, so guard with try/catch or pm.response.to.be.json when the content type is uncertain. _(stages: post-response, tests, scenario-script)_\n- `pm.response.text()` — Raw body as string. _(stages: post-response, tests, scenario-script)_\n- `pm.response.rawBody` — Raw body string. _(stages: post-response, tests, scenario-script)_\n- `pm.response.headers` — Response HeaderList. _(stages: post-response, tests, scenario-script)_\n- `pm.response.responseTime` — Duration in ms. _(stages: post-response, tests, scenario-script)_\n- `pm.response.responseSize` — Body size in bytes. _(stages: post-response, tests, scenario-script)_\n- `pm.response.to.have.status(code)` — Assertion shortcuts; also .to.have.header/.jsonBody/.body and .to.be.ok/.json/.success/.clientError/... plus .to.not.<predicate>. _(stages: post-response, tests, scenario-script)_\n\n## pm.sendRequest\n\nFire an ad-hoc HTTP request from inside a script.\n\n- `pm.sendRequest(urlOrOptions, callback?)` — Options: { url, method, header: {name: value}, body }. Body accepts a plain object (auto-JSON) OR Postman style { mode: 'raw', raw: JSON.stringify({...}) } / { mode: 'urlencoded', urlencoded: [{key, value}] }. Prefer `const res = await pm.sendRequest({...})`; callback form gets (err, res). The response object is { code, status, statusText, headers, body, responseTime, json(), text() } — note it is NOT pm.response.\n\n## pm.db\n\nDatabase access (Oracle / MongoDB / PostgreSQL / MySQL). Disabled by feature policy in some contexts — tests then report SKIP.\n\n- `pm.db.query({ connectionId, query })` — Run an ad-hoc query — ALWAYS await it. SQL connections (Oracle/Postgres/MySQL): `query` is the SQL text. MongoDB: `query` is a JSON STRING of a command object, e.g. `JSON.stringify({ collection: 'users', operation: 'findOne', filter: { email } })` — operation is find|findOne|aggregate|countDocuments|insertOne|updateOne|deleteOne|…, the match key is `filter` (NOT a `db.coll.find(...)` shell string and NOT `query`), and aggregate uses `pipeline`. Resolves to { success, error, rowCount, rows, firstRow(), connectionId, connectionName, connectionType, durationMs, executedAt }. firstRow is a FUNCTION: res.firstRow()?.STATUS (Oracle columns are UPPERCASE); for a Mongo existence check assert rowCount > 0. _(requires the database capability — may be disabled by feature policy)_\n- `pm.db.pre` — Result object of the declared pre-request DB query: { success, error, rowCount, rows, firstRow() }. Not a promise — read directly. _(requires the database capability — may be disabled by feature policy)_\n- `pm.db.post` — Result object of the declared post-response DB query (same shape as pm.db.pre). _(stages: post-response, tests)_ _(requires the database capability — may be disabled by feature policy)_\n\n## pm.kafka\n\nCaptured Kafka events from the request's Kafka tab listener.\n\n- `pm.kafka.event()` — The matched event's parsed payload (or null). _(stages: post-response, tests)_ _(requires the kafka capability — may be disabled by feature policy)_\n- `pm.kafka.messages()` — Every captured message in the listen window. _(stages: post-response, tests)_ _(requires the kafka capability — may be disabled by feature policy)_\n\n## pm.redis\n\nRun ad-hoc Redis commands and read results of declared pre/post commands.\n\n- `pm.redis.command({ connectionId, command })` — Run an ad-hoc Redis command (GET/SET/DEL/EXISTS/TTL) — ALWAYS await it. Resolves to { success, error, result, resultText, commandName, key, connectionId, connectionName, command, resolvedCommand, durationMs, executedAt }. Omit connectionId to use the request's configured Redis connection. _(requires the redis capability — may be disabled by feature policy)_\n- `pm.redis.get(key)` — Read a value already captured by a declared GET. _(requires the redis capability — may be disabled by feature policy)_\n- `pm.redis.results.pre` — Array of pre-stage command results (by line index). _(requires the redis capability — may be disabled by feature policy)_\n- `pm.redis.results.post` — Array of post-stage command results. _(stages: post-response, tests)_ _(requires the redis capability — may be disabled by feature policy)_\n\n## pm.random\n\nDeterministic-format random data generators.\n\n- `pm.random.uuid()` — UUID v4.\n- `pm.random.email()` — Random email address.\n- `pm.random.string(length?)` — Alphanumeric string.\n- `pm.random.int(min, max)` — Integer in range.\n- `pm.random.bigdecimal(min, max, scale)` — Decimal with given scale.\n- `pm.random.boolean()` — true/false.\n- `pm.random.phone()` — Phone number string.\n- `pm.random.name()` — Person name.\n- `pm.random.date(format?)` — Date string.\n\n## pm.counter\n\nMonotonic counter scoped to the run.\n\n- `pm.counter.next()` — Next value (starts at 1).\n- `pm.counter.start(startAt?)` — Counter starting at a custom value.\n\n## pm.info\n\nExecution metadata snapshot.\n\n- `pm.info.eventName` — \"prerequest\" | \"test\".\n- `pm.info.iteration` — Zero-based data-driven iteration index.\n- `pm.info.iterationCount` — Total iterations — only meaningful in collection/data-driven runs. Never use it to gate token/cache logic in single sends.\n- `pm.info.requestName` — Current request's name.\n- `pm.info.requestId` — Current request's id.\n\n## pm.execution\n\nCollection-run flow control.\n\n- `pm.execution.setNextRequest(name)` — Jump to a named request next (collection runs).\n- `pm.execution.skipRequest()` — Skip the current request. _(stages: pre-request)_\n- `pm.execution.location` — Folder path of the current request.\n\n## pm.node\n\nScenario workflow context (only meaningful inside scenario script nodes).\n\n- `pm.node.nodeLabel` — Current node's label. _(stages: scenario-script)_\n- `pm.node.setNextRequest(name)` — Route the workflow to a named node. _(stages: scenario-script)_\n\n## pm.log\n\nStructured logging into the run report.\n\n- `pm.log(...args)` — Like console.log; entries land in the run's log panel.\n\n## CryptoJS\n\ncrypto-js global (NOT under pm.*).\n\n- `CryptoJS.SHA256(msg) / SHA1 / SHA512 / MD5` — Hashes; .toString() or .toString(CryptoJS.enc.Hex).\n- `CryptoJS.HmacSHA256(msg, key)` — HMAC family (SHA1/224/384/512, MD5 variants).\n- `CryptoJS.AES.encrypt(msg, key) / .decrypt(cipher, key)` — AES; decrypt result needs .toString(CryptoJS.enc.Utf8).\n- `CryptoJS.PBKDF2(password, salt, options)` — Key derivation.\n- `CryptoJS.enc.Utf8 / Base64 / Hex / Latin1` — Encoders for .toString(...).\n- `CryptoJS.lib.WordArray.create / random(n)` — Raw word arrays (e.g. random IVs).\n\n## _\n\nlodash global (NOT under pm.*).\n\n- `_.get(obj, path, default?) / _.pick / _.groupBy / _.sortBy / _.uniq / ...` — Full lodash surface for data wrangling.\n\n## timers\n\nSafe per-execution timer wrappers (callbacks never outlive the run).\n\n- `setTimeout(fn, ms) / clearTimeout(id)` — Use with await new Promise(r => setTimeout(r, ms)) for polling loops.\n- `setInterval(fn, ms) / clearInterval(id)` — Interval variant.\n\n## Stage rules\n\n- `pre-request`: runs BEFORE the HTTP call. `pm.response` does not exist; `pm.request` mutations take effect.\n- `post-response` / `tests`: run AFTER the call. `pm.response` is available; `pm.request` mutations have no effect.\n- `scenario-script`: a scenario Script node. Prior node outputs are readable via `pm.variables.resolve(\"{{NodeLabel.path}}\")`; the script's return value becomes the node output.\n- Members without a stage note are available in every stage.\n",
11
+ "sandbox-globals": "<!-- GENERATED FILE — do not edit by hand. Source: callman_core (npm run ai:packs). -->\n\n# Script sandbox — available and blocked globals\n\nThe sandbox is a Node `vm` context. Generated code must never reference a blocked global — the script fails at runtime.\n\n## Available built-ins\n\n`AggregateError`, `Array`, `ArrayBuffer`, `BigInt`, `BigInt64Array`, `BigUint64Array`, `Boolean`, `DataView`, `Date`, `Error`, `EvalError`, `Float32Array`, `Float64Array`, `Infinity`, `Int16Array`, `Int32Array`, `Int8Array`, `JSON`, `Map`, `Math`, `NaN`, `Number`, `Object`, `Promise`, `RangeError`, `ReferenceError`, `RegExp`, `Set`, `String`, `Symbol`, `SyntaxError`, `TextDecoder`, `TextEncoder`, `TypeError`, `URIError`, `URL`, `URLSearchParams`, `Uint16Array`, `Uint32Array`, `Uint8Array`, `Uint8ClampedArray`, `WeakMap`, `WeakSet`, `atob`, `btoa`, `decodeURIComponent`, `encodeURIComponent`, `isFinite`, `isNaN`, `parseFloat`, `parseInt`, `structuredClone`, `undefined`\n\nPlus the injected helpers: `pm`, `console`, `CryptoJS`, `_` (lodash), `setTimeout`/`clearTimeout`/`setInterval`/`clearInterval` (safe per-run wrappers).\n\n## Blocked (never use)\n\n`Buffer`, `Function`, `WebSocket`, `Worker`, `XMLHttpRequest`, `document`, `eval`, `exports`, `fetch`, `global`, `globalThis`, `importScripts`, `module`, `navigator`, `process`, `require`, `self`, `window`\n\nNotes:\n- No `fetch` — use `pm.sendRequest` for HTTP.\n- No `Buffer` — use `atob`/`btoa`/`TextEncoder`/`Uint8Array`.\n- No `require`/`import` — `CryptoJS` and `_` are already in scope.\n",
12
+ "templating": "<!-- GENERATED FILE — do not edit by hand. Source: callman_core (npm run ai:packs). -->\n\n# Template tokens (`{{...}}`)\n\nAnywhere a `{{...}}` is accepted (URLs, headers, bodies, DB queries, Kafka payloads, scenario node configs), substitution is PLAIN TEXT replacement — no quoting, no escaping. Quote SQL strings yourself (`WHERE id = '{{userId}}'`). A missing variable resolves to an empty string.\n\n## Variable lookups\n\n- `{{name}}` — environment → globals lookup.\n- `{{env.name}}` / `{{global.name}}` — forced scope.\n- `{{response.body.<path>}}` — current request's response (request context only; dot-indexed arrays: `items.0.id`).\n- `{{<NodeLabel>.<path>}}` — a prior scenario node's output (scenario context only; bracket-indexed arrays: `rows[0].id`).\n\n## Random generators\n\n| Token | Meaning | Example output |\n| --- | --- | --- |\n| `{{random.email}}` | Random email address | `sam.user42@example.com` |\n| `{{random.string}}` | Random alphanumeric string | `aZ19xPq20LmN` |\n| `{{random.uuid}}` | Random UUID v4 | `1d7fe6b6-6f47-4fa9-b57a-d2e1d285be51` |\n| `{{random.int}}` | Random integer | `48291` |\n| `{{random.bigdecimal}}` | Random decimal number | `1842.552190` |\n| `{{random.boolean}}` | Random boolean | `true` |\n| `{{random.phone}}` | Random phone number | `+15558675309` |\n| `{{random.date(\"YYYY-MM-DD\")}}` | Random date | `2026-04-06` |\n| `{{random.name}}` | Random human name | `Aylin Karimli` |\n\n## Counters\n\n| Token | Meaning | Example output |\n| --- | --- | --- |\n| `{{counter}}` | Incrementing counter per request | `1, 2, 3...` |\n| `{{counter.start(100)}}` | Counter starting at 100 | `100, 101, 102...` |\n\n## Postman-compatible `$` tokens\n\n| Token | Meaning | Example output |\n| --- | --- | --- |\n| `{{$guid}}` | Postman compat — UUID v4 | `1d7fe6b6-6f47-4fa9-b57a-d2e1d285be51` |\n| `{{$randomUUID}}` | Postman compat — UUID v4 | `1d7fe6b6-6f47-4fa9-b57a-d2e1d285be51` |\n| `{{$timestamp}}` | Postman compat — unix seconds | `1718793600` |\n| `{{$isoTimestamp}}` | Postman compat — ISO 8601 | `2026-05-18T10:24:00.123Z` |\n| `{{$randomInt}}` | Postman compat — 0-1000 | `482` |\n| `{{$randomBoolean}}` | Postman compat | `true` |\n| `{{$randomAlphaNumeric}}` | Postman compat — 8 chars | `aZ19xPq2` |\n| `{{$randomHexaDecimal}}` | Postman compat — 0xNNNNNNNN | `0x4f3a1c2d` |\n| `{{$randomString}}` | Postman compat — 12 chars | `aZ19xPq20LmN` |\n| `{{$randomFirstName}}` | Postman compat | `Aylin` |\n| `{{$randomLastName}}` | Postman compat | `Karimov` |\n| `{{$randomFullName}}` | Postman compat | `Aylin Karimov` |\n| `{{$randomUserName}}` | Postman compat | `aylin.karimov42` |\n| `{{$randomNamePrefix}}` | Postman compat | `Dr.` |\n| `{{$randomNameSuffix}}` | Postman compat | `Jr.` |\n| `{{$randomEmail}}` | Postman compat | `sam.user42@example.com` |\n| `{{$randomUrl}}` | Postman compat | `https://acme.io/q1w2e3` |\n| `{{$randomDomainName}}` | Postman compat | `acme.io` |\n| `{{$randomDomainSuffix}}` | Postman compat | `io` |\n| `{{$randomUserAgent}}` | Postman compat | `Mozilla/5.0 (...)` |\n| `{{$randomIP}}` | Postman compat — IPv4 | `192.168.1.42` |\n| `{{$randomIPV4}}` | Postman compat | `192.168.1.42` |\n| `{{$randomIPV6}}` | Postman compat | `fe80::1ff:fe23:4567:890a` |\n| `{{$randomMACAddress}}` | Postman compat | `1A:2B:3C:4D:5E:6F` |\n| `{{$randomPassword}}` | Postman compat | `x4Z9p2Aq!` |\n| `{{$randomSemver}}` | Postman compat | `3.7.42` |\n| `{{$randomPhoneNumber}}` | Postman compat | `+15558675309` |\n| `{{$randomCity}}` | Postman compat | `Baku` |\n| `{{$randomCountry}}` | Postman compat | `Azerbaijan` |\n| `{{$randomCountryCode}}` | Postman compat | `AZ` |\n| `{{$randomStreetAddress}}` | Postman compat | `742 Maple St` |\n| `{{$randomZipCode}}` | Postman compat | `10042` |\n| `{{$randomLatitude}}` | Postman compat | `40.412345` |\n| `{{$randomLongitude}}` | Postman compat | `-74.012345` |\n| `{{$randomCompanyName}}` | Postman compat | `Acme Labs Inc.` |\n| `{{$randomJobTitle}}` | Postman compat | `Senior Software Engineer` |\n| `{{$randomJobArea}}` | Postman compat | `Engineering` |\n| `{{$randomDepartment}}` | Postman compat | `Engineering` |\n| `{{$randomProduct}}` | Postman compat | `Acme Cloud` |\n| `{{$randomCatchPhrase}}` | Postman compat | `Scalable mesh` |\n| `{{$randomCreditCardMask}}` | Postman compat | `****-****-****-4242` |\n| `{{$randomCreditCardNumber}}` | Postman compat | `4242424242424242` |\n| `{{$randomBankAccount}}` | Postman compat | `0123456789` |\n| `{{$randomBankRoutingNumber}}` | Postman compat | `021000089` |\n| `{{$randomCurrencyCode}}` | Postman compat | `USD` |\n| `{{$randomPrice}}` | Postman compat | `42.99` |\n| `{{$randomTransactionType}}` | Postman compat | `payment` |\n| `{{$randomDatetime}}` | Postman compat | `2026-04-06T10:24:00.000Z` |\n| `{{$randomDatePast}}` | Postman compat | `2025-10-12T...` |\n| `{{$randomDateFuture}}` | Postman compat | `2026-11-04T...` |\n| `{{$randomDateRecent}}` | Postman compat — last 7 days | `2026-05-15T...` |\n| `{{$randomDateSoon}}` | Postman compat — next 7 days | `2026-05-22T...` |\n| `{{$randomTime}}` | Postman compat | `14:23:07` |\n| `{{$randomWeekday}}` | Postman compat | `Wednesday` |\n| `{{$randomMonth}}` | Postman compat | `April` |\n| `{{$randomColor}}` | Postman compat | `purple` |\n| `{{$randomHexColor}}` | Postman compat | `#A78BFA` |\n| `{{$randomWord}}` | Postman compat — lorem | `ipsum` |\n| `{{$randomWords}}` | Postman compat — lorem phrase | `lorem ipsum dolor` |\n| `{{$randomSentence}}` | Postman compat | `Lorem ipsum dolor sit amet.` |\n| `{{$randomParagraph}}` | Postman compat | `Lorem ipsum dolor sit amet...` |\n| `{{$randomFileName}}` | Postman compat | `q1w2e3r4.pdf` |\n| `{{$randomFileExt}}` | Postman compat | `json` |\n| `{{$randomFileType}}` | Postman compat | `image` |\n| `{{$randomMimeType}}` | Postman compat | `application/json` |\n| `{{$randomImageUrl}}` | Postman compat | `https://picsum.photos/400/300` |\n"
13
+ };
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerResources = void 0;
4
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
5
+ const callman_core_1 = require("callman-core");
6
+ const summarize_js_1 = require("../domain/diagram/summarize.js");
7
+ const requestShape_js_1 = require("../domain/requestShape.js");
8
+ const summarize_js_2 = require("../domain/scenario/summarize.js");
9
+ const truncate_js_1 = require("../lib/truncate.js");
10
+ const lookups_js_1 = require("../tools/lookups.js");
11
+ const diagramSchema_js_1 = require("./docs/diagramSchema.js");
12
+ const overview_js_1 = require("./docs/overview.js");
13
+ const requestSchema_js_1 = require("./docs/requestSchema.js");
14
+ const aiPacks_js_1 = require("./generated/aiPacks.js");
15
+ // Resources: reference material a model reads on demand (schemas, the
16
+ // scripting API, the scenario node reference, the diagram component catalog
17
+ // — all generated from callman-core so they can never drift from the engine)
18
+ // plus live views of workspace data by URI.
19
+ const text = (uri, body, mimeType = "text/markdown") => ({
20
+ contents: [{ uri: uri.href, mimeType, text: body }],
21
+ });
22
+ const json = (uri, body) => text(uri, (0, truncate_js_1.safeStringify)(body, 2), "application/json");
23
+ // Template variables arrive percent-encoded ("Users%20API") — decode them so a
24
+ // name with spaces works as a reference.
25
+ const variable = (value) => {
26
+ const raw = Array.isArray(value) ? (value[0] ?? "") : (value ?? "");
27
+ try {
28
+ return decodeURIComponent(raw);
29
+ }
30
+ catch {
31
+ return raw;
32
+ }
33
+ };
34
+ const registerResources = (server, ctx) => {
35
+ // ── static docs ──────────────────────────────────────────────────────
36
+ const staticDocs = [
37
+ { name: "docs-overview", uri: "callman://docs/overview", title: "How to work with Callman", description: "Conventions: whoami first, names as references, dryRun, confirm, secrets, scenarios, diagrams.", body: () => overview_js_1.OVERVIEW_DOC },
38
+ { name: "docs-request-schema", uri: "callman://docs/request-schema", title: "Request input schema", description: "The compact request form (body variants, auth, variables, scripts, folder skeleton).", body: () => requestSchema_js_1.REQUEST_SCHEMA_DOC },
39
+ { name: "docs-scenario-nodes", uri: "callman://docs/scenario-nodes", title: "Scenario node reference", description: "Every scenario node type with its config fields and defaults, graph rules and examples (from callman-core).", body: () => (0, callman_core_1.buildScenarioSystemPrompt)() },
40
+ { name: "docs-scripting-pm-api", uri: "callman://docs/scripting/pm-api", title: "Scripting: pm.* API", description: "The pm.* API available in pre-request / post-response / test scripts, per stage.", body: () => (0, callman_core_1.renderPmApiReference)() },
41
+ { name: "docs-scripting-db-queries", uri: "callman://docs/scripting/db-queries", title: "Scripting: database queries", description: "How pm.db.* queries work per database provider.", body: () => (0, callman_core_1.renderDbQueryReference)() },
42
+ { name: "docs-scripting-templating", uri: "callman://docs/scripting/templating", title: "Templating: {{variables}} and generators", description: "Variable resolution order and dynamic generators ({{$uuid}}, {{$randomInt}} …).", body: () => aiPacks_js_1.AI_PACKS.templating ?? "" },
43
+ { name: "docs-scripting-sandbox", uri: "callman://docs/scripting/sandbox", title: "Scripting: sandbox and feature policy", description: "Globals available in the script sandbox and the feature policy for DB/Kafka capabilities.", body: () => `${aiPacks_js_1.AI_PACKS["sandbox-globals"] ?? ""}\n\n${aiPacks_js_1.AI_PACKS["feature-policy"] ?? ""}` },
44
+ { name: "docs-diagram-schema", uri: "callman://docs/diagram-schema", title: "Diagram schema", description: "The compact diagram input, edge semantics, patch operations and the stored DiagramDocument.", body: () => diagramSchema_js_1.DIAGRAM_SCHEMA_DOC },
45
+ ];
46
+ for (const doc of staticDocs) {
47
+ server.registerResource(doc.name, doc.uri, { title: doc.title, description: doc.description, mimeType: "text/markdown" }, async (uri) => text(uri, doc.body()));
48
+ }
49
+ // ── component catalog ────────────────────────────────────────────────
50
+ const catalog = () => {
51
+ const grouped = (0, callman_core_1.diagramComponentsByCategory)();
52
+ return callman_core_1.DIAGRAM_CATEGORY_ORDER.map((category) => ({
53
+ category,
54
+ label: callman_core_1.DIAGRAM_CATEGORY_LABELS[category],
55
+ components: grouped[category].map((component) => ({
56
+ type: component.type,
57
+ label: component.label,
58
+ ...(component.aliases?.length ? { aliases: component.aliases } : {}),
59
+ ...(component.container ? { container: true } : {}),
60
+ })),
61
+ }));
62
+ };
63
+ server.registerResource("diagram-components", "callman://diagram/components", { title: "Diagram component catalog", description: "Every component type usable in create_diagram / patch_diagram, grouped by category. Use the `type` values verbatim.", mimeType: "application/json" }, async (uri) => json(uri, { categories: catalog(), note: "Use `type` verbatim as a node's type. Container components take children via `parent`." }));
64
+ server.registerResource("diagram-components-category", new mcp_js_1.ResourceTemplate("callman://diagram/components/{category}", {
65
+ list: undefined,
66
+ complete: { category: () => [...callman_core_1.DIAGRAM_CATEGORY_ORDER] },
67
+ }), { title: "Diagram components in one category", description: `One category of the component catalog: ${callman_core_1.DIAGRAM_CATEGORY_ORDER.join(", ")}.`, mimeType: "application/json" }, async (uri, variables) => {
68
+ const category = variable(variables.category);
69
+ const entry = catalog().find((group) => group.category === category);
70
+ if (!entry)
71
+ throw new Error(`Unknown category "${category}". Known: ${callman_core_1.DIAGRAM_CATEGORY_ORDER.join(", ")}`);
72
+ return json(uri, entry);
73
+ });
74
+ // ── live workspace data ──────────────────────────────────────────────
75
+ server.registerResource("workspaces", "callman://workspaces", { title: "Your workspaces", description: "The workspaces the token can act in, with your role.", mimeType: "application/json" }, async (uri) => json(uri, { workspaces: await ctx.listWorkspaces() }));
76
+ server.registerResource("workspace-collections", new mcp_js_1.ResourceTemplate("callman://workspace/{workspace}/collections", { list: undefined }), { title: "Collections of a workspace", description: "Collections (id, name, counts) of a workspace by id or name.", mimeType: "application/json" }, async (uri, variables) => {
77
+ const ws = await ctx.resolveWorkspace(variable(variables.workspace));
78
+ const collections = await ctx.api.listAllCollections(ws.id);
79
+ return json(uri, { workspace: { id: ws.id, name: ws.name }, collections: collections.map((collection) => ({ id: collection.id, name: collection.name, requestCount: collection.requestCount ?? null, folderCount: collection.folderCount ?? null })) });
80
+ });
81
+ server.registerResource("workspace-environments", new mcp_js_1.ResourceTemplate("callman://workspace/{workspace}/environments", { list: undefined }), { title: "Environments of a workspace", description: "Environments with their variable keys (values masked by the server).", mimeType: "application/json" }, async (uri, variables) => {
82
+ const ws = await ctx.resolveWorkspace(variable(variables.workspace));
83
+ const { items } = await ctx.api.listEnvironments(ws.id);
84
+ return json(uri, { workspace: { id: ws.id, name: ws.name }, environments: items.map((environment) => ({ id: environment.id, name: environment.name, variableKeys: environment.variables.map((entry) => entry.key) })) });
85
+ });
86
+ server.registerResource("collection-tree", new mcp_js_1.ResourceTemplate("callman://collection/{collection}/tree", { list: undefined }), { title: "A collection's folders and requests", description: "Folders and requests of a collection (id or name) in the default workspace.", mimeType: "application/json" }, async (uri, variables) => {
87
+ const ws = await ctx.resolveWorkspace();
88
+ const resolved = await (0, lookups_js_1.resolveCollection)(ctx, ws.id, variable(variables.collection));
89
+ const tree = await (0, lookups_js_1.loadTree)(ctx, ws.id, resolved.item.id);
90
+ return json(uri, { collection: { id: resolved.item.id, name: resolved.item.name }, folders: tree.folders, requests: tree.requests.map(requestShape_js_1.requestSummaryView) });
91
+ });
92
+ server.registerResource("request", new mcp_js_1.ResourceTemplate("callman://request/{request}", { list: undefined }), { title: "A saved request", description: "One request (id or unique name) in the default workspace, secrets masked.", mimeType: "application/json" }, async (uri, variables) => {
93
+ const ws = await ctx.resolveWorkspace();
94
+ const { request } = await (0, lookups_js_1.resolveRequest)(ctx, ws.id, variable(variables.request));
95
+ return json(uri, { request: (0, requestShape_js_1.compactRequestView)(request, { full: true }) });
96
+ });
97
+ server.registerResource("environment", new mcp_js_1.ResourceTemplate("callman://environment/{environment}", { list: undefined }), { title: "An environment", description: "One environment (id or name) in the default workspace, values masked by the server.", mimeType: "application/json" }, async (uri, variables) => {
98
+ const ws = await ctx.resolveWorkspace();
99
+ const resolved = await (0, lookups_js_1.resolveEnvironment)(ctx, ws.id, variable(variables.environment));
100
+ const fresh = await ctx.api.getEnvironment(ws.id, resolved.item.id);
101
+ return json(uri, { environment: { id: fresh.id, name: fresh.name, variables: fresh.variables } });
102
+ });
103
+ server.registerResource("scenario", new mcp_js_1.ResourceTemplate("callman://scenario/{scenario}", { list: undefined }), { title: "A scenario", description: "One scenario (id or name): nodes with configs (clipped, secrets masked) and edges.", mimeType: "application/json" }, async (uri, variables) => {
104
+ const ws = await ctx.resolveWorkspaceOrNull();
105
+ const resolved = await (0, lookups_js_1.resolveScenario)(ctx, ws?.id ?? null, variable(variables.scenario));
106
+ return json(uri, { scenario: (0, summarize_js_2.scenarioFullView)(resolved.item) });
107
+ });
108
+ server.registerResource("diagram", new mcp_js_1.ResourceTemplate("callman://diagram/{diagram}", { list: undefined }), { title: "A diagram", description: "One diagram (id or name) as nodes/edges with edge semantics.", mimeType: "application/json" }, async (uri, variables) => {
109
+ const ref = variable(variables.diagram);
110
+ const resolved = await (0, lookups_js_1.resolveDiagram)(ctx, ref);
111
+ const parsed = (0, callman_core_1.safeParseDiagramDocument)(resolved.item.document);
112
+ if (!parsed.ok)
113
+ throw new Error(`Stored diagram is invalid: ${parsed.errors.join("; ")}`);
114
+ return json(uri, { diagram: { id: resolved.item.id, name: resolved.item.name, canEdit: resolved.item.canEdit, ...(0, summarize_js_1.diagramGraphView)(parsed.document) } });
115
+ });
116
+ };
117
+ exports.registerResources = registerResources;
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executeCollection = exports.requestFailed = void 0;
4
+ const callman_core_1 = require("callman-core");
5
+ const requestFailed = (result) => {
6
+ if (typeof result.passed === "boolean")
7
+ return !result.passed;
8
+ // Same rule as callme-cli (summary.ts): status 0 = transport failure.
9
+ return (result.status === 0 ||
10
+ result.status >= 400 ||
11
+ result.scriptResults.some((test) => test.status === "FAIL") ||
12
+ result.contractResults.some((test) => test.status === "FAIL"));
13
+ };
14
+ exports.requestFailed = requestFailed;
15
+ const diffEnv = (before, after, set, unset) => {
16
+ for (const key of Object.keys(after)) {
17
+ if (!(key in before) || before[key] !== after[key])
18
+ set.add(key);
19
+ }
20
+ for (const key of Object.keys(before))
21
+ if (!(key in after))
22
+ unset.add(key);
23
+ };
24
+ const executeCollection = async ({ collection, env, connections = {}, bail = false, only = null, deadlineMs, onProgress, }) => {
25
+ const envStore = new callman_core_1.EnvStore(env);
26
+ const results = [];
27
+ const setKeys = new Set();
28
+ const unsetKeys = new Set();
29
+ const startedAt = Date.now();
30
+ let previousResponse = null;
31
+ let bailed = false;
32
+ const featurePolicy = {
33
+ database: collection.runnerSettings?.database !== false,
34
+ kafka: false,
35
+ };
36
+ const wanted = only ? new Set(only) : null;
37
+ const runnable = collection.requests.filter((request) => request.isEnabledInRunner !== false && (!wanted || wanted.has(request.id)));
38
+ for (const [index, request] of runnable.entries()) {
39
+ if (deadlineMs && Date.now() - startedAt > deadlineMs) {
40
+ bailed = true;
41
+ break;
42
+ }
43
+ const before = envStore.all();
44
+ const rows = request.dataContract?.rows ?? [];
45
+ if (rows.length > 0) {
46
+ const { iterations } = await (0, callman_core_1.runRequestWithDataset)({ request, env: envStore, previousResponse, connections, featurePolicy }, { requestId: request.id, columns: request.dataContract?.columns ?? [], rows });
47
+ let rowBailed = false;
48
+ for (const iteration of iterations) {
49
+ const result = {
50
+ requestId: request.id,
51
+ requestName: `${request.name} [row ${iteration.rowIndex + 1}]`,
52
+ status: iteration.status,
53
+ duration: iteration.durationMs,
54
+ response: iteration.response ?? null,
55
+ request: iteration.request,
56
+ scriptResults: iteration.scriptResults,
57
+ contractResults: iteration.contractResults,
58
+ passed: iteration.passed,
59
+ };
60
+ results.push(result);
61
+ onProgress?.({ index, total: runnable.length, request, result });
62
+ if (bail && !iteration.passed) {
63
+ rowBailed = true;
64
+ break;
65
+ }
66
+ }
67
+ diffEnv(before, envStore.all(), setKeys, unsetKeys);
68
+ previousResponse = null;
69
+ if (rowBailed) {
70
+ bailed = true;
71
+ break;
72
+ }
73
+ continue;
74
+ }
75
+ const outcome = await (0, callman_core_1.runRequest)({ request, env: envStore, previousResponse, connections, featurePolicy });
76
+ diffEnv(before, envStore.all(), setKeys, unsetKeys);
77
+ previousResponse = outcome.response;
78
+ results.push(outcome.result);
79
+ onProgress?.({ index, total: runnable.length, request, result: outcome.result });
80
+ if (bail && (0, exports.requestFailed)(outcome.result)) {
81
+ bailed = true;
82
+ break;
83
+ }
84
+ }
85
+ const passed = results.filter((result) => !(0, exports.requestFailed)(result)).length;
86
+ return {
87
+ results,
88
+ summary: { total: results.length, passed, failed: results.length - passed },
89
+ envChanges: { set: [...setKeys].sort(), unset: [...unsetKeys].sort() },
90
+ bailed,
91
+ };
92
+ };
93
+ exports.executeCollection = executeCollection;
@@ -0,0 +1,246 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildConnectionRuntimeMap = exports.validateCollection = void 0;
4
+ const errors_js_1 = require("../client/errors.js");
5
+ // The pipeline bundle (`GET /api/pipeline/bundle`) → a runnable collection.
6
+ // A verbatim port of callme-cli's loaders.validateCollection and
7
+ // remote.buildConnectionRuntimeMap: bearer/basic/apiKey auth baked into
8
+ // headers/query, OAuth 2.0 carried through for core to resolve at run time,
9
+ // DB/Redis connection configs mapped to core's runtime map (Kafka skipped —
10
+ // the local runner does not consume).
11
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
12
+ // A function DECLARATION with an explicit `never` return type — TypeScript only
13
+ // narrows control flow after a call to one of those (not a const arrow).
14
+ function fail(message) {
15
+ throw new errors_js_1.ToolInputError("BUNDLE_INVALID", message);
16
+ }
17
+ const normalizeKeyValues = (input, label) => {
18
+ if (input === undefined)
19
+ return {};
20
+ if (Array.isArray(input)) {
21
+ const record = {};
22
+ for (const [index, entry] of input.entries()) {
23
+ if (!isRecord(entry))
24
+ fail(`${label}[${index}] must be an object`);
25
+ if (entry.enabled === false)
26
+ continue;
27
+ const key = typeof entry.key === "string" ? entry.key.trim() : "";
28
+ if (!key)
29
+ continue;
30
+ record[key] = entry.value === undefined || entry.value === null ? "" : String(entry.value);
31
+ }
32
+ return record;
33
+ }
34
+ if (!isRecord(input))
35
+ fail(`${label} must be an object or key/value array`);
36
+ return Object.fromEntries(Object.entries(input)
37
+ .map(([key, value]) => [key.trim(), value === null ? "" : String(value)])
38
+ .filter(([key]) => key));
39
+ };
40
+ const hasHeader = (headers, key) => Object.keys(headers).some((headerKey) => headerKey.toLowerCase() === key.toLowerCase());
41
+ const setHeader = (headers, key, value) => {
42
+ const existing = Object.keys(headers).find((headerKey) => headerKey.toLowerCase() === key.toLowerCase());
43
+ return { ...headers, [existing ?? key]: value };
44
+ };
45
+ const applyAuthHeaders = (headers, auth) => {
46
+ if (!isRecord(auth) || typeof auth.type !== "string" || auth.type === "none")
47
+ return headers;
48
+ if (auth.type === "bearer" && typeof auth.bearerToken === "string" && auth.bearerToken.trim()) {
49
+ return setHeader(headers, "Authorization", `Bearer ${auth.bearerToken}`);
50
+ }
51
+ if (auth.type === "basic" && typeof auth.basicUsername === "string" && typeof auth.basicPassword === "string") {
52
+ return setHeader(headers, "Authorization", `Basic ${Buffer.from(`${auth.basicUsername}:${auth.basicPassword}`).toString("base64")}`);
53
+ }
54
+ if ((auth.type === "apikey" || auth.type === "apiKey") &&
55
+ auth.apiKeyLocation !== "query" &&
56
+ typeof auth.apiKeyKey === "string" &&
57
+ typeof auth.apiKeyValue === "string" &&
58
+ auth.apiKeyKey.trim()) {
59
+ return setHeader(headers, auth.apiKeyKey, auth.apiKeyValue);
60
+ }
61
+ return headers;
62
+ };
63
+ const applyAuthQuery = (query, auth) => {
64
+ if (!isRecord(auth) ||
65
+ (auth.type !== "apikey" && auth.type !== "apiKey") ||
66
+ auth.apiKeyLocation !== "query" ||
67
+ typeof auth.apiKeyKey !== "string" ||
68
+ typeof auth.apiKeyValue !== "string" ||
69
+ !auth.apiKeyKey.trim()) {
70
+ return query;
71
+ }
72
+ return { ...query, [auth.apiKeyKey]: auth.apiKeyValue };
73
+ };
74
+ const applyDefaultHeaders = (headers, body) => {
75
+ let next = { ...headers };
76
+ if (!hasHeader(next, "Accept"))
77
+ next = setHeader(next, "Accept", "*/*");
78
+ if (body !== undefined && body !== null && !hasHeader(next, "Content-Type"))
79
+ next = setHeader(next, "Content-Type", "application/json");
80
+ return next;
81
+ };
82
+ const scriptOf = (request) => {
83
+ const scripts = [request.postResponseScript, request.testsScript, request.tests]
84
+ .filter((script) => typeof script === "string" && script.trim().length > 0);
85
+ return scripts.length > 0 ? scripts.join("\n\n") : undefined;
86
+ };
87
+ const dbNode = (value) => isRecord(value)
88
+ ? {
89
+ enabled: value.enabled === true,
90
+ connectionId: typeof value.connectionId === "string" ? value.connectionId : null,
91
+ query: typeof value.query === "string" ? value.query : "",
92
+ }
93
+ : undefined;
94
+ const databaseOf = (request) => {
95
+ if (!isRecord(request.database))
96
+ return undefined;
97
+ const preRequest = dbNode(request.database.preRequest);
98
+ const postResponse = dbNode(request.database.postResponse);
99
+ return preRequest || postResponse ? { preRequest, postResponse } : undefined;
100
+ };
101
+ const commandStrings = (value) => Array.isArray(value)
102
+ ? value
103
+ .map((entry) => (typeof entry === "string" ? entry : isRecord(entry) && typeof entry.command === "string" ? entry.command : ""))
104
+ .filter((command) => command.trim().length > 0)
105
+ : [];
106
+ const redisOf = (request) => {
107
+ if (!isRecord(request.redis))
108
+ return undefined;
109
+ const preCommands = commandStrings(request.redis.preCommands);
110
+ const postCommands = commandStrings(request.redis.postCommands);
111
+ const connectionId = typeof request.redis.connectionId === "string" ? request.redis.connectionId : null;
112
+ if (!connectionId && preCommands.length === 0 && postCommands.length === 0)
113
+ return undefined;
114
+ return { enabled: request.redis.enabled === true, connectionId, preCommands, postCommands };
115
+ };
116
+ const dataContractOf = (request) => {
117
+ const raw = request.dataContract;
118
+ if (!isRecord(raw) || !Array.isArray(raw.rows) || raw.rows.length === 0)
119
+ return undefined;
120
+ return { columns: Array.isArray(raw.columns) ? raw.columns : [], rows: raw.rows };
121
+ };
122
+ const validateCollection = (input) => {
123
+ if (!isRecord(input))
124
+ fail("bundle.collection must be an object");
125
+ const record = input;
126
+ const name = typeof record.name === "string" && record.name.trim()
127
+ ? record.name.trim()
128
+ : isRecord(record.collection) && typeof record.collection.name === "string"
129
+ ? record.collection.name.trim()
130
+ : fail("collection.name must be a non-empty string");
131
+ if (!Array.isArray(record.requests))
132
+ fail("collection.requests must be an array");
133
+ const requests = record.requests.map((raw, index) => {
134
+ const label = `requests[${index}]`;
135
+ if (!isRecord(raw))
136
+ fail(`${label} must be an object`);
137
+ const request = raw;
138
+ for (const field of ["id", "name", "method", "url"]) {
139
+ if (typeof request[field] !== "string" || !request[field].trim())
140
+ fail(`${label}.${field} must be a non-empty string`);
141
+ }
142
+ const headers = applyAuthHeaders(normalizeKeyValues(request.headers, `${label}.headers`), request.auth);
143
+ const query = applyAuthQuery(normalizeKeyValues(request.query, `${label}.query`), request.auth);
144
+ const preRequestScript = typeof request.preRequestScript === "string" && request.preRequestScript.trim() ? request.preRequestScript : undefined;
145
+ const contracts = Array.isArray(request.contracts) ? request.contracts : Array.isArray(request.contractRules) ? request.contractRules : undefined;
146
+ const database = databaseOf(request);
147
+ const redis = redisOf(request);
148
+ const dataContract = dataContractOf(request);
149
+ return {
150
+ id: request.id.trim(),
151
+ name: request.name.trim(),
152
+ method: request.method.trim().toUpperCase(),
153
+ url: request.url.trim(),
154
+ folderId: typeof request.folderId === "string" ? request.folderId : null,
155
+ isEnabledInRunner: request.isEnabledInRunner !== false,
156
+ headers: applyDefaultHeaders(headers, request.body),
157
+ query,
158
+ ...(isRecord(request.auth) && request.auth.type === "oauth2" ? { auth: request.auth } : {}),
159
+ body: request.body,
160
+ tests: scriptOf(request),
161
+ ...(preRequestScript ? { preRequestScript } : {}),
162
+ contracts,
163
+ ...(database ? { database } : {}),
164
+ ...(redis ? { redis } : {}),
165
+ ...(dataContract ? { dataContract } : {}),
166
+ };
167
+ });
168
+ const settingsSource = isRecord(record.runnerSettings)
169
+ ? record.runnerSettings
170
+ : isRecord(record.collection) && isRecord(record.collection.runnerSettings)
171
+ ? record.collection.runnerSettings
172
+ : undefined;
173
+ return {
174
+ name,
175
+ requests,
176
+ ...(settingsSource
177
+ ? { runnerSettings: { database: settingsSource.database !== false, kafka: settingsSource.kafka === true, redis: settingsSource.redis !== false } }
178
+ : {}),
179
+ };
180
+ };
181
+ exports.validateCollection = validateCollection;
182
+ // ── connections ────────────────────────────────────────────────────────
183
+ const PROVIDER_TO_DB_TYPE = {
184
+ mongodb: "mongo",
185
+ postgresql: "postgres",
186
+ mysql: "mysql",
187
+ oracle: "oracle",
188
+ mssql: "mssql",
189
+ };
190
+ const toNumber = (value) => {
191
+ const parsed = typeof value === "number" ? value : Number(value);
192
+ return Number.isFinite(parsed) ? parsed : undefined;
193
+ };
194
+ const toText = (value) => (typeof value === "string" && value.trim() ? value : undefined);
195
+ const buildConnectionRuntimeMap = (connections) => {
196
+ const map = {};
197
+ const skipped = [];
198
+ for (const connection of connections ?? []) {
199
+ const config = connection.config ?? {};
200
+ let runtime = null;
201
+ if (connection.type === "database") {
202
+ const dbType = PROVIDER_TO_DB_TYPE[connection.provider];
203
+ if (!dbType) {
204
+ skipped.push(`${connection.name} (${connection.provider})`);
205
+ continue;
206
+ }
207
+ runtime = {
208
+ kind: "db",
209
+ id: connection.id,
210
+ name: connection.name,
211
+ type: dbType,
212
+ connectionMode: config.connectionMode === "connectionString" ? "connectionString" : "detailed",
213
+ connectionString: toText(config.connectionString),
214
+ host: toText(config.host),
215
+ port: toNumber(config.port),
216
+ database: toText(config.database),
217
+ serviceName: toText(config.serviceName),
218
+ instanceName: toText(config.instanceName),
219
+ username: toText(config.username),
220
+ password: typeof config.password === "string" ? config.password : undefined,
221
+ ssl: config.ssl === true,
222
+ trustServerCertificate: config.trustServerCertificate === true,
223
+ };
224
+ }
225
+ else if (connection.type === "redis") {
226
+ runtime = {
227
+ kind: "redis",
228
+ id: connection.id,
229
+ name: connection.name,
230
+ host: toText(config.host) ?? "",
231
+ port: toNumber(config.port) ?? 6379,
232
+ username: toText(config.username),
233
+ password: typeof config.password === "string" ? config.password : undefined,
234
+ dbIndex: toNumber(config.dbIndex),
235
+ ssl: config.ssl === true,
236
+ };
237
+ }
238
+ else {
239
+ skipped.push(`${connection.name} (${connection.type})`);
240
+ continue;
241
+ }
242
+ map[connection.id] = runtime;
243
+ }
244
+ return { map, skipped };
245
+ };
246
+ exports.buildConnectionRuntimeMap = buildConnectionRuntimeMap;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ // Minimal {{key}} substitution for `run_request dryRun` previews. The real run
3
+ // uses callman-core's full templating (dynamic $variables, nested paths,
4
+ // data.* rows); this only needs to show which plain keys resolve.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resolveTemplate = void 0;
7
+ const TEMPLATE = /\{\{\s*([^}]+?)\s*\}\}/g;
8
+ const resolveTemplate = (value, env) => value.replace(TEMPLATE, (whole, rawKey) => {
9
+ const key = rawKey.trim();
10
+ if (!(key in env))
11
+ return whole;
12
+ const resolved = env[key];
13
+ return resolved === null || resolved === undefined ? "" : typeof resolved === "string" ? resolved : JSON.stringify(resolved);
14
+ });
15
+ exports.resolveTemplate = resolveTemplate;