@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/index.js +83 -8
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +15 -1
- package/dist/server.js +83 -8
- package/dist/server.js.map +1 -1
- package/package.json +8 -5
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:
|
|
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
|
|
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) =>
|
|
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) =>
|
|
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
|
|
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" && (
|
|
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:
|
|
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.
|
|
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
|
]);
|