@mrrlin-dev/mcp 0.4.55 → 0.4.59

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 (2) hide show
  1. package/dist/bin.cjs +221 -113
  2. package/package.json +2 -2
package/dist/bin.cjs CHANGED
@@ -21134,7 +21134,7 @@ function browserTable(binPath, distribution, homeDir) {
21134
21134
  }
21135
21135
  function blockRegex(id) {
21136
21136
  const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
21137
- return new RegExp(`(^|\\n)\\[mcp_servers\\.${escaped}\\][\\s\\S]*?(?=\\n\\[|$)`);
21137
+ return new RegExp(`(^|\\n)\\[mcp_servers\\.${escaped}\\][\\s\\S]*?(?=\\n\\[(?!\\]|mcp_servers\\.${escaped}\\.)|$)`);
21138
21138
  }
21139
21139
  function renderBlock(id, expected) {
21140
21140
  const lines2 = [
@@ -36969,7 +36969,7 @@ var ARTIFACT_CHECKS = {
36969
36969
  var ARTIFACT_DESTINATIONS = {
36970
36970
  document: "wiki",
36971
36971
  page: "git",
36972
- file_set: null,
36972
+ file_set: "artifacts",
36973
36973
  code_change: "git",
36974
36974
  structured_data: null,
36975
36975
  message: null
@@ -36978,6 +36978,52 @@ function resolveKindCapability(kind) {
36978
36978
  return ARTIFACT_DESTINATIONS[kind];
36979
36979
  }
36980
36980
 
36981
+ // ../../packages/schemas/dist/capability-refusal.js
36982
+ var REFUSAL_TEMPLATES = {
36983
+ no_route: {
36984
+ happened: ({ artifactKind, projectSlug }) => `Nothing is configured to deliver \`${artifactKind}\` for project \`${projectSlug}\`.`,
36985
+ action: ({ capability }) => `Grant an MCP server that provides the "${capability}" capability and route it on the Integrations page. Retrying before that will refuse identically.`
36986
+ },
36987
+ no_grant: {
36988
+ happened: ({ projectSlug, capability }) => `Project \`${projectSlug}\` routes "${capability}" to a server whose access has been revoked.`,
36989
+ action: () => "Grant that server again on the Integrations page, or re-point the route. Retrying before that will refuse identically."
36990
+ },
36991
+ project_mismatch: {
36992
+ happened: ({ capability }) => `The route for "${capability}" belongs to a different project than this task does.`,
36993
+ action: () => "Mrrlin refuses rather than delivering one project's work into another project's destination. Re-point the route in the task's own project."
36994
+ },
36995
+ ambiguous_route: {
36996
+ happened: ({ projectSlug, artifactKind }) => `Project \`${projectSlug}\` has more than one route that delivers \`${artifactKind}\`.`,
36997
+ action: () => "Mrrlin will not guess which one. Name the capability explicitly, or remove the route you do not want."
36998
+ },
36999
+ blocked_kind: {
37000
+ happened: ({ artifactKind }) => `Mrrlin has no destination for \`${artifactKind}\` yet.`,
37001
+ action: () => "Produce a kind that does have one, or record the result on the task instead."
37002
+ },
37003
+ gate_refused: {
37004
+ happened: ({ projectSlug }) => `The operator declined this action for project \`${projectSlug}\`.`,
37005
+ action: () => "This is an answer, not a failure \u2014 do not retry it. Ask the operator directly if it should be allowed."
37006
+ },
37007
+ transport_error: {
37008
+ happened: () => "Mrrlin could not reach the service that decides whether this delivery is allowed, so nothing was sent.",
37009
+ action: () => "This is safe to retry."
37010
+ },
37011
+ delivery_failed: {
37012
+ happened: ({ projectSlug }) => `The delivery was allowed, but the destination itself failed for project \`${projectSlug}\`.`,
37013
+ action: () => "It may have partly completed, so do not blindly retry \u2014 check whether the result already exists first."
37014
+ }
37015
+ };
37016
+ function describeCapabilityRefusal(input) {
37017
+ const ctx = {
37018
+ projectSlug: input.projectSlug,
37019
+ capability: input.capability ?? "the requested capability",
37020
+ artifactKind: input.artifactKind ?? "this artifact kind"
37021
+ };
37022
+ const template = REFUSAL_TEMPLATES[input.reason];
37023
+ const happened = typeof input.detail === "string" && input.detail.length > 0 ? input.detail : template.happened(ctx);
37024
+ return `${happened} ${template.action(ctx)}`;
37025
+ }
37026
+
36981
37027
  // ../../packages/schemas/dist/operationIds.js
36982
37028
  var openApiOperationIds = {
36983
37029
  appendExecutionArtifact: "appendExecutionArtifact",
@@ -42488,7 +42534,7 @@ Do NOT derail the current task - if the operator has an in-flight question, answ
42488
42534
  }
42489
42535
 
42490
42536
  // src/_generated/version.ts
42491
- var PKG_VERSION = "0.4.55";
42537
+ var PKG_VERSION = "0.4.59";
42492
42538
 
42493
42539
  // src/api-base-url-migrate.ts
42494
42540
  var import_node_fs4 = __toESM(require("node:fs"), 1);
@@ -42758,7 +42804,7 @@ function migrateCodexConfig(deps = {}) {
42758
42804
  const text = d.readFile(file2);
42759
42805
  const host = findRetiredHost(text);
42760
42806
  if (!host && !hasLiveLegacyStagingFlag(text, "toml")) return { file: file2, status: "clean" };
42761
- const managedBlockRe = /^\[mcp_servers\.mrrlin\][^\n]*\n(?:(?!\[)[^\n]*\n?)*/gm;
42807
+ const managedBlockRe = /^\[mcp_servers\.mrrlin(?:\]|\.env\])[^\n]*\n(?:(?!\[)[^\n]*\n?)*/gm;
42762
42808
  const blocks = text.match(managedBlockRe) ?? [];
42763
42809
  if (blocks.length === 0) {
42764
42810
  return {
@@ -42773,34 +42819,52 @@ function migrateCodexConfig(deps = {}) {
42773
42819
  let out = text;
42774
42820
  let changed = 0;
42775
42821
  for (const block of blocks) {
42822
+ let blockNextApiUrl;
42823
+ const urlMatch = /MRRLIN_API_BASE_URL\s*=\s*"([^"]*)"/.exec(block);
42824
+ const matchedUrl = urlMatch?.[1];
42825
+ if (matchedUrl !== void 0) {
42826
+ const successor = migratedApiUrl(matchedUrl);
42827
+ if (successor) blockNextApiUrl = successor;
42828
+ }
42829
+ if (!blockNextApiUrl && /MRRLIN_STAGING\s*=\s*"1"/.test(block)) {
42830
+ blockNextApiUrl = STAGING_API_BASE_URL;
42831
+ }
42776
42832
  let blockChanged = false;
42777
42833
  const healedBlock = block.split("\n").map((line) => {
42778
42834
  if (line.trimStart().startsWith("#")) return line;
42779
- let nextApiUrl;
42780
42835
  let healedLine = line.replace(assignRe, (match, url2) => {
42781
42836
  const successor = migratedApiUrl(url2);
42782
42837
  if (!successor) return match;
42783
- nextApiUrl = successor;
42784
42838
  return `MRRLIN_API_BASE_URL = ${JSON.stringify(successor)}`;
42785
42839
  });
42786
42840
  healedLine = healedLine.replace(stagingAssignRe, () => {
42787
- nextApiUrl = STAGING_API_BASE_URL;
42788
42841
  return `MRRLIN_API_BASE_URL = ${JSON.stringify(STAGING_API_BASE_URL)}`;
42789
42842
  });
42790
- if (nextApiUrl && isFirstPartyOrLoopbackUrl(nextApiUrl)) {
42843
+ if (blockNextApiUrl && isFirstPartyOrLoopbackUrl(blockNextApiUrl)) {
42791
42844
  healedLine = healedLine.replace(
42792
42845
  allowRemoteAssignRe,
42793
42846
  (match) => match.startsWith(",") && match.endsWith(",") ? "," : ""
42794
42847
  ).replace(/\{\s*,\s*/, "{ ").replace(/,\s*\}/, " }").replace(/,\s*,/g, ",");
42848
+ if (/^[ \t]*MRRLIN_API_ALLOW_REMOTE\s*=\s*"1"[ \t]*$/.test(healedLine)) {
42849
+ healedLine = "";
42850
+ }
42795
42851
  }
42796
42852
  if (healedLine !== line) blockChanged = true;
42797
42853
  return healedLine;
42854
+ }).filter((line, i) => {
42855
+ if (line === "" && block.split("\n")[i] !== "") return false;
42856
+ return true;
42798
42857
  }).join("\n");
42799
42858
  if (!blockChanged) continue;
42800
- const deduped = healedBlock.replace(
42859
+ let deduped = healedBlock.replace(
42801
42860
  /MRRLIN_API_BASE_URL = "https:\/\/api-staging\.mrrlin\.com"\s*,\s*MRRLIN_API_BASE_URL = "https:\/\/api-staging\.mrrlin\.com"/g,
42802
42861
  `MRRLIN_API_BASE_URL = "https://api-staging.mrrlin.com"`
42803
42862
  );
42863
+ deduped = deduped.replace(
42864
+ /^[ \t]*MRRLIN_API_BASE_URL\s*=\s*"https:\/\/api-staging\.mrrlin\.com"[ \t]*\r?\n([\s\S]*?)^[ \t]*MRRLIN_API_BASE_URL\s*=\s*"https:\/\/api-staging\.mrrlin\.com"[ \t]*\r?\n/gm,
42865
+ `MRRLIN_API_BASE_URL = "https://api-staging.mrrlin.com"
42866
+ $1`
42867
+ );
42804
42868
  out = out.replace(block, () => deduped);
42805
42869
  changed += 1;
42806
42870
  }
@@ -48117,7 +48181,7 @@ async function driveRun(deps, projectSlug, runId) {
48117
48181
  task,
48118
48182
  runId,
48119
48183
  leaseId,
48120
- `capability_not_routed: run ${runId} targets ${task.id}, which requires artifact kind "${kind}" -- that kind has no capability at all`,
48184
+ `capability_not_routed: run ${runId} targets ${task.id}, ${describeCapabilityRefusal({ reason: "blocked_kind", projectSlug, artifactKind: kind })}`,
48121
48185
  "capability_not_routed"
48122
48186
  );
48123
48187
  return;
@@ -48130,7 +48194,12 @@ async function driveRun(deps, projectSlug, runId) {
48130
48194
  task,
48131
48195
  runId,
48132
48196
  leaseId,
48133
- `capability_not_routed: run ${runId} targets ${task.id}, which requires artifact kind "${kind}" -- no route (${routeResolution.reason})`,
48197
+ // Consensus round 1 (chunk 4): capability was omitted here, so no_route/no_grant/
48198
+ // project_mismatch's action text (which interpolates it) fell back to the literal string
48199
+ // "the requested capability" instead of naming "wiki"/"artifacts"/"git" -- resolveKindCapability
48200
+ // is non-null on this branch (the blocked_kind check above already returned if it were),
48201
+ // matching deliverBuiltIn's identical call in tools.ts.
48202
+ `capability_not_routed: run ${runId} targets ${task.id}, ${describeCapabilityRefusal({ reason: routeResolution.reason, projectSlug, artifactKind: kind, capability: resolveKindCapability(kind), detail: routeResolution.message })}`,
48134
48203
  "capability_not_routed"
48135
48204
  );
48136
48205
  return;
@@ -64906,6 +64975,81 @@ async function deliverToGit(server, toolName, payload) {
64906
64975
  return invokeCapability(server, toolName, args);
64907
64976
  }
64908
64977
 
64978
+ // src/mcp-tool-error.ts
64979
+ var McpToolCodedError = class extends Error {
64980
+ code;
64981
+ violations;
64982
+ constructor(code, message, violations) {
64983
+ super(message);
64984
+ this.name = "McpToolCodedError";
64985
+ this.code = code;
64986
+ this.violations = violations;
64987
+ }
64988
+ };
64989
+
64990
+ // src/delivery/artifacts.ts
64991
+ async function deliverToArtifacts(client, projectSlug, payload, bareFetch) {
64992
+ const { bytes: bytes3, class: artifactClass, contentType, description, filename, runId, taskId } = payload;
64993
+ const created = await client.createArtifactFile(projectSlug, {
64994
+ class: artifactClass,
64995
+ contentType,
64996
+ filename,
64997
+ runId,
64998
+ sizeBytes: bytes3.byteLength,
64999
+ taskId
65000
+ });
65001
+ let stage = "upload";
65002
+ try {
65003
+ if (created.upload.kind === "presigned-post") {
65004
+ const form = new FormData();
65005
+ for (const [field, value] of Object.entries(created.upload.fields)) {
65006
+ form.append(field, value);
65007
+ }
65008
+ form.append("file", new Blob([bytes3], { type: contentType }), filename);
65009
+ const fetchImpl = bareFetch ?? globalThis.fetch;
65010
+ const uploadResponse = await fetchImpl(created.upload.url, { body: form, method: "POST" });
65011
+ if (!uploadResponse.ok) {
65012
+ throw new Error(`Presigned upload failed: ${uploadResponse.status} ${await uploadResponse.text()}`);
65013
+ }
65014
+ } else {
65015
+ await client.uploadArtifactFileContent(projectSlug, created.artifact.id, bytes3, contentType);
65016
+ }
65017
+ stage = "complete";
65018
+ const completed = await client.completeArtifactFile(projectSlug, created.artifact.id);
65019
+ if (completed.runId) {
65020
+ stage = "append-run-artifact";
65021
+ await client.appendExecutionArtifact(projectSlug, completed.runId, {
65022
+ id: `EA-${completed.id}`,
65023
+ kind: "file",
65024
+ payload: {
65025
+ artifactFileId: completed.id,
65026
+ class: completed.class,
65027
+ contentType: completed.contentType,
65028
+ description: description ?? null,
65029
+ filename: completed.filename,
65030
+ sizeBytes: completed.sizeBytes,
65031
+ stableUrl: created.stableUrl
65032
+ }
65033
+ });
65034
+ }
65035
+ const markdown = contentType.startsWith("image/") ? `![${completed.filename}](${created.stableUrl})` : `[${completed.filename}](${created.stableUrl})`;
65036
+ return {
65037
+ artifactFile: completed,
65038
+ markdown,
65039
+ stableUrl: created.stableUrl
65040
+ };
65041
+ } catch (error51) {
65042
+ const original = error51 instanceof MrrlinApiError ? error51.code : error51 instanceof McpToolCodedError ? error51.code : "ARTIFACT_FILE_UPLOAD_FAILED";
65043
+ const message = error51 instanceof Error ? error51.message : String(error51);
65044
+ const note = stage === "append-run-artifact" ? "file uploaded and completed successfully; only the run-history append failed \u2014 do NOT re-upload, reference the stableUrl directly" : "a pending row may remain; it is reaped automatically after 1h";
65045
+ throw new McpToolCodedError(
65046
+ original,
65047
+ `artifactFileId=${created.artifact.id} stableUrl=${created.stableUrl} (failed at ${stage}; ${note}): ${message}`,
65048
+ error51 instanceof MrrlinApiError ? error51.violations ?? void 0 : error51 instanceof McpToolCodedError ? error51.violations : void 0
65049
+ );
65050
+ }
65051
+ }
65052
+
64909
65053
  // src/delivery/index.ts
64910
65054
  async function deliverThroughCapability(client, input) {
64911
65055
  if (resolveKindCapability(input.artifactKind) === null) {
@@ -64923,7 +65067,7 @@ async function deliverThroughCapability(client, input) {
64923
65067
  return { ok: false, reason: "transport_error" };
64924
65068
  }
64925
65069
  if (!resolution.ok) {
64926
- return { ok: false, reason: resolution.reason };
65070
+ return { ok: false, reason: resolution.reason, message: resolution.message };
64927
65071
  }
64928
65072
  const { route, verdict } = resolution;
64929
65073
  if (verdict === "silent") {
@@ -64945,7 +65089,14 @@ var NoGrantForServerError = class extends Error {
64945
65089
  };
64946
65090
  async function proceedToDestination(client, route, input) {
64947
65091
  try {
64948
- const result = await callDestination(client, input.taskProjectSlug, route, input.payload, input.mcpConfigPath);
65092
+ const result = await callDestination(
65093
+ client,
65094
+ input.taskProjectSlug,
65095
+ route,
65096
+ input.payload,
65097
+ input.mcpConfigPath,
65098
+ input.bareFetch
65099
+ );
64949
65100
  const recorded = await recordUse(client, route, input, "ok");
64950
65101
  return { ok: true, use: recorded, result };
64951
65102
  } catch (error51) {
@@ -64954,7 +65105,15 @@ async function proceedToDestination(client, route, input) {
64954
65105
  return { ok: false, reason: "no_grant" };
64955
65106
  }
64956
65107
  await recordUse(client, route, input, "error");
64957
- return { ok: false, reason: "delivery_failed" };
65108
+ const code = error51 instanceof McpToolCodedError || error51 instanceof MrrlinApiError ? error51.code : void 0;
65109
+ const violations = error51 instanceof MrrlinApiError || error51 instanceof McpToolCodedError ? error51.violations : void 0;
65110
+ return {
65111
+ ok: false,
65112
+ reason: "delivery_failed",
65113
+ message: error51 instanceof Error ? error51.message : void 0,
65114
+ code,
65115
+ violations
65116
+ };
64958
65117
  }
64959
65118
  }
64960
65119
  async function refuse(client, route, input) {
@@ -65111,7 +65270,7 @@ async function recordUse(client, route, input, outcome) {
65111
65270
  return null;
65112
65271
  }
65113
65272
  }
65114
- async function callDestination(client, projectSlug, route, payload, mcpConfigPath) {
65273
+ async function callDestination(client, projectSlug, route, payload, mcpConfigPath, bareFetch) {
65115
65274
  const operation = isRecord6(payload) ? payload.operation : void 0;
65116
65275
  if (route.capability === "wiki") {
65117
65276
  if (operation !== "create" && operation !== "update") {
@@ -65127,6 +65286,12 @@ async function callDestination(client, projectSlug, route, payload, mcpConfigPat
65127
65286
  if (server === null) throw new NoGrantForServerError(`no local MCP config for server "${route.serverId}"`);
65128
65287
  return deliverToGit(server, route.toolName, payload);
65129
65288
  }
65289
+ if (route.capability === "artifacts") {
65290
+ if (operation !== "upload") {
65291
+ throw new Error(`callDestination: payload.operation "${String(operation)}" is not valid for artifacts`);
65292
+ }
65293
+ return deliverToArtifacts(client, projectSlug, payload, bareFetch);
65294
+ }
65130
65295
  throw new Error(`callDestination: no destination wired for capability "${route.capability}"`);
65131
65296
  }
65132
65297
  function isRecord6(value) {
@@ -67298,14 +67463,6 @@ var ARTIFACT_EXTENSION_TYPES = {
67298
67463
  ".webp": "image/webp",
67299
67464
  ".gif": "image/gif"
67300
67465
  };
67301
- var McpToolCodedError = class extends Error {
67302
- code;
67303
- constructor(code, message) {
67304
- super(message);
67305
- this.name = "McpToolCodedError";
67306
- this.code = code;
67307
- }
67308
- };
67309
67466
  function withAuth(options) {
67310
67467
  const baseFetch = options.fetch ?? globalThis.fetch;
67311
67468
  const authedFetch = async (input, init = {}) => {
@@ -67343,7 +67500,11 @@ function classifyClientError(fallbackCode, fallbackMessage, raw) {
67343
67500
  };
67344
67501
  }
67345
67502
  if (raw instanceof McpToolCodedError) {
67346
- return { code: raw.code, message: raw.message || fallbackMessage };
67503
+ return {
67504
+ code: raw.code,
67505
+ message: raw.message || fallbackMessage,
67506
+ ...raw.violations ? { violations: raw.violations } : {}
67507
+ };
67347
67508
  }
67348
67509
  if (raw instanceof Error) {
67349
67510
  return { code: fallbackCode, message: raw.message || fallbackMessage };
@@ -67370,18 +67531,33 @@ function pingAsyncWorkerDispatch(projectSlug, jobId) {
67370
67531
  }).catch(() => {
67371
67532
  });
67372
67533
  }
67373
- async function deliverBuiltIn(client, projectSlug, artifactKind, payload, mcpConfigPath) {
67534
+ async function deliverBuiltIn(client, projectSlug, artifactKind, payload, extra = {}) {
67374
67535
  const result = await deliverThroughCapability(client, {
67375
67536
  projectSlug,
67376
67537
  taskProjectSlug: projectSlug,
67377
67538
  artifactKind,
67378
- taskId: null,
67379
- runId: null,
67539
+ taskId: extra.taskId ?? null,
67540
+ runId: extra.runId ?? null,
67380
67541
  payload,
67381
- mcpConfigPath
67542
+ mcpConfigPath: extra.mcpConfigPath,
67543
+ bareFetch: extra.bareFetch
67382
67544
  });
67383
67545
  if (!result.ok) {
67384
- throw new McpToolCodedError(`CAPABILITY_${result.reason.toUpperCase()}`, `Delivery refused: ${result.reason}`);
67546
+ throw new McpToolCodedError(
67547
+ result.code ?? `CAPABILITY_${result.reason.toUpperCase()}`,
67548
+ describeCapabilityRefusal({
67549
+ reason: result.reason,
67550
+ projectSlug,
67551
+ artifactKind,
67552
+ capability: resolveKindCapability(artifactKind),
67553
+ detail: result.message
67554
+ }),
67555
+ // Consensus round 1 (chunk 4): a destination's own MrrlinApiError (e.g. artifact-file creation's
67556
+ // 409) carries structured violations that classifyClientError already surfaces for every other
67557
+ // tool -- deliverThroughCapability threads them onto DeliveryResult, converted here from the
67558
+ // nullable client shape to McpToolCodedError's optional-array one.
67559
+ result.violations ?? void 0
67560
+ );
67385
67561
  }
67386
67562
  return result.result;
67387
67563
  }
@@ -67463,68 +67639,6 @@ async function getAgentProviderForPanel(client, opts = {}) {
67463
67639
  }
67464
67640
  function createMrrlinTools(options) {
67465
67641
  const client = createMrrlinClient(withAuth(options));
67466
- async function uploadArtifactBytes(c, args) {
67467
- const { bytes: bytes3, class: artifactClass, contentType, description, filename, projectSlug, runId, taskId } = args;
67468
- const created = await c.createArtifactFile(projectSlug, {
67469
- class: artifactClass,
67470
- contentType,
67471
- filename,
67472
- runId,
67473
- sizeBytes: bytes3.byteLength,
67474
- taskId
67475
- });
67476
- let stage = "upload";
67477
- try {
67478
- if (created.upload.kind === "presigned-post") {
67479
- const form = new FormData();
67480
- for (const [field, value] of Object.entries(created.upload.fields)) {
67481
- form.append(field, value);
67482
- }
67483
- form.append("file", new Blob([bytes3], { type: contentType }), filename);
67484
- const bareFetch = options.fetch ?? globalThis.fetch;
67485
- const uploadResponse = await bareFetch(created.upload.url, { body: form, method: "POST" });
67486
- if (!uploadResponse.ok) {
67487
- throw new Error(
67488
- `Presigned upload failed: ${uploadResponse.status} ${await uploadResponse.text()}`
67489
- );
67490
- }
67491
- } else {
67492
- await c.uploadArtifactFileContent(projectSlug, created.artifact.id, bytes3, contentType);
67493
- }
67494
- stage = "complete";
67495
- const completed = await c.completeArtifactFile(projectSlug, created.artifact.id);
67496
- if (completed.runId) {
67497
- stage = "append-run-artifact";
67498
- await c.appendExecutionArtifact(projectSlug, completed.runId, {
67499
- id: `EA-${completed.id}`,
67500
- kind: "file",
67501
- payload: {
67502
- artifactFileId: completed.id,
67503
- class: completed.class,
67504
- contentType: completed.contentType,
67505
- description: description ?? null,
67506
- filename: completed.filename,
67507
- sizeBytes: completed.sizeBytes,
67508
- stableUrl: created.stableUrl
67509
- }
67510
- });
67511
- }
67512
- const markdown = contentType.startsWith("image/") ? `![${completed.filename}](${created.stableUrl})` : `[${completed.filename}](${created.stableUrl})`;
67513
- return {
67514
- artifactFile: completed,
67515
- markdown,
67516
- stableUrl: created.stableUrl
67517
- };
67518
- } catch (error51) {
67519
- const original = error51 instanceof MrrlinApiError ? error51.code : error51 instanceof McpToolCodedError ? error51.code : "ARTIFACT_FILE_UPLOAD_FAILED";
67520
- const message = error51 instanceof Error ? error51.message : String(error51);
67521
- const note = stage === "append-run-artifact" ? "file uploaded and completed successfully; only the run-history append failed \u2014 do NOT re-upload, reference the stableUrl directly" : "a pending row may remain; it is reaped automatically after 1h";
67522
- throw new McpToolCodedError(
67523
- original,
67524
- `artifactFileId=${created.artifact.id} stableUrl=${created.stableUrl} (failed at ${stage}; ${note}): ${message}`
67525
- );
67526
- }
67527
- }
67528
67642
  return {
67529
67643
  [mcpToolNames.archivePlan]: makeTool(
67530
67644
  client,
@@ -67569,7 +67683,7 @@ function createMrrlinTools(options) {
67569
67683
  projectSlug,
67570
67684
  "code_change",
67571
67685
  { operation: "branch", ...input },
67572
- options.mcpConfigPath
67686
+ { mcpConfigPath: options.mcpConfigPath }
67573
67687
  )
67574
67688
  ),
67575
67689
  [mcpToolNames.createGithubPullRequest]: makeTool(
@@ -67582,7 +67696,7 @@ function createMrrlinTools(options) {
67582
67696
  projectSlug,
67583
67697
  "code_change",
67584
67698
  { operation: "pull_request", ...input },
67585
- options.mcpConfigPath
67699
+ { mcpConfigPath: options.mcpConfigPath }
67586
67700
  )
67587
67701
  ),
67588
67702
  [mcpToolNames.createPlan]: makeTool(
@@ -67659,7 +67773,7 @@ function createMrrlinTools(options) {
67659
67773
  projectSlug,
67660
67774
  "document",
67661
67775
  { operation: "create", page: input },
67662
- options.mcpConfigPath
67776
+ { mcpConfigPath: options.mcpConfigPath }
67663
67777
  )
67664
67778
  ),
67665
67779
  [mcpToolNames.deleteTaskDependency]: makeTool(
@@ -67854,7 +67968,7 @@ function createMrrlinTools(options) {
67854
67968
  projectSlug,
67855
67969
  "document",
67856
67970
  { operation: "update", pageId, patch },
67857
- options.mcpConfigPath
67971
+ { mcpConfigPath: options.mcpConfigPath }
67858
67972
  )
67859
67973
  ),
67860
67974
  [mcpToolNames.markSpecReady]: makeTool(
@@ -68152,16 +68266,13 @@ function createMrrlinTools(options) {
68152
68266
  );
68153
68267
  }
68154
68268
  const filename = import_node_path32.default.basename(filePath);
68155
- return uploadArtifactBytes(c, {
68156
- bytes: bytes3,
68157
- class: artifactClass,
68158
- contentType,
68159
- description,
68160
- filename,
68269
+ return deliverBuiltIn(
68270
+ c,
68161
68271
  projectSlug,
68162
- runId,
68163
- taskId
68164
- });
68272
+ "file_set",
68273
+ { operation: "upload", bytes: bytes3, class: artifactClass, contentType, description, filename, runId, taskId },
68274
+ { mcpConfigPath: options.mcpConfigPath, bareFetch: options.fetch ?? globalThis.fetch, taskId, runId }
68275
+ );
68165
68276
  }
68166
68277
  ),
68167
68278
  [mcpToolNames.deliverFile]: makeTool(
@@ -68197,16 +68308,13 @@ function createMrrlinTools(options) {
68197
68308
  "Artifact exceeds 5MB; split or summarize instead."
68198
68309
  );
68199
68310
  }
68200
- return uploadArtifactBytes(c, {
68201
- bytes: bytes3,
68202
- class: artifactClass,
68203
- contentType,
68204
- description,
68205
- filename,
68311
+ return deliverBuiltIn(
68312
+ c,
68206
68313
  projectSlug,
68207
- runId,
68208
- taskId
68209
- });
68314
+ "file_set",
68315
+ { operation: "upload", bytes: bytes3, class: artifactClass, contentType, description, filename, runId, taskId },
68316
+ { mcpConfigPath: options.mcpConfigPath, bareFetch: options.fetch ?? globalThis.fetch, taskId, runId }
68317
+ );
68210
68318
  }
68211
68319
  ),
68212
68320
  [mcpToolNames.listArtifactFiles]: makeTool(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrrlin-dev/mcp",
3
- "version": "0.4.55",
3
+ "version": "0.4.59",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mrrlin-mcp": "dist/bin.cjs"
@@ -24,8 +24,8 @@
24
24
  "@mrrlin/client": "0.0.0",
25
25
  "@mrrlin/agent-client": "0.0.0",
26
26
  "@mrrlin/director-e2e": "0.0.0",
27
- "@mrrlin/tsconfig": "0.0.0",
28
27
  "@mrrlin/schemas": "0.0.0",
28
+ "@mrrlin/tsconfig": "0.0.0",
29
29
  "@mrrlin/wiki": "0.0.0"
30
30
  },
31
31
  "dependencies": {