@mrrlin-dev/mcp 0.3.46 → 0.3.47
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 +96 -27
- package/package.json +4 -4
package/dist/bin.cjs
CHANGED
|
@@ -36550,6 +36550,7 @@ var mrrlinAsyncJobSchema = external_exports.object({
|
|
|
36550
36550
|
failureReason: mrrlinAsyncJobFailureReasonSchema.nullable().default(null),
|
|
36551
36551
|
requestedHash: external_exports.string().nullable().default(null),
|
|
36552
36552
|
finalReviewedHash: external_exports.string().nullable().default(null),
|
|
36553
|
+
supersededAt: external_exports.string().nullable().default(null),
|
|
36553
36554
|
attemptCount: external_exports.number().int().nonnegative(),
|
|
36554
36555
|
leaseId: external_exports.string().nullable().default(null),
|
|
36555
36556
|
claimedAt: external_exports.string().nullable().default(null),
|
|
@@ -36714,7 +36715,7 @@ var mrrlinDeliverablePayloadSchema = external_exports.object({
|
|
|
36714
36715
|
contentHash: external_exports.string().min(1),
|
|
36715
36716
|
format: external_exports.enum(["markdown"])
|
|
36716
36717
|
});
|
|
36717
|
-
var SUPPORTED_EXECUTION_DOMAINS = ["code"];
|
|
36718
|
+
var SUPPORTED_EXECUTION_DOMAINS = ["code", "seo"];
|
|
36718
36719
|
function isExecutionDomainSupported(domain2) {
|
|
36719
36720
|
return SUPPORTED_EXECUTION_DOMAINS.includes(domain2);
|
|
36720
36721
|
}
|
|
@@ -37510,7 +37511,8 @@ var mrrlinProjectSchedulerPolicySchema = external_exports.object({
|
|
|
37510
37511
|
prodGraceSeconds: external_exports.number().int().nonnegative(),
|
|
37511
37512
|
projectSlug: mrrlinProjectSlugSchema,
|
|
37512
37513
|
updatedAt: external_exports.string().datetime(),
|
|
37513
|
-
wakeFloor: external_exports.string().datetime().nullable()
|
|
37514
|
+
wakeFloor: external_exports.string().datetime().nullable(),
|
|
37515
|
+
maxConsecutiveJobFailures: external_exports.number().int().positive()
|
|
37514
37516
|
});
|
|
37515
37517
|
var mrrlinProjectSchedulerPolicyUpsertSchema = external_exports.object({
|
|
37516
37518
|
autoSpecApproval: mrrlinAutoSpecApprovalSchema.optional(),
|
|
@@ -37519,7 +37521,8 @@ var mrrlinProjectSchedulerPolicyUpsertSchema = external_exports.object({
|
|
|
37519
37521
|
eligibleAutonomyLevels: external_exports.array(mrrlinAutonomyLevelSchema).min(1).optional(),
|
|
37520
37522
|
maxConcurrentAutonomousRuns: external_exports.number().int().nonnegative().optional(),
|
|
37521
37523
|
prodGraceSeconds: external_exports.number().int().nonnegative().optional(),
|
|
37522
|
-
wakeFloor: external_exports.string().datetime().nullable().optional()
|
|
37524
|
+
wakeFloor: external_exports.string().datetime().nullable().optional(),
|
|
37525
|
+
maxConsecutiveJobFailures: external_exports.number().int().positive().optional()
|
|
37523
37526
|
}).refine((value) => Object.keys(value).length > 0, {
|
|
37524
37527
|
message: "ProjectSchedulerPolicyUpsert requires at least one field"
|
|
37525
37528
|
});
|
|
@@ -37680,7 +37683,10 @@ var mrrlinInboxItemActionPayloadSchema = external_exports.object({
|
|
|
37680
37683
|
runId: mrrlinExecutionRunIdSchema,
|
|
37681
37684
|
// Optional (additive): when true, approving the proposal creates a full code-execution run
|
|
37682
37685
|
// (worktree + push/PR path). Scheduler proposals set it; legacy payloads omit it.
|
|
37683
|
-
codeExecution: external_exports.boolean().optional()
|
|
37686
|
+
codeExecution: external_exports.boolean().optional(),
|
|
37687
|
+
// Optional scheduler recovery action carried by an info item.
|
|
37688
|
+
retryToolName: external_exports.string().min(1).optional(),
|
|
37689
|
+
retryDedupKey: external_exports.string().min(1).optional()
|
|
37684
37690
|
});
|
|
37685
37691
|
var mrrlinInboxQuestionOptionSchema = external_exports.object({
|
|
37686
37692
|
answer: external_exports.string().trim().min(1),
|
|
@@ -38401,6 +38407,7 @@ function createMrrlinClient(config2) {
|
|
|
38401
38407
|
},
|
|
38402
38408
|
async listInboxItems(projectSlug, filters = {}) {
|
|
38403
38409
|
const url2 = appendQuery(`${projectPath(projectSlug)}/inbox`, {
|
|
38410
|
+
groupId: filters.groupId,
|
|
38404
38411
|
kind: filters.kind,
|
|
38405
38412
|
readState: filters.readState,
|
|
38406
38413
|
status: filters.status,
|
|
@@ -39110,7 +39117,7 @@ function startCodexProbe(deps = {}) {
|
|
|
39110
39117
|
}
|
|
39111
39118
|
|
|
39112
39119
|
// src/_generated/version.ts
|
|
39113
|
-
var PKG_VERSION = "0.3.
|
|
39120
|
+
var PKG_VERSION = "0.3.47";
|
|
39114
39121
|
|
|
39115
39122
|
// src/api-base-url.ts
|
|
39116
39123
|
var DEFAULT_API_BASE_URL = "http://127.0.0.1:8787";
|
|
@@ -39269,14 +39276,14 @@ function startSchedulerTickLoop(deps) {
|
|
|
39269
39276
|
let stopped = false;
|
|
39270
39277
|
let timer = null;
|
|
39271
39278
|
const env = deps.env ?? process.env;
|
|
39272
|
-
const schedule = (
|
|
39279
|
+
const schedule = (delayMs2) => {
|
|
39273
39280
|
if (stopped) return;
|
|
39274
39281
|
timer = setTimeout(() => {
|
|
39275
39282
|
void fireSchedulerTick(deps).then(({ nextWakeAt }) => {
|
|
39276
39283
|
if (stopped) return;
|
|
39277
39284
|
schedule(computeNextTickDelayMs(nextWakeAt, Date.now(), { env }));
|
|
39278
39285
|
});
|
|
39279
|
-
},
|
|
39286
|
+
}, delayMs2);
|
|
39280
39287
|
timer.unref?.();
|
|
39281
39288
|
};
|
|
39282
39289
|
schedule(computeNextTickDelayMs((/* @__PURE__ */ new Date()).toISOString(), Date.now(), { env }));
|
|
@@ -41358,12 +41365,16 @@ var EXECUTION_TURN_BUDGET_PREFIX = "Execution turn exceeded the run wall-clock b
|
|
|
41358
41365
|
var EXECUTION_TURN_TIMEOUT_RETRY_CODE = "execution_turn_timeout_retry";
|
|
41359
41366
|
var EXECUTION_TURN_TIMEOUT_RETRY_SUMMARY = "Execution turn timed out; requeued for one automatic retry.";
|
|
41360
41367
|
var EXECUTION_TURN_TIMEOUT_RETRY_CURSOR = "execution_turn_timeout_retry:1";
|
|
41368
|
+
var AWAITING_MERGE_STATUS_RETRY_DELAYS_MS = [50, 100];
|
|
41361
41369
|
function readPositiveIntEnv(name, fallback) {
|
|
41362
41370
|
const raw = (process.env[name] ?? "").trim();
|
|
41363
41371
|
if (!raw) return fallback;
|
|
41364
41372
|
const parsed = Number.parseInt(raw, 10);
|
|
41365
41373
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
41366
41374
|
}
|
|
41375
|
+
function delayMs(ms) {
|
|
41376
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
41377
|
+
}
|
|
41367
41378
|
function execTurnIdleTimeoutMs() {
|
|
41368
41379
|
return readPositiveIntEnv("MRRLIN_DIRECTOR_BRIDGE_EXEC_TURN_IDLE_TIMEOUT_SECONDS", DEFAULT_EXEC_TURN_IDLE_TIMEOUT_SECONDS) * 1e3;
|
|
41369
41380
|
}
|
|
@@ -42387,19 +42398,42 @@ async function reconcileTaskAwaitingMerge(deps, projectSlug, task, runId, reason
|
|
|
42387
42398
|
}
|
|
42388
42399
|
}).catch(() => {
|
|
42389
42400
|
});
|
|
42401
|
+
let lastError = null;
|
|
42402
|
+
for (let attempt = 1; attempt <= AWAITING_MERGE_STATUS_RETRY_DELAYS_MS.length + 1; attempt += 1) {
|
|
42403
|
+
try {
|
|
42404
|
+
await deps.client.updateTask(projectSlug, task.id, { status: "handoff_needed" });
|
|
42405
|
+
return;
|
|
42406
|
+
} catch (error51) {
|
|
42407
|
+
lastError = error51;
|
|
42408
|
+
const retryDelay = AWAITING_MERGE_STATUS_RETRY_DELAYS_MS[attempt - 1];
|
|
42409
|
+
if (retryDelay !== void 0) {
|
|
42410
|
+
await delayMs(retryDelay);
|
|
42411
|
+
}
|
|
42412
|
+
}
|
|
42413
|
+
}
|
|
42390
42414
|
try {
|
|
42391
|
-
await deps.client.
|
|
42392
|
-
} catch
|
|
42393
|
-
|
|
42394
|
-
|
|
42395
|
-
|
|
42396
|
-
|
|
42397
|
-
|
|
42398
|
-
|
|
42399
|
-
|
|
42400
|
-
|
|
42401
|
-
|
|
42415
|
+
await deps.client.updateExecutionRun(projectSlug, runId, { status: "handoff_queued" });
|
|
42416
|
+
} catch {
|
|
42417
|
+
}
|
|
42418
|
+
try {
|
|
42419
|
+
await deps.client.createInboxItem(projectSlug, {
|
|
42420
|
+
id: `II-${import_node_crypto4.default.randomUUID()}`,
|
|
42421
|
+
kind: "handoff",
|
|
42422
|
+
taskId: task.id,
|
|
42423
|
+
body: `Task ${task.id} (${task.title}) still needs operator follow-up: ${reason}. Mrrlin could not move the task back to Handoff needed automatically.`
|
|
42424
|
+
});
|
|
42425
|
+
} catch {
|
|
42402
42426
|
}
|
|
42427
|
+
console.warn(
|
|
42428
|
+
JSON.stringify({
|
|
42429
|
+
event: "reconcile_awaiting_merge_failed",
|
|
42430
|
+
projectSlug,
|
|
42431
|
+
taskId: task.id,
|
|
42432
|
+
runId,
|
|
42433
|
+
error: lastError instanceof Error ? lastError.message : String(lastError),
|
|
42434
|
+
attempts: AWAITING_MERGE_STATUS_RETRY_DELAYS_MS.length + 1
|
|
42435
|
+
})
|
|
42436
|
+
);
|
|
42403
42437
|
}
|
|
42404
42438
|
async function notifyOperatorHandoff(deps, projectSlug, task, runId, reason) {
|
|
42405
42439
|
try {
|
|
@@ -42560,7 +42594,12 @@ async function driveAsyncJob(deps, projectSlug, jobId) {
|
|
|
42560
42594
|
let outcome = { kind: "failed", failureReason: "provider_unavailable", error: "did not run" };
|
|
42561
42595
|
try {
|
|
42562
42596
|
for (; ; ) {
|
|
42563
|
-
const begun = await deps.client.beginAsyncJobAttempt(
|
|
42597
|
+
const begun = await deps.client.beginAsyncJobAttempt(
|
|
42598
|
+
projectSlug,
|
|
42599
|
+
jobId,
|
|
42600
|
+
leaseId,
|
|
42601
|
+
await deriveRequestedHash(deps.client, claimed.toolName, input)
|
|
42602
|
+
);
|
|
42564
42603
|
if (!begun) return;
|
|
42565
42604
|
if (begun.attemptCount > ASYNC_JOB_MAX_ATTEMPTS) {
|
|
42566
42605
|
outcome = { kind: "failed", failureReason: "provider_unavailable", error: "exceeded retry budget" };
|
|
@@ -42611,8 +42650,17 @@ async function driveAsyncJob(deps, projectSlug, jobId) {
|
|
|
42611
42650
|
}
|
|
42612
42651
|
if (descriptor2.wakeDirector) deps.wake(projectSlug, claimed.directorSessionId, delivery.body, delivery.kind);
|
|
42613
42652
|
}
|
|
42614
|
-
function
|
|
42615
|
-
return
|
|
42653
|
+
async function deriveRequestedHash(client, toolName, input) {
|
|
42654
|
+
if (input.requestedHash) return input.requestedHash;
|
|
42655
|
+
if (toolName === "run_spec_consensus" && input.pageId) {
|
|
42656
|
+
const page = await client.getWikiPage(input.projectSlug, input.pageId);
|
|
42657
|
+
return page.contentHash ?? import_node_crypto5.default.createHash("sha256").update(page.markdownBody).digest("hex");
|
|
42658
|
+
}
|
|
42659
|
+
if (toolName === "draft_task_spec" && input.taskId) {
|
|
42660
|
+
const task = await client.getTask(input.projectSlug, input.taskId);
|
|
42661
|
+
return task.updatedAt ?? import_node_crypto5.default.createHash("sha256").update(JSON.stringify(task)).digest("hex");
|
|
42662
|
+
}
|
|
42663
|
+
return import_node_crypto5.default.createHash("sha256").update(JSON.stringify(input)).digest("hex");
|
|
42616
42664
|
}
|
|
42617
42665
|
async function runAsyncBackstopSweep(deps, drive = (slug, jobId) => driveAsyncJob(deps, slug, jobId)) {
|
|
42618
42666
|
const projects = await deps.client.listProjects();
|
|
@@ -47490,7 +47538,7 @@ function buildThreadStartParams(msg, config2, desiredModel) {
|
|
|
47490
47538
|
" bullets (`- AND ...` as needed). Scenarios make the spec verifiable.",
|
|
47491
47539
|
"- Keep behavior contracts in the spec; implementation details belong in `## Implementation Plan`.",
|
|
47492
47540
|
"- Apply this format ONLY to Specs/{id} pages; do not retro-fit it onto other wiki page types.",
|
|
47493
|
-
"- Spec consensus runs ASYNCHRONOUSLY. Call `run_spec_consensus` for a `Specs/{id}` page; it returns IMMEDIATELY. On `already_converged`, the spec is already marked ready \u2014 proceed straight to `create_execution_run`; do NOT call `mark_spec_ready` and do NOT re-run consensus. On `queued` or `already_running`, tell the user it was launched and END your turn \u2014 do NOT poll or call it again; the result arrives in the inbox (an `info` item on CONVERGED, a `handoff` item if it was blocked/failed). When a consensus `info` item says CONVERGED, proceed to `create_execution_run`. When a `handoff` says it was blocked, address the recorded issues in the spec (any edit re-arms the gate) and call `run_spec_consensus` once more. For a NON-code task (domain seo/marketing/content, ADR 0020)
|
|
47541
|
+
"- Spec consensus runs ASYNCHRONOUSLY. Call `run_spec_consensus` for a `Specs/{id}` page; it returns IMMEDIATELY. On `already_converged`, the spec is already marked ready \u2014 proceed straight to `create_execution_run`; do NOT call `mark_spec_ready` and do NOT re-run consensus. On `queued` or `already_running`, tell the user it was launched and END your turn \u2014 do NOT poll or call it again; the result arrives in the inbox (an `info` item on CONVERGED, a `handoff` item if it was blocked/failed). When a consensus `info` item says CONVERGED, proceed to `create_execution_run`. When a `handoff` says it was blocked, address the recorded issues in the spec (any edit re-arms the gate) and call `run_spec_consensus` once more. For a NON-code task (domain seo/marketing/content, ADR 0020): supported domains like `seo` proceed to `create_execution_run` after consensus converges; unsupported domains fail-close with `non_code_execution_unsupported`. Report the spec's review outcome to the operator.",
|
|
47494
47542
|
'- When a task needs a browser (login flows, UI verification/clicks, scraping), pass `prerequisites:[{mcp:"mrrlin-browser",reason:"..."}]` to `create_execution_run`. If that run later fails into a handoff, the operator gets a one-click "Launch browser & resume" that brings up the dedicated browser as the turn starts.',
|
|
47495
47543
|
"- When you actually drive a browser (calling `browser_navigate`, `browser_click`, `browser_snapshot`, `browser_type`, etc.), invoke those tools from the **`mrrlin-browser`** MCP server ONLY. Do NOT use tools from any other browser MCP (`playwright`, `chrome-devtools`, `puppeteer`, etc.) even if they are also connected on this operator's box \u2014 those use a shared/default Playwright profile that is fragile across runs. Only `mrrlin-browser` uses this project's dedicated Chromium + persistent operator profile (`~/.mrrlin/browser/profile`). If your host exposes multiple browser MCPs with overlapping tool names, prefer the `mrrlin-browser` server unconditionally.",
|
|
47496
47544
|
"",
|
|
@@ -53658,8 +53706,8 @@ async function cachedResult(client, input) {
|
|
|
53658
53706
|
}
|
|
53659
53707
|
return { status: "already_converged", payload: { outcome: "CONVERGED", contentHash: page.contentHash } };
|
|
53660
53708
|
}
|
|
53661
|
-
if (review?.outcome === "CONSENSUS_BLOCKED") {
|
|
53662
|
-
return { status: "already_reviewed", payload: { outcome:
|
|
53709
|
+
if (review?.outcome === "CONSENSUS_BLOCKED" || review?.outcome === "CONSENSUS_BLOCKED_CLARIFICATION") {
|
|
53710
|
+
return { status: "already_reviewed", payload: { outcome: review.outcome, contentHash: page.contentHash } };
|
|
53663
53711
|
}
|
|
53664
53712
|
return null;
|
|
53665
53713
|
}
|
|
@@ -53708,6 +53756,27 @@ async function run(ctx, input) {
|
|
|
53708
53756
|
}
|
|
53709
53757
|
if (result.outcome === "CONSENSUS_BLOCKED") {
|
|
53710
53758
|
const clarifications = result.clarifications ?? [];
|
|
53759
|
+
if (clarifications.length > 0) {
|
|
53760
|
+
try {
|
|
53761
|
+
const page = await ctx.client.getWikiPage(input.projectSlug, input.pageId);
|
|
53762
|
+
if (page) {
|
|
53763
|
+
const domain2 = await resolveSpecDomain(ctx.client, input.projectSlug, {
|
|
53764
|
+
id: page.id,
|
|
53765
|
+
taskId: page.taskId ?? null
|
|
53766
|
+
});
|
|
53767
|
+
await ctx.client.recordSpecConsensusReview(input.projectSlug, input.pageId, {
|
|
53768
|
+
contentHash: domainScopedReviewHash(page.contentHash, domain2),
|
|
53769
|
+
outcome: "CONSENSUS_BLOCKED_CLARIFICATION",
|
|
53770
|
+
rounds: 0
|
|
53771
|
+
});
|
|
53772
|
+
}
|
|
53773
|
+
} catch (error52) {
|
|
53774
|
+
process.stderr.write(
|
|
53775
|
+
`[mrrlin-mcp consensus] clarification verdict write failed for ${input.projectSlug}/${input.pageId}: ${error52 instanceof Error ? error52.message : String(error52)}
|
|
53776
|
+
`
|
|
53777
|
+
);
|
|
53778
|
+
}
|
|
53779
|
+
}
|
|
53711
53780
|
let filedQuestionCount = 0;
|
|
53712
53781
|
if (clarifications.length > 0) {
|
|
53713
53782
|
const page = await ctx.client.getWikiPage(input.projectSlug, input.pageId);
|
|
@@ -53731,7 +53800,7 @@ async function run(ctx, input) {
|
|
|
53731
53800
|
taskId: scopeId,
|
|
53732
53801
|
body: clarification.question,
|
|
53733
53802
|
origin: "gate",
|
|
53734
|
-
|
|
53803
|
+
questionOptions,
|
|
53735
53804
|
...groupId ? { groupId } : {}
|
|
53736
53805
|
});
|
|
53737
53806
|
} catch {
|
|
@@ -53751,7 +53820,7 @@ async function run(ctx, input) {
|
|
|
53751
53820
|
planId: scopeId,
|
|
53752
53821
|
body: clarification.question,
|
|
53753
53822
|
origin: "gate",
|
|
53754
|
-
|
|
53823
|
+
questionOptions,
|
|
53755
53824
|
...groupId ? { groupId } : {}
|
|
53756
53825
|
});
|
|
53757
53826
|
} catch {
|
|
@@ -54806,7 +54875,7 @@ var mcpToolDescriptions = {
|
|
|
54806
54875
|
[mcpToolNames.resetDirectorThread]: "Clear a task's persisted Director execution thread handle so the next execution run starts a fresh provider thread. Records a director_thread_reset task event.",
|
|
54807
54876
|
[mcpToolNames.updateWikiPage]: "Update a markdown Wiki page.",
|
|
54808
54877
|
[mcpToolNames.markSpecReady]: "Mark a wiki page (folder=Specs) as ready (or not) for execution-run gating. The Director sets this true after validating the spec; any edit to the page's markdown auto-resets it to false.",
|
|
54809
|
-
[mcpToolNames.runSpecConsensus]: 'Enqueue the consensus review gate over a Specs/{id} page. Returns IMMEDIATELY with one of: already_converged (a CONVERGED review already exists for the current content \u2014 proceed straight to create_execution_run, do NOT call mark_spec_ready, it is already set), already_reviewed (a terminal CONSENSUS_BLOCKED for this content), already_running (a consensus job is in flight), or queued (a new job was launched). The review runs in the background; its result/blocker arrives in the inbox (info on CONVERGED, handoff on failure) and is surfaced into the open chat. Do NOT call again for the same spec and do NOT poll. On queued/already_running, tell the user it was launched and end the turn. Pass extraHeads: ["researcher"] for specs referencing external libraries/APIs, or ["debugger"] for root-cause/investigation specs to add opt-in specialist reviewers on top of the fixed four. For a NON-code task (domain seo/marketing/content, ADR 0020)
|
|
54878
|
+
[mcpToolNames.runSpecConsensus]: 'Enqueue the consensus review gate over a Specs/{id} page. Returns IMMEDIATELY with one of: already_converged (a CONVERGED review already exists for the current content \u2014 proceed straight to create_execution_run, do NOT call mark_spec_ready, it is already set), already_reviewed (a terminal CONSENSUS_BLOCKED for this content), already_running (a consensus job is in flight), or queued (a new job was launched). The review runs in the background; its result/blocker arrives in the inbox (info on CONVERGED, handoff on failure) and is surfaced into the open chat. Do NOT call again for the same spec and do NOT poll. On queued/already_running, tell the user it was launched and end the turn. Pass extraHeads: ["researcher"] for specs referencing external libraries/APIs, or ["debugger"] for root-cause/investigation specs to add opt-in specialist reviewers on top of the fixed four. For a NON-code task (domain seo/marketing/content, ADR 0020): supported domains like `seo` proceed to `create_execution_run` after consensus; unsupported domains fail-close with `non_code_execution_unsupported`. Report the spec\'s review outcome to the operator.',
|
|
54810
54879
|
[mcpToolNames.runCodeReviewerGate]: `Review the current branch's code diff (vs baseRef) with a Code Reviewer gate \u2014 independent reviewers iterate review\u2192fix\u2192re-check (checkpoint, scope-limited reviser edits, typecheck/build fast-gate, rollback) until the diff converges or is blocked. Run before opening a PR. Pass extraHeads: ["security-analyst"] for sensitive diffs (auth, secrets, input handling, new endpoints).`,
|
|
54811
54880
|
[mcpToolNames.appendExecutionArtifact]: "Append a durable artifact (plan, checkpoint, command output, test result, diff summary, self-review, error, deploy attempt, or handoff judgement) to an execution run.",
|
|
54812
54881
|
[mcpToolNames.recordProducedUrl]: 'Call this after publishing each web page produced by the task, so the UI link opens the page itself instead of the deployed site root. Pass the page\'s full https URL (for external pages, e.g. "https://dev.to/<slug>") OR a path starting with "/" for the deploy environment (e.g. "/blog/<slug>") \u2014 paths are resolved against the run\'s deployed env URL at render time. Optional `label` (\u226440 chars) is shown next to the link; omit and the UI defaults to the page title. Call once per page; multiple calls dedupe by resolved URL in the UI.',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrrlin-dev/mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.47",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mrrlin-mcp": "dist/bin.cjs"
|
|
@@ -21,17 +21,17 @@
|
|
|
21
21
|
"@types/ws": "^8.18.1",
|
|
22
22
|
"esbuild": "^0.24.0",
|
|
23
23
|
"tsx": "^4.22.3",
|
|
24
|
-
"@mrrlin/client": "0.0.0",
|
|
25
24
|
"@mrrlin/director-e2e": "0.0.0",
|
|
26
25
|
"@mrrlin/wiki": "0.0.0",
|
|
27
|
-
"@mrrlin/
|
|
26
|
+
"@mrrlin/client": "0.0.0",
|
|
28
27
|
"@mrrlin/codex-client": "0.0.0",
|
|
28
|
+
"@mrrlin/schemas": "0.0.0",
|
|
29
29
|
"@mrrlin/tsconfig": "0.0.0"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@iarna/toml": "^2.2.5",
|
|
33
33
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
34
|
-
"@mrrlin-dev/external-agents": "
|
|
34
|
+
"@mrrlin-dev/external-agents": "latest",
|
|
35
35
|
"@playwright/mcp": "0.0.76",
|
|
36
36
|
"playwright-core": "1.61.0-alpha-1781023400000",
|
|
37
37
|
"proper-lockfile": "^4.1.2",
|