@mrrlin-dev/mcp 0.3.57 → 0.3.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 +89 -22
- package/package.json +5 -5
package/dist/bin.cjs
CHANGED
|
@@ -20665,10 +20665,7 @@ function normalizeUrl(value) {
|
|
|
20665
20665
|
var RETIRED_API_BASE_URLS = {
|
|
20666
20666
|
// Retired 2026-07-28 when staging moved to the mrrlin2 Vercel team; serves a decommissioned
|
|
20667
20667
|
// Supabase project and now answers `GET /health` with 402 DEPLOYMENT_DISABLED. Added in 0.3.50.
|
|
20668
|
-
"mrrlin-api-fnnzzz-fnnzzzs-projects.vercel.app": STAGING_API_BASE_URL
|
|
20669
|
-
// Retired 2026-08-11 when staging moved to the mrrlin3 Vercel team after mrrlin2 hit usage
|
|
20670
|
-
// limits. Added in 0.3.57.
|
|
20671
|
-
"mrrlin-api-mrrlin2.vercel.app": STAGING_API_BASE_URL
|
|
20668
|
+
"mrrlin-api-fnnzzz-fnnzzzs-projects.vercel.app": STAGING_API_BASE_URL
|
|
20672
20669
|
};
|
|
20673
20670
|
function isSameApiHost(a, b) {
|
|
20674
20671
|
const origin = (value) => {
|
|
@@ -39460,7 +39457,7 @@ function startCodexProbe(deps = {}) {
|
|
|
39460
39457
|
}
|
|
39461
39458
|
|
|
39462
39459
|
// src/_generated/version.ts
|
|
39463
|
-
var PKG_VERSION = "0.3.
|
|
39460
|
+
var PKG_VERSION = "0.3.59";
|
|
39464
39461
|
|
|
39465
39462
|
// src/api-base-url-migrate.ts
|
|
39466
39463
|
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
@@ -40749,7 +40746,7 @@ function reviserIdentityInstructions(taskId, title) {
|
|
|
40749
40746
|
function buildSpecGateDeps(args) {
|
|
40750
40747
|
const { client, projectSlug, specPageId, cwd, codexExecutable, extraHeadCount = 0 } = args;
|
|
40751
40748
|
const rounds = Number(process.env["MRRLIN_CONSENSUS_ROUNDS"] ?? 5);
|
|
40752
|
-
const maxHeadCalls = rounds * (4 + extraHeadCount + 1);
|
|
40749
|
+
const maxHeadCalls = 2 * rounds * (4 + extraHeadCount + 1);
|
|
40753
40750
|
const timeoutMs = Number(process.env["MRRLIN_CONSENSUS_HEAD_TIMEOUT_MS"] ?? 15e4);
|
|
40754
40751
|
let intentPromise = null;
|
|
40755
40752
|
function loadIntent() {
|
|
@@ -40913,7 +40910,7 @@ function buildCodeGateDeps(args) {
|
|
|
40913
40910
|
const { client, projectSlug, baseRef, cwd, codexExecutable, extraHeads } = args;
|
|
40914
40911
|
const rounds = Number(process.env["MRRLIN_CONSENSUS_ROUNDS"] ?? 5);
|
|
40915
40912
|
const heads = ["code-reviewer", ...extraHeads ?? []];
|
|
40916
|
-
const maxHeadCalls = rounds * (heads.length + 1);
|
|
40913
|
+
const maxHeadCalls = 2 * rounds * (heads.length + 1);
|
|
40917
40914
|
const headTimeoutMs = Number(process.env["MRRLIN_CONSENSUS_HEAD_TIMEOUT_MS"] ?? 15e4);
|
|
40918
40915
|
const reviserTimeoutMs = Number(process.env["MRRLIN_CODEGATE_REVISER_TIMEOUT_MS"] ?? 6e5);
|
|
40919
40916
|
const gitArgs = { cwd, baseRef, run: defaultRunCmd };
|
|
@@ -41011,7 +41008,7 @@ async function buildDeliverableGateDeps(args) {
|
|
|
41011
41008
|
}
|
|
41012
41009
|
}
|
|
41013
41010
|
const heads = resolveHeads(domain2);
|
|
41014
|
-
const maxHeadCalls = rounds * (heads.length + 1);
|
|
41011
|
+
const maxHeadCalls = 2 * rounds * (heads.length + 1);
|
|
41015
41012
|
const criteriaBlock = renderCriteriaBlock(criteria);
|
|
41016
41013
|
return {
|
|
41017
41014
|
heads,
|
|
@@ -43897,6 +43894,46 @@ function createBoundedSemaphore(slots) {
|
|
|
43897
43894
|
};
|
|
43898
43895
|
}
|
|
43899
43896
|
|
|
43897
|
+
// src/consensus/escalation.ts
|
|
43898
|
+
function diagnoseStall(history, configuredRounds) {
|
|
43899
|
+
const n = history.length;
|
|
43900
|
+
const nonRespPerRound = history.map((h) => h.headOutcomes.filter((o) => !o.responded).length);
|
|
43901
|
+
const infraRoundCount = nonRespPerRound.filter((c) => c >= 2).length;
|
|
43902
|
+
const infraQualifies = infraRoundCount > n / 2;
|
|
43903
|
+
if (infraQualifies) {
|
|
43904
|
+
const roundIndices = [];
|
|
43905
|
+
nonRespPerRound.forEach((c, i) => {
|
|
43906
|
+
if (c >= 2) roundIndices.push(i + 1);
|
|
43907
|
+
});
|
|
43908
|
+
const evidence2 = `INFRA basis: \u22652 non\u2011responding heads in ${infraRoundCount} of ${n} rounds (rounds ${roundIndices.join(",")})`;
|
|
43909
|
+
let grant = 3;
|
|
43910
|
+
const headroom = 2 * configuredRounds - n;
|
|
43911
|
+
grant = Math.max(1, Math.min(grant, headroom));
|
|
43912
|
+
return { diagnosis: "INFRA", grantedRounds: grant, evidence: evidence2 };
|
|
43913
|
+
}
|
|
43914
|
+
if (n >= 2) {
|
|
43915
|
+
const counts = history.map((h) => h.accepted.length);
|
|
43916
|
+
const last = counts[n - 1];
|
|
43917
|
+
const secondLast = counts[n - 2];
|
|
43918
|
+
const lastFall = last < secondLast;
|
|
43919
|
+
if (lastFall) {
|
|
43920
|
+
let falls = 1;
|
|
43921
|
+
if (n >= 3 && secondLast < counts[n - 3]) {
|
|
43922
|
+
falls++;
|
|
43923
|
+
}
|
|
43924
|
+
let grant = 2 + falls;
|
|
43925
|
+
if (grant > 5) grant = 5;
|
|
43926
|
+
const headroom = 2 * configuredRounds - n;
|
|
43927
|
+
grant = Math.max(1, Math.min(grant, headroom));
|
|
43928
|
+
const seqDesc = counts.map((c, i) => `round${i + 1}:${c}`).join(" \u2192 ");
|
|
43929
|
+
const evidence2 = `SUBSTANCE basis: accepted count fell (${seqDesc})`;
|
|
43930
|
+
return { diagnosis: "SUBSTANCE", grantedRounds: grant, evidence: evidence2 };
|
|
43931
|
+
}
|
|
43932
|
+
}
|
|
43933
|
+
const evidence = n === 0 ? "empty history" : `no infra or substance basis found in ${n} rounds`;
|
|
43934
|
+
return { diagnosis: "AMBIGUITY", grantedRounds: 0, evidence };
|
|
43935
|
+
}
|
|
43936
|
+
|
|
43900
43937
|
// src/consensus/loop.ts
|
|
43901
43938
|
async function runConsensus(input) {
|
|
43902
43939
|
const sem = createBoundedSemaphore(input.concurrency ?? input.heads.length);
|
|
@@ -43904,9 +43941,12 @@ async function runConsensus(input) {
|
|
|
43904
43941
|
let artifact = input.artifact;
|
|
43905
43942
|
let calls = 0;
|
|
43906
43943
|
const dismissedFwd = [];
|
|
43907
|
-
|
|
43944
|
+
let effectiveRounds = input.rounds;
|
|
43945
|
+
let escalated = false;
|
|
43946
|
+
let decision;
|
|
43947
|
+
for (let round = 1; round <= effectiveRounds; round++) {
|
|
43908
43948
|
if (calls + input.heads.length > input.maxHeadCalls) {
|
|
43909
|
-
return { outcome: "CONSENSUS_BLOCKED", rounds: round - 1, finalArtifact: artifact, history };
|
|
43949
|
+
return { outcome: "CONSENSUS_BLOCKED", rounds: round - 1, finalArtifact: artifact, history, ...decision ? { escalation: decision } : {} };
|
|
43910
43950
|
}
|
|
43911
43951
|
const dismissedBlock = dismissedFwd.length ? `PREVIOUSLY DISMISSED (do not re-raise unless new information):
|
|
43912
43952
|
${dismissedFwd.slice(-20).join("\n")}` : "";
|
|
@@ -43930,12 +43970,19 @@ ${dismissedFwd.slice(-20).join("\n")}` : "";
|
|
|
43930
43970
|
if (responding.length === 0) {
|
|
43931
43971
|
return { outcome: "CONSENSUS_UNAVAILABLE", rounds: round, finalArtifact: artifact, history };
|
|
43932
43972
|
}
|
|
43973
|
+
const headOutcomes = input.heads.map((persona) => ({
|
|
43974
|
+
persona,
|
|
43975
|
+
responded: false
|
|
43976
|
+
}));
|
|
43933
43977
|
const issues = [];
|
|
43934
|
-
const verdicts = [];
|
|
43935
43978
|
for (const { idx, res } of responding) {
|
|
43936
43979
|
const parsed = parseVerdict(res.text);
|
|
43937
|
-
verdicts.push(parsed.verdict);
|
|
43938
43980
|
parsed.issues.forEach((iss, n) => issues.push({ ...iss, id: `r${round}-h${idx}-${n}` }));
|
|
43981
|
+
const outcome = headOutcomes[idx];
|
|
43982
|
+
if (outcome) {
|
|
43983
|
+
outcome.responded = true;
|
|
43984
|
+
outcome.verdict = parsed.verdict;
|
|
43985
|
+
}
|
|
43939
43986
|
if (parsed.verdict !== "APPROVE" && parsed.issues.length === 0 && parsed.parseFallbacks.length === 0) {
|
|
43940
43987
|
issues.push({
|
|
43941
43988
|
category: "ambiguity",
|
|
@@ -43947,7 +43994,7 @@ ${dismissedFwd.slice(-20).join("\n")}` : "";
|
|
|
43947
43994
|
let adj;
|
|
43948
43995
|
if (issues.length > 0) {
|
|
43949
43996
|
if (calls + 1 > input.maxHeadCalls) {
|
|
43950
|
-
return { outcome: "CONSENSUS_BLOCKED", rounds: round, finalArtifact: artifact, history };
|
|
43997
|
+
return { outcome: "CONSENSUS_BLOCKED", rounds: round, finalArtifact: artifact, history, ...decision ? { escalation: decision } : {} };
|
|
43951
43998
|
}
|
|
43952
43999
|
calls++;
|
|
43953
44000
|
try {
|
|
@@ -43958,17 +44005,25 @@ ${dismissedFwd.slice(-20).join("\n")}` : "";
|
|
|
43958
44005
|
} else {
|
|
43959
44006
|
adj = { adjudicatedVerdict: "APPROVE", accepted: [], dismissed: [] };
|
|
43960
44007
|
}
|
|
43961
|
-
history.push({ round,
|
|
44008
|
+
history.push({ round, accepted: adj.accepted, dismissed: adj.dismissed, headOutcomes });
|
|
43962
44009
|
adj.dismissed.forEach((d) => dismissedFwd.push(`- ${d.id}: ${d.reason}`));
|
|
43963
44010
|
if (adj.accepted.length === 0) {
|
|
43964
|
-
return { outcome: "CONVERGED", rounds: round, finalArtifact: artifact, history };
|
|
44011
|
+
return { outcome: "CONVERGED", rounds: round, finalArtifact: artifact, history, ...decision ? { escalation: decision } : {} };
|
|
43965
44012
|
}
|
|
43966
|
-
if (round ===
|
|
43967
|
-
|
|
44013
|
+
if (round === effectiveRounds) {
|
|
44014
|
+
if (!decision) {
|
|
44015
|
+
decision = diagnoseStall(history, input.rounds);
|
|
44016
|
+
}
|
|
44017
|
+
if (decision.grantedRounds > 0 && !escalated) {
|
|
44018
|
+
escalated = true;
|
|
44019
|
+
effectiveRounds = Math.min(effectiveRounds + decision.grantedRounds, input.rounds * 2);
|
|
44020
|
+
} else {
|
|
44021
|
+
return { outcome: "CONSENSUS_BLOCKED", rounds: round, finalArtifact: artifact, history, ...decision ? { escalation: decision } : {} };
|
|
44022
|
+
}
|
|
43968
44023
|
}
|
|
43969
44024
|
artifact = await input.revise(artifact, adj.accepted);
|
|
43970
44025
|
}
|
|
43971
|
-
return { outcome: "CONSENSUS_BLOCKED", rounds:
|
|
44026
|
+
return { outcome: "CONSENSUS_BLOCKED", rounds: effectiveRounds, finalArtifact: artifact, history };
|
|
43972
44027
|
}
|
|
43973
44028
|
|
|
43974
44029
|
// src/consensus/deliverable-gate.ts
|
|
@@ -44018,7 +44073,12 @@ async function runDeliverableGate(_target, deps) {
|
|
|
44018
44073
|
whyBlocking: `reviewer raised a ${issue2.category} issue`,
|
|
44019
44074
|
category: issue2.category
|
|
44020
44075
|
}));
|
|
44021
|
-
return
|
|
44076
|
+
return {
|
|
44077
|
+
outcome: "CONSENSUS_BLOCKED",
|
|
44078
|
+
rounds: result.rounds,
|
|
44079
|
+
...clarifications.length > 0 ? { clarifications } : {},
|
|
44080
|
+
...result.escalation ? { escalation: result.escalation } : {}
|
|
44081
|
+
};
|
|
44022
44082
|
}
|
|
44023
44083
|
return { outcome: result.outcome, rounds: result.rounds };
|
|
44024
44084
|
}
|
|
@@ -48907,8 +48967,8 @@ var DEFAULT_DIRECTOR_BRIDGE_ALLOWED_ORIGINS = [
|
|
|
48907
48967
|
"http://[::1]:*",
|
|
48908
48968
|
// Staging Vercel team migrated 2026-07-28 (see docs/reference/deployments.md). The prior
|
|
48909
48969
|
// fnnzzz-fnnzzzs-projects web alias was dropped once no operator was left on an old build.
|
|
48910
|
-
// mrrlin2 hit usage limits and was replaced by mrrlin3 on 2026-08-11
|
|
48911
|
-
|
|
48970
|
+
// mrrlin2 hit usage limits and was replaced by mrrlin3 on 2026-08-11; the mrrlin2 web alias
|
|
48971
|
+
// was dropped the same day since no operator was left on that build either.
|
|
48912
48972
|
"https://mrrlin-web-mrrlin3.vercel.app",
|
|
48913
48973
|
"https://app.mrrlin.dev",
|
|
48914
48974
|
"https://mrrlin-web.vercel.app"
|
|
@@ -55207,7 +55267,11 @@ async function runSpecGate(_target, deps, opts) {
|
|
|
55207
55267
|
if (result.outcome === "CONSENSUS_BLOCKED") {
|
|
55208
55268
|
const accepted = result.history.at(-1)?.accepted ?? [];
|
|
55209
55269
|
const operatorClarifications = accepted.filter((issue2) => issue2.category === "ambiguity" || issue2.category === "scope").map((issue2) => mapAcceptedIssueToClarification(issue2));
|
|
55210
|
-
return
|
|
55270
|
+
return {
|
|
55271
|
+
outcome: "CONSENSUS_BLOCKED",
|
|
55272
|
+
...operatorClarifications.length > 0 ? { operatorClarifications } : {},
|
|
55273
|
+
...result.escalation ? { escalation: result.escalation } : {}
|
|
55274
|
+
};
|
|
55211
55275
|
}
|
|
55212
55276
|
return { outcome: result.outcome };
|
|
55213
55277
|
}
|
|
@@ -55774,6 +55838,9 @@ async function handleConsensusBlocked(result, ctx, input, resolvedTaskId) {
|
|
|
55774
55838
|
} else {
|
|
55775
55839
|
error51 = "Consensus blocked: reviewers did not converge within budget.";
|
|
55776
55840
|
}
|
|
55841
|
+
if (result.escalation) {
|
|
55842
|
+
error51 += ` (diagnosis: ${result.escalation.diagnosis})`;
|
|
55843
|
+
}
|
|
55777
55844
|
return {
|
|
55778
55845
|
kind: "failed",
|
|
55779
55846
|
failureReason: "consensus_blocked",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrrlin-dev/mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.59",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mrrlin-mcp": "dist/bin.cjs"
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
"@types/ws": "^8.18.1",
|
|
22
22
|
"esbuild": "^0.24.0",
|
|
23
23
|
"tsx": "^4.22.3",
|
|
24
|
+
"@mrrlin/director-e2e": "0.0.0",
|
|
25
|
+
"@mrrlin/wiki": "0.0.0",
|
|
24
26
|
"@mrrlin/schemas": "0.0.0",
|
|
25
|
-
"@mrrlin/codex-client": "0.0.0",
|
|
26
27
|
"@mrrlin/client": "0.0.0",
|
|
27
|
-
"@mrrlin/
|
|
28
|
-
"@mrrlin/tsconfig": "0.0.0"
|
|
29
|
-
"@mrrlin/wiki": "0.0.0"
|
|
28
|
+
"@mrrlin/codex-client": "0.0.0",
|
|
29
|
+
"@mrrlin/tsconfig": "0.0.0"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@iarna/toml": "^2.2.5",
|