@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.
- package/dist/bin.cjs +221 -113
- 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:
|
|
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.
|
|
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 (
|
|
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
|
-
|
|
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},
|
|
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
|
-
|
|
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})`;
|
|
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(
|
|
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
|
-
|
|
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 {
|
|
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,
|
|
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(
|
|
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})`;
|
|
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
|
|
68156
|
-
|
|
68157
|
-
class: artifactClass,
|
|
68158
|
-
contentType,
|
|
68159
|
-
description,
|
|
68160
|
-
filename,
|
|
68269
|
+
return deliverBuiltIn(
|
|
68270
|
+
c,
|
|
68161
68271
|
projectSlug,
|
|
68162
|
-
|
|
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
|
|
68201
|
-
|
|
68202
|
-
class: artifactClass,
|
|
68203
|
-
contentType,
|
|
68204
|
-
description,
|
|
68205
|
-
filename,
|
|
68311
|
+
return deliverBuiltIn(
|
|
68312
|
+
c,
|
|
68206
68313
|
projectSlug,
|
|
68207
|
-
|
|
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.
|
|
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": {
|