@hiveai/mcp 0.9.13 → 0.9.15

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.
package/dist/server.d.ts CHANGED
@@ -83,6 +83,8 @@ interface BriefingMemory {
83
83
  reasons: Array<"anchor" | "module" | "domain" | "semantic">;
84
84
  match_quality: "exact" | "partial" | "semantic";
85
85
  semantic_score?: number;
86
+ /** Human/agent-readable explanation for why this record was surfaced. */
87
+ why?: string[];
86
88
  body: string;
87
89
  file_path: string;
88
90
  }
@@ -517,10 +519,12 @@ interface PreCommitCheckOutput {
517
519
  summary: {
518
520
  anti_patterns: number;
519
521
  blocking_warnings?: number;
522
+ review_warnings?: number;
523
+ info_warnings?: number;
520
524
  relevant_memories: number;
521
525
  stale_anchors: number;
522
526
  };
523
- warnings: AntiPatternsWarning[];
527
+ warnings: ClassifiedAntiPatternsWarning[];
524
528
  /** Memories anchored to the touched files — convention reminders for the change author. */
525
529
  relevant_memories: Array<{
526
530
  id: string;
@@ -536,6 +540,16 @@ interface PreCommitCheckOutput {
536
540
  }>;
537
541
  notice?: string;
538
542
  }
543
+ type AntiPatternLevel = "blocking" | "review" | "info";
544
+ interface ClassifiedAntiPatternsWarning extends AntiPatternsWarning {
545
+ /**
546
+ * blocking = commit gate should fail for the configured threshold;
547
+ * review = plausible but not strong enough to block;
548
+ * info = weak signal, hidden by default in human CLI output.
549
+ */
550
+ level: AntiPatternLevel;
551
+ rationale: string;
552
+ }
539
553
  /**
540
554
  * One-shot "should I block this commit?" check.
541
555
  *
package/dist/server.js CHANGED
@@ -1392,6 +1392,7 @@ import {
1392
1392
  loadMemoriesFromDir as loadMemoriesFromDir13,
1393
1393
  loadUsageIndex as loadUsageIndex7,
1394
1394
  memoryMatchesAnchorPaths as memoryMatchesAnchorPaths2,
1395
+ pathsOverlap,
1395
1396
  queryCodeMap,
1396
1397
  resolveBriefingBudget,
1397
1398
  serializeMemory as serializeMemory9,
@@ -1700,10 +1701,14 @@ ${m.content}`).join("\n\n---\n\n"),
1700
1701
  const createdAt = loaded?.memory.frontmatter.created_at ?? (/* @__PURE__ */ new Date()).toISOString();
1701
1702
  if (isDecaying(u, createdAt)) decayWarnings.push(m.id);
1702
1703
  }
1703
- const outputMemories = input.format === "compact" ? trimmedMemories.map((m) => ({ ...m, body: compactSummary(m.body) })) : input.format === "actions" ? trimmedMemories.map((m) => ({
1704
+ const formattedMemories = input.format === "compact" ? trimmedMemories.map((m) => ({ ...m, body: compactSummary(m.body) })) : input.format === "actions" ? trimmedMemories.map((m) => ({
1704
1705
  ...m,
1705
1706
  body: extractActionsBriefBody(m.body)
1706
1707
  })) : trimmedMemories;
1708
+ const outputMemories = formattedMemories.map((m) => ({
1709
+ ...m,
1710
+ why: explainWhySurfaced(m, byId.get(m.id), input.files, inferred)
1711
+ }));
1707
1712
  let symbolLocations;
1708
1713
  const symbolsToLookup = new Set(input.symbols);
1709
1714
  for (const m of outputMemories) {
@@ -1869,6 +1874,44 @@ function compactSummary(body) {
1869
1874
  }
1870
1875
  return body.slice(0, 120);
1871
1876
  }
1877
+ function explainWhySurfaced(memory, loaded, inputFiles, inferredModules) {
1878
+ const why = [];
1879
+ const fm = loaded?.memory.frontmatter;
1880
+ if (memory.reasons.includes("anchor") && fm) {
1881
+ const matching = fm.anchor.paths.filter(
1882
+ (p) => inputFiles.length === 0 || inputFiles.some((file) => pathsOverlap(p, file))
1883
+ );
1884
+ if (matching.length > 0) {
1885
+ why.push(`Anchored to touched path${matching.length === 1 ? "" : "s"}: ${matching.slice(0, 4).join(", ")}`);
1886
+ } else if (fm.anchor.paths.length > 0) {
1887
+ why.push(`Pulled by related anchor: ${fm.anchor.paths.slice(0, 4).join(", ")}`);
1888
+ }
1889
+ if (fm.anchor.symbols.length > 0) {
1890
+ why.push(`Anchor symbol${fm.anchor.symbols.length === 1 ? "" : "s"}: ${fm.anchor.symbols.slice(0, 4).join(", ")}`);
1891
+ }
1892
+ }
1893
+ if (memory.reasons.includes("module")) {
1894
+ const moduleHints = [
1895
+ ...memory.module ? [memory.module] : [],
1896
+ ...memory.tags.filter((tag) => inferredModules.includes(tag))
1897
+ ];
1898
+ const shown = moduleHints.length > 0 ? [...new Set(moduleHints)].join(", ") : inferredModules.join(", ");
1899
+ why.push(shown ? `Matched inferred module/tag: ${shown}` : "Matched inferred module context.");
1900
+ }
1901
+ if (memory.reasons.includes("domain")) {
1902
+ why.push("Matched inferred domain from the target file paths.");
1903
+ }
1904
+ if (memory.reasons.includes("semantic")) {
1905
+ const score = memory.semantic_score !== void 0 ? ` score=${Math.round(memory.semantic_score * 100) / 100}` : "";
1906
+ why.push(`${memory.match_quality === "exact" ? "Literal task match" : "Semantic/task relevance"}${score}.`);
1907
+ }
1908
+ why.push(`Confidence: ${memory.confidence}; read ${memory.read_count} time${memory.read_count === 1 ? "" : "s"}.`);
1909
+ if (memory.type === "attempt") why.push("Failed-approach record; read before repeating the same path.");
1910
+ if (memory.status === "proposed" || memory.status === "draft") {
1911
+ why.push("Unvalidated record; use cautiously or ask a human before treating it as policy.");
1912
+ }
1913
+ return why;
1914
+ }
1872
1915
  async function trySemanticHits(ctx, task, limit) {
1873
1916
  let mod;
1874
1917
  try {
@@ -2674,7 +2717,7 @@ import {
2674
2717
  getUsage as getUsage9,
2675
2718
  loadMemoriesFromDir as loadMemoriesFromDir20,
2676
2719
  loadUsageIndex as loadUsageIndex11,
2677
- pathsOverlap,
2720
+ pathsOverlap as pathsOverlap2,
2678
2721
  tokenizeQuery as tokenizeQuery5
2679
2722
  } from "@hiveai/core";
2680
2723
  import { z as z27 } from "zod";
@@ -2710,7 +2753,7 @@ async function memConflicts(input, ctx) {
2710
2753
  const otherText = (other.memory.body + " " + fm.tags.join(" ")).toLowerCase();
2711
2754
  const reasons = [];
2712
2755
  const sim = simScores?.get(fm.id) ?? null;
2713
- const hasPathOverlap = fm.anchor.paths.some((p) => targetPaths.some((tp) => pathsOverlap(p, tp)));
2756
+ const hasPathOverlap = fm.anchor.paths.some((p) => targetPaths.some((tp) => pathsOverlap2(p, tp)));
2714
2757
  const otherTokens = new Set(tokenizeQuery5(otherText));
2715
2758
  const tokenOverlap = countIntersection(targetTokens, otherTokens);
2716
2759
  const isSemanticNeighbor = sim !== null && sim >= input.min_score;
@@ -2745,7 +2788,7 @@ async function memConflicts(input, ctx) {
2745
2788
  body_preview: other.memory.body.split("\n").slice(0, 4).join("\n").slice(0, 300),
2746
2789
  similarity: sim,
2747
2790
  reasons,
2748
- shared_paths: fm.anchor.paths.filter((p) => targetPaths.some((tp) => pathsOverlap(p, tp)))
2791
+ shared_paths: fm.anchor.paths.filter((p) => targetPaths.some((tp) => pathsOverlap2(p, tp)))
2749
2792
  });
2750
2793
  }
2751
2794
  conflicts.sort((a, b) => {
@@ -2835,10 +2878,13 @@ async function preCommitCheck(input, ctx) {
2835
2878
  const filesTouching = new Set(relevantMatches.map((m) => m.id));
2836
2879
  const staleHits = verifyResult.results.filter((r) => r.stale && filesTouching.has(r.id));
2837
2880
  const blockOn = input.block_on;
2838
- const blockingWarnings = apResult.warnings.filter(isBlockingWarning);
2881
+ const classifiedWarnings = apResult.warnings.map(classifyWarning);
2882
+ const blockingWarnings = classifiedWarnings.filter((w) => w.level === "blocking");
2883
+ const reviewWarnings = classifiedWarnings.filter((w) => w.level === "review");
2884
+ const infoWarnings = classifiedWarnings.filter((w) => w.level === "info");
2839
2885
  let should_block = false;
2840
2886
  if (blockOn !== "never") {
2841
- if (blockOn === "any" && (apResult.warnings.length > 0 || staleHits.length > 0)) should_block = true;
2887
+ if (blockOn === "any" && (blockingWarnings.length > 0 || reviewWarnings.length > 0 || staleHits.length > 0)) should_block = true;
2842
2888
  if (blockOn === "high-confidence" && (blockingWarnings.length > 0 || staleHits.length > 0)) should_block = true;
2843
2889
  }
2844
2890
  const relevant_memories = relevantMatches.slice(0, 8).map((m) => ({
@@ -2852,10 +2898,12 @@ async function preCommitCheck(input, ctx) {
2852
2898
  summary: {
2853
2899
  anti_patterns: apResult.warnings.length,
2854
2900
  blocking_warnings: blockingWarnings.length,
2901
+ review_warnings: reviewWarnings.length,
2902
+ info_warnings: infoWarnings.length,
2855
2903
  relevant_memories: relevant_memories.length,
2856
2904
  stale_anchors: staleHits.length
2857
2905
  },
2858
- warnings: apResult.warnings,
2906
+ warnings: classifiedWarnings,
2859
2907
  relevant_memories,
2860
2908
  stale_anchors: staleHits.map((r) => ({
2861
2909
  id: r.id,
@@ -2865,6 +2913,30 @@ async function preCommitCheck(input, ctx) {
2865
2913
  }))
2866
2914
  };
2867
2915
  }
2916
+ function classifyWarning(warning) {
2917
+ if (isBlockingWarning(warning)) {
2918
+ return {
2919
+ ...warning,
2920
+ level: "blocking",
2921
+ rationale: "authoritative/trusted memory plus strong semantic match to the diff (score >= 0.65)"
2922
+ };
2923
+ }
2924
+ const hasSemantic = warning.reasons.includes("semantic");
2925
+ const semanticScore = warning.semantic_score ?? 0;
2926
+ const highConfidence = warning.confidence === "authoritative" || warning.confidence === "trusted";
2927
+ if (hasSemantic && semanticScore >= 0.45 || highConfidence && warning.reasons.includes("anchor") && warning.reasons.includes("literal")) {
2928
+ return {
2929
+ ...warning,
2930
+ level: "review",
2931
+ rationale: hasSemantic ? "semantic match is plausible but below blocking threshold" : "anchored high-confidence memory also matched diff tokens, but no strong semantic proof"
2932
+ };
2933
+ }
2934
+ return {
2935
+ ...warning,
2936
+ level: "info",
2937
+ rationale: "weak signal only (literal/anchor/low semantic evidence); surfaced for audit, hidden in concise CLI output"
2938
+ };
2939
+ }
2868
2940
  function isBlockingWarning(warning) {
2869
2941
  const highConfidence = warning.confidence === "authoritative" || warning.confidence === "trusted";
2870
2942
  if (!highConfidence) return false;
@@ -3456,7 +3528,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
3456
3528
  // src/server.ts
3457
3529
  import { loadConfigSync } from "@hiveai/core";
3458
3530
  var SERVER_NAME = "haive";
3459
- var SERVER_VERSION = "0.9.13";
3531
+ var SERVER_VERSION = "0.9.15";
3460
3532
  function jsonResult(data) {
3461
3533
  return {
3462
3534
  content: [
@@ -3470,9 +3542,12 @@ function jsonResult(data) {
3470
3542
  var ENFORCEMENT_PROFILE_TOOLS = /* @__PURE__ */ new Set([
3471
3543
  "get_briefing",
3472
3544
  "mem_save",
3545
+ "mem_tried",
3473
3546
  "mem_search",
3547
+ "mem_get",
3474
3548
  "mem_verify",
3475
3549
  "mem_relevant_to",
3550
+ "code_map",
3476
3551
  "pre_commit_check",
3477
3552
  "mem_session_end"
3478
3553
  ]);