@productbrain/mcp 0.0.1-beta.6459 → 0.0.1-beta.6461

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.
@@ -847,6 +847,169 @@ async function resolveCollection(params) {
847
847
  return result2 ?? null;
848
848
  }
849
849
 
850
+ // src/tools/coherency-refusal.ts
851
+ function asDescription(value) {
852
+ if (typeof value !== "string") return void 0;
853
+ const trimmed = value.trim();
854
+ return trimmed.length > 0 ? trimmed : void 0;
855
+ }
856
+ var GENERIC_RECOVERY_LINE = "Respond and retry: link the entry to the strategic spine, pass `coherencyAcknowledgement`, or supply a typed `steeringOverrideReason`.";
857
+ function coherencyRefusedResult(toolName, entryId, refusal, options) {
858
+ const headingLevel = options?.headingLevel ?? 1;
859
+ const heading = "#".repeat(headingLevel);
860
+ const lines = [
861
+ `${heading} Write refused by the coherency gate`,
862
+ "",
863
+ refusal.reason ?? `The coherency gate refused this write on ${entryId}.`
864
+ ];
865
+ if (refusal.subject?.name) {
866
+ lines.push(`On: ${refusal.subject.name}`);
867
+ }
868
+ if (refusal.mode) {
869
+ lines.push("", `Mode: ${refusal.mode}`);
870
+ }
871
+ const routes = refusal.routes;
872
+ const routeKeys = routes ? Object.keys(routes) : [];
873
+ if (routeKeys.length > 0) {
874
+ lines.push("", `${"#".repeat(headingLevel + 1)} Recovery routes`);
875
+ const beforeRoutes = lines.length;
876
+ if (routes && typeof routes.link === "object" && routes.link !== null) {
877
+ const link = routes.link;
878
+ lines.push(`- **link:** ${asDescription(link.description) ?? "Link the entry to the strategic spine."}`);
879
+ }
880
+ if (routes && typeof routes.acknowledge === "object" && routes.acknowledge !== null) {
881
+ const ack = routes.acknowledge;
882
+ const responses = ack.responses?.join(" | ") ?? "linked | accepted-fix | diverged";
883
+ lines.push(
884
+ `- **acknowledge** (\`${ack.param ?? "coherencyAcknowledgement"}\`): ${responses}${ack.minReasonChars ? ` (\u2265${ack.minReasonChars} chars for diverged)` : ""}. ${asDescription(ack.description) ?? ""}`.trim()
885
+ );
886
+ }
887
+ if (routes && typeof routes.override === "object" && routes.override !== null) {
888
+ const ov = routes.override;
889
+ lines.push(
890
+ `- **override** (\`${ov.param ?? "steeringOverrideReason"}\`): \u2265${ov.minChars ?? 12} chars. ${asDescription(ov.description) ?? ""}`.trim()
891
+ );
892
+ }
893
+ if (lines.length === beforeRoutes) {
894
+ lines.push(GENERIC_RECOVERY_LINE);
895
+ }
896
+ } else {
897
+ lines.push("", GENERIC_RECOVERY_LINE);
898
+ }
899
+ return failureResult(
900
+ lines.join("\n"),
901
+ "COHERENCY_REFUSED",
902
+ `Coherency gate refused ${toolName} on ${entryId}.`,
903
+ "Use one of the refusal's routes (link / coherencyAcknowledgement / steeringOverrideReason), then retry.",
904
+ void 0,
905
+ { entryId, refusal }
906
+ );
907
+ }
908
+
909
+ // src/lib/collectionCache.ts
910
+ var collectionCache = new ScopedCache(COLLECTION_CACHE_TTL_MS);
911
+ async function getCollections() {
912
+ const scope = cacheScope();
913
+ const hit = collectionCache.get(scope);
914
+ if (hit) return hit.collections;
915
+ const result2 = await kernelQuery("chain.listCollections") ?? [];
916
+ const bySlug = new Map(result2.map((c) => [c.slug, c]));
917
+ collectionCache.set(scope, { collections: result2, bySlug });
918
+ return result2;
919
+ }
920
+ async function getCollectionBySlug(slug) {
921
+ await getCollections();
922
+ return collectionCache.get(cacheScope())?.bySlug.get(slug);
923
+ }
924
+ function invalidateCollectionCacheForScope() {
925
+ collectionCache.delete(cacheScope());
926
+ }
927
+ async function isGoverned(slug) {
928
+ const col = await getCollectionBySlug(slug);
929
+ return !!col?.governed;
930
+ }
931
+
932
+ // src/lib/versionWrite.ts
933
+ function buildVersionPatch(params) {
934
+ const { capture, targetProseKey } = params;
935
+ const data = { ...capture.fields ?? {} };
936
+ if (capture.prose.trim()) data[targetProseKey] = capture.prose;
937
+ return capture.name ? { name: capture.name, data } : { data };
938
+ }
939
+ function readVersionWriteOutcome(result2) {
940
+ if (result2 && typeof result2 === "object" && result2.outcome === "refused") {
941
+ const rawRefusal = result2.refusal;
942
+ const refusal = rawRefusal && typeof rawRefusal === "object" ? rawRefusal : { reason: "The workspace refused this update." };
943
+ return { ok: false, refusal };
944
+ }
945
+ if (result2 && typeof result2 === "object" && typeof result2.id === "string") {
946
+ return { ok: true, id: result2.id };
947
+ }
948
+ return { ok: false, refusal: { reason: "The workspace refused this update." } };
949
+ }
950
+
951
+ // src/tools/captureVersion.ts
952
+ function buildVersionPreviewResult(groundingEntry, name) {
953
+ return successResult(
954
+ `# Would save as a new version of ${groundingEntry.entryId}
955
+
956
+ No DB writes \u2014 call without \`preview:true\` to version for real.`,
957
+ `Would save as a new version of ${groundingEntry.entryId}.`,
958
+ { id: groundingEntry.entryId, kind: "version", preview: true, name }
959
+ );
960
+ }
961
+ async function resolveTargetProseKey(collectionSlug) {
962
+ const col = await getCollectionBySlug(collectionSlug).catch(() => void 0);
963
+ return col?.descriptionFieldKey || "description";
964
+ }
965
+ async function runVersionCapture(params) {
966
+ const { groundingEntry, name, description, data, sourceRef, sourceExcerpt, links, groundingElapsedMs } = params;
967
+ const versionAgentId = getAgentSessionId();
968
+ const targetProseKey = await resolveTargetProseKey(groundingEntry.collectionSlug);
969
+ const patch = buildVersionPatch({ capture: { prose: description ?? "", fields: data ?? void 0 }, targetProseKey });
970
+ try {
971
+ const rawResult = await kernelMutation("chain.updateEntry", {
972
+ entryId: groundingEntry.entryId,
973
+ ...patch,
974
+ autoPublish: true,
975
+ changeNote: "Captured as a new version via MCP",
976
+ changedBy: versionAgentId ? `agent:${versionAgentId}` : "capture",
977
+ ...sourceRef ? { sourceRef } : {},
978
+ ...sourceExcerpt ? { sourceExcerpt } : {}
979
+ });
980
+ void kernelMutation("chain.recordGroundingOutcome", {
981
+ surface: "mcp",
982
+ promptShown: false,
983
+ highestRatio: groundingEntry.score,
984
+ hadGovernance: false,
985
+ grounding_ms: groundingElapsedMs
986
+ }).catch(() => void 0);
987
+ const outcome = readVersionWriteOutcome(rawResult);
988
+ if (!outcome.ok) {
989
+ return coherencyRefusedResult("capture", groundingEntry.entryId, outcome.refusal);
990
+ }
991
+ if (links && links.length > 0) {
992
+ await kernelMutation("chain.createEntryRelations", {
993
+ relations: links.slice(0, 25).map((l) => ({ fromEntryId: groundingEntry.entryId, toEntryId: l.to, type: l.type, proposedBy: "user" })),
994
+ sessionId: versionAgentId ?? void 0
995
+ }).catch(() => void 0);
996
+ }
997
+ return successResult(
998
+ `# Saved as a new version of ${groundingEntry.entryId}
999
+
1000
+ ${name}`,
1001
+ `Saved as a new version of ${groundingEntry.entryId}.`,
1002
+ { id: groundingEntry.entryId, kind: "version" }
1003
+ );
1004
+ } catch (error) {
1005
+ const classified = classifyError(error);
1006
+ return failureResult(classified.message, classified.code, classified.message, classified.recovery, classified.availableActions, classified.diagnostics);
1007
+ }
1008
+ }
1009
+ async function captureVersionOrPreview(preview, params) {
1010
+ return preview ? buildVersionPreviewResult(params.groundingEntry, params.name) : runVersionCapture(params);
1011
+ }
1012
+
850
1013
  // src/lib/fieldTypes.ts
851
1014
  var FIELD_TYPE_DEFAULTS = {
852
1015
  "string": "",
@@ -909,29 +1072,6 @@ function inferSourceDate(...values) {
909
1072
  return `${inferredYear}-${month}-${day}`;
910
1073
  }
911
1074
 
912
- // src/lib/collectionCache.ts
913
- var collectionCache = new ScopedCache(COLLECTION_CACHE_TTL_MS);
914
- async function getCollections() {
915
- const scope = cacheScope();
916
- const hit = collectionCache.get(scope);
917
- if (hit) return hit.collections;
918
- const result2 = await kernelQuery("chain.listCollections") ?? [];
919
- const bySlug = new Map(result2.map((c) => [c.slug, c]));
920
- collectionCache.set(scope, { collections: result2, bySlug });
921
- return result2;
922
- }
923
- async function getCollectionBySlug(slug) {
924
- await getCollections();
925
- return collectionCache.get(cacheScope())?.bySlug.get(slug);
926
- }
927
- function invalidateCollectionCacheForScope() {
928
- collectionCache.delete(cacheScope());
929
- }
930
- async function isGoverned(slug) {
931
- const col = await getCollectionBySlug(slug);
932
- return !!col?.governed;
933
- }
934
-
935
1075
  // src/lib/textMatch.ts
936
1076
  var STOP_WORDS = /* @__PURE__ */ new Set([
937
1077
  "the",
@@ -2335,6 +2475,7 @@ ${groundingReport.duplicates.map((d) => `- **${d.entryId}** ${d.name} [${d.colle
2335
2475
  }
2336
2476
  };
2337
2477
  }
2478
+ if (groundingEntry?.kind === "version") return captureVersionOrPreview(preview ?? false, { groundingEntry, name, description, data: userData, sourceRef, sourceExcerpt, links, groundingElapsedMs });
2338
2479
  const data = buildDataFromFields(col.fields ?? [], profile.descriptionField, description);
2339
2480
  for (const def of profile.defaults) {
2340
2481
  if (def.value !== "infer" && def.value !== "today") {
@@ -2538,7 +2679,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`entries action=up
2538
2679
  const tAfterCreate = Date.now();
2539
2680
  void kernelMutation("chain.recordGroundingOutcome", {
2540
2681
  surface: "mcp",
2541
- promptShown: groundingEntry?.kind === "ask" || groundingEntry?.kind === "version",
2682
+ promptShown: groundingEntry?.kind === "ask",
2542
2683
  highestRatio: Math.max(
2543
2684
  ...groundingReport.duplicates.map((d) => d.overlapRatio),
2544
2685
  ...groundingReport.related.map((r) => r.overlapRatio),
@@ -3719,65 +3860,6 @@ async function runConflictPreflight(name, description, collectionHint) {
3719
3860
  }
3720
3861
  }
3721
3862
 
3722
- // src/tools/coherency-refusal.ts
3723
- function asDescription(value) {
3724
- if (typeof value !== "string") return void 0;
3725
- const trimmed = value.trim();
3726
- return trimmed.length > 0 ? trimmed : void 0;
3727
- }
3728
- var GENERIC_RECOVERY_LINE = "Respond and retry: link the entry to the strategic spine, pass `coherencyAcknowledgement`, or supply a typed `steeringOverrideReason`.";
3729
- function coherencyRefusedResult(toolName, entryId, refusal, options) {
3730
- const headingLevel = options?.headingLevel ?? 1;
3731
- const heading = "#".repeat(headingLevel);
3732
- const lines = [
3733
- `${heading} Write refused by the coherency gate`,
3734
- "",
3735
- refusal.reason ?? `The coherency gate refused this write on ${entryId}.`
3736
- ];
3737
- if (refusal.subject?.name) {
3738
- lines.push(`On: ${refusal.subject.name}`);
3739
- }
3740
- if (refusal.mode) {
3741
- lines.push("", `Mode: ${refusal.mode}`);
3742
- }
3743
- const routes = refusal.routes;
3744
- const routeKeys = routes ? Object.keys(routes) : [];
3745
- if (routeKeys.length > 0) {
3746
- lines.push("", `${"#".repeat(headingLevel + 1)} Recovery routes`);
3747
- const beforeRoutes = lines.length;
3748
- if (routes && typeof routes.link === "object" && routes.link !== null) {
3749
- const link = routes.link;
3750
- lines.push(`- **link:** ${asDescription(link.description) ?? "Link the entry to the strategic spine."}`);
3751
- }
3752
- if (routes && typeof routes.acknowledge === "object" && routes.acknowledge !== null) {
3753
- const ack = routes.acknowledge;
3754
- const responses = ack.responses?.join(" | ") ?? "linked | accepted-fix | diverged";
3755
- lines.push(
3756
- `- **acknowledge** (\`${ack.param ?? "coherencyAcknowledgement"}\`): ${responses}${ack.minReasonChars ? ` (\u2265${ack.minReasonChars} chars for diverged)` : ""}. ${asDescription(ack.description) ?? ""}`.trim()
3757
- );
3758
- }
3759
- if (routes && typeof routes.override === "object" && routes.override !== null) {
3760
- const ov = routes.override;
3761
- lines.push(
3762
- `- **override** (\`${ov.param ?? "steeringOverrideReason"}\`): \u2265${ov.minChars ?? 12} chars. ${asDescription(ov.description) ?? ""}`.trim()
3763
- );
3764
- }
3765
- if (lines.length === beforeRoutes) {
3766
- lines.push(GENERIC_RECOVERY_LINE);
3767
- }
3768
- } else {
3769
- lines.push("", GENERIC_RECOVERY_LINE);
3770
- }
3771
- return failureResult(
3772
- lines.join("\n"),
3773
- "COHERENCY_REFUSED",
3774
- `Coherency gate refused ${toolName} on ${entryId}.`,
3775
- "Use one of the refusal's routes (link / coherencyAcknowledgement / steeringOverrideReason), then retry.",
3776
- void 0,
3777
- { entryId, refusal }
3778
- );
3779
- }
3780
-
3781
3863
  // src/tools/knowledge/getHistory.ts
3782
3864
  import { z as z7 } from "zod/v3";
3783
3865
  var getHistorySchema = z7.object({
@@ -16671,4 +16753,4 @@ export {
16671
16753
  createProductBrainServer,
16672
16754
  initFeatureFlags
16673
16755
  };
16674
- //# sourceMappingURL=chunk-WFKDNJYA.js.map
16756
+ //# sourceMappingURL=chunk-PZDI2QMN.js.map