@rudderhq/cli 0.4.2 → 0.4.3-canary.1

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
@@ -1623,7 +1623,7 @@ var init_organization_skill = __esm({
1623
1623
 
1624
1624
  // ../packages/shared/dist/validators/organization.js
1625
1625
  import { z as z11 } from "zod";
1626
- var logoAssetIdSchema, brandColorSchema, createOrganizationSchema, updateOrganizationSchema, updateOrganizationBrandingSchema, updateOrganizationWorkspaceFileSchema, createOrganizationWorkspaceFileSchema, createOrganizationWorkspaceDirectorySchema, renameOrganizationWorkspaceEntrySchema, moveOrganizationWorkspaceEntrySchema;
1626
+ var logoAssetIdSchema, brandColorSchema, createOrganizationSchema, updateOrganizationSchema, updateOrganizationBrandingSchema, updateOrganizationWorkspaceFileSchema, createOrganizationWorkspaceFileSchema, createOrganizationWorkspaceDirectorySchema, renameOrganizationWorkspaceEntrySchema, moveOrganizationWorkspaceEntrySchema, copyOrganizationWorkspaceEntrySchema;
1627
1627
  var init_organization = __esm({
1628
1628
  "../packages/shared/dist/validators/organization.js"() {
1629
1629
  "use strict";
@@ -1668,6 +1668,9 @@ var init_organization = __esm({
1668
1668
  moveOrganizationWorkspaceEntrySchema = z11.object({
1669
1669
  destinationDirectoryPath: z11.string().trim().max(1e3).default("")
1670
1670
  });
1671
+ copyOrganizationWorkspaceEntrySchema = z11.object({
1672
+ destinationDirectoryPath: z11.string().trim().max(1e3).optional()
1673
+ });
1671
1674
  }
1672
1675
  });
1673
1676
 
@@ -1823,13 +1826,14 @@ var init_agent = __esm({
1823
1826
  runtimeConfig: z13.record(z13.unknown()).optional().default({}),
1824
1827
  budgetMonthlyCents: z13.number().int().nonnegative().optional().default(0),
1825
1828
  permissions: agentPermissionsSchema.optional(),
1826
- metadata: z13.record(z13.unknown()).optional().nullable()
1829
+ metadata: z13.record(z13.unknown()).optional().nullable(),
1830
+ seedOrganizationIntelligenceDefaults: z13.boolean().optional().default(false)
1827
1831
  });
1828
- createAgentHireSchema = createAgentSchema.extend({
1832
+ createAgentHireSchema = createAgentSchema.omit({ seedOrganizationIntelligenceDefaults: true }).extend({
1829
1833
  sourceIssueId: z13.string().uuid().optional().nullable(),
1830
1834
  sourceIssueIds: z13.array(z13.string().uuid()).optional()
1831
1835
  });
1832
- updateAgentSchema = createAgentSchema.omit({ permissions: true }).partial().extend({
1836
+ updateAgentSchema = createAgentSchema.omit({ permissions: true, seedOrganizationIntelligenceDefaults: true }).partial().extend({
1833
1837
  permissions: z13.never().optional(),
1834
1838
  replaceAgentRuntimeConfig: z13.boolean().optional(),
1835
1839
  status: z13.enum(AGENT_STATUSES).optional(),
@@ -3589,7 +3593,7 @@ var init_env = __esm({
3589
3593
  });
3590
3594
 
3591
3595
  // src/runtime/install.ts
3592
- import { execFileSync, spawnSync } from "node:child_process";
3596
+ import { execFileSync, spawnSync as spawnSync2 } from "node:child_process";
3593
3597
  import { cp, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
3594
3598
  import { createRequire } from "node:module";
3595
3599
  import path5 from "node:path";
@@ -3697,7 +3701,7 @@ async function ensureRuntimeInstalled(options) {
3697
3701
  postgresPayload2
3698
3702
  );
3699
3703
  }
3700
- const spawnSyncImpl = options.spawnSyncImpl ?? spawnSync;
3704
+ const spawnSyncImpl = options.spawnSyncImpl ?? spawnSync2;
3701
3705
  const existingRuntimeOutput = await tryRepairExistingRuntimePackage({
3702
3706
  spawnSyncImpl,
3703
3707
  cacheDir,
@@ -4446,11 +4450,11 @@ var init_server_entry = __esm({
4446
4450
  });
4447
4451
 
4448
4452
  // src/version.ts
4449
- import { existsSync, readFileSync } from "node:fs";
4453
+ import { existsSync as existsSync2, readFileSync } from "node:fs";
4450
4454
  import path7 from "node:path";
4451
4455
  import { fileURLToPath as fileURLToPath3 } from "node:url";
4452
4456
  function readPackageVersion(packagePath, expectedName) {
4453
- if (!existsSync(packagePath)) return null;
4457
+ if (!existsSync2(packagePath)) return null;
4454
4458
  try {
4455
4459
  const parsed = JSON.parse(readFileSync(packagePath, "utf8"));
4456
4460
  if (parsed.name === expectedName && parsed.version) return parsed.version;
@@ -6044,7 +6048,7 @@ var init_doctor = __esm({
6044
6048
  });
6045
6049
 
6046
6050
  // src/install.ts
6047
- import { execFileSync as execFileSync2, spawnSync as spawnSync2 } from "node:child_process";
6051
+ import { execFileSync as execFileSync2, spawnSync as spawnSync3 } from "node:child_process";
6048
6052
  function normalizePath(value) {
6049
6053
  return (value ?? "").replaceAll("\\", "/").toLowerCase();
6050
6054
  }
@@ -6127,7 +6131,7 @@ function detectPersistentCliState(options = {}) {
6127
6131
  };
6128
6132
  }
6129
6133
  function installPersistentCli(options) {
6130
- const spawnSyncImpl = options.spawnSyncImpl ?? spawnSync2;
6134
+ const spawnSyncImpl = options.spawnSyncImpl ?? spawnSync3;
6131
6135
  const command = `npm install --global ${options.installSpec}`;
6132
6136
  const initialResult = runNpmGlobalInstall(spawnSyncImpl, ["install", "--global", options.installSpec]);
6133
6137
  const initialOutput = collectSpawnOutput2(initialResult);
@@ -6815,7 +6819,8 @@ var init_onboard = __esm({
6815
6819
  import { Command, CommanderError } from "commander";
6816
6820
 
6817
6821
  // src/agent-v1-mcp-server.ts
6818
- import { spawn } from "node:child_process";
6822
+ import { spawn, spawnSync } from "node:child_process";
6823
+ import { existsSync } from "node:fs";
6819
6824
  import fs from "node:fs/promises";
6820
6825
  import os from "node:os";
6821
6826
  import path from "node:path";
@@ -7847,6 +7852,9 @@ function mcpBoolean(description) {
7847
7852
  function mcpNumber(description) {
7848
7853
  return { type: "number", description };
7849
7854
  }
7855
+ function mcpStringArray(description) {
7856
+ return { type: "array", items: { type: "string" }, description };
7857
+ }
7850
7858
  function mcpInputSchemaForCapability(id) {
7851
7859
  const properties = {};
7852
7860
  const add = (key, value) => {
@@ -7861,6 +7869,9 @@ function mcpInputSchemaForCapability(id) {
7861
7869
  if (id.startsWith("project.")) add("project", mcpString("Project UUID or shortname."));
7862
7870
  if (id.startsWith("library.file.")) {
7863
7871
  add("path", mcpString("Library-relative file or directory path."));
7872
+ if (id === "library.file.list") {
7873
+ add("directory", mcpString("Library-relative directory path. Defaults to the run's project Library path when available."));
7874
+ }
7864
7875
  add("body", mcpString("Direct file content for put operations."));
7865
7876
  }
7866
7877
  if (id.startsWith("approval.")) {
@@ -7883,6 +7894,7 @@ function mcpInputSchemaForCapability(id) {
7883
7894
  if (id.startsWith("runs.")) add("run", mcpString("Run id or short run id."));
7884
7895
  if (id.startsWith("agent.skills.")) {
7885
7896
  add("selectionRefs", { type: "array", items: { type: "string" }, description: "Skill selection refs." });
7897
+ add("skills", { type: "array", items: { type: "string" }, description: "Skill selection refs alias." });
7886
7898
  add("desiredSkills", mcpString("Comma-separated desired skill refs for sync."));
7887
7899
  }
7888
7900
  for (const [key, description] of Object.entries({
@@ -7892,19 +7904,105 @@ function mcpInputSchemaForCapability(id) {
7892
7904
  name: "Name.",
7893
7905
  description: "Description or summary text.",
7894
7906
  status: "Status filter or new status.",
7895
- limit: "Page size or result limit.",
7896
7907
  cursor: "Pagination cursor.",
7897
7908
  source: "Source path or source label.",
7898
- kind: "Trigger kind."
7909
+ kind: "Trigger kind.",
7910
+ label: "Trigger label.",
7911
+ skill: "Skill key, id, or display name.",
7912
+ slug: "Slug.",
7913
+ markdown: "Direct Markdown content.",
7914
+ role: "Agent role.",
7915
+ reportsTo: "Manager or reporting agent reference.",
7916
+ capabilities: "Agent capability summary.",
7917
+ wakeCommentId: "Issue comment id that triggered the wake.",
7918
+ expectedStatuses: "Comma-separated checkout precondition statuses.",
7919
+ after: "Pagination anchor or lower bound.",
7920
+ order: "Sort order.",
7921
+ priority: "Issue or automation priority.",
7922
+ assigneeAgentId: "Target assignee agent id or reference.",
7923
+ projectId: "Project id or reference.",
7924
+ goalId: "Goal id or reference.",
7925
+ parentId: "Parent issue id or reference.",
7926
+ parentIssueId: "Parent issue id or reference.",
7927
+ requestDepth: "Requested issue depth.",
7928
+ billingCode: "Billing code.",
7929
+ hiddenAt: "Hidden timestamp.",
7930
+ archivedAt: "Archived timestamp.",
7931
+ targetDate: "Target date.",
7932
+ color: "Display color.",
7933
+ scope: "Search or visibility scope.",
7934
+ sha: "Git commit SHA.",
7935
+ message: "Commit or status message.",
7936
+ branch: "Git branch name.",
7937
+ repoPath: "Repository path.",
7938
+ workspacePath: "Workspace path.",
7939
+ relatedAgentId: "Agent id used as a filter or related principal.",
7940
+ leadAgentId: "Lead agent id or reference.",
7941
+ approvalId: "Approval id or short approval id alias.",
7942
+ automationId: "Automation id alias.",
7943
+ chatId: "Chat conversation id alias.",
7944
+ commentId: "Issue comment id alias.",
7945
+ skillId: "Skill id alias.",
7946
+ user: "User id, reference, or self.",
7947
+ since: "Activity start timestamp.",
7948
+ until: "Activity end timestamp.",
7949
+ include: "Comma-separated optional data sections.",
7950
+ content: "Direct content alias for body.",
7951
+ roots: "Comma-separated local roots.",
7952
+ projectIds: "Comma-separated project ids.",
7953
+ workspaceIds: "Comma-separated workspace ids.",
7954
+ cronExpression: "Cron expression.",
7955
+ timezone: "Timezone.",
7956
+ signingMode: "Webhook signing mode.",
7957
+ replayWindowSec: "Webhook replay window in seconds.",
7958
+ instructions: "Automation instructions.",
7959
+ outputMode: "Automation output mode.",
7960
+ concurrencyPolicy: "Automation concurrency policy.",
7961
+ catchUpPolicy: "Automation catch-up policy.",
7962
+ triggerId: "Automation trigger id.",
7963
+ idempotencyKey: "Idempotency key.",
7964
+ summary: "Chat summary.",
7965
+ preferredAgentId: "Preferred responding agent id or reference.",
7966
+ issueCreationMode: "Chat issue creation mode.",
7967
+ editUserMessageId: "User message id to edit.",
7968
+ updatedAfter: "Run updated-after timestamp.",
7969
+ runIdPrefix: "Run id prefix filter.",
7970
+ runtime: "Runtime type filter.",
7971
+ issueId: "Issue id filter.",
7972
+ usedSkill: "Used skill filter.",
7973
+ loadedSkill: "Loaded skill filter.",
7974
+ createdBefore: "Created-before timestamp.",
7975
+ evidence: "Skill evidence type.",
7976
+ aroundError: "Transcript error step id.",
7977
+ maxOutputChars: "Maximum output characters."
7978
+ })) {
7979
+ add(key, mcpString(description));
7980
+ }
7981
+ for (const [key, description] of Object.entries({
7982
+ limit: "Page size or result limit.",
7983
+ count: "Count represented by a report.",
7984
+ turnLimit: "Maximum turns to return.",
7985
+ contextTurns: "Number of context turns.",
7986
+ maxChars: "Maximum characters.",
7987
+ snippetChars: "Maximum snippet characters."
7988
+ })) {
7989
+ add(key, mcpNumber(description));
7990
+ }
7991
+ for (const [key, description] of Object.entries({
7992
+ selectionRefs: "Skill selection refs.",
7993
+ selections: "Skill selection refs alias.",
7994
+ skills: "Skill selection refs alias.",
7995
+ images: "Local image paths to attach when supported.",
7996
+ goalIds: "Goal ids."
7899
7997
  })) {
7900
- add(key, key === "limit" ? mcpNumber(description) : mcpString(description));
7998
+ add(key, mcpStringArray(description));
7901
7999
  }
7902
- for (const key of ["enable", "enabled", "disabled", "reopen", "planMode", "includeTranscript", "includeOutput", "notifyOnIssueCreated"]) {
8000
+ for (const key of ["clearTitle", "clearCapabilities", "clearDescription", "clearReportsTo", "enable", "enabled", "disabled", "reopen", "planMode", "includeTranscript", "includeOutput", "includeOutputs", "notifyOnIssueCreated", "errorsOnly", "chronological", "narrative"]) {
7903
8001
  add(key, mcpBoolean(`Boolean option ${key}.`));
7904
8002
  }
7905
8003
  return {
7906
8004
  type: "object",
7907
- additionalProperties: true,
8005
+ additionalProperties: false,
7908
8006
  properties
7909
8007
  };
7910
8008
  }
@@ -7946,6 +8044,30 @@ function formatAgentCliCapabilitiesHumanReadable(capabilities = getAgentCliCapab
7946
8044
 
7947
8045
  // src/agent-v1-mcp-server.ts
7948
8046
  var RUDDER_MCP_SERVER_NAME = "rudder-control-plane";
8047
+ var RESERVED_MODEL_ARGUMENTS = /* @__PURE__ */ new Set([
8048
+ "orgId",
8049
+ "org_id",
8050
+ "companyId",
8051
+ "company_id",
8052
+ "agentId",
8053
+ "agent_id",
8054
+ "runId",
8055
+ "run_id",
8056
+ "apiBase",
8057
+ "api_base",
8058
+ "apiKey",
8059
+ "api_key",
8060
+ "authorization"
8061
+ ]);
8062
+ var NORMALIZED_RESERVED_MODEL_ARGUMENTS = /* @__PURE__ */ new Set([
8063
+ "orgid",
8064
+ "companyid",
8065
+ "agentid",
8066
+ "runid",
8067
+ "apibase",
8068
+ "apikey",
8069
+ "authorization"
8070
+ ]);
7949
8071
  function buildMcpServerEnv(env = process.env) {
7950
8072
  return {
7951
8073
  ...process.env,
@@ -7955,6 +8077,7 @@ function buildMcpServerEnv(env = process.env) {
7955
8077
  RUDDER_ORG_ID: env.RUDDER_ORG_ID,
7956
8078
  RUDDER_AGENT_ID: env.RUDDER_AGENT_ID,
7957
8079
  RUDDER_RUN_ID: env.RUDDER_RUN_ID,
8080
+ RUDDER_PROJECT_LIBRARY_PATH: env.RUDDER_PROJECT_LIBRARY_PATH,
7958
8081
  RUDDER_MCP_RUDDER_BIN: env.RUDDER_MCP_RUDDER_BIN
7959
8082
  };
7960
8083
  }
@@ -7964,6 +8087,9 @@ function buildAgentV1ToolCallPlan(toolName, rawArgs, env = buildMcpServerEnv())
7964
8087
  if (!capabilityId) {
7965
8088
  throw new Error(`Unknown Rudder MCP tool: ${toolName}`);
7966
8089
  }
8090
+ const capability = getAgentCliCapabilityById(capabilityId);
8091
+ rejectModelProvidedRuntimeIdentity(input);
8092
+ assertRuntimeMcpContext(capability, env);
7967
8093
  const tempFiles = [];
7968
8094
  const args = cliArgsForCapability(capabilityId, input, tempFiles, env);
7969
8095
  args.push("--json");
@@ -7976,7 +8102,8 @@ function buildAgentV1ToolCallPlan(toolName, rawArgs, env = buildMcpServerEnv())
7976
8102
  RUDDER_API_KEY: env.RUDDER_API_KEY,
7977
8103
  RUDDER_ORG_ID: env.RUDDER_ORG_ID,
7978
8104
  RUDDER_AGENT_ID: env.RUDDER_AGENT_ID,
7979
- RUDDER_RUN_ID: env.RUDDER_RUN_ID
8105
+ RUDDER_RUN_ID: env.RUDDER_RUN_ID,
8106
+ RUDDER_PROJECT_LIBRARY_PATH: env.RUDDER_PROJECT_LIBRARY_PATH
7980
8107
  },
7981
8108
  tempFiles
7982
8109
  };
@@ -7990,7 +8117,7 @@ async function runAgentV1McpJsonRpcMessage(message, env = buildMcpServerEnv()) {
7990
8117
  return isNotification ? null : rpcResult(id, {});
7991
8118
  case "initialize":
7992
8119
  return rpcResult(id, {
7993
- protocolVersion: "2024-11-05",
8120
+ protocolVersion: requestedProtocolVersion(message.params) ?? "2024-11-05",
7994
8121
  capabilities: { tools: {} },
7995
8122
  serverInfo: { name: RUDDER_MCP_SERVER_NAME, version: "1.0.0" }
7996
8123
  });
@@ -8011,35 +8138,82 @@ async function runAgentV1McpJsonRpcMessage(message, env = buildMcpServerEnv()) {
8011
8138
  }
8012
8139
  async function runMcpStdioServer(env = buildMcpServerEnv()) {
8013
8140
  let buffer = "";
8141
+ let mode = null;
8014
8142
  process.stdin.setEncoding("utf8");
8015
8143
  for await (const chunk of process.stdin) {
8016
8144
  buffer += chunk;
8017
- const lines = buffer.split(/\r?\n/);
8018
- buffer = lines.pop() ?? "";
8019
- for (const line of lines) {
8020
- if (!line.trim()) continue;
8021
- const parsed = JSON.parse(line);
8022
- const response = await runAgentV1McpJsonRpcMessage(parsed, env);
8023
- if (response) process.stdout.write(`${JSON.stringify(response)}
8145
+ const parsed = parseMcpStdioMessages(buffer, mode);
8146
+ mode = parsed.mode ?? mode;
8147
+ buffer = parsed.remainder;
8148
+ for (const message of parsed.messages) {
8149
+ const response = await runAgentV1McpJsonRpcMessage(message, env);
8150
+ if (!response) continue;
8151
+ const payload = JSON.stringify(response);
8152
+ process.stdout.write(parsed.mode === "framed" ? `Content-Length: ${Buffer.byteLength(payload, "utf8")}\r
8153
+ \r
8154
+ ${payload}` : `${payload}
8024
8155
  `);
8025
8156
  }
8026
8157
  }
8027
8158
  }
8159
+ function parseMcpStdioMessages(buffer, mode = null) {
8160
+ const messages = [];
8161
+ const detectedMode = mode ?? detectMcpStdioMode(buffer);
8162
+ if (!detectedMode) {
8163
+ return { messages, remainder: buffer, mode: null };
8164
+ }
8165
+ if (detectedMode === "framed") {
8166
+ let restBuffer = Buffer.from(buffer, "utf8");
8167
+ while (true) {
8168
+ const restText = restBuffer.toString("utf8");
8169
+ const headerEnd = restText.indexOf("\r\n\r\n");
8170
+ if (headerEnd < 0) break;
8171
+ const header = restText.slice(0, headerEnd);
8172
+ const match = /^Content-Length:\s*(\d+)\s*$/im.exec(header);
8173
+ if (!match) break;
8174
+ const length = Number(match[1]);
8175
+ const bodyStart = Buffer.byteLength(restText.slice(0, headerEnd + 4), "utf8");
8176
+ const bodyEnd = bodyStart + length;
8177
+ if (restBuffer.byteLength < bodyEnd) break;
8178
+ const body = restBuffer.subarray(bodyStart, bodyEnd).toString("utf8");
8179
+ messages.push(JSON.parse(body));
8180
+ restBuffer = restBuffer.subarray(bodyEnd);
8181
+ }
8182
+ return { messages, remainder: restBuffer.toString("utf8"), mode: "framed" };
8183
+ }
8184
+ const lines = buffer.split(/\r?\n/);
8185
+ const remainder = lines.pop() ?? "";
8186
+ for (const line of lines) {
8187
+ if (!line.trim()) continue;
8188
+ messages.push(JSON.parse(line));
8189
+ }
8190
+ return { messages, remainder, mode: "newline" };
8191
+ }
8192
+ function detectMcpStdioMode(buffer) {
8193
+ const trimmed = buffer.trimStart();
8194
+ if (!trimmed) return null;
8195
+ const contentLength = "Content-Length:";
8196
+ if (contentLength.toLowerCase().startsWith(trimmed.toLowerCase())) return null;
8197
+ if (/^Content-Length:/iu.test(trimmed)) return "framed";
8198
+ return "newline";
8199
+ }
8028
8200
  async function callToolSafely(params, env) {
8029
8201
  try {
8030
8202
  return await callTool(params, env);
8031
8203
  } catch (err) {
8032
8204
  const details = errorDetails(err);
8205
+ const payload = {
8206
+ status: "error",
8207
+ code: isRecord(details) && typeof details.code === "string" ? details.code : "rudder_mcp_tool_error",
8208
+ message: errorMessage(err),
8209
+ details: details ?? null
8210
+ };
8033
8211
  return {
8034
8212
  content: [{
8035
8213
  type: "text",
8036
- text: JSON.stringify({
8037
- status: "error",
8038
- code: isRecord(details) && typeof details.code === "string" ? details.code : "rudder_mcp_tool_error",
8039
- message: errorMessage(err),
8040
- details: details ?? null
8041
- })
8214
+ text: JSON.stringify(payload)
8042
8215
  }],
8216
+ structuredContent: payload,
8043
8217
  isError: true
8044
8218
  };
8045
8219
  }
@@ -8062,21 +8236,25 @@ async function callTool(params, env) {
8062
8236
  }
8063
8237
  const result = await runRudderCli(materializedArgs, plan.env);
8064
8238
  if (result.exitCode === 0) {
8239
+ const text6 = result.stdout.trim() || "{}";
8065
8240
  return {
8066
- content: [{ type: "text", text: result.stdout.trim() || "{}" }],
8241
+ content: [{ type: "text", text: text6 }],
8242
+ ...structuredContentFromJsonText(text6),
8067
8243
  isError: false
8068
8244
  };
8069
8245
  }
8246
+ const payload = {
8247
+ status: "error",
8248
+ code: "rudder_cli_command_failed",
8249
+ message: result.stderr.trim() || result.stdout.trim() || "Rudder CLI command failed",
8250
+ details: { exitCode: result.exitCode }
8251
+ };
8070
8252
  return {
8071
8253
  content: [{
8072
8254
  type: "text",
8073
- text: JSON.stringify({
8074
- status: "error",
8075
- code: "rudder_cli_command_failed",
8076
- message: result.stderr.trim() || result.stdout.trim() || "Rudder CLI command failed",
8077
- details: { exitCode: result.exitCode }
8078
- })
8255
+ text: JSON.stringify(payload)
8079
8256
  }],
8257
+ structuredContent: payload,
8080
8258
  isError: true
8081
8259
  };
8082
8260
  } finally {
@@ -8247,7 +8425,7 @@ function cliArgsForCapability(capabilityId, input, tempFiles, env) {
8247
8425
  return args;
8248
8426
  }
8249
8427
  case "library.file.list":
8250
- return ["library", "file", "list", optionalString(input.directory ?? input.path) ?? "projects"];
8428
+ return ["library", "file", "list", optionalString(input.directory ?? input.path) ?? optionalString(env.RUDDER_PROJECT_LIBRARY_PATH) ?? "projects"];
8251
8429
  case "library.file.get":
8252
8430
  return ["library", "file", "get", requiredString(input, "path")];
8253
8431
  case "library.file.ref":
@@ -8468,16 +8646,16 @@ function cliArgsForCapability(capabilityId, input, tempFiles, env) {
8468
8646
  return args;
8469
8647
  }
8470
8648
  case "runs.get":
8471
- return ["runs", "get", requiredAnyString(input, ["run", "runId"])];
8649
+ return ["runs", "get", requiredString(input, "run")];
8472
8650
  case "runs.events":
8473
- return ["runs", "events", requiredAnyString(input, ["run", "runId"])];
8651
+ return ["runs", "events", requiredString(input, "run")];
8474
8652
  case "runs.log": {
8475
- const args = ["runs", "log", requiredAnyString(input, ["run", "runId"])];
8653
+ const args = ["runs", "log", requiredString(input, "run")];
8476
8654
  pushOptional(args, "--max-chars", input.maxChars);
8477
8655
  return args;
8478
8656
  }
8479
8657
  case "runs.transcript": {
8480
- const args = ["runs", "transcript", requiredAnyString(input, ["run", "runId"])];
8658
+ const args = ["runs", "transcript", requiredString(input, "run")];
8481
8659
  pushBoolean(args, "--errors-only", input.errorsOnly);
8482
8660
  pushOptional(args, "--around-error", input.aroundError);
8483
8661
  pushOptional(args, "--context-turns", input.contextTurns);
@@ -8490,14 +8668,14 @@ function cliArgsForCapability(capabilityId, input, tempFiles, env) {
8490
8668
  return args;
8491
8669
  }
8492
8670
  case "runs.errors": {
8493
- const args = ["runs", "errors", requiredAnyString(input, ["run", "runId"])];
8671
+ const args = ["runs", "errors", requiredString(input, "run")];
8494
8672
  pushOptional(args, "--max-chars", input.maxChars);
8495
8673
  return args;
8496
8674
  }
8497
8675
  case "runs.cancel":
8498
- return ["runs", "cancel", requiredAnyString(input, ["run", "runId"])];
8676
+ return ["runs", "cancel", requiredString(input, "run")];
8499
8677
  case "runs.retry":
8500
- return ["runs", "retry", requiredAnyString(input, ["run", "runId"])];
8678
+ return ["runs", "retry", requiredString(input, "run")];
8501
8679
  default:
8502
8680
  throw new Error(`Rudder MCP tool is not implemented: ${capabilityId}`);
8503
8681
  }
@@ -8505,10 +8683,14 @@ function cliArgsForCapability(capabilityId, input, tempFiles, env) {
8505
8683
  function toMcpToolListEntry(tool) {
8506
8684
  return {
8507
8685
  name: tool.name,
8508
- description: `${tool.description} Mutating: ${tool.mutating ? "yes" : "no"}. Org context: ${tool.requiresOrgId ? "required" : "runtime/env"}. Agent context: ${tool.requiresAgentId ? "required" : "runtime/env"}. Run attribution: ${tool.attachesRunIdWhenAvailable ? "attached when available" : "not attached"}.`,
8686
+ description: `${tool.description} Mutating: ${tool.mutating ? "yes" : "no"}. Runtime identity and authorization are injected by the Rudder-managed MCP server and are not accepted as tool input. Org context: ${tool.requiresOrgId ? "required from runtime env" : "not required by this tool"}. Agent context: ${tool.requiresAgentId ? "required from runtime env" : "runtime env when available"}. Run attribution: ${tool.attachesRunIdWhenAvailable ? "attached from runtime env when available" : "not attached"}.`,
8509
8687
  inputSchema: tool.inputSchema
8510
8688
  };
8511
8689
  }
8690
+ function requestedProtocolVersion(params) {
8691
+ if (!isRecord(params)) return null;
8692
+ return typeof params.protocolVersion === "string" && params.protocolVersion.trim().length > 0 ? params.protocolVersion.trim() : null;
8693
+ }
8512
8694
  function toolNameToCapabilityId(toolName) {
8513
8695
  const manifest = buildAgentV1McpToolsManifest("agent-v1");
8514
8696
  return manifest.tools.find((tool) => tool.name === toolName)?.id ?? null;
@@ -8578,16 +8760,46 @@ function pushRuntimeAgentArg(args, _input, env, required) {
8578
8760
  throw new Error("Runtime agent ID is required. Set RUDDER_AGENT_ID.");
8579
8761
  }
8580
8762
  }
8763
+ function rejectModelProvidedRuntimeIdentity(input) {
8764
+ const reserved = Object.keys(input).filter(
8765
+ (key) => RESERVED_MODEL_ARGUMENTS.has(key) || RESERVED_MODEL_ARGUMENTS.has(key.toLowerCase()) || NORMALIZED_RESERVED_MODEL_ARGUMENTS.has(normalizeRuntimeIdentityKey(key)) || key.toUpperCase().startsWith("RUDDER_")
8766
+ );
8767
+ if (reserved.length === 0) return;
8768
+ const err = new Error(`Rudder MCP runtime identity is managed by the server; do not pass these arguments: ${reserved.sort().join(", ")}`);
8769
+ err.code = "rudder_mcp_reserved_identity_argument";
8770
+ throw err;
8771
+ }
8772
+ function normalizeRuntimeIdentityKey(key) {
8773
+ return key.replace(/[^a-z0-9]/giu, "").toLowerCase();
8774
+ }
8775
+ function assertRuntimeMcpContext(capability, env) {
8776
+ const missing = [];
8777
+ if (!optionalString(env.RUDDER_API_URL)) missing.push("RUDDER_API_URL");
8778
+ if (!optionalString(env.RUDDER_API_KEY)) missing.push("RUDDER_API_KEY");
8779
+ if (capability.requiresOrgId && !optionalString(env.RUDDER_ORG_ID)) missing.push("RUDDER_ORG_ID");
8780
+ if (capability.requiresAgentId && !optionalString(env.RUDDER_AGENT_ID)) missing.push("RUDDER_AGENT_ID");
8781
+ if (missing.length === 0) return;
8782
+ const err = new Error(`Rudder MCP runtime context is incomplete. Missing ${missing.join(", ")}.`);
8783
+ err.code = "rudder_mcp_missing_runtime_context";
8784
+ throw err;
8785
+ }
8786
+ function structuredContentFromJsonText(text6) {
8787
+ try {
8788
+ const parsed = JSON.parse(text6);
8789
+ if (isRecord(parsed)) return { structuredContent: parsed };
8790
+ return { structuredContent: { result: parsed } };
8791
+ } catch {
8792
+ return {};
8793
+ }
8794
+ }
8581
8795
  function renderCsv(value) {
8582
8796
  if (!Array.isArray(value)) return value;
8583
8797
  return value.map((entry) => optionalString(entry)).filter(Boolean).join(",");
8584
8798
  }
8585
8799
  function runRudderCli(args, env) {
8586
- const command = env.RUDDER_MCP_RUDDER_BIN || process.execPath;
8587
- const modulePath = fileURLToPath(new URL("./index.js", import.meta.url));
8588
- const commandArgs = env.RUDDER_MCP_RUDDER_BIN ? args : [modulePath, ...args];
8800
+ const invocation = resolveRudderCliInvocation(args, env);
8589
8801
  return new Promise((resolve) => {
8590
- const child = spawn(command, commandArgs, { env, stdio: ["ignore", "pipe", "pipe"] });
8802
+ const child = spawn(invocation.command, invocation.args, { env, stdio: ["ignore", "pipe", "pipe"] });
8591
8803
  let stdout = "";
8592
8804
  let stderr = "";
8593
8805
  child.stdout?.on("data", (chunk) => {
@@ -8600,6 +8812,30 @@ function runRudderCli(args, env) {
8600
8812
  child.on("error", (err) => resolve({ exitCode: 1, stdout, stderr: err.message }));
8601
8813
  });
8602
8814
  }
8815
+ function resolveRudderCliInvocation(args, env) {
8816
+ if (env.RUDDER_MCP_RUDDER_BIN) {
8817
+ return { command: env.RUDDER_MCP_RUDDER_BIN, args };
8818
+ }
8819
+ const modulePath = fileURLToPath(new URL("./index.js", import.meta.url));
8820
+ if (existsSync(modulePath)) {
8821
+ return { command: process.execPath, args: [modulePath, ...args] };
8822
+ }
8823
+ if (hasRunnableRudderOnPath(env)) {
8824
+ return { command: "rudder", args };
8825
+ }
8826
+ return {
8827
+ command: process.execPath,
8828
+ args: [modulePath, ...args]
8829
+ };
8830
+ }
8831
+ function hasRunnableRudderOnPath(env) {
8832
+ const probe = spawnSync("rudder", ["--version"], {
8833
+ env,
8834
+ encoding: "utf8",
8835
+ stdio: ["ignore", "pipe", "pipe"]
8836
+ });
8837
+ return !probe.error;
8838
+ }
8603
8839
  function rpcResult(id, result) {
8604
8840
  return { jsonrpc: "2.0", id, result };
8605
8841
  }
@@ -9524,10 +9760,11 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
9524
9760
  "- Project Library locator lives in `$RUDDER_PROJECT_LIBRARY_PATH` when the run has project context, for example `projects/<project-key>`.",
9525
9761
  '- Library-backed project resources use `sourceType: "library"`; their `locator` points into `library:projects/<project-key>/`.',
9526
9762
  "- Project Context is explicit operator-curated context, not the whole knowledge boundary. When it is insufficient, inspect broader Library and org workspace know-how before concluding context is missing.",
9527
- "- In local trusted runs, durable generated project work files should be written directly under `$RUDDER_PROJECT_LIBRARY_ROOT` with normal filesystem tools.",
9763
+ "- In local trusted runs, durable generated project work files should be written directly under `$RUDDER_PROJECT_LIBRARY_ROOT` with normal filesystem tools when the run has project context.",
9528
9764
  "- `library:projects/<project-key>/...` is the Rudder product locator for those files, not the Markdown link syntax and not a reason to route ordinary local edits through the CLI.",
9529
- '- When you create or update a durable Library file, always include a user-visible Markdown link to that file in your final chat reply or issue comment. Use `rudder library file ref "$RUDDER_PROJECT_LIBRARY_PATH/<relative-file>" --json` and paste the returned `markdownLink`; do not pass the absolute `$RUDDER_PROJECT_LIBRARY_ROOT/...` path to `ref`, and do not hand-write `library-entry://...` or `library-file://...` links.',
9530
- '- If `$RUDDER_PROJECT_LIBRARY_ROOT` is unset or inaccessible, use `rudder library file get/put "$RUDDER_PROJECT_LIBRARY_PATH/<relative-file>"` as the remote or restricted runtime fallback.',
9765
+ "- When there is no project context, durable generated chat/work artifacts belong under the organization Library artifacts fallback: `$RUDDER_ORG_WORKSPACE_ROOT/artifacts/YYYY-MM-DD/<conversation-title>/<relative-file>` and product locator `library:artifacts/YYYY-MM-DD/<conversation-title>/<relative-file>`. Use the current date and a concise slug of the current chat/thread title for `<conversation-title>`. Do not choose an existing project, such as Getting Started, just to obtain a project Library path.",
9766
+ '- When you create or update a durable Library file, always include a user-visible Markdown link to that file in your final chat reply or issue comment. With project context, use `rudder library file ref "$RUDDER_PROJECT_LIBRARY_PATH/<relative-file>" --json`; without project context, use `rudder library file ref "artifacts/YYYY-MM-DD/<conversation-title>/<relative-file>" --json`. Paste the returned `markdownLink`; do not pass absolute filesystem paths to `ref`, and do not hand-write `library-entry://...` or `library-file://...` links.',
9767
+ '- If `$RUDDER_PROJECT_LIBRARY_ROOT` is unset or inaccessible but `$RUDDER_PROJECT_LIBRARY_PATH` exists, use `rudder library file get/put "$RUDDER_PROJECT_LIBRARY_PATH/<relative-file>"` as the remote or restricted runtime fallback. If there is no project context, use the organization artifacts fallback path instead.',
9531
9768
  "- Use `$RUDDER_RUNTIME_TMPDIR` for transient scratch files and temporary verification files when it is set; otherwise use `/tmp`. Do not put durable work product there.",
9532
9769
  "- Local trusted runtimes may expose the host operator home as `$RUDDER_OPERATOR_HOME`; use it only when a local skill or script intentionally needs operator-owned desktop app or CLI state. Do not replace `$HOME` with it.",
9533
9770
  "",
@@ -9546,7 +9783,7 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
9546
9783
  "- Projects: use `[](project://<project-id>)` when citing a Rudder project.",
9547
9784
  "- Chat threads: use `[](chat://<conversation-id>)` when citing a Rudder chat conversation.",
9548
9785
  "- Skills: use `[](skill://<skill-ref>)` when citing a Rudder skill reference. The skill ref may be an org skill, agent skill, bundled Rudder skill, or local-machine skill ref; the UI resolves the display label when metadata is available.",
9549
- '- Library files: use the `markdownLink` returned by `rudder library file ref "$RUDDER_PROJECT_LIBRARY_PATH/<relative-file>" --json`; do not hand-write `library-entry://...` links, and treat `library-file://...` as legacy path syntax only.',
9786
+ '- Library files: use the `markdownLink` returned by `rudder library file ref "$RUDDER_PROJECT_LIBRARY_PATH/<relative-file>" --json` with project context, or `rudder library file ref "artifacts/YYYY-MM-DD/<conversation-title>/<relative-file>" --json` without project context; do not hand-write `library-entry://...` links, and treat `library-file://...` as legacy path syntax only.',
9550
9787
  "",
9551
9788
  "Write these as normal Markdown links, not inside code spans or code blocks, unless you are literally documenting the syntax.",
9552
9789
  "",
@@ -14891,7 +15128,7 @@ init_home();
14891
15128
  init_install2();
14892
15129
  init_install();
14893
15130
  import * as p15 from "@clack/prompts";
14894
- import { spawn as spawn3, spawnSync as spawnSync3 } from "node:child_process";
15131
+ import { spawn as spawn3, spawnSync as spawnSync4 } from "node:child_process";
14895
15132
  import { createHash, randomUUID } from "node:crypto";
14896
15133
  import { createWriteStream, constants as fsConstants, mkdirSync, readFileSync as readFileSync2 } from "node:fs";
14897
15134
  import { access, chmod, copyFile, cp as cp2, mkdir as mkdir3, mkdtemp, readdir as readdir3, readFile as readFile6, rm as rm2, stat as stat4, utimes, writeFile as writeFile3 } from "node:fs/promises";
@@ -15748,7 +15985,7 @@ async function withDesktopInstallLock(paths, fn, options = {}) {
15748
15985
  }
15749
15986
  }
15750
15987
  function runChecked(command, args, options = {}) {
15751
- const result = spawnSync3(command, args, {
15988
+ const result = spawnSync4(command, args, {
15752
15989
  encoding: "utf8",
15753
15990
  stdio: ["ignore", "pipe", "pipe"],
15754
15991
  ...options
@@ -15835,7 +16072,7 @@ function isInstalledDesktopCurrent(metadata, releaseTag, assetName, assetChecksu
15835
16072
  }
15836
16073
  function forceQuitDesktopProcess(pid, target) {
15837
16074
  if (target.platform === "windows") {
15838
- spawnSync3("taskkill.exe", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
16075
+ spawnSync4("taskkill.exe", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
15839
16076
  return;
15840
16077
  }
15841
16078
  try {
@@ -15848,7 +16085,7 @@ function quotePowerShellString(value) {
15848
16085
  }
15849
16086
  function findDesktopExecutablePids(executablePath, target) {
15850
16087
  if (target.platform === "windows") {
15851
- const result2 = spawnSync3("powershell.exe", [
16088
+ const result2 = spawnSync4("powershell.exe", [
15852
16089
  "-NoProfile",
15853
16090
  "-Command",
15854
16091
  `Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -eq ${quotePowerShellString(executablePath)} } | Select-Object -ExpandProperty ProcessId`
@@ -15859,7 +16096,7 @@ function findDesktopExecutablePids(executablePath, target) {
15859
16096
  if (result2.status !== 0) return [];
15860
16097
  return result2.stdout.split(/\r?\n/).map((line) => Number.parseInt(line.trim(), 10)).filter((pid) => Number.isInteger(pid) && pid > 0 && pid !== process.pid);
15861
16098
  }
15862
- const result = spawnSync3("ps", ["-eo", "pid=,args="], {
16099
+ const result = spawnSync4("ps", ["-eo", "pid=,args="], {
15863
16100
  encoding: "utf8",
15864
16101
  stdio: ["ignore", "pipe", "ignore"]
15865
16102
  });
@@ -15886,7 +16123,7 @@ async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
15886
16123
  async function requestDesktopQuit(executablePath, target, options = {}) {
15887
16124
  if (!await pathExists2(executablePath)) return { ok: true, status: "not_running" };
15888
16125
  const responsePath = path22.join(tmpdir(), `rudder-update-quit-${process.pid}-${Date.now()}.json`);
15889
- const result = spawnSync3(executablePath, [
16126
+ const result = spawnSync4(executablePath, [
15890
16127
  `${DESKTOP_UPDATE_QUIT_ARG}=${responsePath}`,
15891
16128
  ...options.forceUpdate ? [DESKTOP_UPDATE_FORCE_ARG] : []
15892
16129
  ], {
@@ -16065,7 +16302,7 @@ async function copyPortableAppBundle(sourcePath, destinationPath) {
16065
16302
  if (process.platform === "win32") {
16066
16303
  await mkdir3(destinationPath, { recursive: true });
16067
16304
  const command = buildWindowsRobocopyMirrorCommand(sourcePath, destinationPath);
16068
- const result = spawnSync3(command.command, command.args, {
16305
+ const result = spawnSync4(command.command, command.args, {
16069
16306
  encoding: "utf8",
16070
16307
  stdio: ["ignore", "pipe", "pipe"]
16071
16308
  });
@@ -16076,7 +16313,7 @@ async function copyPortableAppBundle(sourcePath, destinationPath) {
16076
16313
  }
16077
16314
  async function removeMacQuarantine(paths, target) {
16078
16315
  if (target.platform !== "macos") return;
16079
- const result = spawnSync3("xattr", ["-dr", "com.apple.quarantine", paths.appPath], { stdio: "ignore" });
16316
+ const result = spawnSync4("xattr", ["-dr", "com.apple.quarantine", paths.appPath], { stdio: "ignore" });
16080
16317
  if (result.status !== 0) {
16081
16318
  p15.log.warn(`Could not remove macOS quarantine attributes from ${paths.appPath}.`);
16082
16319
  }
@@ -16125,7 +16362,7 @@ async function createPlatformLaunchers(paths, target) {
16125
16362
  return;
16126
16363
  }
16127
16364
  if (target.platform === "windows") {
16128
- const result = spawnSync3("powershell.exe", [
16365
+ const result = spawnSync4("powershell.exe", [
16129
16366
  "-NoProfile",
16130
16367
  "-ExecutionPolicy",
16131
16368
  "Bypass",