@mrrlin-dev/mcp 0.3.56 → 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 +99 -20
- package/package.json +4 -4
package/dist/bin.cjs
CHANGED
|
@@ -20658,7 +20658,7 @@ var toml = __toESM(require_toml(), 1);
|
|
|
20658
20658
|
|
|
20659
20659
|
// src/api-base-url.ts
|
|
20660
20660
|
var DEFAULT_API_BASE_URL = "http://127.0.0.1:8787";
|
|
20661
|
-
var STAGING_API_BASE_URL = "https://mrrlin-api-
|
|
20661
|
+
var STAGING_API_BASE_URL = "https://mrrlin-api-mrrlin3.vercel.app";
|
|
20662
20662
|
function normalizeUrl(value) {
|
|
20663
20663
|
return value.replace(/\/$/, "");
|
|
20664
20664
|
}
|
|
@@ -36636,6 +36636,7 @@ var mrrlinOperatorSettingsUpdateSchema = external_exports.object({
|
|
|
36636
36636
|
});
|
|
36637
36637
|
var operatorSettingsResponseSchema = external_exports.object({ data: mrrlinOperatorSettingsSchema });
|
|
36638
36638
|
var operatorPresenceResponseSchema = external_exports.object({ data: external_exports.object({ lastPresenceAt: external_exports.string().datetime() }) });
|
|
36639
|
+
var operatorPresenceRequestSchema = external_exports.object({ projectSlug: external_exports.string().min(1).optional() }).strict().optional();
|
|
36639
36640
|
var mrrlinConsensusConfigSchema = external_exports.object({ consensusEnabled: external_exports.boolean() });
|
|
36640
36641
|
var consensusConfigResponseSchema = external_exports.object({ data: mrrlinConsensusConfigSchema });
|
|
36641
36642
|
var agentPoolSnapshotSchema = external_exports.object({
|
|
@@ -38932,8 +38933,14 @@ function createMrrlinClient(config2) {
|
|
|
38932
38933
|
});
|
|
38933
38934
|
return operatorSettingsResponseSchema.parse(body).data;
|
|
38934
38935
|
},
|
|
38935
|
-
async recordOperatorPresence() {
|
|
38936
|
-
const
|
|
38936
|
+
async recordOperatorPresence(input) {
|
|
38937
|
+
const projectSlug = input?.projectSlug;
|
|
38938
|
+
const body = await request(`/operator/presence`, {
|
|
38939
|
+
method: "POST",
|
|
38940
|
+
// Omit the body entirely when no slug is given — background tabs beat bodyless today and
|
|
38941
|
+
// must continue to (see design.md deploy-skew probe).
|
|
38942
|
+
...projectSlug !== void 0 ? { body: JSON.stringify({ projectSlug }), headers: { "content-type": "application/json" } } : {}
|
|
38943
|
+
});
|
|
38937
38944
|
return operatorPresenceResponseSchema.parse(body).data;
|
|
38938
38945
|
},
|
|
38939
38946
|
async getOperatorAgentPool() {
|
|
@@ -39450,7 +39457,7 @@ function startCodexProbe(deps = {}) {
|
|
|
39450
39457
|
}
|
|
39451
39458
|
|
|
39452
39459
|
// src/_generated/version.ts
|
|
39453
|
-
var PKG_VERSION = "0.3.
|
|
39460
|
+
var PKG_VERSION = "0.3.59";
|
|
39454
39461
|
|
|
39455
39462
|
// src/api-base-url-migrate.ts
|
|
39456
39463
|
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
@@ -40739,7 +40746,7 @@ function reviserIdentityInstructions(taskId, title) {
|
|
|
40739
40746
|
function buildSpecGateDeps(args) {
|
|
40740
40747
|
const { client, projectSlug, specPageId, cwd, codexExecutable, extraHeadCount = 0 } = args;
|
|
40741
40748
|
const rounds = Number(process.env["MRRLIN_CONSENSUS_ROUNDS"] ?? 5);
|
|
40742
|
-
const maxHeadCalls = rounds * (4 + extraHeadCount + 1);
|
|
40749
|
+
const maxHeadCalls = 2 * rounds * (4 + extraHeadCount + 1);
|
|
40743
40750
|
const timeoutMs = Number(process.env["MRRLIN_CONSENSUS_HEAD_TIMEOUT_MS"] ?? 15e4);
|
|
40744
40751
|
let intentPromise = null;
|
|
40745
40752
|
function loadIntent() {
|
|
@@ -40903,7 +40910,7 @@ function buildCodeGateDeps(args) {
|
|
|
40903
40910
|
const { client, projectSlug, baseRef, cwd, codexExecutable, extraHeads } = args;
|
|
40904
40911
|
const rounds = Number(process.env["MRRLIN_CONSENSUS_ROUNDS"] ?? 5);
|
|
40905
40912
|
const heads = ["code-reviewer", ...extraHeads ?? []];
|
|
40906
|
-
const maxHeadCalls = rounds * (heads.length + 1);
|
|
40913
|
+
const maxHeadCalls = 2 * rounds * (heads.length + 1);
|
|
40907
40914
|
const headTimeoutMs = Number(process.env["MRRLIN_CONSENSUS_HEAD_TIMEOUT_MS"] ?? 15e4);
|
|
40908
40915
|
const reviserTimeoutMs = Number(process.env["MRRLIN_CODEGATE_REVISER_TIMEOUT_MS"] ?? 6e5);
|
|
40909
40916
|
const gitArgs = { cwd, baseRef, run: defaultRunCmd };
|
|
@@ -41001,7 +41008,7 @@ async function buildDeliverableGateDeps(args) {
|
|
|
41001
41008
|
}
|
|
41002
41009
|
}
|
|
41003
41010
|
const heads = resolveHeads(domain2);
|
|
41004
|
-
const maxHeadCalls = rounds * (heads.length + 1);
|
|
41011
|
+
const maxHeadCalls = 2 * rounds * (heads.length + 1);
|
|
41005
41012
|
const criteriaBlock = renderCriteriaBlock(criteria);
|
|
41006
41013
|
return {
|
|
41007
41014
|
heads,
|
|
@@ -43887,6 +43894,46 @@ function createBoundedSemaphore(slots) {
|
|
|
43887
43894
|
};
|
|
43888
43895
|
}
|
|
43889
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
|
+
|
|
43890
43937
|
// src/consensus/loop.ts
|
|
43891
43938
|
async function runConsensus(input) {
|
|
43892
43939
|
const sem = createBoundedSemaphore(input.concurrency ?? input.heads.length);
|
|
@@ -43894,9 +43941,12 @@ async function runConsensus(input) {
|
|
|
43894
43941
|
let artifact = input.artifact;
|
|
43895
43942
|
let calls = 0;
|
|
43896
43943
|
const dismissedFwd = [];
|
|
43897
|
-
|
|
43944
|
+
let effectiveRounds = input.rounds;
|
|
43945
|
+
let escalated = false;
|
|
43946
|
+
let decision;
|
|
43947
|
+
for (let round = 1; round <= effectiveRounds; round++) {
|
|
43898
43948
|
if (calls + input.heads.length > input.maxHeadCalls) {
|
|
43899
|
-
return { outcome: "CONSENSUS_BLOCKED", rounds: round - 1, finalArtifact: artifact, history };
|
|
43949
|
+
return { outcome: "CONSENSUS_BLOCKED", rounds: round - 1, finalArtifact: artifact, history, ...decision ? { escalation: decision } : {} };
|
|
43900
43950
|
}
|
|
43901
43951
|
const dismissedBlock = dismissedFwd.length ? `PREVIOUSLY DISMISSED (do not re-raise unless new information):
|
|
43902
43952
|
${dismissedFwd.slice(-20).join("\n")}` : "";
|
|
@@ -43920,12 +43970,19 @@ ${dismissedFwd.slice(-20).join("\n")}` : "";
|
|
|
43920
43970
|
if (responding.length === 0) {
|
|
43921
43971
|
return { outcome: "CONSENSUS_UNAVAILABLE", rounds: round, finalArtifact: artifact, history };
|
|
43922
43972
|
}
|
|
43973
|
+
const headOutcomes = input.heads.map((persona) => ({
|
|
43974
|
+
persona,
|
|
43975
|
+
responded: false
|
|
43976
|
+
}));
|
|
43923
43977
|
const issues = [];
|
|
43924
|
-
const verdicts = [];
|
|
43925
43978
|
for (const { idx, res } of responding) {
|
|
43926
43979
|
const parsed = parseVerdict(res.text);
|
|
43927
|
-
verdicts.push(parsed.verdict);
|
|
43928
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
|
+
}
|
|
43929
43986
|
if (parsed.verdict !== "APPROVE" && parsed.issues.length === 0 && parsed.parseFallbacks.length === 0) {
|
|
43930
43987
|
issues.push({
|
|
43931
43988
|
category: "ambiguity",
|
|
@@ -43937,7 +43994,7 @@ ${dismissedFwd.slice(-20).join("\n")}` : "";
|
|
|
43937
43994
|
let adj;
|
|
43938
43995
|
if (issues.length > 0) {
|
|
43939
43996
|
if (calls + 1 > input.maxHeadCalls) {
|
|
43940
|
-
return { outcome: "CONSENSUS_BLOCKED", rounds: round, finalArtifact: artifact, history };
|
|
43997
|
+
return { outcome: "CONSENSUS_BLOCKED", rounds: round, finalArtifact: artifact, history, ...decision ? { escalation: decision } : {} };
|
|
43941
43998
|
}
|
|
43942
43999
|
calls++;
|
|
43943
44000
|
try {
|
|
@@ -43948,17 +44005,25 @@ ${dismissedFwd.slice(-20).join("\n")}` : "";
|
|
|
43948
44005
|
} else {
|
|
43949
44006
|
adj = { adjudicatedVerdict: "APPROVE", accepted: [], dismissed: [] };
|
|
43950
44007
|
}
|
|
43951
|
-
history.push({ round,
|
|
44008
|
+
history.push({ round, accepted: adj.accepted, dismissed: adj.dismissed, headOutcomes });
|
|
43952
44009
|
adj.dismissed.forEach((d) => dismissedFwd.push(`- ${d.id}: ${d.reason}`));
|
|
43953
44010
|
if (adj.accepted.length === 0) {
|
|
43954
|
-
return { outcome: "CONVERGED", rounds: round, finalArtifact: artifact, history };
|
|
44011
|
+
return { outcome: "CONVERGED", rounds: round, finalArtifact: artifact, history, ...decision ? { escalation: decision } : {} };
|
|
43955
44012
|
}
|
|
43956
|
-
if (round ===
|
|
43957
|
-
|
|
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
|
+
}
|
|
43958
44023
|
}
|
|
43959
44024
|
artifact = await input.revise(artifact, adj.accepted);
|
|
43960
44025
|
}
|
|
43961
|
-
return { outcome: "CONSENSUS_BLOCKED", rounds:
|
|
44026
|
+
return { outcome: "CONSENSUS_BLOCKED", rounds: effectiveRounds, finalArtifact: artifact, history };
|
|
43962
44027
|
}
|
|
43963
44028
|
|
|
43964
44029
|
// src/consensus/deliverable-gate.ts
|
|
@@ -44008,7 +44073,12 @@ async function runDeliverableGate(_target, deps) {
|
|
|
44008
44073
|
whyBlocking: `reviewer raised a ${issue2.category} issue`,
|
|
44009
44074
|
category: issue2.category
|
|
44010
44075
|
}));
|
|
44011
|
-
return
|
|
44076
|
+
return {
|
|
44077
|
+
outcome: "CONSENSUS_BLOCKED",
|
|
44078
|
+
rounds: result.rounds,
|
|
44079
|
+
...clarifications.length > 0 ? { clarifications } : {},
|
|
44080
|
+
...result.escalation ? { escalation: result.escalation } : {}
|
|
44081
|
+
};
|
|
44012
44082
|
}
|
|
44013
44083
|
return { outcome: result.outcome, rounds: result.rounds };
|
|
44014
44084
|
}
|
|
@@ -48897,7 +48967,9 @@ var DEFAULT_DIRECTOR_BRIDGE_ALLOWED_ORIGINS = [
|
|
|
48897
48967
|
"http://[::1]:*",
|
|
48898
48968
|
// Staging Vercel team migrated 2026-07-28 (see docs/reference/deployments.md). The prior
|
|
48899
48969
|
// fnnzzz-fnnzzzs-projects web alias was dropped once no operator was left on an old build.
|
|
48900
|
-
|
|
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.
|
|
48972
|
+
"https://mrrlin-web-mrrlin3.vercel.app",
|
|
48901
48973
|
"https://app.mrrlin.dev",
|
|
48902
48974
|
"https://mrrlin-web.vercel.app"
|
|
48903
48975
|
];
|
|
@@ -55195,7 +55267,11 @@ async function runSpecGate(_target, deps, opts) {
|
|
|
55195
55267
|
if (result.outcome === "CONSENSUS_BLOCKED") {
|
|
55196
55268
|
const accepted = result.history.at(-1)?.accepted ?? [];
|
|
55197
55269
|
const operatorClarifications = accepted.filter((issue2) => issue2.category === "ambiguity" || issue2.category === "scope").map((issue2) => mapAcceptedIssueToClarification(issue2));
|
|
55198
|
-
return
|
|
55270
|
+
return {
|
|
55271
|
+
outcome: "CONSENSUS_BLOCKED",
|
|
55272
|
+
...operatorClarifications.length > 0 ? { operatorClarifications } : {},
|
|
55273
|
+
...result.escalation ? { escalation: result.escalation } : {}
|
|
55274
|
+
};
|
|
55199
55275
|
}
|
|
55200
55276
|
return { outcome: result.outcome };
|
|
55201
55277
|
}
|
|
@@ -55762,6 +55838,9 @@ async function handleConsensusBlocked(result, ctx, input, resolvedTaskId) {
|
|
|
55762
55838
|
} else {
|
|
55763
55839
|
error51 = "Consensus blocked: reviewers did not converge within budget.";
|
|
55764
55840
|
}
|
|
55841
|
+
if (result.escalation) {
|
|
55842
|
+
error51 += ` (diagnosis: ${result.escalation.diagnosis})`;
|
|
55843
|
+
}
|
|
55765
55844
|
return {
|
|
55766
55845
|
kind: "failed",
|
|
55767
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"
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
"esbuild": "^0.24.0",
|
|
23
23
|
"tsx": "^4.22.3",
|
|
24
24
|
"@mrrlin/director-e2e": "0.0.0",
|
|
25
|
-
"@mrrlin/schemas": "0.0.0",
|
|
26
25
|
"@mrrlin/wiki": "0.0.0",
|
|
26
|
+
"@mrrlin/schemas": "0.0.0",
|
|
27
27
|
"@mrrlin/client": "0.0.0",
|
|
28
|
-
"@mrrlin/
|
|
29
|
-
"@mrrlin/
|
|
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",
|