@mrrlin-dev/mcp 0.4.21 → 0.4.22
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 +306 -33
- package/package.json +4 -4
package/dist/bin.cjs
CHANGED
|
@@ -36811,6 +36811,7 @@ var openApiOperationIds = {
|
|
|
36811
36811
|
retireThread: "retireThread",
|
|
36812
36812
|
applyIntentVerdict: "applyIntentVerdict",
|
|
36813
36813
|
armIntentCheck: "armIntentCheck",
|
|
36814
|
+
settleExecutionRunOutcome: "settleExecutionRunOutcome",
|
|
36814
36815
|
// Run-scoped, model-facing half of the resume contract (D8). Distinct from upsertTaskState:
|
|
36815
36816
|
// that one is the server's own write (whole record, explicit lastRunSeq), this one is the
|
|
36816
36817
|
// executor reporting narrative only, with the ordering value derived server-side from the run.
|
|
@@ -37434,8 +37435,17 @@ var mrrlinExecutionArtifactKindSchema = external_exports.enum([
|
|
|
37434
37435
|
"produced_url",
|
|
37435
37436
|
"resume_spec",
|
|
37436
37437
|
"deliverable",
|
|
37437
|
-
"pull_request_state"
|
|
37438
|
+
"pull_request_state",
|
|
37439
|
+
"non_code_outcome"
|
|
37438
37440
|
]);
|
|
37441
|
+
var mrrlinNonCodeOutcomeSchema = external_exports.enum(["completed", "blocked_missing_input", "negative_result"]);
|
|
37442
|
+
var mrrlinIntentProvenanceRefSchema = external_exports.object({
|
|
37443
|
+
kind: external_exports.enum(["director_chat_message", "wiki_page"]),
|
|
37444
|
+
id: external_exports.string().min(1),
|
|
37445
|
+
role: external_exports.enum(["user", "assistant", "system"]).optional(),
|
|
37446
|
+
contentHash: external_exports.string().min(1).optional()
|
|
37447
|
+
});
|
|
37448
|
+
var mrrlinIntentProvenanceSchema = external_exports.array(mrrlinIntentProvenanceRefSchema).default([]);
|
|
37439
37449
|
var mrrlinDeployAttemptPayloadSchema = external_exports.object({
|
|
37440
37450
|
env: external_exports.enum(["dev", "prod"]),
|
|
37441
37451
|
workflowId: external_exports.number().int(),
|
|
@@ -37541,6 +37551,8 @@ var mrrlinTaskSchema = external_exports.object({
|
|
|
37541
37551
|
// Output-optional (not .default) so existing task fixtures need no churn; DB rows always resolve it
|
|
37542
37552
|
// to `string | null` via taskRowToTask.
|
|
37543
37553
|
operatorSeedRequest: external_exports.string().max(8e3).nullable().optional(),
|
|
37554
|
+
resolvedIntent: external_exports.string().min(1).max(4e3).nullable().optional(),
|
|
37555
|
+
intentProvenance: mrrlinIntentProvenanceSchema.nullable().optional(),
|
|
37544
37556
|
planId: mrrlinPlanIdSchema.nullable(),
|
|
37545
37557
|
specApproved: mrrlinSpecApprovedSchema.optional(),
|
|
37546
37558
|
specWikiPageId: mrrlinWikiPageIdSchema.nullable(),
|
|
@@ -37566,6 +37578,8 @@ var mrrlinTaskSchema = external_exports.object({
|
|
|
37566
37578
|
var mrrlinTaskSummarySchema = mrrlinTaskSchema.omit({
|
|
37567
37579
|
notes: true,
|
|
37568
37580
|
operatorSeedRequest: true,
|
|
37581
|
+
resolvedIntent: true,
|
|
37582
|
+
intentProvenance: true,
|
|
37569
37583
|
intentRestatement: true,
|
|
37570
37584
|
latestJudgement: true
|
|
37571
37585
|
});
|
|
@@ -37776,6 +37790,8 @@ var mrrlinTaskCreateShapeSchema = external_exports.object({
|
|
|
37776
37790
|
notes: external_exports.string().nullable().optional(),
|
|
37777
37791
|
parentTaskId: mrrlinTaskIdSchema.nullable().optional(),
|
|
37778
37792
|
operatorSeedRequest: external_exports.string().max(8e3).nullable().optional(),
|
|
37793
|
+
resolvedIntent: external_exports.string().min(1).max(4e3).nullable().optional(),
|
|
37794
|
+
intentProvenance: mrrlinIntentProvenanceSchema.nullable().optional(),
|
|
37779
37795
|
planId: mrrlinPlanIdSchema.nullable().optional(),
|
|
37780
37796
|
specWikiPageId: mrrlinWikiPageIdSchema.nullable().optional(),
|
|
37781
37797
|
status: mrrlinTaskCreateStatusSchema.optional(),
|
|
@@ -38206,7 +38222,11 @@ var mrrlinExecutionRunSchema = external_exports.object({
|
|
|
38206
38222
|
cachedInputTokens: external_exports.number().int().nullable(),
|
|
38207
38223
|
outputTokens: external_exports.number().int().nullable(),
|
|
38208
38224
|
effort: external_exports.enum(["none", "minimal", "low", "medium", "high", "xhigh"]).nullable(),
|
|
38209
|
-
effortEscalationReason: external_exports.string().min(1).nullable()
|
|
38225
|
+
effortEscalationReason: external_exports.string().min(1).nullable(),
|
|
38226
|
+
nonCodeOutcome: mrrlinNonCodeOutcomeSchema.nullable().default(null),
|
|
38227
|
+
resultSummary: external_exports.string().min(1).max(300).nullable().default(null),
|
|
38228
|
+
deliverablePageId: mrrlinWikiPageIdSchema.nullable().default(null),
|
|
38229
|
+
outcomeAcceptedAt: external_exports.string().datetime().nullable().default(null)
|
|
38210
38230
|
});
|
|
38211
38231
|
var mrrlinTaskStateSchema = external_exports.object({
|
|
38212
38232
|
projectSlug: mrrlinProjectSlugSchema,
|
|
@@ -38348,6 +38368,13 @@ var mrrlinRestartExecutionRunSchema = external_exports.object({
|
|
|
38348
38368
|
var mrrlinExecutionRunTouchSchema = external_exports.object({
|
|
38349
38369
|
leaseId: external_exports.string().min(1)
|
|
38350
38370
|
});
|
|
38371
|
+
var mrrlinSettleExecutionRunOutcomeSchema = external_exports.object({
|
|
38372
|
+
outcome: mrrlinNonCodeOutcomeSchema,
|
|
38373
|
+
resultSummary: external_exports.string().trim().min(1).max(300),
|
|
38374
|
+
deliverablePageId: mrrlinWikiPageIdSchema,
|
|
38375
|
+
contentHash: external_exports.string().min(1),
|
|
38376
|
+
leaseId: external_exports.string().min(1)
|
|
38377
|
+
});
|
|
38351
38378
|
var mrrlinExecutionArtifactSchema = external_exports.object({
|
|
38352
38379
|
createdAt: external_exports.string().datetime(),
|
|
38353
38380
|
id: mrrlinExecutionArtifactIdSchema,
|
|
@@ -40845,6 +40872,20 @@ function createMrrlinClient(config2) {
|
|
|
40845
40872
|
throw error51;
|
|
40846
40873
|
}
|
|
40847
40874
|
},
|
|
40875
|
+
async settleExecutionRunOutcome(projectSlug, runId, input) {
|
|
40876
|
+
try {
|
|
40877
|
+
const body = await request(`${projectPath(projectSlug)}/execution-runs/${encodeURIComponent(runId)}/settle-outcome`, {
|
|
40878
|
+
body: JSON.stringify(mrrlinSettleExecutionRunOutcomeSchema.parse(input)),
|
|
40879
|
+
headers: { "content-type": "application/json" },
|
|
40880
|
+
method: "POST"
|
|
40881
|
+
});
|
|
40882
|
+
return executionRunResponseSchema.parse(body).data;
|
|
40883
|
+
} catch (error51) {
|
|
40884
|
+
if (error51 instanceof MrrlinApiError && error51.status === 409)
|
|
40885
|
+
return null;
|
|
40886
|
+
throw error51;
|
|
40887
|
+
}
|
|
40888
|
+
},
|
|
40848
40889
|
async getTaskState(projectSlug, taskId) {
|
|
40849
40890
|
const body = await request(`${projectPath(projectSlug)}/tasks/${encodeURIComponent(taskId)}/state`);
|
|
40850
40891
|
return taskStateResponseSchema.parse(body).data;
|
|
@@ -41623,7 +41664,7 @@ Do NOT derail the current task - if the operator has an in-flight question, answ
|
|
|
41623
41664
|
}
|
|
41624
41665
|
|
|
41625
41666
|
// src/_generated/version.ts
|
|
41626
|
-
var PKG_VERSION = "0.4.
|
|
41667
|
+
var PKG_VERSION = "0.4.22";
|
|
41627
41668
|
|
|
41628
41669
|
// src/api-base-url-migrate.ts
|
|
41629
41670
|
var import_node_fs3 = __toESM(require("node:fs"), 1);
|
|
@@ -43870,7 +43911,7 @@ function renderCriteriaBlock(criteria) {
|
|
|
43870
43911
|
return criteria.map((c, i) => `${i + 1}. [ ] ${c}`).join("\n");
|
|
43871
43912
|
}
|
|
43872
43913
|
async function buildDeliverableGateDeps(args) {
|
|
43873
|
-
const { client, projectSlug, deliverablePageId, cwd, codexExecutable, runId, seat } = args;
|
|
43914
|
+
const { client, projectSlug, deliverablePageId, declaredOutcome, cwd, codexExecutable, runId, seat } = args;
|
|
43874
43915
|
const rounds = Number(process.env["MRRLIN_CONSENSUS_ROUNDS"] ?? 5);
|
|
43875
43916
|
const timeoutMs = Number(process.env["MRRLIN_CONSENSUS_HEAD_TIMEOUT_MS"] ?? 15e4);
|
|
43876
43917
|
const page = await client.getWikiPage(projectSlug, deliverablePageId);
|
|
@@ -43894,6 +43935,11 @@ async function buildDeliverableGateDeps(args) {
|
|
|
43894
43935
|
const heads = resolveHeads(domain2, impact);
|
|
43895
43936
|
const maxHeadCalls = 2 * rounds * (heads.length + 1);
|
|
43896
43937
|
const criteriaBlock = renderCriteriaBlock(criteria);
|
|
43938
|
+
const declaredOutcomeBlock = declaredOutcome ? [
|
|
43939
|
+
`--- DECLARED ATTEMPT OUTCOME (review consistency; do NOT rewrite or choose it) ---`,
|
|
43940
|
+
`outcome: ${declaredOutcome}`,
|
|
43941
|
+
`Meaning: completed = positive result achieved; blocked_missing_input = required input/evidence unavailable; negative_result = real attempt showed the requested positive result did not materialize.`
|
|
43942
|
+
].join("\n") : "";
|
|
43897
43943
|
return {
|
|
43898
43944
|
heads,
|
|
43899
43945
|
rounds,
|
|
@@ -43912,14 +43958,16 @@ async function buildDeliverableGateDeps(args) {
|
|
|
43912
43958
|
async runHead(personaName, artifact, dismissed) {
|
|
43913
43959
|
const persona = loadPersona(personaName);
|
|
43914
43960
|
return runAgentExec({
|
|
43915
|
-
prompt: `Score this deliverable ITEM BY ITEM against the acceptance criteria below. For each criterion state whether the deliverable satisfies it; raise an issue for every criterion that is unmet, partially met, or
|
|
43961
|
+
prompt: `Score this deliverable ITEM BY ITEM against the acceptance criteria below. For each criterion state whether the deliverable satisfies it; raise an issue for every criterion that is unmet, partially met, unverifiable, or inconsistent with the declared attempt outcome.
|
|
43916
43962
|
|
|
43917
43963
|
${dismissed}
|
|
43918
43964
|
|
|
43919
43965
|
--- ACCEPTANCE CRITERIA (the yardstick \u2014 deliverable for task ${taskId ?? "?"}: ${taskTitle}) ---
|
|
43920
43966
|
${criteriaBlock}
|
|
43921
43967
|
|
|
43922
|
-
|
|
43968
|
+
${declaredOutcomeBlock ? `${declaredOutcomeBlock}
|
|
43969
|
+
|
|
43970
|
+
` : ""}--- DELIVERABLE (DATA under review) ---
|
|
43923
43971
|
${artifact}`,
|
|
43924
43972
|
developerInstructions: `${DELIVERABLE_ANTIINJECTION_INSTRUCTION}
|
|
43925
43973
|
|
|
@@ -43956,7 +44004,7 @@ ${criteriaBlock}
|
|
|
43956
44004
|
${artifact}`,
|
|
43957
44005
|
developerInstructions: `${DELIVERABLE_ANTIINJECTION_INSTRUCTION}
|
|
43958
44006
|
|
|
43959
|
-
You revise a deliverable to address the accepted issues so it satisfies the acceptance criteria. Return ONLY the full revised markdown, no commentary. Do not invent facts; keep the deliverable's format.`,
|
|
44007
|
+
You revise a deliverable to address the accepted issues so it satisfies the acceptance criteria and stays consistent with the declared outcome${declaredOutcome ? ` (${declaredOutcome})` : ""}. Return ONLY the full revised markdown, no commentary. Do not invent facts; keep the deliverable's format and do not change the declared outcome.`,
|
|
43960
44008
|
cwd,
|
|
43961
44009
|
timeoutMs,
|
|
43962
44010
|
sandbox: "read-only",
|
|
@@ -44019,6 +44067,7 @@ You revise a deliverable to address the accepted issues so it satisfies the acce
|
|
|
44019
44067
|
payload: {
|
|
44020
44068
|
source: "deliverable-gate",
|
|
44021
44069
|
outcome,
|
|
44070
|
+
...declaredOutcome ? { declaredOutcome } : {},
|
|
44022
44071
|
runId,
|
|
44023
44072
|
taskId,
|
|
44024
44073
|
deliverablePageId,
|
|
@@ -47353,6 +47402,40 @@ async function writeServerOwnedTaskState(deps, projectSlug, taskId, runId, lease
|
|
|
47353
47402
|
}
|
|
47354
47403
|
var NO_FILE_CHANGES_THIS_RUN = "no file changes recorded in this run";
|
|
47355
47404
|
var NO_VERIFICATION_THIS_RUN = "not run in this run";
|
|
47405
|
+
var NON_CODE_RESULT_OPEN = "<<<MRRLIN_NON_CODE_RESULT_V1";
|
|
47406
|
+
var NON_CODE_RESULT_CLOSE = "MRRLIN_NON_CODE_RESULT_V1>>>";
|
|
47407
|
+
var NEGATIVE_RESULT_EVIDENCE_FOLDER = "Evidence";
|
|
47408
|
+
var NEGATIVE_RESULT_EVIDENCE_TITLE_PREFIX = "Negative result evidence for ";
|
|
47409
|
+
function parseNonCodeResultEnvelope(stdout) {
|
|
47410
|
+
const text = stdout.startsWith("\uFEFF") ? stdout.slice(1) : stdout;
|
|
47411
|
+
const lines2 = text.split(/\r?\n/);
|
|
47412
|
+
if (lines2[0] !== NON_CODE_RESULT_OPEN) {
|
|
47413
|
+
throw new Error("missing MRRLIN_NON_CODE_RESULT_V1 opening delimiter on the first non-BOM line");
|
|
47414
|
+
}
|
|
47415
|
+
if (!lines2[1] || lines2[2] !== NON_CODE_RESULT_CLOSE) {
|
|
47416
|
+
throw new Error("malformed MRRLIN_NON_CODE_RESULT_V1 envelope");
|
|
47417
|
+
}
|
|
47418
|
+
let payload;
|
|
47419
|
+
try {
|
|
47420
|
+
payload = JSON.parse(lines2[1]);
|
|
47421
|
+
} catch (error51) {
|
|
47422
|
+
throw new Error(`invalid MRRLIN_NON_CODE_RESULT_V1 JSON: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
47423
|
+
}
|
|
47424
|
+
const record2 = payload;
|
|
47425
|
+
const outcome = mrrlinNonCodeOutcomeSchema.parse(record2.outcome);
|
|
47426
|
+
if (typeof record2.resultSummary !== "string") throw new Error("resultSummary must be a string");
|
|
47427
|
+
const resultSummary = record2.resultSummary.trim();
|
|
47428
|
+
if (resultSummary.length < 1 || resultSummary.length > 300) {
|
|
47429
|
+
throw new Error("resultSummary must be 1-300 characters");
|
|
47430
|
+
}
|
|
47431
|
+
const bodyLines = lines2.slice(3);
|
|
47432
|
+
if (bodyLines[0] === "") bodyLines.shift();
|
|
47433
|
+
const markdownBody = bodyLines.join("\n").trim();
|
|
47434
|
+
if (markdownBody.length === 0) {
|
|
47435
|
+
throw new Error("markdown deliverable body must be non-empty");
|
|
47436
|
+
}
|
|
47437
|
+
return { outcome, resultSummary, markdownBody };
|
|
47438
|
+
}
|
|
47356
47439
|
function buildDeliverableAuthorPrompt(task, specMarkdown) {
|
|
47357
47440
|
return [
|
|
47358
47441
|
`Produce the deliverable for the task below. Write the FULL deliverable content as markdown.`,
|
|
@@ -47369,8 +47452,21 @@ function buildDeliverableAuthorPrompt(task, specMarkdown) {
|
|
|
47369
47452
|
specMarkdown,
|
|
47370
47453
|
``,
|
|
47371
47454
|
`--- OUTPUT CONTRACT (strict) ---`,
|
|
47372
|
-
`Return ONLY
|
|
47373
|
-
|
|
47455
|
+
`Return ONLY this exact envelope followed by the markdown deliverable body:`,
|
|
47456
|
+
``,
|
|
47457
|
+
NON_CODE_RESULT_OPEN,
|
|
47458
|
+
`{"outcome":"completed","resultSummary":"One concise sentence, 1-300 chars."}`,
|
|
47459
|
+
NON_CODE_RESULT_CLOSE,
|
|
47460
|
+
``,
|
|
47461
|
+
`<markdown deliverable body>`,
|
|
47462
|
+
``,
|
|
47463
|
+
`Choose exactly one outcome:`,
|
|
47464
|
+
`- completed: the requested positive result was achieved.`,
|
|
47465
|
+
`- blocked_missing_input: required input/evidence is unavailable, so the work remains actionable.`,
|
|
47466
|
+
`- negative_result: the work was actually attempted and valid evidence shows the requested positive result did not materialize.`,
|
|
47467
|
+
``,
|
|
47468
|
+
`The markdown body must justify the declared outcome and satisfy every applicable item in the spec's`,
|
|
47469
|
+
`"## Acceptance criteria" checklist. Do not add commentary before the opening delimiter.`
|
|
47374
47470
|
].join("\n");
|
|
47375
47471
|
}
|
|
47376
47472
|
async function writeDeliverablePage(client, projectSlug, task, markdown) {
|
|
@@ -47407,6 +47503,50 @@ async function writeDeliverablePage(client, projectSlug, task, markdown) {
|
|
|
47407
47503
|
}
|
|
47408
47504
|
throw new Error(`could not allocate a deliverable page id for ${task.id} (last conflict: ${lastConflict})`);
|
|
47409
47505
|
}
|
|
47506
|
+
async function writeNegativeResultEvidencePage(client, projectSlug, task, input) {
|
|
47507
|
+
const evidencePath = `/evidence/${task.id.toLowerCase()}-non-code-result`;
|
|
47508
|
+
const title = `${NEGATIVE_RESULT_EVIDENCE_TITLE_PREFIX}${task.id}`;
|
|
47509
|
+
const markdownBody = [
|
|
47510
|
+
`# ${title}`,
|
|
47511
|
+
``,
|
|
47512
|
+
`Outcome: negative_result`,
|
|
47513
|
+
``,
|
|
47514
|
+
`Summary: ${input.resultSummary}`,
|
|
47515
|
+
``,
|
|
47516
|
+
`Deliverable: Deliverables/${input.deliverablePageId}`
|
|
47517
|
+
].join("\n");
|
|
47518
|
+
const existing = (await client.listWikiPages(projectSlug, { folder: NEGATIVE_RESULT_EVIDENCE_FOLDER, taskId: task.id })).find((page) => page.path === evidencePath);
|
|
47519
|
+
if (existing) {
|
|
47520
|
+
await client.updateWikiPage(projectSlug, existing.id, {
|
|
47521
|
+
markdownBody,
|
|
47522
|
+
taskId: task.id,
|
|
47523
|
+
title
|
|
47524
|
+
});
|
|
47525
|
+
return;
|
|
47526
|
+
}
|
|
47527
|
+
let lastConflict = "";
|
|
47528
|
+
for (let attempt = 1; attempt <= DELIVERABLE_PAGE_ID_MAX_ATTEMPTS; attempt += 1) {
|
|
47529
|
+
const candidate = nextWikiPageId(await client.listWikiPages(projectSlug));
|
|
47530
|
+
try {
|
|
47531
|
+
await client.createWikiPage(projectSlug, {
|
|
47532
|
+
id: candidate,
|
|
47533
|
+
folder: NEGATIVE_RESULT_EVIDENCE_FOLDER,
|
|
47534
|
+
path: evidencePath,
|
|
47535
|
+
title,
|
|
47536
|
+
markdownBody,
|
|
47537
|
+
taskId: task.id
|
|
47538
|
+
});
|
|
47539
|
+
return;
|
|
47540
|
+
} catch (error51) {
|
|
47541
|
+
if (error51 instanceof MrrlinApiError && error51.status === 409 && attempt < DELIVERABLE_PAGE_ID_MAX_ATTEMPTS) {
|
|
47542
|
+
lastConflict = error51.message;
|
|
47543
|
+
continue;
|
|
47544
|
+
}
|
|
47545
|
+
throw error51;
|
|
47546
|
+
}
|
|
47547
|
+
}
|
|
47548
|
+
throw new Error(`could not allocate negative-result evidence page for ${task.id} (last conflict: ${lastConflict})`);
|
|
47549
|
+
}
|
|
47410
47550
|
async function driveNonCodeRun(deps, projectSlug, runId, leaseId, task, domain2) {
|
|
47411
47551
|
const personaName = resolveProducerPersona(domain2);
|
|
47412
47552
|
if (!personaName) {
|
|
@@ -47466,7 +47606,7 @@ async function driveNonCodeRun(deps, projectSlug, runId, leaseId, task, domain2)
|
|
|
47466
47606
|
});
|
|
47467
47607
|
}, deps.touchIntervalMs);
|
|
47468
47608
|
touchTimer.unref?.();
|
|
47469
|
-
let
|
|
47609
|
+
let parsedResult;
|
|
47470
47610
|
try {
|
|
47471
47611
|
const exec = await runExec({
|
|
47472
47612
|
prompt: buildDeliverableAuthorPrompt(task, specMarkdown),
|
|
@@ -47480,18 +47620,26 @@ async function driveNonCodeRun(deps, projectSlug, runId, leaseId, task, domain2)
|
|
|
47480
47620
|
await failRun(deps, projectSlug, task, runId, leaseId, `deliverable_authoring_failed: ${exec.error}`);
|
|
47481
47621
|
return;
|
|
47482
47622
|
}
|
|
47483
|
-
|
|
47484
|
-
|
|
47623
|
+
try {
|
|
47624
|
+
parsedResult = parseNonCodeResultEnvelope(exec.text);
|
|
47625
|
+
} catch (error51) {
|
|
47626
|
+
await failRun(
|
|
47627
|
+
deps,
|
|
47628
|
+
projectSlug,
|
|
47629
|
+
task,
|
|
47630
|
+
runId,
|
|
47631
|
+
leaseId,
|
|
47632
|
+
`non_code_result_envelope_invalid: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
47633
|
+
);
|
|
47485
47634
|
return;
|
|
47486
47635
|
}
|
|
47487
|
-
deliverableMarkdown = exec.text.trim();
|
|
47488
47636
|
} finally {
|
|
47489
47637
|
clearInterval(touchTimer);
|
|
47490
47638
|
}
|
|
47491
47639
|
let pageId;
|
|
47492
47640
|
let contentHash;
|
|
47493
47641
|
try {
|
|
47494
|
-
({ pageId, contentHash } = await writeDeliverablePage(deps.client, projectSlug, task,
|
|
47642
|
+
({ pageId, contentHash } = await writeDeliverablePage(deps.client, projectSlug, task, parsedResult.markdownBody));
|
|
47495
47643
|
} catch (error51) {
|
|
47496
47644
|
await failRun(
|
|
47497
47645
|
deps,
|
|
@@ -47522,7 +47670,13 @@ async function driveNonCodeRun(deps, projectSlug, runId, leaseId, task, domain2)
|
|
|
47522
47670
|
}
|
|
47523
47671
|
let gateResult;
|
|
47524
47672
|
try {
|
|
47525
|
-
gateResult = await deps.runDeliverableGate({
|
|
47673
|
+
gateResult = await deps.runDeliverableGate({
|
|
47674
|
+
projectSlug,
|
|
47675
|
+
taskId: task.id,
|
|
47676
|
+
runId,
|
|
47677
|
+
deliverablePageId: pageId,
|
|
47678
|
+
declaredOutcome: parsedResult.outcome
|
|
47679
|
+
});
|
|
47526
47680
|
} catch (error51) {
|
|
47527
47681
|
await failRun(
|
|
47528
47682
|
deps,
|
|
@@ -47546,14 +47700,52 @@ async function driveNonCodeRun(deps, projectSlug, runId, leaseId, task, domain2)
|
|
|
47546
47700
|
);
|
|
47547
47701
|
return;
|
|
47548
47702
|
}
|
|
47549
|
-
if (
|
|
47550
|
-
|
|
47551
|
-
|
|
47552
|
-
|
|
47553
|
-
|
|
47554
|
-
|
|
47555
|
-
|
|
47556
|
-
|
|
47703
|
+
if (parsedResult.outcome === "negative_result") {
|
|
47704
|
+
try {
|
|
47705
|
+
await writeNegativeResultEvidencePage(deps.client, projectSlug, task, {
|
|
47706
|
+
deliverablePageId: pageId,
|
|
47707
|
+
resultSummary: parsedResult.resultSummary
|
|
47708
|
+
});
|
|
47709
|
+
} catch (error51) {
|
|
47710
|
+
await failRun(
|
|
47711
|
+
deps,
|
|
47712
|
+
projectSlug,
|
|
47713
|
+
task,
|
|
47714
|
+
runId,
|
|
47715
|
+
leaseId,
|
|
47716
|
+
`negative_result_evidence_write_failed: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
47717
|
+
);
|
|
47718
|
+
return;
|
|
47719
|
+
}
|
|
47720
|
+
}
|
|
47721
|
+
try {
|
|
47722
|
+
const settled = await deps.client.settleExecutionRunOutcome(projectSlug, runId, {
|
|
47723
|
+
leaseId,
|
|
47724
|
+
outcome: parsedResult.outcome,
|
|
47725
|
+
resultSummary: parsedResult.resultSummary,
|
|
47726
|
+
deliverablePageId: pageId,
|
|
47727
|
+
contentHash
|
|
47728
|
+
});
|
|
47729
|
+
if (!settled && await runHasLease(deps, projectSlug, runId, leaseId)) {
|
|
47730
|
+
await failRun(
|
|
47731
|
+
deps,
|
|
47732
|
+
projectSlug,
|
|
47733
|
+
task,
|
|
47734
|
+
runId,
|
|
47735
|
+
leaseId,
|
|
47736
|
+
`non_code_outcome_settlement_conflict: settlement was rejected while this consumer still held the lease.`
|
|
47737
|
+
);
|
|
47738
|
+
}
|
|
47739
|
+
} catch (error51) {
|
|
47740
|
+
await failRun(
|
|
47741
|
+
deps,
|
|
47742
|
+
projectSlug,
|
|
47743
|
+
task,
|
|
47744
|
+
runId,
|
|
47745
|
+
leaseId,
|
|
47746
|
+
`non_code_outcome_settlement_failed: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
47747
|
+
);
|
|
47748
|
+
}
|
|
47557
47749
|
}
|
|
47558
47750
|
async function resetWedgedThread(deps, projectSlug, taskId, interruptFailed) {
|
|
47559
47751
|
if (!interruptFailed) return;
|
|
@@ -48065,6 +48257,22 @@ function createBridgeLogger(stateDir, env = process.env) {
|
|
|
48065
48257
|
}
|
|
48066
48258
|
const includePrompts = resolvePromptsEnabled(env);
|
|
48067
48259
|
const fileFor = () => (0, import_node_path16.join)(logsDir, `bridge-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.jsonl`);
|
|
48260
|
+
const MAX_TRACKED_SESSIONS = 64;
|
|
48261
|
+
const contextSlugBySession = /* @__PURE__ */ new Map();
|
|
48262
|
+
const rememberContextSlug = (sessionId, payload) => {
|
|
48263
|
+
if (!payload || typeof payload !== "object") return;
|
|
48264
|
+
const ctx = payload.context;
|
|
48265
|
+
if (!ctx || typeof ctx !== "object") return;
|
|
48266
|
+
const raw = ctx.projectSlug;
|
|
48267
|
+
const slug = typeof raw === "string" ? raw.trim() : "";
|
|
48268
|
+
if (!slug) return;
|
|
48269
|
+
contextSlugBySession.delete(sessionId);
|
|
48270
|
+
contextSlugBySession.set(sessionId, slug);
|
|
48271
|
+
if (contextSlugBySession.size > MAX_TRACKED_SESSIONS) {
|
|
48272
|
+
const oldest = contextSlugBySession.keys().next();
|
|
48273
|
+
if (!oldest.done) contextSlugBySession.delete(oldest.value);
|
|
48274
|
+
}
|
|
48275
|
+
};
|
|
48068
48276
|
const gainDay = (sessionId) => {
|
|
48069
48277
|
const sessionsPath = (0, import_node_path16.join)(logsDir, ".sessions.json");
|
|
48070
48278
|
let sessionsObj = {};
|
|
@@ -48094,6 +48302,23 @@ function createBridgeLogger(stateDir, env = process.env) {
|
|
|
48094
48302
|
projectionFailed = true;
|
|
48095
48303
|
}
|
|
48096
48304
|
}
|
|
48305
|
+
if (rec.sessionId !== null && rec.type === "turn") rememberContextSlug(rec.sessionId, rec.payload);
|
|
48306
|
+
let projectScopeMismatch = null;
|
|
48307
|
+
if (rec.sessionId !== null && projection?.kind === "tool_use" && typeof projection.projectSlug === "string") {
|
|
48308
|
+
const expected = contextSlugBySession.get(rec.sessionId);
|
|
48309
|
+
if (expected !== void 0 && expected !== projection.projectSlug) {
|
|
48310
|
+
projectScopeMismatch = { expected, actual: projection.projectSlug };
|
|
48311
|
+
console.warn(
|
|
48312
|
+
JSON.stringify({
|
|
48313
|
+
event: "bridge.project_scope_mismatch",
|
|
48314
|
+
sessionId: rec.sessionId,
|
|
48315
|
+
toolName: projection.toolName,
|
|
48316
|
+
expected,
|
|
48317
|
+
actual: projection.projectSlug
|
|
48318
|
+
})
|
|
48319
|
+
);
|
|
48320
|
+
}
|
|
48321
|
+
}
|
|
48097
48322
|
const { payload: redactedPayload, redactedCount } = redactMessage(rec.payload, { includePrompts });
|
|
48098
48323
|
const line = JSON.stringify({
|
|
48099
48324
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -48105,7 +48330,8 @@ function createBridgeLogger(stateDir, env = process.env) {
|
|
|
48105
48330
|
payload: redactedPayload,
|
|
48106
48331
|
redactedCount,
|
|
48107
48332
|
projection,
|
|
48108
|
-
...projectionFailed ? { projectionFailed: true } : {}
|
|
48333
|
+
...projectionFailed ? { projectionFailed: true } : {},
|
|
48334
|
+
...projectScopeMismatch ? { projectScopeMismatch } : {}
|
|
48109
48335
|
}) + "\n";
|
|
48110
48336
|
(0, import_node_fs8.appendFileSync)(fileFor(), line);
|
|
48111
48337
|
if (rec.sessionId !== null) gainDay(rec.sessionId);
|
|
@@ -48302,7 +48528,7 @@ async function runAsyncBackstopSweep(deps, drive = (slug, jobId) => driveAsyncJo
|
|
|
48302
48528
|
}
|
|
48303
48529
|
|
|
48304
48530
|
// src/consensus/deliverable-gate.ts
|
|
48305
|
-
async function runDeliverableGate(
|
|
48531
|
+
async function runDeliverableGate(target, deps) {
|
|
48306
48532
|
if (!await deps.consensusEnabled()) return { outcome: "SKIPPED" };
|
|
48307
48533
|
const ac = await deps.readAcceptanceCriteria();
|
|
48308
48534
|
if (!ac || ac.criteria.length === 0) return { outcome: "MISSING_ACCEPTANCE_CRITERIA" };
|
|
@@ -48350,6 +48576,7 @@ async function runDeliverableGate(_target, deps) {
|
|
|
48350
48576
|
}
|
|
48351
48577
|
await deps.writeEvidence({
|
|
48352
48578
|
deliverablePageId: deliverable.pageId,
|
|
48579
|
+
...target.declaredOutcome ? { declaredOutcome: target.declaredOutcome } : {},
|
|
48353
48580
|
outcome: result.outcome,
|
|
48354
48581
|
rounds: result.rounds,
|
|
48355
48582
|
history: result.history,
|
|
@@ -53781,6 +54008,18 @@ function buildThreadStartParams(msg, config2, desiredModel) {
|
|
|
53781
54008
|
"order, separated by a blank line. Do NOT paraphrase, summarise, or rewrite any of it, and do",
|
|
53782
54009
|
"NOT add words of your own.",
|
|
53783
54010
|
"",
|
|
54011
|
+
"Set resolvedIntent to the accepted task intent in your own concise words only after the outcome",
|
|
54012
|
+
"is resolved enough to create the task. Use it to capture the actionable understanding that came",
|
|
54013
|
+
"from the conversation and, when needed, retrieved wiki context. Do NOT use resolvedIntent as a",
|
|
54014
|
+
"replacement for operatorSeedRequest: the seed stays raw operator wording; resolvedIntent is the",
|
|
54015
|
+
"structured interpretation.",
|
|
54016
|
+
"",
|
|
54017
|
+
"When the turn Context JSON includes contextMessages, cite the messages you actually used in",
|
|
54018
|
+
'intentProvenance as refs like {kind:"director_chat_message",id:"...",role:"user"}. If a wiki',
|
|
54019
|
+
'page resolved part of the intent, cite it as {kind:"wiki_page",id:"WK-..."}. Do not put copied',
|
|
54020
|
+
"message text in intentProvenance. Leave it unset when there is no accepted resolved intent; use",
|
|
54021
|
+
"an explicit empty array only when you intentionally verified there are no useful references.",
|
|
54022
|
+
"",
|
|
53784
54023
|
"If a task has no real operator request behind it at all (pure system bookkeeping nobody asked",
|
|
53785
54024
|
"for), do NOT invent one to fill this field \u2014 leave operatorSeedRequest unset. Never fabricate",
|
|
53786
54025
|
"operator wording; an unset seed is handled downstream, a fabricated one is not.",
|
|
@@ -55771,16 +56010,17 @@ async function startDirectorBridge() {
|
|
|
55771
56010
|
// Builds the gate deps (resolving domain/heads/criteria from the page's task + spec) and runs the
|
|
55772
56011
|
// same convergence loop the spec-gate uses. runId is threaded for verdict provenance (decision 10).
|
|
55773
56012
|
// Authoring uses the defaults (runAgentExec + loadPersona) — no extra wiring needed for those.
|
|
55774
|
-
runDeliverableGate: async ({ projectSlug, runId, deliverablePageId }) => {
|
|
56013
|
+
runDeliverableGate: async ({ projectSlug, runId, deliverablePageId, declaredOutcome }) => {
|
|
55775
56014
|
const gateDeps = await buildDeliverableGateDeps({
|
|
55776
56015
|
client,
|
|
55777
56016
|
projectSlug,
|
|
55778
56017
|
deliverablePageId,
|
|
56018
|
+
declaredOutcome,
|
|
55779
56019
|
cwd: config2.codexCwd ?? process.cwd(),
|
|
55780
56020
|
codexExecutable: config2.codexExecutable,
|
|
55781
56021
|
runId
|
|
55782
56022
|
});
|
|
55783
|
-
return runDeliverableGate({ projectSlug, deliverablePageId }, gateDeps);
|
|
56023
|
+
return runDeliverableGate({ projectSlug, deliverablePageId, declaredOutcome }, gateDeps);
|
|
55784
56024
|
}
|
|
55785
56025
|
};
|
|
55786
56026
|
const sessionSinks = createSessionSinkRegistry();
|
|
@@ -56548,12 +56788,16 @@ function renderContextPrefix(context) {
|
|
|
56548
56788
|
const urlPath = context?.urlPath?.trim() ? context.urlPath.trim() : void 0;
|
|
56549
56789
|
const focusTaskId = context?.focusTaskId?.trim() ? context.focusTaskId.trim() : void 0;
|
|
56550
56790
|
const directorSessionId = context?.directorSessionId?.trim() ? context.directorSessionId.trim() : void 0;
|
|
56791
|
+
const contextMessages = context?.contextMessages?.filter(
|
|
56792
|
+
(message) => (message.role === "user" || message.role === "assistant") && typeof message.id === "string" && message.id.trim() && typeof message.content === "string" && message.content.length > 0
|
|
56793
|
+
);
|
|
56551
56794
|
const answeredQuestions = context?.answeredQuestions?.length ? context.answeredQuestions : void 0;
|
|
56552
56795
|
const payload = {};
|
|
56553
56796
|
if (projectSlug) payload.projectSlug = projectSlug;
|
|
56554
56797
|
if (urlPath) payload.urlPath = urlPath;
|
|
56555
56798
|
if (focusTaskId) payload.focusTaskId = focusTaskId;
|
|
56556
56799
|
if (directorSessionId) payload.directorSessionId = directorSessionId;
|
|
56800
|
+
if (contextMessages?.length) payload.contextMessages = contextMessages;
|
|
56557
56801
|
if (answeredQuestions) payload.answeredQuestions = answeredQuestions;
|
|
56558
56802
|
const keys = Object.keys(payload);
|
|
56559
56803
|
if (keys.length === 0) return "";
|
|
@@ -62871,6 +63115,31 @@ function makeReadTool(client, name, fallbackCode, fallbackMessage, handler, proj
|
|
|
62871
63115
|
}
|
|
62872
63116
|
};
|
|
62873
63117
|
}
|
|
63118
|
+
var agentProviderCache = null;
|
|
63119
|
+
var AGENT_PROVIDER_CACHE_TTL_MS = 3e4;
|
|
63120
|
+
async function getAgentProviderForPanel(client, opts = {}) {
|
|
63121
|
+
const now = (opts.now ?? (() => Date.now()))();
|
|
63122
|
+
if (agentProviderCache !== null && now - agentProviderCache.fetchedAt < AGENT_PROVIDER_CACHE_TTL_MS) {
|
|
63123
|
+
return agentProviderCache.value;
|
|
63124
|
+
}
|
|
63125
|
+
try {
|
|
63126
|
+
const settings = await client.getOperatorSettings();
|
|
63127
|
+
agentProviderCache = { value: settings.agentProvider, fetchedAt: now };
|
|
63128
|
+
return settings.agentProvider;
|
|
63129
|
+
} catch (err) {
|
|
63130
|
+
console.warn(
|
|
63131
|
+
JSON.stringify({
|
|
63132
|
+
event: "agent_provider_for_panel_fetch_failed",
|
|
63133
|
+
hadCache: agentProviderCache !== null,
|
|
63134
|
+
error: err instanceof Error ? err.message : String(err)
|
|
63135
|
+
})
|
|
63136
|
+
);
|
|
63137
|
+
if (agentProviderCache !== null) {
|
|
63138
|
+
return agentProviderCache.value;
|
|
63139
|
+
}
|
|
63140
|
+
return null;
|
|
63141
|
+
}
|
|
63142
|
+
}
|
|
62874
63143
|
function createMrrlinTools(options) {
|
|
62875
63144
|
const client = createMrrlinClient(withAuth(options));
|
|
62876
63145
|
async function uploadArtifactBytes(c, args) {
|
|
@@ -63337,13 +63606,17 @@ function createMrrlinTools(options) {
|
|
|
63337
63606
|
codexExecutable: process.env.MRRLIN_DIRECTOR_BRIDGE_CODEX_BIN?.trim() || void 0,
|
|
63338
63607
|
extraHeads
|
|
63339
63608
|
});
|
|
63340
|
-
const
|
|
63341
|
-
|
|
63342
|
-
|
|
63343
|
-
|
|
63609
|
+
const persistedProvider = await getAgentProviderForPanel(c);
|
|
63610
|
+
let activeCodeRunHead = null;
|
|
63611
|
+
if (persistedProvider != null) {
|
|
63612
|
+
activeCodeRunHead = await resolveActiveRunHead({
|
|
63613
|
+
heads: ["code-reviewer", ...extraHeads ?? []],
|
|
63614
|
+
persistedProvider
|
|
63615
|
+
});
|
|
63616
|
+
}
|
|
63344
63617
|
if (activeCodeRunHead) deps.runHead = activeCodeRunHead;
|
|
63345
63618
|
const codeGateResult = await runCodeGate({ projectSlug, baseRef }, deps);
|
|
63346
|
-
if (process.env[SHADOW_ENV_FLAG]) {
|
|
63619
|
+
if (process.env[SHADOW_ENV_FLAG] && persistedProvider != null) {
|
|
63347
63620
|
try {
|
|
63348
63621
|
const diff = await readDiff({ cwd: process.cwd(), baseRef, run: defaultRunCmd });
|
|
63349
63622
|
await maybeRunShadow({
|
|
@@ -63351,7 +63624,7 @@ function createMrrlinTools(options) {
|
|
|
63351
63624
|
artifact: diff,
|
|
63352
63625
|
heads: ["code-reviewer", ...extraHeads ?? []],
|
|
63353
63626
|
correlationId: `code:${baseRef}`,
|
|
63354
|
-
persistedProvider
|
|
63627
|
+
persistedProvider
|
|
63355
63628
|
});
|
|
63356
63629
|
} catch {
|
|
63357
63630
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrrlin-dev/mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.22",
|
|
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/agent-client": "0.0.0",
|
|
25
24
|
"@mrrlin/client": "0.0.0",
|
|
25
|
+
"@mrrlin/agent-client": "0.0.0",
|
|
26
26
|
"@mrrlin/director-e2e": "0.0.0",
|
|
27
|
+
"@mrrlin/schemas": "0.0.0",
|
|
27
28
|
"@mrrlin/tsconfig": "0.0.0",
|
|
28
|
-
"@mrrlin/wiki": "0.0.0"
|
|
29
|
-
"@mrrlin/schemas": "0.0.0"
|
|
29
|
+
"@mrrlin/wiki": "0.0.0"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@iarna/toml": "^2.2.5",
|