@productbrain/mcp 0.0.1-beta.11288 → 0.0.1-beta.11296

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.
@@ -31,17 +31,8 @@ import {
31
31
  runWithSeatedSession,
32
32
  runWithToolContext,
33
33
  setSessionOriented,
34
- startAgentSession,
35
- trackCaptureContractMiss,
36
- trackCaptureQualityHints,
37
- trackChainEntryCommitted,
38
- trackCommitErrorByCode,
39
- trackKnowledgeGap,
40
- trackQualityCheck,
41
- trackQualityVerdict,
42
- trackSessionCaptureRate,
43
- trackZeroCaptureAuditFired
44
- } from "./chunk-GQCZUKKL.js";
34
+ startAgentSession
35
+ } from "./chunk-XAFCPBXE.js";
45
36
 
46
37
  // src/server.ts
47
38
  import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -535,10 +526,9 @@ function recordGap(gap) {
535
526
  const timestamped = { ...gap, timestamp: Date.now() };
536
527
  const sessionKey = currentSessionKey();
537
528
  const gaps = getGapsForSession(sessionKey);
538
- if (isDuplicate(gaps, timestamped)) return false;
529
+ if (isDuplicate(gaps, timestamped)) return;
539
530
  gaps.push(timestamped);
540
531
  persistGap(gap);
541
- return true;
542
532
  }
543
533
  function persistGap(gap) {
544
534
  const sessionId = getAgentSessionId();
@@ -1235,35 +1225,7 @@ Use \`context action=get\` to inspect the existing entry, or \`entries action=up
1235
1225
  if (verdictResult?.verdict && verdictResult.verdict.tier !== "passive" && verdictResult.verdict.criteria.length > 0) {
1236
1226
  coachingSection = formatRubricCoaching(verdictResult);
1237
1227
  }
1238
- if (verdictResult?.verdict) {
1239
- try {
1240
- const v = verdictResult.verdict;
1241
- const failedCount = (v.criteria ?? []).filter((c) => !c.passed).length;
1242
- trackQualityVerdict(wsCtx.workspaceId, {
1243
- entry_id: finalEntryId,
1244
- entry_type: v.canonicalKey ?? landedCollection,
1245
- tier: v.tier,
1246
- context: "capture",
1247
- passed: v.passed,
1248
- source: verdictResult.source ?? "heuristic",
1249
- criteria_total: v.criteria?.length ?? 0,
1250
- criteria_failed: failedCount,
1251
- llm_scheduled: v.tier !== "passive",
1252
- methodology_version: v.methodologyVersion
1253
- });
1254
- } catch {
1255
- }
1256
- }
1257
- let finalStatus = "draft";
1258
- if (wasAutoCommittedServerSide) {
1259
- finalStatus = "committed";
1260
- trackChainEntryCommitted(wsCtx.workspaceId, {
1261
- entry_id: finalEntryId,
1262
- collection: landedCollection,
1263
- commit_method: "auto",
1264
- surface: "mcp_capture"
1265
- });
1266
- }
1228
+ const finalStatus = wasAutoCommittedServerSide ? "committed" : "draft";
1267
1229
  const lines = [
1268
1230
  `# Captured: ${finalEntryId || name}`,
1269
1231
  `**${name}** added to \`${landedCollection}\` as \`${finalStatus}\``,
@@ -1303,13 +1265,6 @@ Use \`context action=get\` to inspect the existing entry, or \`entries action=up
1303
1265
  }
1304
1266
  lines.push(`_These hints are advisory \u2014 your entry was captured. Use \`entries action=update entryId="${finalEntryId}"\` to address them._`);
1305
1267
  }
1306
- if (formativeHints.length > 0) {
1307
- trackCaptureQualityHints(wsCtx.workspaceId, {
1308
- collection: landedCollection,
1309
- hint_count: formativeHints.length,
1310
- hint_fields: formativeHints.map((h) => h.field)
1311
- });
1312
- }
1313
1268
  if (entryWarnings.length > 0) {
1314
1269
  lines.push("");
1315
1270
  lines.push("## Validation Warnings");
@@ -1798,36 +1753,17 @@ async function handleCommitEntry({ entryId, preview, steeringOverrideReason, qua
1798
1753
  );
1799
1754
  const stored = judgeWait?.latest?.verdict;
1800
1755
  const coachingResult = stored ? { verdict: stored, source: stored.source } : judgeWait?.evaluation ?? null;
1801
- let result2;
1802
- try {
1803
- result2 = await kernelMutation("chain.commitEntry", {
1804
- entryId,
1805
- author: getAgentSessionId() ? `agent:${getAgentSessionId()}` : void 0,
1806
- sessionId: getAgentSessionId() ?? void 0,
1807
- ...preview ? { preview: true } : {},
1808
- ...steeringOverrideReason ? { steeringOverrideReason } : {},
1809
- ...qualityOverrideReason ? { qualityOverrideReason } : {},
1810
- // TASK-954
1811
- ...coherencyAcknowledgement ? { coherencyAcknowledgement } : {},
1812
- ...conflictEvidence.length > 0 ? { conflicts: conflictEvidence } : {}
1813
- });
1814
- } catch (commitErr) {
1815
- const errCode = commitErr?.code;
1816
- if (errCode === "VALIDATION_FAILED") {
1817
- try {
1818
- const wsCtx2 = await getWorkspaceContext();
1819
- const e = commitErr;
1820
- trackCommitErrorByCode(wsCtx2.workspaceId, {
1821
- error_code: errCode,
1822
- missing_field_count: e.missingRequiredFields?.length ?? 0,
1823
- field_error_count: e.fieldErrors?.length ?? 0,
1824
- entry_id: entryId
1825
- });
1826
- } catch {
1827
- }
1828
- }
1829
- throw commitErr;
1830
- }
1756
+ const result2 = await kernelMutation("chain.commitEntry", {
1757
+ entryId,
1758
+ author: getAgentSessionId() ? `agent:${getAgentSessionId()}` : void 0,
1759
+ sessionId: getAgentSessionId() ?? void 0,
1760
+ ...preview ? { preview: true } : {},
1761
+ ...steeringOverrideReason ? { steeringOverrideReason } : {},
1762
+ ...qualityOverrideReason ? { qualityOverrideReason } : {},
1763
+ // TASK-954
1764
+ ...coherencyAcknowledgement ? { coherencyAcknowledgement } : {},
1765
+ ...conflictEvidence.length > 0 ? { conflicts: conflictEvidence } : {}
1766
+ });
1831
1767
  if (result2?.status === "coherency_refused" && result2?.refusal) {
1832
1768
  return coherencyRefusedResult(`${toolName} action=commit`, entryId, result2.refusal);
1833
1769
  }
@@ -1872,13 +1808,6 @@ No DB writes \u2014 call without \`preview:true\` to accept for real.` }],
1872
1808
  const docId = result2?._id ?? entry._id;
1873
1809
  const wsCtx = await getWorkspaceContext();
1874
1810
  await recordSessionActivity({ entryModified: docId });
1875
- const coll = entry.collectionSlug ?? entry.collection?.slug;
1876
- trackChainEntryCommitted(wsCtx.workspaceId, {
1877
- entry_id: entry.entryId ?? entryId,
1878
- collection: coll,
1879
- commit_method: "manual",
1880
- surface: "mcp_commit_tool"
1881
- });
1882
1811
  const judged = judgedAcceptedLine(judgeWait);
1883
1812
  const lines = [
1884
1813
  `# Accepted: ${entryId}`,
@@ -1902,26 +1831,6 @@ No DB writes \u2014 call without \`preview:true\` to accept for real.` }],
1902
1831
  "Run context action=gather on the conflicting entries to review; use entries action=update to reconcile the two, or to mark this entry status='archived' if it's actually superseded."
1903
1832
  );
1904
1833
  }
1905
- if (coachingResult?.verdict) {
1906
- try {
1907
- const v = coachingResult.verdict;
1908
- const failedCount = (v.criteria ?? []).filter((c) => !c.passed).length;
1909
- trackQualityVerdict(wsCtx.workspaceId, {
1910
- entry_id: entryId,
1911
- entry_type: v.canonicalKey ?? entry.canonicalKey ?? "",
1912
- tier: v.tier,
1913
- context: "commit",
1914
- passed: v.passed,
1915
- source: coachingResult.source ?? "heuristic",
1916
- criteria_total: v.criteria?.length ?? 0,
1917
- criteria_failed: failedCount,
1918
- llm_scheduled: judgeWait?.evaluation?.reused !== true && v.tier !== "passive",
1919
- // TASK-612: a reused verdict schedules nothing
1920
- methodology_version: v.methodologyVersion
1921
- });
1922
- } catch {
1923
- }
1924
- }
1925
1834
  if (coachingResult?.verdict && coachingResult.verdict.tier !== "passive" && coachingResult.verdict.criteria.length > 0) {
1926
1835
  const coaching = formatRubricCoaching(coachingResult);
1927
1836
  if (coaching) {
@@ -3032,11 +2941,7 @@ async function handleSearch(server, query, collection, status2) {
3032
2941
  const platform = platformSearchLines(answer2.platform);
3033
2942
  const matches = results.length + platform.count;
3034
2943
  if (matches === 0) {
3035
- const recorded = recordGap({ query, tool: "context", action: "search", gapType: "search_zero", collectionScope: collection });
3036
- if (recorded) {
3037
- getWorkspaceId().then((wsId) => trackKnowledgeGap(wsId, { query, tool: "context", action: "search", gap_type: "search_zero", collection_scope: collection })).catch(() => {
3038
- });
3039
- }
2944
+ recordGap({ query, tool: "context", action: "search", gapType: "search_zero", collectionScope: collection });
3040
2945
  return {
3041
2946
  content: [{
3042
2947
  type: "text",
@@ -4257,11 +4162,7 @@ async function handleGather(server, entryId, task, mode2, maxHops, maxResults, s
4257
4162
  }
4258
4163
  const root2 = result3.root;
4259
4164
  if (result3.context.length === 0) {
4260
- const recorded = recordGap({ query: root2.entryId, tool: "context", action: "gather", gapType: "context_graph_empty" });
4261
- if (recorded) {
4262
- getWorkspaceId().then((wsId) => trackKnowledgeGap(wsId, { query: root2.entryId, tool: "context", action: "gather", gap_type: "context_graph_empty" })).catch(() => {
4263
- });
4264
- }
4165
+ recordGap({ query: root2.entryId, tool: "context", action: "gather", gapType: "context_graph_empty" });
4265
4166
  return {
4266
4167
  content: [{
4267
4168
  type: "text",
@@ -4347,11 +4248,7 @@ Use \`relations action=create\` to link it to the entries it relates to.`
4347
4248
  const shownCount = result3 ? result3.steeringContext.length + result3.supportingContext.length : 0;
4348
4249
  if (!result3 || shownCount === 0) {
4349
4250
  const taskQuery = task.slice(0, 200);
4350
- const recorded = recordGap({ query: taskQuery, tool: "context", action: "gather", gapType: "context_task_empty" });
4351
- if (recorded) {
4352
- getWorkspaceId().then((wsId) => trackKnowledgeGap(wsId, { query: taskQuery, tool: "context", action: "gather", gap_type: "context_task_empty" })).catch(() => {
4353
- });
4354
- }
4251
+ recordGap({ query: taskQuery, tool: "context", action: "gather", gapType: "context_task_empty" });
4355
4252
  return {
4356
4253
  content: [{
4357
4254
  type: "text",
@@ -4489,11 +4386,7 @@ _This helps future sessions start with better constraints and context._`
4489
4386
  }
4490
4387
  const root = result2.root;
4491
4388
  if (result2.related.length === 0) {
4492
- const recorded = recordGap({ query: root.entryId, tool: "context", action: "gather", gapType: "context_entry_isolated" });
4493
- if (recorded) {
4494
- getWorkspaceId().then((wsId) => trackKnowledgeGap(wsId, { query: root.entryId, tool: "context", action: "gather", gap_type: "context_entry_isolated" })).catch(() => {
4495
- });
4496
- }
4389
+ recordGap({ query: root.entryId, tool: "context", action: "gather", gapType: "context_entry_isolated" });
4497
4390
  return {
4498
4391
  content: [{
4499
4392
  type: "text",
@@ -9289,21 +9182,6 @@ Entry \`${entryId}\` not found. Use \`search\` to find the right ID.`,
9289
9182
  const verdictSection = formatRubricVerdictSection(verdict2);
9290
9183
  lines.push(verdictSection || `Verdict tier \`${verdict2.tier ?? "unknown"}\` for \`${entryId}\` \u2014 no rubric criteria to report.`);
9291
9184
  }
9292
- try {
9293
- const wsForTracking = await getWorkspaceContext();
9294
- trackQualityCheck(wsForTracking.workspaceId, {
9295
- entry_id: entryId,
9296
- entry_type: verdict2.canonicalKey ?? "",
9297
- tier: verdict2.tier ?? "",
9298
- passed: verdict2.passed ?? false,
9299
- source: verdict2.source ?? "",
9300
- llm_status: verdict2.llmStatus,
9301
- llm_duration_ms: verdict2.llmDurationMs,
9302
- llm_error: verdict2.llmError,
9303
- has_roger_martin: !!verdict2.rogerMartin
9304
- });
9305
- } catch {
9306
- }
9307
9185
  const passedCount = criteria.filter((c) => c.passed).length;
9308
9186
  return successResult(
9309
9187
  lines.join("\n"),
@@ -9324,7 +9202,6 @@ Entry \`${entryId}\` not found. Use \`search\` to find the right ID.`,
9324
9202
  }
9325
9203
  async function handleReEvaluate(entryId, context) {
9326
9204
  requireWriteAccess();
9327
- const ws = await getWorkspaceContext();
9328
9205
  const result2 = await kernelMutation("quality.reEvaluateEntry", {
9329
9206
  entryId,
9330
9207
  context
@@ -9346,21 +9223,6 @@ async function handleReEvaluate(entryId, context) {
9346
9223
  source: result2.source,
9347
9224
  llmStatus: llmScheduled ? "pending" : "skipped"
9348
9225
  }));
9349
- try {
9350
- trackQualityVerdict(ws.workspaceId, {
9351
- entry_id: entryId,
9352
- entry_type: result2.verdict.canonicalKey ?? "",
9353
- tier: result2.verdict.tier ?? "",
9354
- context,
9355
- passed: result2.verdict.passed ?? false,
9356
- source: "heuristic",
9357
- criteria_total: result2.verdict.criteria?.length ?? 0,
9358
- criteria_failed: result2.verdict.criteria?.filter((c) => !c.passed).length ?? 0,
9359
- llm_scheduled: llmScheduled,
9360
- methodology_version: result2.verdict.methodologyVersion
9361
- });
9362
- } catch {
9363
- }
9364
9226
  const criteria = result2.verdict.criteria ?? [];
9365
9227
  const reEvalScore = criteria.filter((c) => c.passed).length;
9366
9228
  const reEvalMaxScore = criteria.length;
@@ -9590,12 +9452,6 @@ async function runWrapupReview() {
9590
9452
  }
9591
9453
  lines.push("");
9592
9454
  lines.push(`> **${data.closeNudge}**`);
9593
- if (data.captureAudit) {
9594
- const wsCtx = await getWorkspaceContext();
9595
- if (wsCtx) {
9596
- trackZeroCaptureAuditFired(wsCtx.workspaceId);
9597
- }
9598
- }
9599
9455
  const gapCount = getSessionGaps().length;
9600
9456
  return {
9601
9457
  text: lines.join("\n"),
@@ -9614,7 +9470,6 @@ async function runWrapupCommitAll(data) {
9614
9470
  if (!sessionId) {
9615
9471
  return { text: "No active session.", committed: 0, failed: 0, overflowUnscanned: 0 };
9616
9472
  }
9617
- const wsCtx = await getWorkspaceContext();
9618
9473
  const results = [];
9619
9474
  const allDrafts = [...data.drafts, ...data.overflowDrafts ?? []];
9620
9475
  const overflowUnscanned = data.overflowUnscanned ?? 0;
@@ -9635,11 +9490,6 @@ async function runWrapupCommitAll(data) {
9635
9490
  continue;
9636
9491
  }
9637
9492
  await recordSessionActivity({ entryModified: draft.docId });
9638
- trackChainEntryCommitted(wsCtx.workspaceId, {
9639
- entry_id: draft.entryId,
9640
- commit_method: "manual",
9641
- surface: "mcp_wrapup"
9642
- });
9643
9493
  results.push({ entryId: draft.entryId, ok: true });
9644
9494
  } catch (err) {
9645
9495
  const msg = err instanceof Error ? err.message : String(err);
@@ -10313,15 +10163,6 @@ async function handleClose() {
10313
10163
  clearSessionGaps();
10314
10164
  if (!closed) throw new Error("No active agent session to close.");
10315
10165
  const { created, modified, relationsCreated: relations, capturesTruncated, modifiedTruncated, capLine } = closed;
10316
- const wsCtx = await getWorkspaceContext();
10317
- if (wsCtx) {
10318
- trackSessionCaptureRate(wsCtx.workspaceId, {
10319
- entries_created: created,
10320
- entries_modified: modified,
10321
- relations_created: relations,
10322
- had_captures: created > 0
10323
- });
10324
- }
10325
10166
  const lines = [
10326
10167
  `Session ${sessionId} closed.`,
10327
10168
  ""
@@ -11334,7 +11175,7 @@ async function handleQuestionAnswer(entryId, text, answerEntryId) {
11334
11175
  const resolvedAnswerEntryId = answerEntryId ? await resolveEntryRef(answerEntryId, "Answer entry") : void 0;
11335
11176
  const result2 = await kernelMutation("question.answer", { entryId: resolvedEntryId, text, answerEntryId: resolvedAnswerEntryId });
11336
11177
  const askerName = (result2.askerName ? stripControlChars(result2.askerName) : "") || "The asker";
11337
- const message = result2.idempotent ? result2.processedVia === "force_closed" ? `${entryId} is already processed (force-closed) \u2014 no change.` : result2.processedVia === "declined" ? `${entryId} is already processed (declined) \u2014 no change.` : `${entryId} is already answered \u2014 no change.` : `${entryId} is answered. ${askerName} will see the answer at their next session (and in pb question list --mine).`;
11178
+ const message = result2.idempotent ? result2.processedVia === "force_closed" ? `${entryId} is already processed (force-closed) \u2014 no change.` : result2.processedVia === "declined" ? `${entryId} is already processed (declined) \u2014 no change.` : `${entryId} already has this answer \u2014 no change. ${result2.answeredLine ? stripControlChars(result2.answeredLine) : ""}`.trim() : result2.replaced ? `${entryId} is answered again; the previous answer stays in its history. ${askerName} will see the new answer at their next session.` : `${entryId} is answered. ${askerName} will see the answer at their next session (and in pb question list --mine).`;
11338
11179
  return successResult(message, message, result2);
11339
11180
  } catch (err) {
11340
11181
  return questionErrorResult(err, "answer", { entryId, text, answerEntryId });
@@ -11882,12 +11723,6 @@ ${entry.labels.map((l) => `- ${l.name ?? l.slug}`).join("\n")}`);
11882
11723
  }),
11883
11724
  async (uri, { slug }) => {
11884
11725
  const collectionSlug = slug;
11885
- let workspaceId = null;
11886
- try {
11887
- const ctx = await getWorkspaceContext();
11888
- workspaceId = ctx.workspaceId;
11889
- } catch {
11890
- }
11891
11726
  let contract = null;
11892
11727
  try {
11893
11728
  contract = await kernelQuery(
@@ -11898,9 +11733,6 @@ ${entry.labels.map((l) => `- ${l.name ?? l.slug}`).join("\n")}`);
11898
11733
  contract = null;
11899
11734
  }
11900
11735
  if (!contract) {
11901
- if (workspaceId) {
11902
- trackCaptureContractMiss(workspaceId, { slug: collectionSlug });
11903
- }
11904
11736
  return {
11905
11737
  contents: [{
11906
11738
  uri: uri.href,
@@ -12229,4 +12061,4 @@ export {
12229
12061
  SERVER_VERSION,
12230
12062
  createProductBrainServer
12231
12063
  };
12232
- //# sourceMappingURL=chunk-X754OBQP.js.map
12064
+ //# sourceMappingURL=chunk-OHJGWECT.js.map