callman-mcp 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +45 -16
  3. package/dist/client/api.d.ts +64 -3
  4. package/dist/client/api.d.ts.map +1 -1
  5. package/dist/client/api.js +67 -2
  6. package/dist/client/api.js.map +1 -1
  7. package/dist/client/errors.d.ts.map +1 -1
  8. package/dist/client/errors.js +33 -7
  9. package/dist/client/errors.js.map +1 -1
  10. package/dist/client/types.d.ts +91 -2
  11. package/dist/client/types.d.ts.map +1 -1
  12. package/dist/context.d.ts +2 -0
  13. package/dist/context.d.ts.map +1 -1
  14. package/dist/context.js +7 -2
  15. package/dist/context.js.map +1 -1
  16. package/dist/domain/contracts.d.ts +893 -0
  17. package/dist/domain/contracts.d.ts.map +1 -0
  18. package/dist/domain/contracts.js +90 -0
  19. package/dist/domain/contracts.js.map +1 -0
  20. package/dist/domain/diagram/build.d.ts +520 -18
  21. package/dist/domain/diagram/build.d.ts.map +1 -1
  22. package/dist/domain/diagram/build.js +65 -19
  23. package/dist/domain/diagram/build.js.map +1 -1
  24. package/dist/domain/diagram/patch.d.ts +624 -51
  25. package/dist/domain/diagram/patch.d.ts.map +1 -1
  26. package/dist/domain/diagram/patch.js +180 -40
  27. package/dist/domain/diagram/patch.js.map +1 -1
  28. package/dist/domain/diagram/style.d.ts +315 -0
  29. package/dist/domain/diagram/style.d.ts.map +1 -0
  30. package/dist/domain/diagram/style.js +124 -0
  31. package/dist/domain/diagram/style.js.map +1 -0
  32. package/dist/domain/diagram/summarize.d.ts +8 -0
  33. package/dist/domain/diagram/summarize.d.ts.map +1 -1
  34. package/dist/domain/diagram/summarize.js +28 -13
  35. package/dist/domain/diagram/summarize.js.map +1 -1
  36. package/dist/domain/requestIntegrations.d.ts +719 -0
  37. package/dist/domain/requestIntegrations.d.ts.map +1 -0
  38. package/dist/domain/requestIntegrations.js +222 -0
  39. package/dist/domain/requestIntegrations.js.map +1 -0
  40. package/dist/domain/requestShape.d.ts +1350 -152
  41. package/dist/domain/requestShape.d.ts.map +1 -1
  42. package/dist/domain/requestShape.js +336 -121
  43. package/dist/domain/requestShape.js.map +1 -1
  44. package/dist/domain/resolve.d.ts +2 -1
  45. package/dist/domain/resolve.d.ts.map +1 -1
  46. package/dist/domain/resolve.js +5 -1
  47. package/dist/domain/resolve.js.map +1 -1
  48. package/dist/domain/scenario/build.d.ts +82 -26
  49. package/dist/domain/scenario/build.d.ts.map +1 -1
  50. package/dist/domain/scenario/build.js +196 -65
  51. package/dist/domain/scenario/build.js.map +1 -1
  52. package/dist/domain/scenario/nodeConfig.d.ts +11 -0
  53. package/dist/domain/scenario/nodeConfig.d.ts.map +1 -0
  54. package/dist/domain/scenario/nodeConfig.js +251 -0
  55. package/dist/domain/scenario/nodeConfig.js.map +1 -0
  56. package/dist/domain/scenario/summarize.d.ts +145 -25
  57. package/dist/domain/scenario/summarize.d.ts.map +1 -1
  58. package/dist/domain/scenario/summarize.js +84 -29
  59. package/dist/domain/scenario/summarize.js.map +1 -1
  60. package/dist/lib/mask.d.ts +0 -18
  61. package/dist/lib/mask.d.ts.map +1 -1
  62. package/dist/lib/mask.js +2 -44
  63. package/dist/lib/mask.js.map +1 -1
  64. package/dist/lib/pagination.d.ts +3 -2
  65. package/dist/lib/pagination.d.ts.map +1 -1
  66. package/dist/lib/pagination.js +13 -8
  67. package/dist/lib/pagination.js.map +1 -1
  68. package/dist/lib/redact.d.ts +12 -0
  69. package/dist/lib/redact.d.ts.map +1 -0
  70. package/dist/lib/redact.js +50 -0
  71. package/dist/lib/redact.js.map +1 -0
  72. package/dist/lib/strict.d.ts +4 -0
  73. package/dist/lib/strict.d.ts.map +1 -0
  74. package/dist/lib/strict.js +14 -0
  75. package/dist/lib/strict.js.map +1 -0
  76. package/dist/prompts/index.js +7 -7
  77. package/dist/prompts/index.js.map +1 -1
  78. package/dist/resources/docs/contracts.d.ts +2 -0
  79. package/dist/resources/docs/contracts.d.ts.map +1 -0
  80. package/dist/resources/docs/contracts.js +74 -0
  81. package/dist/resources/docs/contracts.js.map +1 -0
  82. package/dist/resources/docs/diagramSchema.d.ts +1 -1
  83. package/dist/resources/docs/diagramSchema.d.ts.map +1 -1
  84. package/dist/resources/docs/diagramSchema.js +95 -28
  85. package/dist/resources/docs/diagramSchema.js.map +1 -1
  86. package/dist/resources/docs/overview.d.ts +1 -1
  87. package/dist/resources/docs/overview.d.ts.map +1 -1
  88. package/dist/resources/docs/overview.js +29 -7
  89. package/dist/resources/docs/overview.js.map +1 -1
  90. package/dist/resources/docs/requestSchema.d.ts +1 -1
  91. package/dist/resources/docs/requestSchema.d.ts.map +1 -1
  92. package/dist/resources/docs/requestSchema.js +85 -16
  93. package/dist/resources/docs/requestSchema.js.map +1 -1
  94. package/dist/resources/generated/aiPacks.d.ts +1 -1
  95. package/dist/resources/generated/aiPacks.d.ts.map +1 -1
  96. package/dist/resources/generated/aiPacks.js +3 -2
  97. package/dist/resources/generated/aiPacks.js.map +1 -1
  98. package/dist/resources/index.d.ts.map +1 -1
  99. package/dist/resources/index.js +19 -19
  100. package/dist/resources/index.js.map +1 -1
  101. package/dist/run/executeCollection.d.ts +3 -1
  102. package/dist/run/executeCollection.d.ts.map +1 -1
  103. package/dist/run/executeCollection.js +16 -4
  104. package/dist/run/executeCollection.js.map +1 -1
  105. package/dist/run/summarize.d.ts +17 -6
  106. package/dist/run/summarize.d.ts.map +1 -1
  107. package/dist/run/summarize.js +48 -41
  108. package/dist/run/summarize.js.map +1 -1
  109. package/dist/run/types.d.ts +1 -0
  110. package/dist/run/types.d.ts.map +1 -1
  111. package/dist/server.d.ts +1 -1
  112. package/dist/server.d.ts.map +1 -1
  113. package/dist/server.js +1 -1
  114. package/dist/server.js.map +1 -1
  115. package/dist/tools/catalog.d.ts +1 -1
  116. package/dist/tools/catalog.d.ts.map +1 -1
  117. package/dist/tools/catalog.js +18 -0
  118. package/dist/tools/catalog.js.map +1 -1
  119. package/dist/tools/collections.d.ts.map +1 -1
  120. package/dist/tools/collections.js +53 -41
  121. package/dist/tools/collections.js.map +1 -1
  122. package/dist/tools/contracts.d.ts +4 -0
  123. package/dist/tools/contracts.d.ts.map +1 -0
  124. package/dist/tools/contracts.js +201 -0
  125. package/dist/tools/contracts.js.map +1 -0
  126. package/dist/tools/diagrams.d.ts.map +1 -1
  127. package/dist/tools/diagrams.js +19 -10
  128. package/dist/tools/diagrams.js.map +1 -1
  129. package/dist/tools/environments.d.ts.map +1 -1
  130. package/dist/tools/environments.js +184 -64
  131. package/dist/tools/environments.js.map +1 -1
  132. package/dist/tools/import.d.ts.map +1 -1
  133. package/dist/tools/import.js +111 -20
  134. package/dist/tools/import.js.map +1 -1
  135. package/dist/tools/index.d.ts +2 -1
  136. package/dist/tools/index.d.ts.map +1 -1
  137. package/dist/tools/index.js +19 -1
  138. package/dist/tools/index.js.map +1 -1
  139. package/dist/tools/lookups.d.ts +38 -7
  140. package/dist/tools/lookups.d.ts.map +1 -1
  141. package/dist/tools/lookups.js +113 -10
  142. package/dist/tools/lookups.js.map +1 -1
  143. package/dist/tools/meta.d.ts.map +1 -1
  144. package/dist/tools/meta.js +9 -4
  145. package/dist/tools/meta.js.map +1 -1
  146. package/dist/tools/requests.d.ts.map +1 -1
  147. package/dist/tools/requests.js +138 -50
  148. package/dist/tools/requests.js.map +1 -1
  149. package/dist/tools/run.d.ts.map +1 -1
  150. package/dist/tools/run.js +84 -28
  151. package/dist/tools/run.js.map +1 -1
  152. package/dist/tools/scenarios.d.ts.map +1 -1
  153. package/dist/tools/scenarios.js +238 -75
  154. package/dist/tools/scenarios.js.map +1 -1
  155. package/dist/tools/shared.d.ts +1 -0
  156. package/dist/tools/shared.d.ts.map +1 -1
  157. package/dist/tools/shared.js +9 -1
  158. package/dist/tools/shared.js.map +1 -1
  159. package/dist/tools/workspaces.d.ts.map +1 -1
  160. package/dist/tools/workspaces.js +44 -7
  161. package/dist/tools/workspaces.js.map +1 -1
  162. package/dist-cjs/client/api.js +67 -2
  163. package/dist-cjs/client/errors.js +33 -7
  164. package/dist-cjs/context.js +7 -2
  165. package/dist-cjs/domain/contracts.js +93 -0
  166. package/dist-cjs/domain/diagram/build.js +71 -20
  167. package/dist-cjs/domain/diagram/patch.js +179 -39
  168. package/dist-cjs/domain/diagram/style.js +130 -0
  169. package/dist-cjs/domain/diagram/summarize.js +28 -13
  170. package/dist-cjs/domain/requestIntegrations.js +228 -0
  171. package/dist-cjs/domain/requestShape.js +342 -121
  172. package/dist-cjs/domain/resolve.js +5 -1
  173. package/dist-cjs/domain/scenario/build.js +197 -65
  174. package/dist-cjs/domain/scenario/nodeConfig.js +260 -0
  175. package/dist-cjs/domain/scenario/summarize.js +86 -29
  176. package/dist-cjs/lib/mask.js +3 -48
  177. package/dist-cjs/lib/pagination.js +13 -8
  178. package/dist-cjs/lib/redact.js +53 -0
  179. package/dist-cjs/lib/strict.js +18 -0
  180. package/dist-cjs/prompts/index.js +7 -7
  181. package/dist-cjs/resources/docs/contracts.js +76 -0
  182. package/dist-cjs/resources/docs/diagramSchema.js +95 -28
  183. package/dist-cjs/resources/docs/overview.js +29 -7
  184. package/dist-cjs/resources/docs/requestSchema.js +85 -16
  185. package/dist-cjs/resources/generated/aiPacks.js +3 -2
  186. package/dist-cjs/resources/index.js +17 -17
  187. package/dist-cjs/run/executeCollection.js +16 -4
  188. package/dist-cjs/run/summarize.js +48 -41
  189. package/dist-cjs/server.js +1 -1
  190. package/dist-cjs/tools/catalog.js +18 -0
  191. package/dist-cjs/tools/collections.js +52 -40
  192. package/dist-cjs/tools/contracts.js +204 -0
  193. package/dist-cjs/tools/diagrams.js +19 -10
  194. package/dist-cjs/tools/environments.js +182 -62
  195. package/dist-cjs/tools/import.js +107 -16
  196. package/dist-cjs/tools/index.js +21 -2
  197. package/dist-cjs/tools/lookups.js +123 -11
  198. package/dist-cjs/tools/meta.js +9 -4
  199. package/dist-cjs/tools/requests.js +134 -46
  200. package/dist-cjs/tools/run.js +82 -26
  201. package/dist-cjs/tools/scenarios.js +235 -72
  202. package/dist-cjs/tools/shared.js +11 -2
  203. package/dist-cjs/tools/workspaces.js +43 -6
  204. package/package.json +2 -2
@@ -37,7 +37,7 @@ exports.registerRunTools = void 0;
37
37
  const zod_1 = require("zod");
38
38
  const errors_js_1 = require("../client/errors.js");
39
39
  const resolve_js_1 = require("../domain/resolve.js");
40
- const mask_js_1 = require("../lib/mask.js");
40
+ const redact_js_1 = require("../lib/redact.js");
41
41
  const truncate_js_1 = require("../lib/truncate.js");
42
42
  const executeCollection_js_1 = require("../run/executeCollection.js");
43
43
  const loadBundle_js_1 = require("../run/loadBundle.js");
@@ -47,8 +47,35 @@ const shared_js_1 = require("./shared.js");
47
47
  // Local execution — the same path as callme-cli: the pipeline bundle
48
48
  // (collection + environment values + connection configs) is fetched with the
49
49
  // token, requests run HERE through callman-core, and only the results go back
50
- // to the model. Variable values are never in the output. One run at a time.
50
+ // to the model. Variable values are never in the output (they come back as
51
+ // {{key}}). One run at a time.
52
+ // What a local run does NOT do, stated up front so a model does not read a
53
+ // missing check as a pass.
54
+ const LOCAL_RUN_LIMITS = "Local-run limits: Kafka steps are skipped; DB assertions (dbAssertions) are evaluated only by the desktop app; no cookie jar between requests; no client certificates (mTLS); each request times out after 30 s. Database and Redis steps run when the collection's runnerSettings allow them and the connection is usable from this machine.";
51
55
  const maxBodyArg = zod_1.z.number().int().min(256).max(truncate_js_1.LIMITS.RUN_BODY_MAX).optional().describe("Response body preview cap in bytes (default 16 KB)");
56
+ // apiKey auth names its own header / query parameter — mask those too, and
57
+ // note the steps a local run skips.
58
+ const inspectBundle = (rawCollection) => {
59
+ const secretHeaders = new Set();
60
+ const secretQuery = new Set();
61
+ const skipped = new Map();
62
+ const requests = rawCollection?.requests;
63
+ for (const raw of Array.isArray(requests) ? requests : []) {
64
+ const request = raw;
65
+ const auth = request.auth;
66
+ if (auth && (auth.type === "apikey" || auth.type === "apiKey") && typeof auth.apiKeyKey === "string" && auth.apiKeyKey.trim()) {
67
+ (auth.apiKeyLocation === "query" ? secretQuery : secretHeaders).add(auth.apiKeyKey.trim());
68
+ }
69
+ const notes = [];
70
+ if (Array.isArray(request.dbAssertions) && request.dbAssertions.length > 0)
71
+ notes.push("DB assertions (desktop only)");
72
+ if (request.kafka && (request.kafka.enabled || request.kafka.prePublish?.enabled || request.kafka.postPublish?.enabled))
73
+ notes.push("Kafka steps");
74
+ if (typeof request.id === "string" && notes.length > 0)
75
+ skipped.set(request.id, notes);
76
+ }
77
+ return { redaction: { secretHeaders, secretQuery }, skipped };
78
+ };
52
79
  const prepareRun = async (ctx, ws, collectionId, environmentRef) => {
53
80
  const environment = environmentRef ? (await (0, lookups_js_1.resolveEnvironment)(ctx, ws, environmentRef)).item : null;
54
81
  const bundle = await ctx.api.pipelineBundle(ws, collectionId, environment?.id ?? null);
@@ -73,76 +100,97 @@ const prepareRun = async (ctx, ws, collectionId, environmentRef) => {
73
100
  const { map, skipped } = (0, loadBundle_js_1.buildConnectionRuntimeMap)(bundle.connections);
74
101
  if (skipped.length > 0)
75
102
  warnings.push(`Connections not usable in a local run: ${skipped.join(", ")}`);
76
- if (collection.runnerSettings?.kafka)
77
- warnings.push("Kafka steps never run from an AI tool.");
103
+ const { redaction, skipped: skippedSteps } = inspectBundle(bundle.collection);
78
104
  return {
79
105
  collection,
80
- env: { ...globals, ...(bundle.environment?.variables ?? {}) },
106
+ env: { ...(bundle.environment?.variables ?? {}) },
107
+ globals,
81
108
  connections: map,
82
109
  environment: bundle.environment ? { id: bundle.environment.id, name: bundle.environment.name } : null,
83
110
  warnings,
111
+ redaction,
112
+ skipped: skippedSteps,
84
113
  };
85
114
  };
115
+ // Warnings for the requests actually run.
116
+ const skippedWarnings = (prepared, ids) => {
117
+ const out = [];
118
+ const names = new Map(prepared.collection.requests.map((request) => [request.id, request.name]));
119
+ for (const id of ids) {
120
+ const notes = prepared.skipped.get(id);
121
+ if (notes)
122
+ out.push(`${names.get(id) ?? id}: not run locally — ${notes.join(", ")}.`);
123
+ }
124
+ return out;
125
+ };
86
126
  const registerRunTools = (server, ctx) => {
87
127
  server.registerTool("run_request", {
88
128
  title: "Run a request locally",
89
- description: "Execute one saved request from this machine with an environment's variables (like the desktop's Send / callme run): returns status, timing, response headers and a bounded body preview, plus test and contract results and the NAMES of variables the scripts changed (never values). dryRun: true shows the resolved request without sending it. Needs requests:run.",
129
+ description: `Execute one saved request from this machine with an environment's variables (like the desktop's Send / callme run) — also when it is switched off for the collection runner. Returns status, timing, the request as sent (url, query, headers, body), response headers and a bounded body, test and contract results, unresolved {{variables}}, script logs and the NAMES of variables the scripts changed. Variable values never appear: they are shown as {{key}}. dryRun: true shows the request without sending it. ${LOCAL_RUN_LIMITS} Needs requests:run.`,
90
130
  inputSchema: {
91
131
  workspace: shared_js_1.workspaceArg,
92
132
  request: (0, shared_js_1.refArg)("Request", "(name, \"METHOD url\" or id)"),
93
133
  collection: zod_1.z.string().max(200).optional().describe("Narrow a name lookup to one collection"),
94
- environment: zod_1.z.string().max(200).optional().describe("Environment name or id; omit to run without one"),
134
+ environment: zod_1.z.string().max(200).optional().describe("Environment name or id from the request's own workspace; omit to run without one"),
95
135
  dryRun: zod_1.z.boolean().optional(),
96
136
  maxBodyBytes: maxBodyArg,
97
137
  },
98
138
  annotations: shared_js_1.RUN,
99
139
  }, (0, shared_js_1.guarded)(async ({ workspace, request, collection, environment, dryRun, maxBodyBytes }) => {
100
- const ws = await ctx.resolveWorkspace(workspace);
101
- const { request: found, annotation } = await (0, lookups_js_1.resolveRequest)(ctx, ws.id, request, collection);
140
+ // The request decides the workspace; the environment must be one of its.
141
+ const { ws, value, note } = await (0, lookups_js_1.findRequest)(ctx, workspace, request, collection);
142
+ const { request: found } = value;
143
+ const annotation = [value.annotation, note].filter(Boolean).join("; ") || undefined;
102
144
  const prepared = await prepareRun(ctx, ws.id, found.collectionId, environment);
103
145
  const runnable = prepared.collection.requests.find((entry) => entry.id === found.id);
104
146
  if (!runnable)
105
147
  throw new errors_js_1.ToolInputError("REQUEST_NOT_IN_BUNDLE", "The request is not part of the collection bundle (was it just deleted?).");
106
148
  if (dryRun) {
107
149
  const { resolveTemplate } = await Promise.resolve().then(() => __importStar(require("../run/resolveTemplate.js")));
108
- const env = prepared.env;
150
+ const env = { ...prepared.globals, ...prepared.env };
151
+ const redactor = (0, redact_js_1.createRedactor)(Object.entries(env).filter((entry) => typeof entry[1] === "string"), prepared.redaction);
152
+ const resolve = (value) => redactor.text(resolveTemplate(value, env));
109
153
  return (0, shared_js_1.ok)({
110
154
  dryRun: true,
111
155
  request: {
112
156
  id: runnable.id,
113
157
  name: runnable.name,
114
158
  method: runnable.method,
115
- url: resolveTemplate(runnable.url, env),
116
- headers: (0, mask_js_1.maskHeaderRecord)(Object.fromEntries(Object.entries(runnable.headers ?? {}).map(([key, value]) => [key, resolveTemplate(value, env)]))),
117
- query: Object.fromEntries(Object.entries(runnable.query ?? {}).map(([key, value]) => [key, resolveTemplate(value, env)])),
118
- body: runnable.body ?? null,
159
+ url: resolve(runnable.url),
160
+ headers: redactor.headers(Object.fromEntries(Object.entries(runnable.headers ?? {}).map(([key, value]) => [key, resolveTemplate(value, env)]))),
161
+ query: redactor.query(Object.fromEntries(Object.entries(runnable.query ?? {}).map(([key, value]) => [key, resolveTemplate(value, env)]))),
162
+ body: redactor.value(runnable.body ?? null),
119
163
  hasPreRequestScript: Boolean(runnable.preRequestScript),
120
164
  hasTests: Boolean(runnable.tests),
121
165
  },
122
166
  environment: prepared.environment,
123
167
  availableVariableKeys: Object.keys(env),
124
- unresolvedVariables: unresolved([runnable.url, ...Object.values(runnable.headers ?? {}), ...Object.values(runnable.query ?? {})], env),
125
- warnings: prepared.warnings,
168
+ unresolvedVariables: unresolved([runnable.url, ...Object.values(runnable.headers ?? {}), ...Object.values(runnable.query ?? {}), (0, truncate_js_1.safeStringify)(runnable.body ?? "")], env),
169
+ warnings: [...prepared.warnings, ...skippedWarnings(prepared, [runnable.id])],
170
+ ...(runnable.isEnabledInRunner === false ? { note: "This request is switched off for the collection runner; run_request still runs it." } : {}),
126
171
  });
127
172
  }
128
173
  const outcome = await ctx.withRunLock(() => (0, executeCollection_js_1.executeCollection)({
129
174
  collection: prepared.collection,
130
175
  env: prepared.env,
176
+ globals: prepared.globals,
131
177
  connections: prepared.connections,
132
178
  only: [found.id],
179
+ includeDisabled: true,
133
180
  deadlineMs: ctx.config.runTimeoutMs,
134
181
  }));
135
182
  const summary = (0, summarize_js_1.summarizeRun)(outcome, maxBodyBytes ?? ctx.config.maxBodyBytes, {
136
183
  collection: { id: found.collectionId },
184
+ workspace: (0, lookups_js_1.workspaceTag)(ws),
137
185
  environment: prepared.environment,
138
- warnings: prepared.warnings,
186
+ warnings: [...prepared.warnings, ...skippedWarnings(prepared, [found.id])],
139
187
  ...(annotation ? { resolved: [{ input: request, matched: found.name, id: found.id, note: annotation }] } : {}),
140
- });
188
+ }, prepared.redaction);
141
189
  return (0, shared_js_1.ok)({ ...summary, result: summary.results[0] ?? null });
142
190
  }));
143
191
  server.registerTool("run_collection", {
144
192
  title: "Run a collection locally",
145
- description: "Run a collection (or one folder of it, or specific requests) sequentially from this machine with an environment, sharing variables between requests like the collection runner. Returns per-request results (bounded bodies), a pass/fail summary and the variable names scripts changed. `bail` stops at the first failure. Needs requests:run.",
193
+ description: `Run a collection (or one folder of it, or specific requests) sequentially from this machine with an environment, sharing variables between requests like the collection runner. Requests switched off for the runner are skipped unless named in \`only\`; data-driven contracts run once per row. Returns per-request results (as in run_request, values shown as {{key}}), a pass/fail summary and the variable names scripts changed. \`bail\` stops at the first failure. ${LOCAL_RUN_LIMITS} Needs requests:run.`,
146
194
  inputSchema: {
147
195
  workspace: shared_js_1.workspaceArg,
148
196
  collection: (0, shared_js_1.refArg)("Collection"),
@@ -154,8 +202,7 @@ const registerRunTools = (server, ctx) => {
154
202
  },
155
203
  annotations: shared_js_1.RUN,
156
204
  }, (0, shared_js_1.guarded)(async ({ workspace, collection, folder, only, environment, bail, maxBodyBytes }) => {
157
- const ws = await ctx.resolveWorkspace(workspace);
158
- const resolved = await (0, lookups_js_1.resolveCollection)(ctx, ws.id, collection);
205
+ const { ws, value: resolved } = await (0, lookups_js_1.findCollection)(ctx, workspace, collection);
159
206
  const prepared = await prepareRun(ctx, ws.id, resolved.item.id, environment);
160
207
  let selection = null;
161
208
  if (folder) {
@@ -175,28 +222,37 @@ const registerRunTools = (server, ctx) => {
175
222
  const outcome = await ctx.withRunLock(() => (0, executeCollection_js_1.executeCollection)({
176
223
  collection: prepared.collection,
177
224
  env: prepared.env,
225
+ globals: prepared.globals,
178
226
  connections: prepared.connections,
179
227
  only: selection,
228
+ includeDisabled: Boolean(only && only.length > 0),
180
229
  bail: bail ?? false,
181
230
  deadlineMs: ctx.config.runTimeoutMs,
182
231
  }));
183
232
  return (0, shared_js_1.ok)((0, summarize_js_1.summarizeRun)(outcome, maxBodyBytes ?? ctx.config.maxBodyBytes, {
184
233
  collection: { id: resolved.item.id, name: resolved.item.name },
234
+ workspace: (0, lookups_js_1.workspaceTag)(ws),
185
235
  environment: prepared.environment,
186
- warnings: prepared.warnings,
236
+ warnings: [...prepared.warnings, ...skippedWarnings(prepared, outcome.results.map((result) => result.requestId))],
187
237
  resolved: [(0, resolve_js_1.resolvedSummary)(collection, resolved)],
188
- }));
238
+ }, prepared.redaction));
189
239
  }));
190
240
  };
191
241
  exports.registerRunTools = registerRunTools;
192
242
  const TEMPLATE = /\{\{\s*([^}]+?)\s*\}\}/g;
243
+ // {{env.x}} / {{global.x}} name the same variable as {{x}}; {{$…}} are
244
+ // generators, {{data.…}} data-contract rows, {{response.…}} / {{random.…}}
245
+ // runtime values — none of those can be "missing" before the run.
193
246
  const unresolved = (values, env) => {
194
247
  const missing = new Set();
195
248
  for (const value of values) {
196
249
  for (const match of value.matchAll(TEMPLATE)) {
197
- const key = match[1].trim();
198
- if (!(key in env) && !key.startsWith("$") && !key.startsWith("data."))
199
- missing.add(key);
250
+ const token = match[1].trim();
251
+ if (token.startsWith("$") || /^(data|response|random)\./.test(token))
252
+ continue;
253
+ const key = token.replace(/^(env|global)\./, "");
254
+ if (!(key in env))
255
+ missing.add(token);
200
256
  }
201
257
  }
202
258
  return [...missing];