@productbrain/mcp 0.0.1-beta.10856 → 0.0.1-beta.10865

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.
@@ -50,7 +50,7 @@ import {
50
50
 
51
51
  // src/server.ts
52
52
  import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
53
- import { z as z34 } from "zod/v3";
53
+ import { z as z35 } from "zod/v3";
54
54
 
55
55
  // src/lib/mcpGatewayClientMessages.ts
56
56
  function agentSessionNotActiveMessage(status2) {
@@ -1016,29 +1016,29 @@ function verdictQualityPhrase(result2) {
1016
1016
  return v.passed ? `Quality: all ${total} rubric criteria pass.` : `Quality: ${passed}/${total} rubric criteria pass \u2014 see the coaching above.`;
1017
1017
  }
1018
1018
  function formatRubricCoaching(result2) {
1019
- const { verdict, rogerMartin } = result2;
1020
- if (!verdict || verdict.criteria.length === 0) return "";
1019
+ const { verdict: verdict2, rogerMartin } = result2;
1020
+ if (!verdict2 || verdict2.criteria.length === 0) return "";
1021
1021
  const lines = ["## Semantic Quality"];
1022
- const failed = (verdict.criteria ?? []).filter((c) => !c.passed);
1023
- const total = verdict.criteria?.length ?? 0;
1022
+ const failed = (verdict2.criteria ?? []).filter((c) => !c.passed);
1023
+ const total = verdict2.criteria?.length ?? 0;
1024
1024
  const passedCount = total - failed.length;
1025
- const checklist = renderChecklist(verdict.canonicalKey, verdict.criteria, result2.source !== "llm");
1025
+ const checklist = renderChecklist(verdict2.canonicalKey, verdict2.criteria, result2.source !== "llm");
1026
1026
  if (checklist) {
1027
- lines.push(`Quality checklist for \`${verdict.canonicalKey}\`:`, "", ...checklist);
1028
- } else if (verdict.passed) {
1029
- lines.push(`All ${total} rubric criteria pass for \`${verdict.canonicalKey}\` (${verdict.tier} tier).`);
1027
+ lines.push(`Quality checklist for \`${verdict2.canonicalKey}\`:`, "", ...checklist);
1028
+ } else if (verdict2.passed) {
1029
+ lines.push(`All ${total} rubric criteria pass for \`${verdict2.canonicalKey}\` (${verdict2.tier} tier).`);
1030
1030
  } else {
1031
- lines.push(`${passedCount}/${total} criteria pass for \`${verdict.canonicalKey}\` (${verdict.tier} tier)`);
1031
+ lines.push(`${passedCount}/${total} criteria pass for \`${verdict2.canonicalKey}\` (${verdict2.tier} tier)`);
1032
1032
  lines.push("");
1033
- for (const c of verdict.criteria) {
1033
+ for (const c of verdict2.criteria) {
1034
1034
  const icon = c.passed ? "[x]" : "[ ]";
1035
1035
  const extra = c.passed ? "" : ` \u2014 ${c.hint}`;
1036
1036
  lines.push(`${icon} ${c.id}${extra}`);
1037
1037
  }
1038
- if (verdict.weakest) {
1038
+ if (verdict2.weakest) {
1039
1039
  lines.push("");
1040
- lines.push(`**Coaching hint:** ${verdict.weakest.hint}`);
1041
- lines.push(`_Question to consider:_ ${verdict.weakest.questionTemplate}`);
1040
+ lines.push(`**Coaching hint:** ${verdict2.weakest.hint}`);
1041
+ lines.push(`_Question to consider:_ ${verdict2.weakest.questionTemplate}`);
1042
1042
  }
1043
1043
  }
1044
1044
  if (rogerMartin) {
@@ -1055,34 +1055,34 @@ function formatRubricCoaching(result2) {
1055
1055
  }
1056
1056
  return lines.join("\n");
1057
1057
  }
1058
- function formatRubricVerdictSection(verdict) {
1059
- if (!verdict || !verdict.criteria || verdict.criteria.length === 0) return "";
1058
+ function formatRubricVerdictSection(verdict2) {
1059
+ if (!verdict2 || !verdict2.criteria || verdict2.criteria.length === 0) return "";
1060
1060
  const lines = ["## Semantic Quality"];
1061
- const failed = verdict.criteria.filter((c) => !c.passed);
1062
- const total = verdict.criteria.length;
1061
+ const failed = verdict2.criteria.filter((c) => !c.passed);
1062
+ const total = verdict2.criteria.length;
1063
1063
  const passedCount = total - failed.length;
1064
- const durationSuffix = verdict.llmDurationMs ? ` in ${(verdict.llmDurationMs / 1e3).toFixed(1)}s` : "";
1065
- const statusNote = verdict.llmStatus === "pending" ? " \u2014 LLM evaluation in progress..." : verdict.llmStatus === "failed" ? ` \u2014 LLM evaluation failed${verdict.llmError ? `: ${verdict.llmError}` : ""}, showing heuristic results` : verdict.source === "llm" && durationSuffix ? ` \u2014 evaluated${durationSuffix}` : "";
1066
- const checklist = renderChecklist(verdict.canonicalKey, verdict.criteria, verdict.llmStatus === "pending");
1064
+ const durationSuffix = verdict2.llmDurationMs ? ` in ${(verdict2.llmDurationMs / 1e3).toFixed(1)}s` : "";
1065
+ const statusNote = verdict2.llmStatus === "pending" ? " \u2014 LLM evaluation in progress..." : verdict2.llmStatus === "failed" ? ` \u2014 LLM evaluation failed${verdict2.llmError ? `: ${verdict2.llmError}` : ""}, showing heuristic results` : verdict2.source === "llm" && durationSuffix ? ` \u2014 evaluated${durationSuffix}` : "";
1066
+ const checklist = renderChecklist(verdict2.canonicalKey, verdict2.criteria, verdict2.llmStatus === "pending");
1067
1067
  if (checklist) {
1068
- lines.push(`Quality checklist for \`${verdict.canonicalKey}\` (${verdict.source} evaluation)${statusNote}:`, "", ...checklist);
1068
+ lines.push(`Quality checklist for \`${verdict2.canonicalKey}\` (${verdict2.source} evaluation)${statusNote}:`, "", ...checklist);
1069
1069
  } else if (failed.length === 0) {
1070
- lines.push(`All ${total} rubric criteria pass for \`${verdict.canonicalKey}\` (${verdict.tier} tier, ${verdict.source} evaluation).${statusNote}`);
1070
+ lines.push(`All ${total} rubric criteria pass for \`${verdict2.canonicalKey}\` (${verdict2.tier} tier, ${verdict2.source} evaluation).${statusNote}`);
1071
1071
  } else {
1072
- lines.push(`${passedCount}/${total} criteria pass for \`${verdict.canonicalKey}\` (${verdict.tier} tier, ${verdict.source} evaluation)${statusNote}`);
1072
+ lines.push(`${passedCount}/${total} criteria pass for \`${verdict2.canonicalKey}\` (${verdict2.tier} tier, ${verdict2.source} evaluation)${statusNote}`);
1073
1073
  lines.push("");
1074
- for (const c of verdict.criteria) {
1074
+ for (const c of verdict2.criteria) {
1075
1075
  const icon = c.passed ? "[x]" : "[ ]";
1076
1076
  const extra = c.passed ? "" : ` \u2014 ${c.hint}`;
1077
1077
  lines.push(`${icon} ${c.id}${extra}`);
1078
1078
  }
1079
- if (verdict.weakest) {
1079
+ if (verdict2.weakest) {
1080
1080
  lines.push("");
1081
- lines.push(`**Top improvement:** ${verdict.weakest.hint}`);
1081
+ lines.push(`**Top improvement:** ${verdict2.weakest.hint}`);
1082
1082
  }
1083
1083
  }
1084
- if (verdict.rogerMartin) {
1085
- const rm = verdict.rogerMartin;
1084
+ if (verdict2.rogerMartin) {
1085
+ const rm = verdict2.rogerMartin;
1086
1086
  lines.push("");
1087
1087
  lines.push("### Roger Martin Test");
1088
1088
  if (rm.isStrategicChoice) {
@@ -2795,7 +2795,7 @@ function checkSchemaRef(ref, schema) {
2795
2795
  }
2796
2796
  return { result: "unverifiable", reason: "could not parse schema reference" };
2797
2797
  }
2798
- function formatTrustReport(collection, entryCount, mappings, refs, fixes, mode, schemaTableCount, projectRoot) {
2798
+ function formatTrustReport(collection, entryCount, mappings, refs, fixes, mode2, schemaTableCount, projectRoot) {
2799
2799
  const verified = mappings.filter((c) => c.result === "verified").length;
2800
2800
  const drifted = mappings.filter((c) => c.result === "drifted").length;
2801
2801
  const unverifiable = mappings.filter((c) => c.result === "unverifiable").length;
@@ -2849,14 +2849,14 @@ function formatTrustReport(collection, entryCount, mappings, refs, fixes, mode,
2849
2849
  lines.push("");
2850
2850
  }
2851
2851
  lines.push(`## Trust Score: ${trustScore}% (${totalPassed} of ${totalChecks} checks passed)`);
2852
- if (mode === "fix" && fixes.length > 0) {
2852
+ if (mode2 === "fix" && fixes.length > 0) {
2853
2853
  lines.push(
2854
2854
  "",
2855
2855
  "## Applied Fixes",
2856
2856
  `Updated codeMapping status from \`aligned\` \u2192 \`drifted\` on ${fixes.length} entr${fixes.length === 1 ? "y" : "ies"}:`
2857
2857
  );
2858
2858
  for (const eid of fixes) lines.push(`- ${eid}`);
2859
- } else if (mode === "report" && drifted > 0) {
2859
+ } else if (mode2 === "report" && drifted > 0) {
2860
2860
  const fixable = mappings.filter((c) => c.result === "drifted" && c.currentStatus === "aligned").length;
2861
2861
  if (fixable > 0) {
2862
2862
  lines.push("", `_${fixable} mapping(s) marked "aligned" but actually drifted. Run with mode="fix" to update._`);
@@ -2872,7 +2872,7 @@ var verifySchema = z7.object({
2872
2872
  var verifyEntrySchema = z7.object({
2873
2873
  entryId: z7.string().max(200).describe("Human entry ID (e.g. '<PREFIX>-<n>') to mark as verified")
2874
2874
  });
2875
- async function handleVerifyChain(server, { collection, mode }) {
2875
+ async function handleVerifyChain(server, { collection, mode: mode2 }) {
2876
2876
  const projectRoot = resolveProjectRoot();
2877
2877
  if (!projectRoot) {
2878
2878
  return failureResult(
@@ -2973,7 +2973,7 @@ async function handleVerifyChain(server, { collection, mode }) {
2973
2973
  const fixes = [];
2974
2974
  const fixUpdateWarnings = [];
2975
2975
  const fixRefusals = [];
2976
- if (mode === "fix") {
2976
+ if (mode2 === "fix") {
2977
2977
  const driftedByEntry = /* @__PURE__ */ new Map();
2978
2978
  for (const mc of mappingChecks) {
2979
2979
  if (mc.result === "drifted" && mc.currentStatus === "aligned") {
@@ -3025,7 +3025,7 @@ async function handleVerifyChain(server, { collection, mode }) {
3025
3025
  mappingChecks,
3026
3026
  refChecks,
3027
3027
  fixes,
3028
- mode,
3028
+ mode2,
3029
3029
  schema.size,
3030
3030
  projectRoot
3031
3031
  );
@@ -3067,7 +3067,7 @@ async function handleVerifyChain(server, { collection, mode }) {
3067
3067
  refsBroken,
3068
3068
  fixesApplied: fixes.length,
3069
3069
  ...fixRefusals.length > 0 ? { fixesRefused: fixRefusals.length, coherencyRefusals: fixRefusals } : {},
3070
- mode
3070
+ mode: mode2
3071
3071
  }
3072
3072
  )
3073
3073
  };
@@ -4931,11 +4931,11 @@ function registerContextTools(server) {
4931
4931
  })
4932
4932
  );
4933
4933
  }
4934
- async function handleGather(server, entryId, task, mode, maxHops, maxResults, strategy = "keyword") {
4934
+ async function handleGather(server, entryId, task, mode2, maxHops, maxResults, strategy = "keyword") {
4935
4935
  if (!entryId && !task) {
4936
4936
  return validationResult("Provide either entryId (graph traversal) or task (auto-load context).");
4937
4937
  }
4938
- if (entryId && mode === "graph") {
4938
+ if (entryId && mode2 === "graph") {
4939
4939
  await server.sendLoggingMessage({
4940
4940
  level: "info",
4941
4941
  data: `Graph traversal for ${entryId} (depth: ${maxHops})...`,
@@ -6813,8 +6813,8 @@ function computeDelta(before, after) {
6813
6813
  if (!beforeSet.has(key)) gapsIntroduced++;
6814
6814
  }
6815
6815
  const netChange = after.totalGaps - before.totalGaps;
6816
- const verdict = netChange < 0 ? "improved" : netChange > 0 ? "degraded" : "unchanged";
6817
- return { before, after, gapsFixed, gapsIntroduced, netChange, verdict };
6816
+ const verdict2 = netChange < 0 ? "improved" : netChange > 0 ? "degraded" : "unchanged";
6817
+ return { before, after, gapsFixed, gapsIntroduced, netChange, verdict: verdict2 };
6818
6818
  }
6819
6819
  function renderCoherenceDelta(delta) {
6820
6820
  const lines = ["### Coherence Delta"];
@@ -7270,13 +7270,13 @@ function getCollectionLabel(canonicalKey, form, workspaceCtx, collectionCtx) {
7270
7270
  // src/tools/orient.ts
7271
7271
  var PURPOSE_GAP_PREFIX = "purpose-gap-";
7272
7272
  var READINESS_GAPS_MAX = 50;
7273
- function formatRetrievalMissLines(verdict) {
7273
+ function formatRetrievalMissLines(verdict2) {
7274
7274
  const lines = [];
7275
- if (verdict.served !== "ok") {
7276
- if (verdict.served === "miss") {
7277
- lines.push(`\u26A0 RETRIEVAL MISS \u2014 ${verdict.kind ?? "unknown"}`);
7275
+ if (verdict2.served !== "ok") {
7276
+ if (verdict2.served === "miss") {
7277
+ lines.push(`\u26A0 RETRIEVAL MISS \u2014 ${verdict2.kind ?? "unknown"}`);
7278
7278
  } else {
7279
- lines.push(`\xB7 weak serve (provisional, ${verdict.rubricVersion}): ${verdict.kind ?? "thin"}`);
7279
+ lines.push(`\xB7 weak serve (provisional, ${verdict2.rubricVersion}): ${verdict2.kind ?? "thin"}`);
7280
7280
  }
7281
7281
  }
7282
7282
  return lines;
@@ -7357,19 +7357,19 @@ function registerOrientTool(server) {
7357
7357
  thinWrapper(async (args) => {
7358
7358
  const parsed = parseOrFail(orientSchema, args);
7359
7359
  if (!parsed.ok) return parsed.result;
7360
- const { action, mode, tier, task, startupSignals, invocationPath } = parsed.data;
7360
+ const { action, mode: mode2, tier, task, startupSignals, invocationPath } = parsed.data;
7361
7361
  return runWithToolContext(
7362
7362
  { tool: "orient", action },
7363
- () => _handleOrient({ mode, tier, task, startupSignals, invocationPath })
7363
+ () => _handleOrient({ mode: mode2, tier, task, startupSignals, invocationPath })
7364
7364
  );
7365
7365
  })
7366
7366
  );
7367
7367
  }
7368
- async function _handleOrient({ mode = "full", tier, task, startupSignals, invocationPath }) {
7368
+ async function _handleOrient({ mode: mode2 = "full", tier, task, startupSignals, invocationPath }) {
7369
7369
  const errors = [];
7370
- const callTier = tier ?? (mode === "brief" ? "summary" : void 0);
7370
+ const callTier = tier ?? (mode2 === "brief" ? "summary" : void 0);
7371
7371
  const agentSessionId = getAgentSessionId();
7372
- if (isSessionOriented() && mode === "brief" && !task) {
7372
+ if (isSessionOriented() && mode2 === "brief" && !task) {
7373
7373
  return buildAlreadyOrientedResult(kernelQuery, agentSessionId, taskGroundingWarningLines());
7374
7374
  }
7375
7375
  let wsCtx = null;
@@ -7468,7 +7468,7 @@ async function _handleOrient({ mode = "full", tier, task, startupSignals, invoca
7468
7468
  lines.push(...retrievalMissLines);
7469
7469
  lines.push("");
7470
7470
  }
7471
- if (mode === "brief") {
7471
+ if (mode2 === "brief") {
7472
7472
  lines.push(...buildOrientBriefingLines(orientView));
7473
7473
  if (orientView?.strategicContext) {
7474
7474
  const sc = orientView.strategicContext;
@@ -9721,7 +9721,7 @@ async function handleSpineCheck(story, refresh = false) {
9721
9721
  })
9722
9722
  };
9723
9723
  }
9724
- const { verdict } = parsed;
9724
+ const { verdict: verdict2 } = parsed;
9725
9725
  const lines = ["## Spine Check"];
9726
9726
  if (stillRunning) {
9727
9727
  lines.push(`> A new check was just triggered and is still running asynchronously \u2014 the result below is from the PREVIOUS run (${new Date(row.createdAt).toISOString()}). Re-run in a few seconds for the fresh result.`, "");
@@ -9731,7 +9731,7 @@ async function handleSpineCheck(story, refresh = false) {
9731
9731
  if (row.stale) {
9732
9732
  lines.push(`> STALE \u2014 ${staleReason}.${stillRunning || scheduleResult.reason === "already-in-flight" ? "" : " Pass refresh:true to recompute."}`, "");
9733
9733
  }
9734
- const s = verdict.structural;
9734
+ const s = verdict2.structural;
9735
9735
  lines.push(`Structural completeness: ${s.passed ? "PASS" : "FAIL"}`);
9736
9736
  if (s.missing.length > 0) lines.push(`Missing: ${s.missing.join(", ")}`);
9737
9737
  if (s.duplicateSingletons.purpose) lines.push(`Duplicate purpose singletons (which is canonical?): ${s.duplicateSingletons.purpose.join(", ")}`);
@@ -9742,19 +9742,19 @@ async function handleSpineCheck(story, refresh = false) {
9742
9742
  }
9743
9743
  if (s.visionConnectedToPurpose === false) lines.push("No vision informs any purpose.");
9744
9744
  if (s.visionPurposeConnectivityTruncated) lines.push("Vision\u2192purpose connectivity unknown (relation set truncated).");
9745
- if (verdict.strategiesTruncated) lines.push("Strategy set truncated \u2014 not every strategy was graded this pass.");
9746
- if (verdict.perStrategyEvaluationTruncated) lines.push("Per-strategy evaluation stopped on the wall-clock budget \u2014 not every fetched strategy was graded this pass.");
9747
- if (verdict.perStrategy.length > 0) {
9748
- lines.push("", `Per-strategy refusal heuristic (${verdict.perStrategy.length}):`);
9749
- for (const p of verdict.perStrategy) {
9745
+ if (verdict2.strategiesTruncated) lines.push("Strategy set truncated \u2014 not every strategy was graded this pass.");
9746
+ if (verdict2.perStrategyEvaluationTruncated) lines.push("Per-strategy evaluation stopped on the wall-clock budget \u2014 not every fetched strategy was graded this pass.");
9747
+ if (verdict2.perStrategy.length > 0) {
9748
+ lines.push("", `Per-strategy refusal heuristic (${verdict2.perStrategy.length}):`);
9749
+ for (const p of verdict2.perStrategy) {
9750
9750
  const refusal = p.refusal.hasRefusalSignal ? "names an explicit alternative it declines" : "no explicit refusal language detected";
9751
9751
  const rm = p.rogerMartin ? `; Roger Martin test: ${p.rogerMartin.isStrategicChoice ? "genuine strategic choice" : "NOT a genuine strategic choice"}` : "; Roger Martin test: FAILED TO EVALUATE (timeout, budget limit, or malformed response) \u2014 not scored";
9752
9752
  lines.push(`- ${p.entryId}: ${refusal}${rm}`);
9753
9753
  }
9754
9754
  }
9755
- if (verdict.story) {
9756
- lines.push("", `One-story judgment [unvalidated, on-demand]: ${verdict.story.passed ? "PASS" : "FAIL"}`);
9757
- if (!verdict.story.passed && verdict.story.failedCriterion) lines.push(`Failed criterion: ${verdict.story.failedCriterion}`);
9755
+ if (verdict2.story) {
9756
+ lines.push("", `One-story judgment [unvalidated, on-demand]: ${verdict2.story.passed ? "PASS" : "FAIL"}`);
9757
+ if (!verdict2.story.passed && verdict2.story.failedCriterion) lines.push(`Failed criterion: ${verdict2.story.failedCriterion}`);
9758
9758
  } else if (row.includesStoryPass) {
9759
9759
  lines.push("", "One-story judgment: requested, but the LLM pass did not return a usable result (timeout or parse failure). Run quality action=spine-check story=true refresh=true to retry \u2014 a plain re-run will not reschedule it.");
9760
9760
  } else {
@@ -9763,12 +9763,12 @@ async function handleSpineCheck(story, refresh = false) {
9763
9763
  return {
9764
9764
  content: [{ type: "text", text: lines.join("\n") }],
9765
9765
  structuredContent: success(
9766
- `Spine check: structural ${s.passed ? "PASS" : "FAIL"}${verdict.story ? `, story ${verdict.story.passed ? "PASS" : "FAIL"} [unvalidated]` : ""}${stillRunning ? " (new run still in progress \u2014 showing previous result)" : ""}.`,
9766
+ `Spine check: structural ${s.passed ? "PASS" : "FAIL"}${verdict2.story ? `, story ${verdict2.story.passed ? "PASS" : "FAIL"} [unvalidated]` : ""}${stillRunning ? " (new run still in progress \u2014 showing previous result)" : ""}.`,
9767
9767
  {
9768
9768
  hasVerdict: true,
9769
9769
  noSpineEntries: false,
9770
9770
  structuralPassed: s.passed,
9771
- storyPassed: verdict.story?.passed ?? null,
9771
+ storyPassed: verdict2.story?.passed ?? null,
9772
9772
  ...freshnessData,
9773
9773
  stillRunning,
9774
9774
  scheduled: scheduleResult.scheduled,
@@ -9897,8 +9897,8 @@ Entry \`${entryId}\` not found. Use \`search\` to find the right ID.`,
9897
9897
  [{ tool: "search", description: "Find the entry", parameters: { query: entryId } }]
9898
9898
  );
9899
9899
  }
9900
- const verdict = res.verdict;
9901
- if (!verdict) {
9900
+ const verdict2 = res.verdict;
9901
+ if (!verdict2) {
9902
9902
  const lines2 = [
9903
9903
  `# Quality Check: ${entryId}`,
9904
9904
  "",
@@ -9911,7 +9911,7 @@ Entry \`${entryId}\` not found. Use \`search\` to find the right ID.`,
9911
9911
  [{ tool: "quality", description: "Evaluate now", parameters: { action: "re-evaluate", entryId } }]
9912
9912
  );
9913
9913
  }
9914
- const criteria = verdict.criteria ?? [];
9914
+ const criteria = verdict2.criteria ?? [];
9915
9915
  const lines = [`# Quality Check: ${entryId}`, ""];
9916
9916
  const staleWhy = res.staleReason === "rubric_removed" ? "this entry type is no longer graded" : res.staleReason === "methodology_changed_since_judged" ? "the rubric changed since it was judged" : "the entry was edited since it was judged";
9917
9917
  if (res.stale) {
@@ -9921,35 +9921,35 @@ Entry \`${entryId}\` not found. Use \`search\` to find the right ID.`,
9921
9921
  );
9922
9922
  }
9923
9923
  if (!res.stale) {
9924
- const verdictSection = formatRubricVerdictSection(verdict);
9925
- lines.push(verdictSection || `Verdict tier \`${verdict.tier ?? "unknown"}\` for \`${entryId}\` \u2014 no rubric criteria to report.`);
9924
+ const verdictSection = formatRubricVerdictSection(verdict2);
9925
+ lines.push(verdictSection || `Verdict tier \`${verdict2.tier ?? "unknown"}\` for \`${entryId}\` \u2014 no rubric criteria to report.`);
9926
9926
  }
9927
9927
  try {
9928
9928
  const wsForTracking = await getWorkspaceContext();
9929
9929
  trackQualityCheck(wsForTracking.workspaceId, {
9930
9930
  entry_id: entryId,
9931
- entry_type: verdict.canonicalKey ?? "",
9932
- tier: verdict.tier ?? "",
9933
- passed: verdict.passed ?? false,
9934
- source: verdict.source ?? "",
9935
- llm_status: verdict.llmStatus,
9936
- llm_duration_ms: verdict.llmDurationMs,
9937
- llm_error: verdict.llmError,
9938
- has_roger_martin: !!verdict.rogerMartin
9931
+ entry_type: verdict2.canonicalKey ?? "",
9932
+ tier: verdict2.tier ?? "",
9933
+ passed: verdict2.passed ?? false,
9934
+ source: verdict2.source ?? "",
9935
+ llm_status: verdict2.llmStatus,
9936
+ llm_duration_ms: verdict2.llmDurationMs,
9937
+ llm_error: verdict2.llmError,
9938
+ has_roger_martin: !!verdict2.rogerMartin
9939
9939
  });
9940
9940
  } catch {
9941
9941
  }
9942
9942
  const passedCount = criteria.filter((c) => c.passed).length;
9943
9943
  return successResult(
9944
9944
  lines.join("\n"),
9945
- res.stale ? `Quality check for ${entryId}: STALE \u2014 ${staleWhy}; re-evaluate for a current one.` : `Quality check for ${entryId}: ${verdict.tier ?? "unknown"} tier, ${passedCount}/${criteria.length} criteria pass.`,
9945
+ res.stale ? `Quality check for ${entryId}: STALE \u2014 ${staleWhy}; re-evaluate for a current one.` : `Quality check for ${entryId}: ${verdict2.tier ?? "unknown"} tier, ${passedCount}/${criteria.length} criteria pass.`,
9946
9946
  {
9947
9947
  entryId,
9948
9948
  entryFound: true,
9949
9949
  hasVerdict: true,
9950
9950
  stale: res.stale ?? false,
9951
- tier: verdict.tier,
9952
- ...res.stale ? {} : { passed: verdict.passed },
9951
+ tier: verdict2.tier,
9952
+ ...res.stale ? {} : { passed: verdict2.passed },
9953
9953
  // TASK-790 (TEN-4407): a hint is failure coaching, so it is shown for a failed criterion
9954
9954
  // only, the same rule the text renders by (lib/rubricFormatting.ts).
9955
9955
  criteria: res.stale ? [] : criteria.map((c) => c.passed ? { id: c.id, passed: true } : { id: c.id, passed: false, hint: c.hint })
@@ -10103,10 +10103,10 @@ async function runWrapupReview() {
10103
10103
  lines.push("| Entry | Collection | Quality | Connections | Coaching |");
10104
10104
  lines.push("|-------|------------|---------|-------------|----------|");
10105
10105
  for (const draft of data.drafts) {
10106
- const verdict = data.qualityVerdicts[draft.entryId];
10106
+ const verdict2 = data.qualityVerdicts[draft.entryId];
10107
10107
  const conns = data.connectionCounts[draft.entryId] ?? 0;
10108
- const qualityStr = verdict ? `${verdict.passed ? "Pass" : "Needs work"} (${verdict.source})` : "\u2014";
10109
- const weakest = verdict?.weakest;
10108
+ const qualityStr = verdict2 ? `${verdict2.passed ? "Pass" : "Needs work"} (${verdict2.source})` : "\u2014";
10109
+ const weakest = verdict2?.weakest;
10110
10110
  const coaching = weakest ? weakest.hint : "\u2014";
10111
10111
  lines.push(`| \`${draft.entryId}\` ${draft.name} | ${draft.collection} | ${qualityStr} | ${conns} | ${coaching} |`);
10112
10112
  }
@@ -11819,27 +11819,82 @@ function registerFeedbackTool(server) {
11819
11819
  }));
11820
11820
  }
11821
11821
 
11822
- // src/tools/question.ts
11822
+ // src/tools/conflicts.ts
11823
11823
  import { z as z31 } from "zod/v3";
11824
+ var ACTIONS = ["list", "resolve"];
11825
+ var mode = z31.enum(["actionable", "all"]);
11826
+ var verdict = z31.enum(["real", "noise"]);
11827
+ var conflictsSchema = z31.object({
11828
+ action: z31.enum(ACTIONS),
11829
+ mode: mode.optional().describe("list: all adds judged and snoozed rows."),
11830
+ issueId: z31.string().max(200).optional().describe("resolve: an id from list."),
11831
+ verdict: verdict.optional().describe("resolve: real keeps the row open; noise closes it.")
11832
+ });
11833
+ var conflictsActionUnion = z31.discriminatedUnion("action", [
11834
+ z31.object({ action: z31.literal("list"), mode: mode.optional() }),
11835
+ z31.object({ action: z31.literal("resolve"), issueId: z31.string().min(1).max(200), verdict })
11836
+ ]);
11837
+ var CONFLICTS_ACTION_SPECS = {
11838
+ list: { params: ["mode"], description: "mode defaults to actionable." },
11839
+ resolve: { params: ["issueId", "verdict"], description: "issueId and verdict are required." }
11840
+ };
11841
+ async function handleConflictsList(listMode = "actionable") {
11842
+ const now = Math.floor(Date.now() / 6e4) * 6e4;
11843
+ const rows = await kernelCall("conflicts.list", { mode: listMode, now });
11844
+ const side = (name, id) => `${sanitizeSingleLineField(name)} (${id ? sanitizeSingleLineField(id) : "gone"})`;
11845
+ const lines = rows.map((r) => `${r.id} \xB7 ${side(r.entryAName, r.entryAId)} \u2194 ${side(r.entryBName, r.entryBId)} \xB7 ${r.conflictType} ${r.confidence.toFixed(2)} \xB7 ${sanitizeSingleLineField(r.explanation)}` + (r.guidance ? ` \xB7 ${sanitizeSingleLineField(r.guidance)}` : ""));
11846
+ const truncated = rows[0]?.listTruncated === true;
11847
+ const count = `${rows.length}${truncated ? "+" : ""} contradiction${rows.length === 1 && !truncated ? "" : "s"}`;
11848
+ const summary = rows.length === 0 ? listMode === "all" ? "No open contradictions." : "No contradictions await your verdict. mode=all shows judged and snoozed rows." : listMode === "all" ? `${count} open, judged and snoozed included.` : `${count}. Resolve one: conflicts action=resolve issueId=<id> verdict=real|noise`;
11849
+ return successResult([summary, ...lines].join("\n"), summary, { mode: listMode, rows });
11850
+ }
11851
+ async function handleConflictsResolve(issueId, word) {
11852
+ requireWriteAccess();
11853
+ const result2 = await kernelCall("conflicts.resolve", {
11854
+ issueId,
11855
+ verdict: word === "noise" ? "false_alarm" : "real"
11856
+ });
11857
+ const message = word === "real" ? "Verdict recorded: real. The row stays open until one entry changes." : "Verdict recorded: noise. The row is closed.";
11858
+ return successResult(message, message, { issueId, verdict: word, result: result2 });
11859
+ }
11860
+ function registerConflictsTool(server) {
11861
+ const handlers = {
11862
+ list: (data) => handleConflictsList(data.mode),
11863
+ resolve: (data) => handleConflictsResolve(data.issueId, data.verdict)
11864
+ };
11865
+ server.registerTool("conflicts", {
11866
+ title: "Conflicts",
11867
+ description: "Contradictions found between entries: list them, or resolve one as real or noise.",
11868
+ inputSchema: conflictsSchema,
11869
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }
11870
+ }, thinWrapper(async (args) => {
11871
+ const parsed = parseOrFail(conflictsSchema, args);
11872
+ if (!parsed.ok) return parsed.result;
11873
+ return runWithToolContext({ tool: "conflicts", action: parsed.data.action }, () => dispatchDiscriminated("conflicts", conflictsActionUnion, parsed.data, CONFLICTS_ACTION_SPECS, handlers));
11874
+ }));
11875
+ }
11876
+
11877
+ // src/tools/question.ts
11878
+ import { z as z32 } from "zod/v3";
11824
11879
  var QUESTION_ACTIONS = ["create", "assign", "answer", "force-close", "list"];
11825
- var questionSchema = z31.object({
11826
- action: z31.enum(QUESTION_ACTIONS).describe(
11880
+ var questionSchema = z32.object({
11881
+ action: z32.enum(QUESTION_ACTIONS).describe(
11827
11882
  "'create': create a new routed question from text \u2014 the dedicated birth action; every question is born escalated to the team lead (generic entry creation and move-and-retype also pair a routing facet). 'assign': reassign ownership to a role (toRole required \u2014 no bare self-confirm, no toPerson). 'answer': close the loop \u2014 writes the answer on the question and moves it to answered; --entry links an existing decision instead. 'force-close': Team-Lead-only escape hatch \u2014 reason required. 'list': the ack-gate read model \u2014 what you owe (or, with mine:true, every question you asked, including closed ones)."
11828
11883
  ),
11829
- entryId: z31.string().max(200).optional().describe("Target question's id (human TEN-nnn form or a raw entry id). Required for every action except 'create'/'list'."),
11830
- text: z31.string().max(5e3).optional().describe("'create': the question text. 'answer': the answer text (mutually exclusive with answerEntryId, max 2000 chars)."),
11831
- blocks: z31.array(z31.string().max(200)).max(50).optional().describe("'create': entry ids this question is blocking (repeatable)."),
11832
- toRole: z31.string().max(200).optional().describe("'assign': reassign to this role (human ROL-nnn form or a raw entry id) \u2014 required."),
11833
- reason: z31.string().max(2e3).optional().describe("'force-close': required reason."),
11834
- answerEntryId: z31.string().max(200).optional().describe("'answer': point at an already-written entry instead of supplying text (mutually exclusive with text)."),
11835
- mine: z31.boolean().optional().describe("'list': true for arm C (every question YOU asked, every status). Omit/false for the ack-gate view (what you owe).")
11884
+ entryId: z32.string().max(200).optional().describe("Target question's id (human TEN-nnn form or a raw entry id). Required for every action except 'create'/'list'."),
11885
+ text: z32.string().max(5e3).optional().describe("'create': the question text. 'answer': the answer text (mutually exclusive with answerEntryId, max 2000 chars)."),
11886
+ blocks: z32.array(z32.string().max(200)).max(50).optional().describe("'create': entry ids this question is blocking (repeatable)."),
11887
+ toRole: z32.string().max(200).optional().describe("'assign': reassign to this role (human ROL-nnn form or a raw entry id) \u2014 required."),
11888
+ reason: z32.string().max(2e3).optional().describe("'force-close': required reason."),
11889
+ answerEntryId: z32.string().max(200).optional().describe("'answer': point at an already-written entry instead of supplying text (mutually exclusive with text)."),
11890
+ mine: z32.boolean().optional().describe("'list': true for arm C (every question YOU asked, every status). Omit/false for the ack-gate view (what you owe).")
11836
11891
  });
11837
- var createVariant = z31.object({ action: z31.literal("create"), text: z31.string().min(1).max(5e3), blocks: z31.array(z31.string().max(200)).max(50).optional() });
11838
- var assignVariant = z31.object({ action: z31.literal("assign"), entryId: z31.string().max(200), toRole: z31.string().max(200).min(1) });
11839
- var answerVariant = z31.object({ action: z31.literal("answer"), entryId: z31.string().max(200), text: z31.string().max(2e3).optional(), answerEntryId: z31.string().max(200).optional() });
11840
- var forceCloseVariant = z31.object({ action: z31.literal("force-close"), entryId: z31.string().max(200), reason: z31.string().min(1).max(2e3) });
11841
- var listVariant = z31.object({ action: z31.literal("list"), mine: z31.boolean().optional() });
11842
- var questionActionUnion = z31.discriminatedUnion("action", [
11892
+ var createVariant = z32.object({ action: z32.literal("create"), text: z32.string().min(1).max(5e3), blocks: z32.array(z32.string().max(200)).max(50).optional() });
11893
+ var assignVariant = z32.object({ action: z32.literal("assign"), entryId: z32.string().max(200), toRole: z32.string().max(200).min(1) });
11894
+ var answerVariant = z32.object({ action: z32.literal("answer"), entryId: z32.string().max(200), text: z32.string().max(2e3).optional(), answerEntryId: z32.string().max(200).optional() });
11895
+ var forceCloseVariant = z32.object({ action: z32.literal("force-close"), entryId: z32.string().max(200), reason: z32.string().min(1).max(2e3) });
11896
+ var listVariant = z32.object({ action: z32.literal("list"), mine: z32.boolean().optional() });
11897
+ var questionActionUnion = z32.discriminatedUnion("action", [
11843
11898
  createVariant,
11844
11899
  assignVariant,
11845
11900
  answerVariant,
@@ -11993,52 +12048,52 @@ function registerQuestionTools(server) {
11993
12048
  }
11994
12049
 
11995
12050
  // src/tools/role.ts
11996
- import { z as z32 } from "zod/v3";
12051
+ import { z as z33 } from "zod/v3";
11997
12052
  var ROLE_ACTIONS = ["accountable", "seat", "unseat", "release_move", "accept_move", "refuse_move"];
11998
- var roleSchema = z32.object({
11999
- action: z32.enum(ROLE_ACTIONS).describe(
12053
+ var roleSchema = z33.object({
12054
+ action: z33.enum(ROLE_ACTIONS).describe(
12000
12055
  "'accountable': what this role owns (explicit), reports on (reporting), and \u2014 not yet computed \u2014 inherits via Team-Lead vacancy coverage. 'seat': put a person in this role. 'unseat': take this role from a person. 'release_move' / 'accept_move' / 'refuse_move': move a role or team to a team with another Team Lead."
12001
12056
  ),
12002
- roleId: z32.string().max(200).optional().describe("The role, by the human chain id `chain.getEntry` or `pb get` would print for it, or a raw entry id."),
12003
- canonicalKey: z32.string().max(200).optional().describe("'accountable': narrow to one kind (e.g. objective, key_result, tension)."),
12004
- limit: z32.number().int().positive().max(200).optional().describe("'accountable': max explicit-list rows per page (default and maximum 200)."),
12005
- cursor: z32.number().optional().describe("'accountable': continue the explicit list from an earlier truncated page's nextCursor."),
12006
- person: z32.string().max(200).optional().describe(
12057
+ roleId: z33.string().max(200).optional().describe("The role, by the human chain id `chain.getEntry` or `pb get` would print for it, or a raw entry id."),
12058
+ canonicalKey: z33.string().max(200).optional().describe("'accountable': narrow to one kind (e.g. objective, key_result, tension)."),
12059
+ limit: z33.number().int().positive().max(200).optional().describe("'accountable': max explicit-list rows per page (default and maximum 200)."),
12060
+ cursor: z33.number().optional().describe("'accountable': continue the explicit list from an earlier truncated page's nextCursor."),
12061
+ person: z33.string().max(200).optional().describe(
12007
12062
  "'seat' / 'unseat': an existing person, by person id or exact email. For 'seat', give this or newPersonName, not both."
12008
12063
  ),
12009
- newPersonName: z32.string().max(120).optional().describe(
12064
+ newPersonName: z33.string().max(120).optional().describe(
12010
12065
  "'seat': the name of a person who has no login yet; a placeholder person is created once and reused for the same exact name. Refused when the name belongs to someone with an account."
12011
12066
  ),
12012
- teamId: z32.string().max(200).optional().describe(
12067
+ teamId: z33.string().max(200).optional().describe(
12013
12068
  "'seat' / 'unseat': the team, by chain id or entry id. Only needed for Team Lead, which lives in every team; any other role is seated in its home team. 'release_move': the team it moves to."
12014
12069
  ),
12015
- childId: z32.string().max(200).optional().describe("'release_move' / 'accept_move' / 'refuse_move': the role or team that moves, by chain id or entry id."),
12016
- why: z32.string().max(1e3).optional().describe("'refuse_move': why the move is refused; it becomes a tension for the old team's Team Lead.")
12070
+ childId: z33.string().max(200).optional().describe("'release_move' / 'accept_move' / 'refuse_move': the role or team that moves, by chain id or entry id."),
12071
+ why: z33.string().max(1e3).optional().describe("'refuse_move': why the move is refused; it becomes a tension for the old team's Team Lead.")
12017
12072
  });
12018
- var accountableVariant = z32.object({
12019
- action: z32.literal("accountable"),
12020
- roleId: z32.string().max(200),
12021
- canonicalKey: z32.string().max(200).optional(),
12022
- limit: z32.number().int().positive().max(200).optional(),
12023
- cursor: z32.number().optional()
12073
+ var accountableVariant = z33.object({
12074
+ action: z33.literal("accountable"),
12075
+ roleId: z33.string().max(200),
12076
+ canonicalKey: z33.string().max(200).optional(),
12077
+ limit: z33.number().int().positive().max(200).optional(),
12078
+ cursor: z33.number().optional()
12024
12079
  });
12025
- var seatVariant = z32.object({
12026
- action: z32.literal("seat"),
12027
- roleId: z32.string().max(200),
12028
- person: z32.string().max(200).optional(),
12029
- newPersonName: z32.string().max(120).optional(),
12030
- teamId: z32.string().max(200).optional()
12080
+ var seatVariant = z33.object({
12081
+ action: z33.literal("seat"),
12082
+ roleId: z33.string().max(200),
12083
+ person: z33.string().max(200).optional(),
12084
+ newPersonName: z33.string().max(120).optional(),
12085
+ teamId: z33.string().max(200).optional()
12031
12086
  });
12032
- var unseatVariant = z32.object({
12033
- action: z32.literal("unseat"),
12034
- roleId: z32.string().max(200),
12035
- person: z32.string().max(200),
12036
- teamId: z32.string().max(200).optional()
12087
+ var unseatVariant = z33.object({
12088
+ action: z33.literal("unseat"),
12089
+ roleId: z33.string().max(200),
12090
+ person: z33.string().max(200),
12091
+ teamId: z33.string().max(200).optional()
12037
12092
  });
12038
- var releaseMoveVariant = z32.object({ action: z32.literal("release_move"), childId: z32.string().max(200), teamId: z32.string().max(200) });
12039
- var acceptMoveVariant = z32.object({ action: z32.literal("accept_move"), childId: z32.string().max(200) });
12040
- var refuseMoveVariant = z32.object({ action: z32.literal("refuse_move"), childId: z32.string().max(200), why: z32.string().max(1e3) });
12041
- var roleActionUnion = z32.discriminatedUnion("action", [
12093
+ var releaseMoveVariant = z33.object({ action: z33.literal("release_move"), childId: z33.string().max(200), teamId: z33.string().max(200) });
12094
+ var acceptMoveVariant = z33.object({ action: z33.literal("accept_move"), childId: z33.string().max(200) });
12095
+ var refuseMoveVariant = z33.object({ action: z33.literal("refuse_move"), childId: z33.string().max(200), why: z33.string().max(1e3) });
12096
+ var roleActionUnion = z33.discriminatedUnion("action", [
12042
12097
  accountableVariant,
12043
12098
  seatVariant,
12044
12099
  unseatVariant,
@@ -12540,7 +12595,7 @@ ${entry.labels.map((l) => `- ${l.name ?? l.slug}`).join("\n")}`);
12540
12595
  }
12541
12596
 
12542
12597
  // src/prompts/index.ts
12543
- import { z as z33 } from "zod/v3";
12598
+ import { z as z34 } from "zod/v3";
12544
12599
  async function buildReviewAgainstRulesPrompt(domain) {
12545
12600
  const entries = await kernelQuery("chain.listEntries", { collectionSlug: "rules" });
12546
12601
  const rules = entries.slice(0, 50);
@@ -12622,27 +12677,27 @@ function registerPrompts(server) {
12622
12677
  server.prompt(
12623
12678
  "review-against-rules",
12624
12679
  "Review code or a design decision against the rules, focused on a given area. Fetches the rules and asks you to do a structured compliance review.",
12625
- { domain: z33.string().describe("Business rule domain (e.g. 'Identity & Access', 'Governance & Decision-Making')") },
12680
+ { domain: z34.string().describe("Business rule domain (e.g. 'Identity & Access', 'Governance & Decision-Making')") },
12626
12681
  async ({ domain }) => buildReviewAgainstRulesPrompt(domain)
12627
12682
  );
12628
12683
  server.prompt(
12629
12684
  "name-check",
12630
12685
  "Check variable names, field names, or API names against the glossary for terminology alignment. Flags drift from canonical terms.",
12631
- { names: z33.string().describe("Comma-separated list of names to check (e.g. 'user_id, workspace_id, entry_status')") },
12686
+ { names: z34.string().describe("Comma-separated list of names to check (e.g. 'user_id, workspace_id, entry_status')") },
12632
12687
  async ({ names }) => buildNameCheckPrompt(names)
12633
12688
  );
12634
12689
  server.prompt(
12635
12690
  "draft-decision-record",
12636
12691
  "Draft a structured decision record from a description of what was decided. Includes context from recent decisions and relevant rules.",
12637
- { context: z33.string().describe("Description of the decision (e.g. 'We decided to keep one body field per entry because...')") },
12692
+ { context: z34.string().describe("Description of the decision (e.g. 'We decided to keep one body field per entry because...')") },
12638
12693
  async ({ context }) => buildDraftDecisionRecordPrompt(context)
12639
12694
  );
12640
12695
  server.prompt(
12641
12696
  "draft-rule-from-context",
12642
12697
  "Draft a new business rule from an observation or discovery made while coding. Fetches existing rules for the domain to ensure consistency.",
12643
12698
  {
12644
- observation: z33.string().describe("What you observed or discovered (e.g. 'A workspace can have more than one owner role')"),
12645
- domain: z33.string().describe("Which domain this rule belongs to (e.g. 'Governance & Decision-Making')")
12699
+ observation: z34.string().describe("What you observed or discovered (e.g. 'A workspace can have more than one owner role')"),
12700
+ domain: z34.string().describe("Which domain this rule belongs to (e.g. 'Governance & Decision-Making')")
12646
12701
  },
12647
12702
  async ({ observation, domain }) => buildDraftRuleFromContextPrompt(observation, domain)
12648
12703
  );
@@ -12738,7 +12793,7 @@ var INSTRUCTIONS = [
12738
12793
  "Finish with `session action=wrapup-review`, then `session action=close`.",
12739
12794
  "If the work falls outside the active work packages, name the gap and ask the user before designing it."
12740
12795
  ].join("\n");
12741
- var sessionIdArg = z34.string().max(200).optional().describe(
12796
+ var sessionIdArg = z35.string().max(200).optional().describe(
12742
12797
  "The sessionId `session action=start` returned. Pass it on every write: the connection does not remember your session between calls."
12743
12798
  );
12744
12799
  function acceptSessionIdOnEveryTool(server) {
@@ -12792,6 +12847,7 @@ function createProductBrainServer() {
12792
12847
  registerWorkflowTools(server);
12793
12848
  registerWorkspaceTools(server);
12794
12849
  registerFeedbackTool(server);
12850
+ registerConflictsTool(server);
12795
12851
  registerQuestionTools(server);
12796
12852
  registerRoleTools(server);
12797
12853
  registerPeopleTools(server);
@@ -12832,4 +12888,4 @@ export {
12832
12888
  createProductBrainServer,
12833
12889
  initFeatureFlags
12834
12890
  };
12835
- //# sourceMappingURL=chunk-JE3PDGWH.js.map
12891
+ //# sourceMappingURL=chunk-WD7EUIF4.js.map