@mrrlin-dev/mcp 0.3.41 → 0.3.45

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.
Files changed (2) hide show
  1. package/dist/bin.cjs +206 -22
  2. package/package.json +5 -4
package/dist/bin.cjs CHANGED
@@ -20672,12 +20672,18 @@ function browserPaths(homeDir = import_node_os.default.homedir()) {
20672
20672
  const root = import_node_path.default.join(homeDir, ".mrrlin", "browser");
20673
20673
  return { root, browsersPath: import_node_path.default.join(root, "browsers"), profilePath: import_node_path.default.join(root, "profile") };
20674
20674
  }
20675
- function resolvePackageBin(pkg) {
20675
+ function resolvePackageBin(pkg, binName) {
20676
20676
  const require2 = moduleRequire();
20677
20677
  const pkgJsonPath = require2.resolve(`${pkg}/package.json`);
20678
20678
  const pkgJson = require2(`${pkg}/package.json`);
20679
20679
  const bin = pkgJson.bin;
20680
- const rel = typeof bin === "string" ? bin : bin ? Object.values(bin)[0] : void 0;
20680
+ let rel;
20681
+ if (binName && bin && typeof bin !== "string") {
20682
+ rel = bin[binName];
20683
+ if (!rel) throw new Error(`${pkg} has no bin entry named ${binName}`);
20684
+ } else {
20685
+ rel = typeof bin === "string" ? bin : bin ? Object.values(bin)[0] : void 0;
20686
+ }
20681
20687
  if (!rel) throw new Error(`${pkg} has no bin entry to resolve a CLI from`);
20682
20688
  return import_node_path.default.join(import_node_path.default.dirname(pkgJsonPath), rel);
20683
20689
  }
@@ -20691,6 +20697,13 @@ function browserServeArgs(homeDir = import_node_os.default.homedir()) {
20691
20697
  env: { PLAYWRIGHT_BROWSERS_PATH: browsersPath }
20692
20698
  };
20693
20699
  }
20700
+ function externalAgentsServeArgs() {
20701
+ return {
20702
+ command: process.execPath,
20703
+ // node
20704
+ args: [resolvePackageBin("@mrrlin-dev/external-agents", "external-agents-mcp")]
20705
+ };
20706
+ }
20694
20707
  async function installBrowser(opts = {}) {
20695
20708
  const homeDir = opts.homeDir ?? import_node_os.default.homedir();
20696
20709
  const { browsersPath } = browserPaths(homeDir);
@@ -20747,8 +20760,9 @@ function mrrlinTable(binPath, distribution, serveEnv) {
20747
20760
  }
20748
20761
  return { ...base, startup_timeout_sec: 30 };
20749
20762
  }
20750
- function externalAgentsTable() {
20751
- return { command: "external-agents-mcp", args: [], startup_timeout_sec: 30 };
20763
+ function externalAgentsTable(binPath, distribution) {
20764
+ const base = distribution === "npm" ? { command: "mrrlin-mcp", args: ["external-agents-serve"] } : { command: "node", args: [binPath, "external-agents-serve"] };
20765
+ return { ...base, startup_timeout_sec: 30 };
20752
20766
  }
20753
20767
  function browserTable(binPath, distribution, homeDir) {
20754
20768
  const base = distribution === "npm" ? { command: "mrrlin-mcp", args: ["browser-serve"] } : { command: "node", args: [binPath, "browser-serve"] };
@@ -20773,8 +20787,22 @@ function managedBlocks(options, distribution) {
20773
20787
  },
20774
20788
  {
20775
20789
  id: "external-agents",
20776
- expected: externalAgentsTable(),
20777
- blockRe: blockRegex("external-agents")
20790
+ expected: externalAgentsTable(options.binPath, distribution),
20791
+ blockRe: blockRegex("external-agents"),
20792
+ // Match ONLY the exact shape this installer used to write: a bare command, optionally with
20793
+ // empty args / a startup_timeout_sec, and NOTHING else. An extra key means the operator
20794
+ // customized the block — most plausibly a hand-added `env` carrying provider API keys, which
20795
+ // renderBlock() would silently drop on rewrite (it renders strictly from `expected`). Such a
20796
+ // block must fall through to CODEX_CONFIG_CONFLICT so replacing it takes an explicit --force,
20797
+ // rather than losing an operator's credentials during a routine update. We deliberately do
20798
+ // NOT carry the env forward instead: KNOWN_MRRLIN_ENV_KEYS treats any foreign key as
20799
+ // operator-authored and never-preserve, so a carried key would turn the NEXT bare re-run into
20800
+ // a conflict and break idempotency.
20801
+ isLegacyOurs: (actual) => {
20802
+ const legacyKeys = /* @__PURE__ */ new Set(["command", "args", "startup_timeout_sec"]);
20803
+ if (!Object.keys(actual).every((key) => legacyKeys.has(key))) return false;
20804
+ return actual.command === "external-agents-mcp" && (actual.args === void 0 || Array.isArray(actual.args) && actual.args.length === 0);
20805
+ }
20778
20806
  }
20779
20807
  ];
20780
20808
  }
@@ -20917,6 +20945,12 @@ async function installCodex(options) {
20917
20945
  if (action === "noop") action = "env-preserved";
20918
20946
  continue;
20919
20947
  }
20948
+ if (block.isLegacyOurs?.(existingTable)) {
20949
+ content = replaceBlock(content, block.blockRe, renderBlock(block));
20950
+ action = "replaced";
20951
+ mutated = true;
20952
+ continue;
20953
+ }
20920
20954
  if (!options.force) {
20921
20955
  const err = {
20922
20956
  code: "CODEX_CONFIG_CONFLICT",
@@ -36358,6 +36392,7 @@ var openApiOperationIds = {
36358
36392
  listInboxItems: "listInboxItems",
36359
36393
  decideInboxItem: "decideInboxItem",
36360
36394
  markInboxItemRead: "markInboxItemRead",
36395
+ markInboxItemsReadByIds: "markInboxItemsReadByIds",
36361
36396
  markAllInboxItemsRead: "markAllInboxItemsRead",
36362
36397
  searchKnowledge: "searchKnowledge",
36363
36398
  updateExecutionRun: "updateExecutionRun",
@@ -37496,16 +37531,116 @@ var mrrlinSchedulerPendingReasonSchema = external_exports.enum([
37496
37531
  "verification_due",
37497
37532
  "wake_floor_passed"
37498
37533
  ]);
37534
+ var mrrlinAutonomousStepSchema = external_exports.enum([
37535
+ "noop",
37536
+ "needs_human",
37537
+ "enqueue_spec_draft",
37538
+ "enqueue_consensus",
37539
+ "auto_approve_spec_and_run",
37540
+ "create_execution_run"
37541
+ ]);
37542
+ var mrrlinAutonomousStepReasonSchema = external_exports.enum([
37543
+ "task_terminal",
37544
+ "active_run_exists",
37545
+ "blocked_by_active",
37546
+ "draft_running",
37547
+ "consensus_running",
37548
+ "spec_missing",
37549
+ "spec_draft_failed",
37550
+ "spec_not_specs_folder",
37551
+ "awaiting_clarification",
37552
+ "consensus_blocked",
37553
+ "consensus_disabled_spec_not_ready",
37554
+ "spec_approval_pending",
37555
+ "non_code_execution_unsupported"
37556
+ ]);
37557
+ var mrrlinAutonomousStepVerdictSchema = external_exports.object({
37558
+ step: mrrlinAutonomousStepSchema,
37559
+ reason: mrrlinAutonomousStepReasonSchema.nullable(),
37560
+ // Additive: when reason is "spec_draft_failed" or "consensus_blocked" (the two reasons that park
37561
+ // a task until a human intervenes), the attempt_count of the async_jobs row that produced that
37562
+ // outcome — so the operator can see "failed x3" and judge whether a retry mechanism is needed.
37563
+ // null for every other reason/step (not applicable), and also null if the job could not be found.
37564
+ failureCount: external_exports.number().int().min(0).nullable()
37565
+ });
37499
37566
  var mrrlinSchedulerPendingTaskSchema = external_exports.object({
37500
37567
  dueAt: external_exports.string().datetime(),
37501
37568
  reason: mrrlinSchedulerPendingReasonSchema,
37502
- task: mrrlinTaskSchema
37569
+ task: mrrlinTaskSchema,
37570
+ // Additive: whether the scheduler considers this task due NOW (per `deriveSchedulerDue`), as
37571
+ // opposed to `dueAt` reporting a future trigger or the evaluatedAt fallback when the task has no
37572
+ // trigger at all. Consumers must read this instead of re-deriving due-ness by re-parsing `dueAt`
37573
+ // against "now" — a task with no trigger has `dueAt === evaluatedAt`, which a naive `dueAt <= now`
37574
+ // re-derivation would misclassify as due.
37575
+ due: external_exports.boolean(),
37576
+ // Additive: the REAL admission verdict for this row, computed only inside the tick's bounded
37577
+ // per-cycle slice (`resolveSchedulerProjectLimit`). `null` means "not evaluated this cycle" —
37578
+ // the row is a genuine actionable candidate by the cheap classifier, but beyond the bound the
37579
+ // tick actually looks at, so no real verdict exists yet. Never infer readiness from `null`.
37580
+ verdict: mrrlinAutonomousStepVerdictSchema.nullable()
37581
+ });
37582
+ var mrrlinSchedulerParkedReasonSchema = external_exports.enum([
37583
+ "running",
37584
+ "awaiting_handoff",
37585
+ "awaiting_clarification",
37586
+ "spec_awaiting_approval",
37587
+ "blocked_by_active"
37588
+ ]);
37589
+ var mrrlinSchedulerParkedTaskSchema = external_exports.object({
37590
+ task: mrrlinTaskSchema,
37591
+ reason: mrrlinSchedulerParkedReasonSchema,
37592
+ blockedByIds: external_exports.array(mrrlinTaskIdSchema),
37593
+ inboxItemId: external_exports.string().nullable(),
37594
+ runId: mrrlinExecutionRunIdSchema.nullable()
37595
+ });
37596
+ var mrrlinInFlightSchedulerEntrySchema = external_exports.discriminatedUnion("kind", [
37597
+ external_exports.object({
37598
+ kind: external_exports.literal("run"),
37599
+ taskId: mrrlinTaskIdSchema,
37600
+ runId: mrrlinExecutionRunIdSchema,
37601
+ status: external_exports.string(),
37602
+ // Additive: the task's own title, resolved server-side from the same task list the handler
37603
+ // already loaded for this request (no extra query). null only when the task itself could not
37604
+ // be found (should not happen for a `run` entry, whose taskId is required, but the wire
37605
+ // contract stays honest about it rather than assuming).
37606
+ taskTitle: external_exports.string().nullable()
37607
+ }),
37608
+ external_exports.object({
37609
+ kind: external_exports.literal("async_job"),
37610
+ taskId: mrrlinTaskIdSchema.nullable(),
37611
+ jobId: external_exports.string(),
37612
+ toolName: external_exports.enum(["draft_task_spec", "run_spec_consensus"]),
37613
+ // Additive: same resolution as the `run` variant above. null when `taskId` is null (a job
37614
+ // genuinely untied to a visible task) or the task could not be found.
37615
+ taskTitle: external_exports.string().nullable()
37616
+ })
37617
+ ]);
37618
+ var mrrlinIneligibleTaskSchema = external_exports.object({
37619
+ task: mrrlinTaskSchema,
37620
+ autonomyLevel: mrrlinAutonomyLevelSchema
37503
37621
  });
37504
37622
  var schedulerPendingTasksResponseSchema = external_exports.object({
37505
37623
  data: external_exports.object({
37506
37624
  evaluatedAt: external_exports.string().datetime(),
37507
37625
  pending: external_exports.array(mrrlinSchedulerPendingTaskSchema),
37508
- policy: mrrlinProjectSchedulerPolicySchema
37626
+ parked: external_exports.array(mrrlinSchedulerParkedTaskSchema),
37627
+ slots: external_exports.number().int(),
37628
+ perProjectLimit: external_exports.number().int().min(1),
37629
+ policy: mrrlinProjectSchedulerPolicySchema,
37630
+ // Additive (see mrrlinInFlightSchedulerEntrySchema doc): the actual runs/jobs occupying
37631
+ // autonomous capacity right now. `slots` is derived from THIS SAME list server-side, so the
37632
+ // count and the list can never disagree.
37633
+ inFlight: external_exports.array(mrrlinInFlightSchedulerEntrySchema),
37634
+ // Additive: tasks the tick never even considers (autonomyLevel outside
37635
+ // policy.eligibleAutonomyLevels), excluding terminal tasks.
37636
+ ineligible: external_exports.array(mrrlinIneligibleTaskSchema),
37637
+ // Additive: how many non-terminal tasks were excluded from BOTH `pending` and `parked` because
37638
+ // their assignee is set and does not match the project operator (github.operator). A COUNT
37639
+ // only, deliberately — the operator asked not to show a list of other people's tasks, just a
37640
+ // disclosure that some exist, so a misconfigured `github.operator` (e.g. it doesn't match the
37641
+ // person actually running the project) is visible as a large number instead of the autopilot
37642
+ // silently doing nothing.
37643
+ excludedByOwnershipCount: external_exports.number().int().min(0)
37509
37644
  })
37510
37645
  });
37511
37646
  var wakeDirectorRequestSchema = external_exports.object({
@@ -37594,6 +37729,7 @@ var mrrlinInboxItemSchema = external_exports.object({
37594
37729
  decidedBy: external_exports.string().min(1).nullable(),
37595
37730
  dedupKey: external_exports.string().nullable(),
37596
37731
  directorSessionId: external_exports.string().min(1).nullable(),
37732
+ groupId: external_exports.string().nullable().default(null),
37597
37733
  id: mrrlinInboxItemIdSchema,
37598
37734
  kind: mrrlinInboxItemKindSchema,
37599
37735
  origin: external_exports.string().nullable().optional(),
@@ -37616,6 +37752,7 @@ var mrrlinInboxItemCreateSchema = external_exports.object({
37616
37752
  actionPayload: mrrlinInboxItemActionPayloadSchema.nullable().optional(),
37617
37753
  body: external_exports.string().min(1),
37618
37754
  directorSessionId: external_exports.string().min(1).optional(),
37755
+ groupId: external_exports.string().min(1).optional(),
37619
37756
  id: mrrlinInboxItemIdSchema,
37620
37757
  kind: mrrlinInboxItemKindSchema,
37621
37758
  origin: external_exports.string().min(1).optional(),
@@ -37646,6 +37783,7 @@ var mrrlinInboxItemDecideSchema = external_exports.object({
37646
37783
  }
37647
37784
  });
37648
37785
  var mrrlinInboxItemListFiltersSchema = external_exports.object({
37786
+ groupId: external_exports.string().optional(),
37649
37787
  kind: mrrlinInboxItemKindSchema.optional(),
37650
37788
  readState: external_exports.enum(["read", "unread"]).optional(),
37651
37789
  status: mrrlinInboxItemStatusSchema.optional(),
@@ -37662,6 +37800,15 @@ var inboxMarkAllReadResponseSchema = external_exports.object({
37662
37800
  readAt: external_exports.string().datetime()
37663
37801
  })
37664
37802
  });
37803
+ var mrrlinInboxItemsMarkReadRequestSchema = external_exports.object({
37804
+ ids: external_exports.array(external_exports.string().min(1)).min(1)
37805
+ });
37806
+ var inboxItemsMarkReadResponseSchema = external_exports.object({
37807
+ data: external_exports.object({
37808
+ markedCount: external_exports.number().int().nonnegative(),
37809
+ readAt: external_exports.string().datetime()
37810
+ })
37811
+ });
37665
37812
  var inboxItemResponseSchema = external_exports.object({ data: mrrlinInboxItemSchema });
37666
37813
  var inboxItemListResponseSchema = external_exports.object({ data: external_exports.array(mrrlinInboxItemSchema) });
37667
37814
 
@@ -38284,6 +38431,14 @@ function createMrrlinClient(config2) {
38284
38431
  });
38285
38432
  return inboxItemReadResponseSchema.parse(body).data;
38286
38433
  },
38434
+ async markInboxItemsReadByIds(projectSlug, ids) {
38435
+ const body = await request(`${projectPath(projectSlug)}/inbox/mark-read`, {
38436
+ body: JSON.stringify({ ids }),
38437
+ headers: { "content-type": "application/json" },
38438
+ method: "POST"
38439
+ });
38440
+ return inboxItemsMarkReadResponseSchema.parse(body).data;
38441
+ },
38287
38442
  async markAllInboxItemsRead(projectSlug) {
38288
38443
  const body = await request(`${projectPath(projectSlug)}/inbox/mark-all-read`, {
38289
38444
  method: "POST"
@@ -38955,7 +39110,7 @@ function startCodexProbe(deps = {}) {
38955
39110
  }
38956
39111
 
38957
39112
  // src/_generated/version.ts
38958
- var PKG_VERSION = "0.3.41";
39113
+ var PKG_VERSION = "0.3.45";
38959
39114
 
38960
39115
  // src/api-base-url.ts
38961
39116
  var DEFAULT_API_BASE_URL = "http://127.0.0.1:8787";
@@ -39248,6 +39403,19 @@ async function collectAgentPoolSnapshot(deps) {
39248
39403
  );
39249
39404
  }
39250
39405
 
39406
+ // src/external-agents-bin.ts
39407
+ function resolveExternalAgentsCliInvocation(override) {
39408
+ if (override && override.trim()) return { command: override, prefixArgs: [] };
39409
+ try {
39410
+ return {
39411
+ command: "node",
39412
+ prefixArgs: [resolvePackageBin("@mrrlin-dev/external-agents", "external-agents")]
39413
+ };
39414
+ } catch {
39415
+ return { command: "external-agents", prefixArgs: [] };
39416
+ }
39417
+ }
39418
+
39251
39419
  // src/agent-pool-loop.ts
39252
39420
  var DEFAULT_INTERVAL_MS2 = 6e4;
39253
39421
  function agentPoolLoopDisabled(env = process.env) {
@@ -39255,7 +39423,7 @@ function agentPoolLoopDisabled(env = process.env) {
39255
39423
  }
39256
39424
  function defaultRunCli(args) {
39257
39425
  const cli = process.env["EXTERNAL_AGENTS_CLI"];
39258
- const [cmd, baseArgs] = cli ? ["node", [cli, ...args]] : ["external-agents", args];
39426
+ const { command, prefixArgs } = cli ? { command: "node", prefixArgs: [cli] } : resolveExternalAgentsCliInvocation();
39259
39427
  return new Promise((resolve) => {
39260
39428
  let stdout = "";
39261
39429
  let settled = false;
@@ -39266,7 +39434,7 @@ function defaultRunCli(args) {
39266
39434
  }
39267
39435
  };
39268
39436
  try {
39269
- const child = (0, import_node_child_process5.spawn)(cmd, baseArgs, { stdio: ["ignore", "pipe", "ignore"] });
39437
+ const child = (0, import_node_child_process5.spawn)(command, [...prefixArgs, ...args], { stdio: ["ignore", "pipe", "ignore"] });
39270
39438
  const timer = setTimeout(() => {
39271
39439
  try {
39272
39440
  child.kill("SIGKILL");
@@ -53128,7 +53296,7 @@ var import_node_child_process11 = require("node:child_process");
53128
53296
  function errMessage3(err) {
53129
53297
  return err instanceof Error ? err.message : String(err);
53130
53298
  }
53131
- function runExternalAgents(bin, args, timeoutMs, spawn3) {
53299
+ function runExternalAgents(bin, args, label, timeoutMs, spawn3) {
53132
53300
  return new Promise((resolve) => {
53133
53301
  let settled = false;
53134
53302
  const timerRef = { id: void 0 };
@@ -53154,20 +53322,20 @@ function runExternalAgents(bin, args, timeoutMs, spawn3) {
53154
53322
  let stdout = "";
53155
53323
  timerRef.id = setTimeout(() => {
53156
53324
  child.kill("SIGKILL");
53157
- finish({ code: null, stdout, error: `external-agents ${args[0]} timed out after ${timeoutMs}ms` });
53325
+ finish({ code: null, stdout, error: `external-agents ${label} timed out after ${timeoutMs}ms` });
53158
53326
  }, timeoutMs);
53159
53327
  child.stdout?.on("data", (chunk) => {
53160
53328
  stdout += chunk.toString();
53161
53329
  });
53162
53330
  child.stderr?.on("data", () => {
53163
53331
  });
53164
- child.on("error", (err) => finish({ code: null, stdout, error: `external-agents ${args[0]} error: ${errMessage3(err)}` }));
53332
+ child.on("error", (err) => finish({ code: null, stdout, error: `external-agents ${label} error: ${errMessage3(err)}` }));
53165
53333
  child.on("close", (code) => finish({ code, stdout }));
53166
53334
  });
53167
53335
  }
53168
53336
  async function pickPanel(input, deps) {
53169
53337
  const spawn3 = deps?.spawn ?? import_node_child_process11.spawn;
53170
- const bin = deps?.externalAgentsBin ?? "external-agents";
53338
+ const { command, prefixArgs } = resolveExternalAgentsCliInvocation(deps?.externalAgentsBin);
53171
53339
  const args = [
53172
53340
  "pick",
53173
53341
  "--tier-prefer",
@@ -53179,7 +53347,7 @@ async function pickPanel(input, deps) {
53179
53347
  "--exclude-providers",
53180
53348
  input.excludeProvider
53181
53349
  ];
53182
- const r = await runExternalAgents(bin, args, input.timeoutMs, spawn3);
53350
+ const r = await runExternalAgents(command, [...prefixArgs, ...args], "pick", input.timeoutMs, spawn3);
53183
53351
  if (r.error) return { ok: false, error: r.error };
53184
53352
  if (r.code === 3) return { ok: true, agents: [] };
53185
53353
  if (r.code !== 0) return { ok: false, error: `external-agents pick exited ${r.code}` };
@@ -53188,9 +53356,9 @@ async function pickPanel(input, deps) {
53188
53356
  }
53189
53357
  async function dispatchHead(agentId, prompt, timeoutMs, deps) {
53190
53358
  const spawn3 = deps?.spawn ?? import_node_child_process11.spawn;
53191
- const bin = deps?.externalAgentsBin ?? "external-agents";
53359
+ const { command, prefixArgs } = resolveExternalAgentsCliInvocation(deps?.externalAgentsBin);
53192
53360
  const args = ["dispatch", agentId, "--json", prompt];
53193
- const r = await runExternalAgents(bin, args, timeoutMs, spawn3);
53361
+ const r = await runExternalAgents(command, [...prefixArgs, ...args], "dispatch", timeoutMs, spawn3);
53194
53362
  if (r.error) return { ok: false, error: r.error };
53195
53363
  const lines2 = r.stdout.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
53196
53364
  const jsonLine = [...lines2].reverse().find((l) => l[0] === "{");
@@ -53551,8 +53719,9 @@ async function run(ctx, input) {
53551
53719
  planId = plans.find((p) => p.specWikiPageId === input.pageId)?.id ?? null;
53552
53720
  }
53553
53721
  if (taskId) {
53722
+ const scopeId = taskId;
53723
+ const groupId = clarifications.length > 1 ? `II-${scopeId}-gate-group-${(0, import_node_crypto8.createHash)("sha256").update(clarifications.map((c) => c.question).sort().join("\n")).digest("hex").slice(0, 10)}` : void 0;
53554
53724
  for (const clarification of clarifications) {
53555
- const scopeId = taskId;
53556
53725
  const id = `II-${scopeId}-gate-${(0, import_node_crypto8.createHash)("sha256").update(clarification.question).digest("hex").slice(0, 10)}`;
53557
53726
  try {
53558
53727
  const questionOptions = buildGateQuestionOptions(clarification.question, clarification.category);
@@ -53562,15 +53731,17 @@ async function run(ctx, input) {
53562
53731
  taskId: scopeId,
53563
53732
  body: clarification.question,
53564
53733
  origin: "gate",
53565
- ...questionOptions ? { questionOptions } : {}
53734
+ ...questionOptions ? { questionOptions } : {},
53735
+ ...groupId ? { groupId } : {}
53566
53736
  });
53567
53737
  } catch {
53568
53738
  }
53569
53739
  }
53570
53740
  filedQuestionCount = clarifications.length;
53571
53741
  } else if (planId) {
53742
+ const scopeId = planId;
53743
+ const groupId = clarifications.length > 1 ? `II-${scopeId}-gate-group-${(0, import_node_crypto8.createHash)("sha256").update(clarifications.map((c) => c.question).sort().join("\n")).digest("hex").slice(0, 10)}` : void 0;
53572
53744
  for (const clarification of clarifications) {
53573
- const scopeId = planId;
53574
53745
  const id = `II-${scopeId}-gate-${(0, import_node_crypto8.createHash)("sha256").update(clarification.question).digest("hex").slice(0, 10)}`;
53575
53746
  try {
53576
53747
  const questionOptions = buildGateQuestionOptions(clarification.question, clarification.category);
@@ -53580,7 +53751,8 @@ async function run(ctx, input) {
53580
53751
  planId: scopeId,
53581
53752
  body: clarification.question,
53582
53753
  origin: "gate",
53583
- ...questionOptions ? { questionOptions } : {}
53754
+ ...questionOptions ? { questionOptions } : {},
53755
+ ...groupId ? { groupId } : {}
53584
53756
  });
53585
53757
  } catch {
53586
53758
  }
@@ -55854,6 +56026,12 @@ Usage:
55854
56026
  command install-codex wires for the
55855
56027
  [mcp_servers.mrrlin-browser] block.
55856
56028
 
56029
+ mrrlin-mcp external-agents-serve
56030
+ Launch the bundled @mrrlin-dev/external-agents
56031
+ MCP server (multi-LLM dispatch pool). This is the
56032
+ command install-codex wires for the
56033
+ [mcp_servers.external-agents] block.
56034
+
55857
56035
  mrrlin-mcp install-codex Idempotently register Mrrlin in
55858
56036
  [--force] ~/.codex/config.toml (or CODEX_HOME). Adds an
55859
56037
  [mcp_servers.mrrlin] block. Development
@@ -56009,6 +56187,12 @@ async function main() {
56009
56187
  process.exitCode = r.status ?? 1;
56010
56188
  return;
56011
56189
  }
56190
+ case "external-agents-serve": {
56191
+ const { command: command2, args } = externalAgentsServeArgs();
56192
+ const r = (0, import_node_child_process13.spawnSync)(command2, args, { stdio: "inherit", env: process.env });
56193
+ process.exitCode = r.status ?? 1;
56194
+ return;
56195
+ }
56012
56196
  case "install-codex": {
56013
56197
  const force = rest.includes("--force");
56014
56198
  const binPath = resolveSelfBinPath();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrrlin-dev/mcp",
3
- "version": "0.3.41",
3
+ "version": "0.3.45",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mrrlin-mcp": "dist/bin.cjs"
@@ -21,16 +21,17 @@
21
21
  "@types/ws": "^8.18.1",
22
22
  "esbuild": "^0.24.0",
23
23
  "tsx": "^4.22.3",
24
+ "@mrrlin/schemas": "0.0.0",
24
25
  "@mrrlin/director-e2e": "0.0.0",
25
26
  "@mrrlin/wiki": "0.0.0",
26
- "@mrrlin/schemas": "0.0.0",
27
+ "@mrrlin/client": "0.0.0",
27
28
  "@mrrlin/codex-client": "0.0.0",
28
- "@mrrlin/tsconfig": "0.0.0",
29
- "@mrrlin/client": "0.0.0"
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": "^0.32.0",
34
35
  "@playwright/mcp": "0.0.76",
35
36
  "playwright-core": "1.61.0-alpha-1781023400000",
36
37
  "proper-lockfile": "^4.1.2",