@rudderhq/cli 0.7.23-canary.2 → 0.7.23-canary.4

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.
package/dist/index.js CHANGED
@@ -28219,6 +28219,122 @@ function formatAgentCliCapabilitiesHumanReadable(capabilities = getAgentCliCapab
28219
28219
  return lines.join("\n").trimEnd();
28220
28220
  }
28221
28221
 
28222
+ // src/agent-v1-mcp-validation.ts
28223
+ function validateMcpToolArguments(toolName, input) {
28224
+ const tool2 = buildAgentV1McpToolsManifest("agent-v1", { surface: "all" }).tools.find((entry) => entry.name === toolName);
28225
+ if (!tool2) return;
28226
+ const schema = tool2.inputSchema;
28227
+ const required = Array.isArray(schema.required) ? schema.required : [];
28228
+ for (const key of required) {
28229
+ const property = String(key);
28230
+ if (!Object.prototype.hasOwnProperty.call(input, property) || input[property] === void 0) {
28231
+ throwInvalidMcpArgument(toolName, property, "is required");
28232
+ }
28233
+ }
28234
+ if (Array.isArray(schema.anyOf)) {
28235
+ const matches = schema.anyOf.some((candidate) => {
28236
+ if (!isRecord2(candidate) || !Array.isArray(candidate.required)) return false;
28237
+ return candidate.required.every((key) => {
28238
+ const property = String(key);
28239
+ return Object.prototype.hasOwnProperty.call(input, property) && input[property] !== void 0;
28240
+ });
28241
+ });
28242
+ if (!matches) {
28243
+ const alternatives = schema.anyOf.flatMap((candidate) => isRecord2(candidate) && Array.isArray(candidate.required) ? candidate.required : []).map(String);
28244
+ throwInvalidMcpArgument(toolName, alternatives.join(" or "), "is required");
28245
+ }
28246
+ }
28247
+ const properties = isRecord2(schema.properties) ? schema.properties : {};
28248
+ for (const [key, value] of Object.entries(input)) {
28249
+ const property = properties[key];
28250
+ if (!isRecord2(property) || value === void 0) continue;
28251
+ const violation = jsonSchemaViolation(value, property);
28252
+ if (violation) throwInvalidMcpArgument(toolName, key, violation);
28253
+ }
28254
+ }
28255
+ function jsonSchemaViolation(value, schema) {
28256
+ if (Array.isArray(schema.anyOf)) {
28257
+ const matches = schema.anyOf.some(
28258
+ (candidate) => isRecord2(candidate) && jsonSchemaViolation(value, candidate) === null
28259
+ );
28260
+ if (!matches) return "does not match any allowed shape";
28261
+ }
28262
+ if (Array.isArray(schema.oneOf)) {
28263
+ const matchingBranches = schema.oneOf.filter(
28264
+ (candidate) => isRecord2(candidate) && jsonSchemaViolation(value, candidate) === null
28265
+ ).length;
28266
+ if (matchingBranches !== 1) return "does not match exactly one allowed shape";
28267
+ }
28268
+ const types = Array.isArray(schema.type) ? schema.type : schema.type === void 0 ? [] : [schema.type];
28269
+ if (types.length > 0) {
28270
+ const validType = types.some((type) => type === "string" ? typeof value === "string" : type === "number" ? typeof value === "number" && Number.isFinite(value) : type === "integer" ? typeof value === "number" && Number.isInteger(value) : type === "boolean" ? typeof value === "boolean" : type === "array" ? Array.isArray(value) : type === "object" ? isRecord2(value) : type === "null" ? value === null : false);
28271
+ if (!validType) return `must be ${types.join(" or ")}`;
28272
+ }
28273
+ if (typeof value === "string") {
28274
+ const characterLength = Array.from(value).length;
28275
+ if (typeof schema.minLength === "number" && characterLength < schema.minLength) {
28276
+ return `must contain at least ${schema.minLength} character(s)`;
28277
+ }
28278
+ if (typeof schema.maxLength === "number" && characterLength > schema.maxLength) {
28279
+ return `must contain at most ${schema.maxLength} characters`;
28280
+ }
28281
+ if (Array.isArray(schema.enum) && !schema.enum.includes(value)) {
28282
+ return `must be one of: ${schema.enum.join(", ")}`;
28283
+ }
28284
+ }
28285
+ if (typeof value === "number") {
28286
+ if (typeof schema.minimum === "number" && value < schema.minimum) {
28287
+ return `must be at least ${schema.minimum}`;
28288
+ }
28289
+ if (typeof schema.maximum === "number" && value > schema.maximum) {
28290
+ return `must be at most ${schema.maximum}`;
28291
+ }
28292
+ }
28293
+ if (Array.isArray(value)) {
28294
+ if (typeof schema.minItems === "number" && value.length < schema.minItems) {
28295
+ return `must contain at least ${schema.minItems} items`;
28296
+ }
28297
+ if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
28298
+ return `must contain at most ${schema.maxItems} items`;
28299
+ }
28300
+ if (isRecord2(schema.items)) {
28301
+ for (const [index, item] of value.entries()) {
28302
+ const violation = jsonSchemaViolation(item, schema.items);
28303
+ if (violation) return `item ${index} ${violation}`;
28304
+ }
28305
+ }
28306
+ }
28307
+ if (isRecord2(value)) {
28308
+ const properties = isRecord2(schema.properties) ? schema.properties : {};
28309
+ if (typeof schema.minProperties === "number" && Object.keys(value).length < schema.minProperties) {
28310
+ return `must contain at least ${schema.minProperties} propert${schema.minProperties === 1 ? "y" : "ies"}`;
28311
+ }
28312
+ const required = Array.isArray(schema.required) ? schema.required.map(String) : [];
28313
+ for (const key of required) {
28314
+ if (!Object.prototype.hasOwnProperty.call(value, key)) return `field ${key} is required`;
28315
+ }
28316
+ if (schema.additionalProperties === false) {
28317
+ const unsupported = Object.keys(value).filter((key) => !(key in properties));
28318
+ if (unsupported.length > 0) return `contains unsupported field(s): ${unsupported.sort().join(", ")}`;
28319
+ }
28320
+ for (const [key, child] of Object.entries(value)) {
28321
+ const childSchema = properties[key];
28322
+ if (!isRecord2(childSchema)) continue;
28323
+ const violation = jsonSchemaViolation(child, childSchema);
28324
+ if (violation) return `field ${key} ${violation}`;
28325
+ }
28326
+ }
28327
+ return null;
28328
+ }
28329
+ function throwInvalidMcpArgument(toolName, key, reason) {
28330
+ const err = new Error(`Invalid argument for ${toolName}: ${key} ${reason}. Consult tools/list for the exact schema.`);
28331
+ err.code = "rudder_mcp_invalid_arguments";
28332
+ throw err;
28333
+ }
28334
+ function isRecord2(value) {
28335
+ return typeof value === "object" && value !== null && !Array.isArray(value);
28336
+ }
28337
+
28222
28338
  // src/client/http.ts
28223
28339
  import { URL as URL3 } from "node:url";
28224
28340
 
@@ -28665,7 +28781,7 @@ function issueTransportUnavailable(state, now, requestScope = state) {
28665
28781
  function attachTransportDiagnostic(error, state, now, requestScope = state) {
28666
28782
  const upstreamDetails = error.details;
28667
28783
  error.details = {
28668
- ...isRecord2(upstreamDetails) ? upstreamDetails : upstreamDetails === void 0 ? {} : { upstreamDetails },
28784
+ ...isRecord3(upstreamDetails) ? upstreamDetails : upstreamDetails === void 0 ? {} : { upstreamDetails },
28669
28785
  issueTransport: transportDiagnostic(state, now, requestScope)
28670
28786
  };
28671
28787
  }
@@ -28822,7 +28938,7 @@ async function writeState(filePath, state) {
28822
28938
  }
28823
28939
  }
28824
28940
  function normalizeIssueTransportState(value) {
28825
- if (!isRecord2(value)) return null;
28941
+ if (!isRecord3(value)) return null;
28826
28942
  const operation = typeof value.operation === "string" ? value.operation.trim() : "";
28827
28943
  const issueId = typeof value.issueId === "string" ? value.issueId.trim() : "";
28828
28944
  const scopeKey = typeof value.scopeKey === "string" && value.scopeKey.trim().length > 0 ? value.scopeKey.trim() : issueId ? `issue:${issueId}` : "";
@@ -28893,7 +29009,7 @@ function issueCommentPayload(value) {
28893
29009
  } catch {
28894
29010
  return null;
28895
29011
  }
28896
- if (!isRecord2(parsed) || typeof parsed.body !== "string" || parsed.body.length === 0) return null;
29012
+ if (!isRecord3(parsed) || typeof parsed.body !== "string" || parsed.body.length === 0) return null;
28897
29013
  return { body: parsed.body, reopen: parsed.reopen === true };
28898
29014
  }
28899
29015
  async function retireExpiredState(stateFilePath, state, now) {
@@ -28953,7 +29069,7 @@ function issueTransportStorageUnavailable(scope, surface) {
28953
29069
  );
28954
29070
  }
28955
29071
  function normalizeFingerprint(value) {
28956
- if (!isRecord2(value) || typeof value.fingerprint !== "string" || typeof value.status !== "number" || typeof value.code !== "string" || typeof value.normalizedMessage !== "string") {
29072
+ if (!isRecord3(value) || typeof value.fingerprint !== "string" || typeof value.status !== "number" || typeof value.code !== "string" || typeof value.normalizedMessage !== "string") {
28957
29073
  return void 0;
28958
29074
  }
28959
29075
  return {
@@ -28986,14 +29102,14 @@ function normalizeScopeValue(value) {
28986
29102
  function transportSurfaceFromEnv() {
28987
29103
  return process.env.RUDDER_TOOL_TRANSPORT_SURFACE === "mcp" ? "mcp" : "cli";
28988
29104
  }
28989
- function isRecord2(value) {
29105
+ function isRecord3(value) {
28990
29106
  return typeof value === "object" && value !== null && !Array.isArray(value);
28991
29107
  }
28992
29108
  function isAlreadyExists(error) {
28993
- return isRecord2(error) && error.code === "EEXIST";
29109
+ return isRecord3(error) && error.code === "EEXIST";
28994
29110
  }
28995
29111
  function isNotFound(error) {
28996
- return isRecord2(error) && error.code === "ENOENT";
29112
+ return isRecord3(error) && error.code === "ENOENT";
28997
29113
  }
28998
29114
 
28999
29115
  // src/client/http.ts
@@ -29923,10 +30039,10 @@ function buildAgentV1ToolCallPlan(toolName, rawArgs, env = buildMcpServerEnv())
29923
30039
  if (!capabilityId) {
29924
30040
  throw new Error(`Unknown Rudder MCP tool: ${toolName}`);
29925
30041
  }
29926
- if (rawArgs !== void 0 && rawArgs !== null && !isRecord3(rawArgs)) {
30042
+ if (rawArgs !== void 0 && rawArgs !== null && !isRecord4(rawArgs)) {
29927
30043
  throwInvalidMcpArgument(toolName, "arguments", "must be object");
29928
30044
  }
29929
- const input = normalizeLegacyToolArguments(capabilityId, isRecord3(rawArgs) ? rawArgs : {});
30045
+ const input = normalizeLegacyToolArguments(capabilityId, isRecord4(rawArgs) ? rawArgs : {});
29930
30046
  const capability = getAgentCliCapabilityById(capabilityId);
29931
30047
  rejectModelProvidedRuntimeIdentity(input);
29932
30048
  rejectUnsupportedToolArguments(toolName, input);
@@ -30036,7 +30152,7 @@ async function runAgentV1McpJsonRpcMessage(message, env = buildMcpServerEnv(), s
30036
30152
  case "tools/list": {
30037
30153
  const tools = surface === "computer" ? computerCapabilityEnabled(env) ? COMPUTER_USE_MCP_TOOLS : [] : surface === "browser" && !browserCapabilityEnabled(env) ? [] : buildAgentV1McpToolsManifest("agent-v1", { surface }).tools.map(toMcpToolListEntry);
30038
30154
  if (isModernMcpRequest(message.params)) {
30039
- const cursor = isRecord3(message.params) ? message.params.cursor : void 0;
30155
+ const cursor = isRecord4(message.params) ? message.params.cursor : void 0;
30040
30156
  if (typeof cursor === "string" && parseMcpToolCursor(cursor) === null) {
30041
30157
  return rpcError(id, -32602, "Invalid tools/list cursor");
30042
30158
  }
@@ -30190,7 +30306,7 @@ async function callToolSafely(params, env, surface, signal) {
30190
30306
  const details = errorDetails(err);
30191
30307
  const payload = {
30192
30308
  status: "error",
30193
- code: isRecord3(details) && typeof details.code === "string" ? details.code : "rudder_mcp_tool_error",
30309
+ code: isRecord4(details) && typeof details.code === "string" ? details.code : "rudder_mcp_tool_error",
30194
30310
  message: errorMessage(err),
30195
30311
  details: details ?? null
30196
30312
  };
@@ -30205,7 +30321,7 @@ async function callToolSafely(params, env, surface, signal) {
30205
30321
  }
30206
30322
  }
30207
30323
  async function callTool(params, env, surface, signal) {
30208
- const record = isRecord3(params) ? params : {};
30324
+ const record = isRecord4(params) ? params : {};
30209
30325
  const toolName = typeof record.name === "string" ? record.name : "";
30210
30326
  if (surface === "computer") {
30211
30327
  if (!computerCapabilityEnabled(env)) {
@@ -30220,7 +30336,7 @@ async function callTool(params, env, surface, signal) {
30220
30336
  error.code = "rudder_mcp_tool_not_available";
30221
30337
  throw error;
30222
30338
  }
30223
- const rawArgs2 = isRecord3(record.arguments) ? record.arguments : {};
30339
+ const rawArgs2 = isRecord4(record.arguments) ? record.arguments : {};
30224
30340
  rejectModelProvidedRuntimeIdentity(rawArgs2);
30225
30341
  const parsed = computerUseActionSchemas[action].safeParse(rawArgs2);
30226
30342
  if (!parsed.success) {
@@ -30239,7 +30355,7 @@ async function callTool(params, env, surface, signal) {
30239
30355
  throw err;
30240
30356
  }
30241
30357
  const rawArgs = record.arguments;
30242
- const args = isRecord3(rawArgs) ? normalizeLegacyToolArguments(toolNameToCapabilityId(toolName) ?? "", rawArgs) : rawArgs;
30358
+ const args = isRecord4(rawArgs) ? normalizeLegacyToolArguments(toolNameToCapabilityId(toolName) ?? "", rawArgs) : rawArgs;
30243
30359
  const plan = buildAgentV1ToolCallPlan(toolName, args, env);
30244
30360
  const directResult = await callToolDirectlyIfSupported(toolName, args, env, signal);
30245
30361
  if (directResult) return directResult;
@@ -30283,7 +30399,7 @@ async function callTool(params, env, surface, signal) {
30283
30399
  async function callToolDirectlyIfSupported(toolName, rawArgs, env, signal) {
30284
30400
  const capabilityId = toolNameToCapabilityId(toolName);
30285
30401
  if (!capabilityId) return null;
30286
- const input = isRecord3(rawArgs) ? rawArgs : {};
30402
+ const input = isRecord4(rawArgs) ? rawArgs : {};
30287
30403
  if (hasLocalImageInputs(input.images)) return null;
30288
30404
  const api = mcpApiClient(env, signal);
30289
30405
  const success = (data) => mcpSuccess(
@@ -30641,7 +30757,7 @@ function mcpApiClient(env, signal) {
30641
30757
  });
30642
30758
  }
30643
30759
  function mcpSuccess(data, maxResultBytes = RUDDER_MCP_MAX_TOOL_RESULT_BYTES) {
30644
- if (isRecord3(data) && (data.mimeType === "image/png" || data.mimeType === "image/jpeg") && typeof data.base64 === "string" && data.base64.length > 0) {
30760
+ if (isRecord4(data) && (data.mimeType === "image/png" || data.mimeType === "image/jpeg") && typeof data.base64 === "string" && data.base64.length > 0) {
30645
30761
  const { base64, ...metadata } = data;
30646
30762
  return {
30647
30763
  content: [{ type: "image", data: base64, mimeType: data.mimeType }],
@@ -30652,9 +30768,9 @@ function mcpSuccess(data, maxResultBytes = RUDDER_MCP_MAX_TOOL_RESULT_BYTES) {
30652
30768
  return mcpSuccessFromJsonText(JSON.stringify(data ?? {}), maxResultBytes);
30653
30769
  }
30654
30770
  function mcpSuccessWithImages(data, maxResultBytes) {
30655
- if (!isRecord3(data) || !Array.isArray(data.images)) return mcpSuccess(data, maxResultBytes);
30771
+ if (!isRecord4(data) || !Array.isArray(data.images)) return mcpSuccess(data, maxResultBytes);
30656
30772
  const images = data.images.filter(
30657
- (entry) => isRecord3(entry) && (entry.mimeType === "image/png" || entry.mimeType === "image/jpeg") && typeof entry.base64 === "string" && entry.base64.length > 0
30773
+ (entry) => isRecord4(entry) && (entry.mimeType === "image/png" || entry.mimeType === "image/jpeg") && typeof entry.base64 === "string" && entry.base64.length > 0
30658
30774
  );
30659
30775
  if (images.length === 0) return mcpSuccess(data, maxResultBytes);
30660
30776
  const metadata = { ...data };
@@ -30899,7 +31015,7 @@ function cliArgsForCapability(capabilityId, input, tempFiles, env) {
30899
31015
  }
30900
31016
  case "issue.comment": {
30901
31017
  const args = ["issue", "comment", requiredAnyString(input, ["issue", "issueId"])];
30902
- pushBodyFile(args, "--body-file", input.body ?? input.comment, tempFiles);
31018
+ pushBodyFile(args, "--body-file", firstNonBlankString(input, ["body", "comment"]), tempFiles);
30903
31019
  pushImages(args, input.images);
30904
31020
  if (input.reopen === true) args.push("--reopen");
30905
31021
  return args;
@@ -30925,15 +31041,16 @@ function cliArgsForCapability(capabilityId, input, tempFiles, env) {
30925
31041
  pushOptional(args, "--request-depth", input.requestDepth);
30926
31042
  pushOptional(args, "--billing-code", input.billingCode);
30927
31043
  pushOptional(args, "--hidden-at", input.hiddenAt);
30928
- if (typeof (input.comment ?? input.body) === "string") {
30929
- pushBodyFile(args, "--comment-file", input.comment ?? input.body, tempFiles);
31044
+ const comment = firstNonBlankString(input, ["comment", "body"]);
31045
+ if (comment) {
31046
+ pushBodyFile(args, "--comment-file", comment, tempFiles);
30930
31047
  }
30931
31048
  pushImages(args, input.images);
30932
31049
  return args;
30933
31050
  }
30934
31051
  case "issue.review": {
30935
31052
  const args = ["issue", "review", requiredAnyString(input, ["issue", "issueId"]), "--decision", requiredString(input, "decision")];
30936
- pushBodyFile(args, "--comment-file", input.comment ?? input.body, tempFiles);
31053
+ pushBodyFile(args, "--comment-file", firstNonBlankString(input, ["comment", "body"]), tempFiles);
30937
31054
  return args;
30938
31055
  }
30939
31056
  case "issue.commit": {
@@ -30946,13 +31063,13 @@ function cliArgsForCapability(capabilityId, input, tempFiles, env) {
30946
31063
  }
30947
31064
  case "issue.done": {
30948
31065
  const args = ["issue", "done", requiredAnyString(input, ["issue", "issueId"])];
30949
- pushBodyFile(args, "--comment-file", input.comment ?? input.body, tempFiles);
31066
+ pushBodyFile(args, "--comment-file", firstNonBlankString(input, ["comment", "body"]), tempFiles);
30950
31067
  pushImages(args, input.images);
30951
31068
  return args;
30952
31069
  }
30953
31070
  case "issue.block": {
30954
31071
  const args = ["issue", "block", requiredAnyString(input, ["issue", "issueId"])];
30955
- pushBodyFile(args, "--comment-file", input.comment ?? input.body, tempFiles);
31072
+ pushBodyFile(args, "--comment-file", firstNonBlankString(input, ["comment", "body"]), tempFiles);
30956
31073
  pushImages(args, input.images);
30957
31074
  return args;
30958
31075
  }
@@ -31016,7 +31133,7 @@ function cliArgsForCapability(capabilityId, input, tempFiles, env) {
31016
31133
  return ["approval", "issues", requiredAnyString(input, ["approval", "approvalId"])];
31017
31134
  case "approval.comment": {
31018
31135
  const args = ["approval", "comment", requiredAnyString(input, ["approval", "approvalId"])];
31019
- pushBodyFile(args, "--body-file", input.body ?? input.comment, tempFiles);
31136
+ pushBodyFile(args, "--body-file", firstNonBlankString(input, ["body", "comment"]), tempFiles);
31020
31137
  return args;
31021
31138
  }
31022
31139
  case "skill.list":
@@ -31352,7 +31469,7 @@ function modernOrLegacyResult(params, result, options) {
31352
31469
  }
31353
31470
  function paginateMcpTools(tools, params) {
31354
31471
  if (!isModernMcpRequest(params)) return { tools };
31355
- const record = isRecord3(params) ? params : {};
31472
+ const record = isRecord4(params) ? params : {};
31356
31473
  const cursor = typeof record.cursor === "string" ? record.cursor : null;
31357
31474
  const offset = cursor === null ? 0 : parseMcpToolCursor(cursor) ?? 0;
31358
31475
  const page = tools.slice(offset, offset + RUDDER_MCP_TOOL_PAGE_SIZE);
@@ -31375,7 +31492,7 @@ function parseMcpToolCursor(cursor) {
31375
31492
  return null;
31376
31493
  }
31377
31494
  function requestedProtocolVersion(params) {
31378
- if (!isRecord3(params)) return null;
31495
+ if (!isRecord4(params)) return null;
31379
31496
  return typeof params.protocolVersion === "string" && params.protocolVersion.trim().length > 0 ? params.protocolVersion.trim() : null;
31380
31497
  }
31381
31498
  function toolNameToCapabilityId(toolName) {
@@ -31389,11 +31506,16 @@ function requiredString(input, key) {
31389
31506
  throw new Error(`Missing required argument: ${key}`);
31390
31507
  }
31391
31508
  function requiredAnyString(input, keys) {
31509
+ const value = firstNonBlankString(input, keys);
31510
+ if (value) return value;
31511
+ throw new Error(`Missing required argument: ${keys[0]}`);
31512
+ }
31513
+ function firstNonBlankString(input, keys) {
31392
31514
  for (const key of keys) {
31393
31515
  const value = optionalString(input[key]);
31394
31516
  if (value) return value;
31395
31517
  }
31396
- throw new Error(`Missing required argument: ${keys[0]}`);
31518
+ return null;
31397
31519
  }
31398
31520
  function optionalString(value) {
31399
31521
  if (typeof value === "string" && value.trim().length > 0) return value.trim();
@@ -31420,7 +31542,7 @@ function pushJson(args, flag, value) {
31420
31542
  args.push(flag, value.trim());
31421
31543
  return;
31422
31544
  }
31423
- if (isRecord3(value) || Array.isArray(value)) {
31545
+ if (isRecord4(value) || Array.isArray(value)) {
31424
31546
  args.push(flag, JSON.stringify(value));
31425
31547
  }
31426
31548
  }
@@ -31477,106 +31599,6 @@ function rejectUnsupportedToolArguments(toolName, input) {
31477
31599
  err.code = "rudder_mcp_invalid_arguments";
31478
31600
  throw err;
31479
31601
  }
31480
- function validateMcpToolArguments(toolName, input) {
31481
- const tool2 = buildAgentV1McpToolsManifest("agent-v1", { surface: "all" }).tools.find((entry) => entry.name === toolName);
31482
- if (!tool2) return;
31483
- const schema = tool2.inputSchema;
31484
- const required = Array.isArray(schema.required) ? schema.required : [];
31485
- for (const key of required) {
31486
- const value = input[key];
31487
- const missing = value === void 0 || value === null || typeof value === "string" && value.trim().length === 0 || Array.isArray(value) && value.length === 0;
31488
- if (missing) throwInvalidMcpArgument(toolName, key, "is required");
31489
- }
31490
- if (Array.isArray(schema.anyOf)) {
31491
- const matches = schema.anyOf.some((candidate) => {
31492
- if (!isRecord3(candidate) || !Array.isArray(candidate.required)) return false;
31493
- return candidate.required.every((key) => {
31494
- const value = input[String(key)];
31495
- return value !== void 0 && value !== null && !(typeof value === "string" && value.trim().length === 0) && !(Array.isArray(value) && value.length === 0);
31496
- });
31497
- });
31498
- if (!matches) {
31499
- const alternatives = schema.anyOf.flatMap((candidate) => isRecord3(candidate) && Array.isArray(candidate.required) ? candidate.required : []).map(String);
31500
- throwInvalidMcpArgument(toolName, alternatives.join(" or "), "is required");
31501
- }
31502
- }
31503
- for (const [key, value] of Object.entries(input)) {
31504
- const property = schema.properties[key];
31505
- if (!isRecord3(property) || value === void 0) continue;
31506
- const violation = jsonSchemaViolation(value, property);
31507
- if (violation) throwInvalidMcpArgument(toolName, key, violation);
31508
- }
31509
- }
31510
- function jsonSchemaViolation(value, schema) {
31511
- if (Array.isArray(schema.oneOf)) {
31512
- const matches = schema.oneOf.some(
31513
- (candidate) => isRecord3(candidate) && jsonSchemaViolation(value, candidate) === null
31514
- );
31515
- if (!matches) return "does not match any allowed shape";
31516
- }
31517
- const types = Array.isArray(schema.type) ? schema.type : schema.type === void 0 ? [] : [schema.type];
31518
- if (types.length > 0) {
31519
- const validType = types.some((type) => type === "string" ? typeof value === "string" : type === "number" ? typeof value === "number" && Number.isFinite(value) : type === "boolean" ? typeof value === "boolean" : type === "array" ? Array.isArray(value) : type === "object" ? isRecord3(value) : false);
31520
- if (!validType) return `must be ${types.join(" or ")}`;
31521
- }
31522
- if (typeof value === "string") {
31523
- const characterLength = Array.from(value).length;
31524
- if (typeof schema.minLength === "number" && characterLength < schema.minLength) {
31525
- return `must contain at least ${schema.minLength} character(s)`;
31526
- }
31527
- if (typeof schema.maxLength === "number" && characterLength > schema.maxLength) {
31528
- return `must contain at most ${schema.maxLength} characters`;
31529
- }
31530
- if (Array.isArray(schema.enum) && !schema.enum.includes(value)) {
31531
- return `must be one of: ${schema.enum.join(", ")}`;
31532
- }
31533
- }
31534
- if (typeof value === "number") {
31535
- if (typeof schema.minimum === "number" && value < schema.minimum) {
31536
- return `must be at least ${schema.minimum}`;
31537
- }
31538
- if (typeof schema.maximum === "number" && value > schema.maximum) {
31539
- return `must be at most ${schema.maximum}`;
31540
- }
31541
- }
31542
- if (Array.isArray(value)) {
31543
- if (typeof schema.minItems === "number" && value.length < schema.minItems) {
31544
- return `must contain at least ${schema.minItems} items`;
31545
- }
31546
- if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
31547
- return `must contain at most ${schema.maxItems} items`;
31548
- }
31549
- if (isRecord3(schema.items)) {
31550
- for (const [index, item] of value.entries()) {
31551
- const violation = jsonSchemaViolation(item, schema.items);
31552
- if (violation) return `item ${index} ${violation}`;
31553
- }
31554
- }
31555
- }
31556
- if (isRecord3(value) && schema.type === "object") {
31557
- const properties = isRecord3(schema.properties) ? schema.properties : {};
31558
- const required = Array.isArray(schema.required) ? schema.required.map(String) : [];
31559
- for (const key of required) {
31560
- if (!(key in value)) return `field ${key} is required`;
31561
- }
31562
- if (schema.additionalProperties === false) {
31563
- const unsupported = Object.keys(value).filter((key) => !(key in properties));
31564
- if (unsupported.length > 0) return `contains unsupported field(s): ${unsupported.sort().join(", ")}`;
31565
- }
31566
- for (const [key, child] of Object.entries(value)) {
31567
- const childSchema = properties[key];
31568
- if (!isRecord3(childSchema)) continue;
31569
- const violation = jsonSchemaViolation(child, childSchema);
31570
- if (violation) return `field ${key} ${violation}`;
31571
- }
31572
- }
31573
- return null;
31574
- }
31575
- function throwInvalidMcpArgument(toolName, key, reason) {
31576
- const err = new Error(`Invalid argument for ${toolName}: ${key} ${reason}. Consult tools/list for the exact schema.`);
31577
- err.code = "rudder_mcp_invalid_arguments";
31578
- throw err;
31579
- }
31580
31602
  var READ_ONLY_BROWSER_LOCATOR_ACTIONS = /* @__PURE__ */ new Set([
31581
31603
  "count",
31582
31604
  "allTextContents",
@@ -31627,7 +31649,7 @@ function assertBrowserCapabilityEnabled(capabilityId, env) {
31627
31649
  function structuredContentFromJsonText(text6) {
31628
31650
  try {
31629
31651
  const parsed = JSON.parse(text6);
31630
- if (isRecord3(parsed)) return { structuredContent: parsed };
31652
+ if (isRecord4(parsed)) return { structuredContent: parsed };
31631
31653
  return { structuredContent: { result: parsed } };
31632
31654
  } catch {
31633
31655
  return {};
@@ -31716,7 +31738,7 @@ function errorMessage(err) {
31716
31738
  function errorDetails(err) {
31717
31739
  if (!(err instanceof Error)) return void 0;
31718
31740
  if (err instanceof ApiRequestError) {
31719
- const details = isRecord3(err.details) ? err.details : err.details === void 0 ? {} : { upstreamDetails: err.details };
31741
+ const details = isRecord4(err.details) ? err.details : err.details === void 0 ? {} : { upstreamDetails: err.details };
31720
31742
  return {
31721
31743
  code: err.code ?? "api_request_error",
31722
31744
  status: err.status,
@@ -31726,7 +31748,7 @@ function errorDetails(err) {
31726
31748
  const code = err.code;
31727
31749
  return code ? { code } : void 0;
31728
31750
  }
31729
- function isRecord3(value) {
31751
+ function isRecord4(value) {
31730
31752
  return typeof value === "object" && value !== null && !Array.isArray(value);
31731
31753
  }
31732
31754