@mrrlin-dev/mcp 0.3.39 → 0.3.41

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 +83 -25
  2. package/package.json +4 -4
package/dist/bin.cjs CHANGED
@@ -38955,7 +38955,7 @@ function startCodexProbe(deps = {}) {
38955
38955
  }
38956
38956
 
38957
38957
  // src/_generated/version.ts
38958
- var PKG_VERSION = "0.3.39";
38958
+ var PKG_VERSION = "0.3.41";
38959
38959
 
38960
38960
  // src/api-base-url.ts
38961
38961
  var DEFAULT_API_BASE_URL = "http://127.0.0.1:8787";
@@ -39137,6 +39137,16 @@ function startSchedulerTickLoop(deps) {
39137
39137
  var import_node_child_process5 = require("node:child_process");
39138
39138
 
39139
39139
  // src/agent-pool-snapshot.ts
39140
+ function normalizeLastUsedAt(value) {
39141
+ if (value === void 0 || value === null) return null;
39142
+ if (typeof value === "number") {
39143
+ if (!Number.isFinite(value)) return null;
39144
+ const ms = value < 1e12 ? value * 1e3 : value;
39145
+ const date5 = new Date(ms);
39146
+ return Number.isNaN(date5.getTime()) ? null : date5.toISOString();
39147
+ }
39148
+ return value;
39149
+ }
39140
39150
  function buildAgentPoolSnapshot(statusRows, stats, opts) {
39141
39151
  if (!opts.available) {
39142
39152
  return {
@@ -39168,7 +39178,7 @@ function buildAgentPoolSnapshot(statusRows, stats, opts) {
39168
39178
  tokens_in: tokensIn,
39169
39179
  tokens_out: tokensOut,
39170
39180
  success_rate: successRate,
39171
- last_used_at: row.last_used_at ?? null
39181
+ last_used_at: normalizeLastUsedAt(row.last_used_at)
39172
39182
  };
39173
39183
  });
39174
39184
  let totalCalls = 0;
@@ -53387,31 +53397,77 @@ async function resolveActiveRunHead(input, deps) {
53387
53397
 
53388
53398
  // src/async-tools/consensus.ts
53389
53399
  var import_node_crypto8 = require("node:crypto");
53390
- function buildGateQuestionOptions(category) {
53391
- if (category === "scope") {
53392
- return [
53393
- {
53394
- 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.",
53395
- description: "Do only the originally requested narrower scope and leave the broader bucket out unless explicitly required.",
53396
- label: "Narrower"
53397
- },
53398
- {
53399
- answer: "Use the broader scope. Update the spec to explicitly include the broader interpretation and any required acceptance criteria.",
53400
- description: "Treat the broader interpretation as in scope and spell out the extra acceptance criteria it adds.",
53401
- label: "Broader"
53402
- }
53403
- ];
53400
+ function normalizeClarificationQuestion(question) {
53401
+ return question.replace(/\s+/g, " ").trim().replace(/[?.!]+$/, "").trim();
53402
+ }
53403
+ function stripLeadingPromptPhrase(part) {
53404
+ return part.replace(
53405
+ /^(?:should|could|would|can|do|does|is|are)\s+(?:this|we|it|the spec|the plan|the task)\s+/i,
53406
+ ""
53407
+ ).trim();
53408
+ }
53409
+ function stripLeadVerb(part) {
53410
+ return part.replace(/^(?:cover|include|support|use|keep|allow|propose|add|handle)\s+/i, "").trim();
53411
+ }
53412
+ function isAbstractOnlyChoice(part) {
53413
+ const normalized = stripLeadVerb(stripLeadingPromptPhrase(part)).replace(/^(?:the|a|an)\s+/i, "").trim().toLowerCase();
53414
+ return /^(?:broader|narrower|safer(?: default)?|stronger(?: interpretation)?)$/.test(normalized);
53415
+ }
53416
+ function sentenceCase(text) {
53417
+ return text ? text.charAt(0).toUpperCase() + text.slice(1) : text;
53418
+ }
53419
+ function deriveGateChoice(question) {
53420
+ const normalized = normalizeClarificationQuestion(question);
53421
+ if (!normalized || normalized.length > 180 || /[;:]/.test(normalized)) return null;
53422
+ const matches = [...normalized.matchAll(/\sor\s/gi)];
53423
+ if (matches.length !== 1) return null;
53424
+ const match = matches[0];
53425
+ if (!match) return null;
53426
+ const splitAt = match.index ?? -1;
53427
+ if (splitAt <= 0) return null;
53428
+ let left = stripLeadingPromptPhrase(normalized.slice(0, splitAt).trim());
53429
+ let right = stripLeadingPromptPhrase(normalized.slice(splitAt + match[0].length).trim());
53430
+ if (!left || !right || /\sor\s/i.test(left) || /\sor\s/i.test(right)) return null;
53431
+ if (isAbstractOnlyChoice(left) || isAbstractOnlyChoice(right)) return null;
53432
+ if (/^only\s+/i.test(left) && /^also\s+/i.test(right)) {
53433
+ const leftScope = stripLeadVerb(left.replace(/^only\s+/i, "").trim());
53434
+ const rightScope = stripLeadVerb(right.replace(/^also\s+/i, "").trim());
53435
+ if (!leftScope || !rightScope) return null;
53436
+ return {
53437
+ leftLabel: `Only ${leftScope}`,
53438
+ leftDescription: `Keep the scope limited to ${leftScope} only.`,
53439
+ leftAnswer: `Keep the scope limited to ${leftScope} only. Update the spec so that limit is explicit.`,
53440
+ rightLabel: `${sentenceCase(leftScope)} + ${rightScope}`,
53441
+ rightDescription: `Expand the scope to cover ${leftScope} and ${rightScope}.`,
53442
+ rightAnswer: `Expand the scope to cover ${leftScope} and ${rightScope}. Update the spec so both are explicitly in scope.`
53443
+ };
53404
53444
  }
53445
+ left = sentenceCase(left);
53446
+ right = sentenceCase(right);
53447
+ if (!left || !right) return null;
53448
+ return {
53449
+ leftLabel: left,
53450
+ leftDescription: `Choose the first direction: ${left}.`,
53451
+ leftAnswer: `Choose ${left}. Update the spec so that direction is explicit.`,
53452
+ rightLabel: right,
53453
+ rightDescription: `Choose the second direction: ${right}.`,
53454
+ rightAnswer: `Choose ${right}. Update the spec so that direction is explicit.`
53455
+ };
53456
+ }
53457
+ function buildGateQuestionOptions(question, category) {
53458
+ if (category !== "scope" && category !== "ambiguity") return null;
53459
+ const derived = deriveGateChoice(question);
53460
+ if (!derived) return null;
53405
53461
  return [
53406
53462
  {
53407
- answer: "Use the safer/default interpretation. Update the spec to document that assumption explicitly.",
53408
- description: "Choose the lower-risk default interpretation and record it explicitly so implementation is unblocked.",
53409
- label: "Safer default"
53463
+ answer: derived.leftAnswer,
53464
+ description: derived.leftDescription,
53465
+ label: derived.leftLabel
53410
53466
  },
53411
53467
  {
53412
- answer: "Use the broader/stronger interpretation. Update the spec to make that interpretation explicit.",
53413
- description: "Commit to the stronger interpretation instead of a conservative default, and update the spec to match.",
53414
- label: "Stronger interpretation"
53468
+ answer: derived.rightAnswer,
53469
+ description: derived.rightDescription,
53470
+ label: derived.rightLabel
53415
53471
  }
53416
53472
  ];
53417
53473
  }
@@ -53499,13 +53555,14 @@ async function run(ctx, input) {
53499
53555
  const scopeId = taskId;
53500
53556
  const id = `II-${scopeId}-gate-${(0, import_node_crypto8.createHash)("sha256").update(clarification.question).digest("hex").slice(0, 10)}`;
53501
53557
  try {
53558
+ const questionOptions = buildGateQuestionOptions(clarification.question, clarification.category);
53502
53559
  await ctx.client.createInboxItem(input.projectSlug, {
53503
53560
  id,
53504
53561
  kind: "question",
53505
53562
  taskId: scopeId,
53506
53563
  body: clarification.question,
53507
53564
  origin: "gate",
53508
- questionOptions: buildGateQuestionOptions(clarification.category)
53565
+ ...questionOptions ? { questionOptions } : {}
53509
53566
  });
53510
53567
  } catch {
53511
53568
  }
@@ -53516,13 +53573,14 @@ async function run(ctx, input) {
53516
53573
  const scopeId = planId;
53517
53574
  const id = `II-${scopeId}-gate-${(0, import_node_crypto8.createHash)("sha256").update(clarification.question).digest("hex").slice(0, 10)}`;
53518
53575
  try {
53576
+ const questionOptions = buildGateQuestionOptions(clarification.question, clarification.category);
53519
53577
  await ctx.client.createInboxItem(input.projectSlug, {
53520
53578
  id,
53521
53579
  kind: "question",
53522
53580
  planId: scopeId,
53523
53581
  body: clarification.question,
53524
53582
  origin: "gate",
53525
- questionOptions: buildGateQuestionOptions(clarification.category)
53583
+ ...questionOptions ? { questionOptions } : {}
53526
53584
  });
53527
53585
  } catch {
53528
53586
  }
@@ -53595,7 +53653,7 @@ function onComplete2(outcome, input) {
53595
53653
  return {
53596
53654
  kind: "handoff",
53597
53655
  ...taskId ? { taskId } : {},
53598
- body: `Consensus could not complete for Specs/${input.pageId}${taskRef}: ${outcome.error} Needs operator attention.`
53656
+ 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.`
53599
53657
  };
53600
53658
  }
53601
53659
  var consensusDescriptor = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrrlin-dev/mcp",
3
- "version": "0.3.39",
3
+ "version": "0.3.41",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mrrlin-mcp": "dist/bin.cjs"
@@ -22,11 +22,11 @@
22
22
  "esbuild": "^0.24.0",
23
23
  "tsx": "^4.22.3",
24
24
  "@mrrlin/director-e2e": "0.0.0",
25
+ "@mrrlin/wiki": "0.0.0",
25
26
  "@mrrlin/schemas": "0.0.0",
26
- "@mrrlin/tsconfig": "0.0.0",
27
27
  "@mrrlin/codex-client": "0.0.0",
28
- "@mrrlin/client": "0.0.0",
29
- "@mrrlin/wiki": "0.0.0"
28
+ "@mrrlin/tsconfig": "0.0.0",
29
+ "@mrrlin/client": "0.0.0"
30
30
  },
31
31
  "dependencies": {
32
32
  "@iarna/toml": "^2.2.5",