@mrrlin-dev/mcp 0.3.40 → 0.3.42

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 +123 -27
  2. package/package.json +2 -2
package/dist/bin.cjs CHANGED
@@ -36358,6 +36358,7 @@ var openApiOperationIds = {
36358
36358
  listInboxItems: "listInboxItems",
36359
36359
  decideInboxItem: "decideInboxItem",
36360
36360
  markInboxItemRead: "markInboxItemRead",
36361
+ markInboxItemsReadByIds: "markInboxItemsReadByIds",
36361
36362
  markAllInboxItemsRead: "markAllInboxItemsRead",
36362
36363
  searchKnowledge: "searchKnowledge",
36363
36364
  updateExecutionRun: "updateExecutionRun",
@@ -37499,12 +37500,35 @@ var mrrlinSchedulerPendingReasonSchema = external_exports.enum([
37499
37500
  var mrrlinSchedulerPendingTaskSchema = external_exports.object({
37500
37501
  dueAt: external_exports.string().datetime(),
37501
37502
  reason: mrrlinSchedulerPendingReasonSchema,
37502
- task: mrrlinTaskSchema
37503
+ task: mrrlinTaskSchema,
37504
+ // Additive: whether the scheduler considers this task due NOW (per `deriveSchedulerDue`), as
37505
+ // opposed to `dueAt` reporting a future trigger or the evaluatedAt fallback when the task has no
37506
+ // trigger at all. Consumers must read this instead of re-deriving due-ness by re-parsing `dueAt`
37507
+ // against "now" — a task with no trigger has `dueAt === evaluatedAt`, which a naive `dueAt <= now`
37508
+ // re-derivation would misclassify as due.
37509
+ due: external_exports.boolean()
37510
+ });
37511
+ var mrrlinSchedulerParkedReasonSchema = external_exports.enum([
37512
+ "running",
37513
+ "awaiting_handoff",
37514
+ "awaiting_clarification",
37515
+ "spec_awaiting_approval",
37516
+ "blocked_by_active"
37517
+ ]);
37518
+ var mrrlinSchedulerParkedTaskSchema = external_exports.object({
37519
+ task: mrrlinTaskSchema,
37520
+ reason: mrrlinSchedulerParkedReasonSchema,
37521
+ blockedByIds: external_exports.array(mrrlinTaskIdSchema),
37522
+ inboxItemId: external_exports.string().nullable(),
37523
+ runId: mrrlinExecutionRunIdSchema.nullable()
37503
37524
  });
37504
37525
  var schedulerPendingTasksResponseSchema = external_exports.object({
37505
37526
  data: external_exports.object({
37506
37527
  evaluatedAt: external_exports.string().datetime(),
37507
37528
  pending: external_exports.array(mrrlinSchedulerPendingTaskSchema),
37529
+ parked: external_exports.array(mrrlinSchedulerParkedTaskSchema),
37530
+ slots: external_exports.number().int(),
37531
+ perProjectLimit: external_exports.number().int().min(1),
37508
37532
  policy: mrrlinProjectSchedulerPolicySchema
37509
37533
  })
37510
37534
  });
@@ -37594,6 +37618,7 @@ var mrrlinInboxItemSchema = external_exports.object({
37594
37618
  decidedBy: external_exports.string().min(1).nullable(),
37595
37619
  dedupKey: external_exports.string().nullable(),
37596
37620
  directorSessionId: external_exports.string().min(1).nullable(),
37621
+ groupId: external_exports.string().nullable().default(null),
37597
37622
  id: mrrlinInboxItemIdSchema,
37598
37623
  kind: mrrlinInboxItemKindSchema,
37599
37624
  origin: external_exports.string().nullable().optional(),
@@ -37616,6 +37641,7 @@ var mrrlinInboxItemCreateSchema = external_exports.object({
37616
37641
  actionPayload: mrrlinInboxItemActionPayloadSchema.nullable().optional(),
37617
37642
  body: external_exports.string().min(1),
37618
37643
  directorSessionId: external_exports.string().min(1).optional(),
37644
+ groupId: external_exports.string().min(1).optional(),
37619
37645
  id: mrrlinInboxItemIdSchema,
37620
37646
  kind: mrrlinInboxItemKindSchema,
37621
37647
  origin: external_exports.string().min(1).optional(),
@@ -37646,6 +37672,7 @@ var mrrlinInboxItemDecideSchema = external_exports.object({
37646
37672
  }
37647
37673
  });
37648
37674
  var mrrlinInboxItemListFiltersSchema = external_exports.object({
37675
+ groupId: external_exports.string().optional(),
37649
37676
  kind: mrrlinInboxItemKindSchema.optional(),
37650
37677
  readState: external_exports.enum(["read", "unread"]).optional(),
37651
37678
  status: mrrlinInboxItemStatusSchema.optional(),
@@ -37662,6 +37689,15 @@ var inboxMarkAllReadResponseSchema = external_exports.object({
37662
37689
  readAt: external_exports.string().datetime()
37663
37690
  })
37664
37691
  });
37692
+ var mrrlinInboxItemsMarkReadRequestSchema = external_exports.object({
37693
+ ids: external_exports.array(external_exports.string().min(1)).min(1)
37694
+ });
37695
+ var inboxItemsMarkReadResponseSchema = external_exports.object({
37696
+ data: external_exports.object({
37697
+ markedCount: external_exports.number().int().nonnegative(),
37698
+ readAt: external_exports.string().datetime()
37699
+ })
37700
+ });
37665
37701
  var inboxItemResponseSchema = external_exports.object({ data: mrrlinInboxItemSchema });
37666
37702
  var inboxItemListResponseSchema = external_exports.object({ data: external_exports.array(mrrlinInboxItemSchema) });
37667
37703
 
@@ -38284,6 +38320,14 @@ function createMrrlinClient(config2) {
38284
38320
  });
38285
38321
  return inboxItemReadResponseSchema.parse(body).data;
38286
38322
  },
38323
+ async markInboxItemsReadByIds(projectSlug, ids) {
38324
+ const body = await request(`${projectPath(projectSlug)}/inbox/mark-read`, {
38325
+ body: JSON.stringify({ ids }),
38326
+ headers: { "content-type": "application/json" },
38327
+ method: "POST"
38328
+ });
38329
+ return inboxItemsMarkReadResponseSchema.parse(body).data;
38330
+ },
38287
38331
  async markAllInboxItemsRead(projectSlug) {
38288
38332
  const body = await request(`${projectPath(projectSlug)}/inbox/mark-all-read`, {
38289
38333
  method: "POST"
@@ -38955,7 +38999,7 @@ function startCodexProbe(deps = {}) {
38955
38999
  }
38956
39000
 
38957
39001
  // src/_generated/version.ts
38958
- var PKG_VERSION = "0.3.40";
39002
+ var PKG_VERSION = "0.3.42";
38959
39003
 
38960
39004
  // src/api-base-url.ts
38961
39005
  var DEFAULT_API_BASE_URL = "http://127.0.0.1:8787";
@@ -53397,31 +53441,77 @@ async function resolveActiveRunHead(input, deps) {
53397
53441
 
53398
53442
  // src/async-tools/consensus.ts
53399
53443
  var import_node_crypto8 = require("node:crypto");
53400
- function buildGateQuestionOptions(category) {
53401
- if (category === "scope") {
53402
- return [
53403
- {
53404
- answer: "Use the narrower scope only. Update the spec to keep the original limited scope and do not add the broader interpretation unless explicitly required.",
53405
- description: "Do only the originally requested narrower scope and leave the broader bucket out unless explicitly required.",
53406
- label: "Narrower"
53407
- },
53408
- {
53409
- answer: "Use the broader scope. Update the spec to explicitly include the broader interpretation and any required acceptance criteria.",
53410
- description: "Treat the broader interpretation as in scope and spell out the extra acceptance criteria it adds.",
53411
- label: "Broader"
53412
- }
53413
- ];
53444
+ function normalizeClarificationQuestion(question) {
53445
+ return question.replace(/\s+/g, " ").trim().replace(/[?.!]+$/, "").trim();
53446
+ }
53447
+ function stripLeadingPromptPhrase(part) {
53448
+ return part.replace(
53449
+ /^(?:should|could|would|can|do|does|is|are)\s+(?:this|we|it|the spec|the plan|the task)\s+/i,
53450
+ ""
53451
+ ).trim();
53452
+ }
53453
+ function stripLeadVerb(part) {
53454
+ return part.replace(/^(?:cover|include|support|use|keep|allow|propose|add|handle)\s+/i, "").trim();
53455
+ }
53456
+ function isAbstractOnlyChoice(part) {
53457
+ const normalized = stripLeadVerb(stripLeadingPromptPhrase(part)).replace(/^(?:the|a|an)\s+/i, "").trim().toLowerCase();
53458
+ return /^(?:broader|narrower|safer(?: default)?|stronger(?: interpretation)?)$/.test(normalized);
53459
+ }
53460
+ function sentenceCase(text) {
53461
+ return text ? text.charAt(0).toUpperCase() + text.slice(1) : text;
53462
+ }
53463
+ function deriveGateChoice(question) {
53464
+ const normalized = normalizeClarificationQuestion(question);
53465
+ if (!normalized || normalized.length > 180 || /[;:]/.test(normalized)) return null;
53466
+ const matches = [...normalized.matchAll(/\sor\s/gi)];
53467
+ if (matches.length !== 1) return null;
53468
+ const match = matches[0];
53469
+ if (!match) return null;
53470
+ const splitAt = match.index ?? -1;
53471
+ if (splitAt <= 0) return null;
53472
+ let left = stripLeadingPromptPhrase(normalized.slice(0, splitAt).trim());
53473
+ let right = stripLeadingPromptPhrase(normalized.slice(splitAt + match[0].length).trim());
53474
+ if (!left || !right || /\sor\s/i.test(left) || /\sor\s/i.test(right)) return null;
53475
+ if (isAbstractOnlyChoice(left) || isAbstractOnlyChoice(right)) return null;
53476
+ if (/^only\s+/i.test(left) && /^also\s+/i.test(right)) {
53477
+ const leftScope = stripLeadVerb(left.replace(/^only\s+/i, "").trim());
53478
+ const rightScope = stripLeadVerb(right.replace(/^also\s+/i, "").trim());
53479
+ if (!leftScope || !rightScope) return null;
53480
+ return {
53481
+ leftLabel: `Only ${leftScope}`,
53482
+ leftDescription: `Keep the scope limited to ${leftScope} only.`,
53483
+ leftAnswer: `Keep the scope limited to ${leftScope} only. Update the spec so that limit is explicit.`,
53484
+ rightLabel: `${sentenceCase(leftScope)} + ${rightScope}`,
53485
+ rightDescription: `Expand the scope to cover ${leftScope} and ${rightScope}.`,
53486
+ rightAnswer: `Expand the scope to cover ${leftScope} and ${rightScope}. Update the spec so both are explicitly in scope.`
53487
+ };
53414
53488
  }
53489
+ left = sentenceCase(left);
53490
+ right = sentenceCase(right);
53491
+ if (!left || !right) return null;
53492
+ return {
53493
+ leftLabel: left,
53494
+ leftDescription: `Choose the first direction: ${left}.`,
53495
+ leftAnswer: `Choose ${left}. Update the spec so that direction is explicit.`,
53496
+ rightLabel: right,
53497
+ rightDescription: `Choose the second direction: ${right}.`,
53498
+ rightAnswer: `Choose ${right}. Update the spec so that direction is explicit.`
53499
+ };
53500
+ }
53501
+ function buildGateQuestionOptions(question, category) {
53502
+ if (category !== "scope" && category !== "ambiguity") return null;
53503
+ const derived = deriveGateChoice(question);
53504
+ if (!derived) return null;
53415
53505
  return [
53416
53506
  {
53417
- answer: "Use the safer/default interpretation. Update the spec to document that assumption explicitly.",
53418
- description: "Choose the lower-risk default interpretation and record it explicitly so implementation is unblocked.",
53419
- label: "Safer default"
53507
+ answer: derived.leftAnswer,
53508
+ description: derived.leftDescription,
53509
+ label: derived.leftLabel
53420
53510
  },
53421
53511
  {
53422
- answer: "Use the broader/stronger interpretation. Update the spec to make that interpretation explicit.",
53423
- description: "Commit to the stronger interpretation instead of a conservative default, and update the spec to match.",
53424
- label: "Stronger interpretation"
53512
+ answer: derived.rightAnswer,
53513
+ description: derived.rightDescription,
53514
+ label: derived.rightLabel
53425
53515
  }
53426
53516
  ];
53427
53517
  }
@@ -53505,34 +53595,40 @@ async function run(ctx, input) {
53505
53595
  planId = plans.find((p) => p.specWikiPageId === input.pageId)?.id ?? null;
53506
53596
  }
53507
53597
  if (taskId) {
53598
+ const scopeId = taskId;
53599
+ 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;
53508
53600
  for (const clarification of clarifications) {
53509
- const scopeId = taskId;
53510
53601
  const id = `II-${scopeId}-gate-${(0, import_node_crypto8.createHash)("sha256").update(clarification.question).digest("hex").slice(0, 10)}`;
53511
53602
  try {
53603
+ const questionOptions = buildGateQuestionOptions(clarification.question, clarification.category);
53512
53604
  await ctx.client.createInboxItem(input.projectSlug, {
53513
53605
  id,
53514
53606
  kind: "question",
53515
53607
  taskId: scopeId,
53516
53608
  body: clarification.question,
53517
53609
  origin: "gate",
53518
- questionOptions: buildGateQuestionOptions(clarification.category)
53610
+ ...questionOptions ? { questionOptions } : {},
53611
+ ...groupId ? { groupId } : {}
53519
53612
  });
53520
53613
  } catch {
53521
53614
  }
53522
53615
  }
53523
53616
  filedQuestionCount = clarifications.length;
53524
53617
  } else if (planId) {
53618
+ const scopeId = planId;
53619
+ 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;
53525
53620
  for (const clarification of clarifications) {
53526
- const scopeId = planId;
53527
53621
  const id = `II-${scopeId}-gate-${(0, import_node_crypto8.createHash)("sha256").update(clarification.question).digest("hex").slice(0, 10)}`;
53528
53622
  try {
53623
+ const questionOptions = buildGateQuestionOptions(clarification.question, clarification.category);
53529
53624
  await ctx.client.createInboxItem(input.projectSlug, {
53530
53625
  id,
53531
53626
  kind: "question",
53532
53627
  planId: scopeId,
53533
53628
  body: clarification.question,
53534
53629
  origin: "gate",
53535
- questionOptions: buildGateQuestionOptions(clarification.category)
53630
+ ...questionOptions ? { questionOptions } : {},
53631
+ ...groupId ? { groupId } : {}
53536
53632
  });
53537
53633
  } catch {
53538
53634
  }
@@ -53605,7 +53701,7 @@ function onComplete2(outcome, input) {
53605
53701
  return {
53606
53702
  kind: "handoff",
53607
53703
  ...taskId ? { taskId } : {},
53608
- body: `Consensus could not complete for Specs/${input.pageId}${taskRef}: ${outcome.error} Needs operator attention.`
53704
+ body: `The spec review stopped for Specs/${input.pageId}${taskRef}. ${outcome.error} Review the item, consult the Director if needed, then continue in Codex or handle it manually.`
53609
53705
  };
53610
53706
  }
53611
53707
  var consensusDescriptor = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrrlin-dev/mcp",
3
- "version": "0.3.40",
3
+ "version": "0.3.42",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mrrlin-mcp": "dist/bin.cjs"
@@ -21,10 +21,10 @@
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
26
  "@mrrlin/schemas": "0.0.0",
27
+ "@mrrlin/client": "0.0.0",
28
28
  "@mrrlin/codex-client": "0.0.0",
29
29
  "@mrrlin/tsconfig": "0.0.0"
30
30
  },