@hiveai/mcp 0.9.14 → 0.9.16
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/README.md +12 -3
- package/dist/index.js +132 -12
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +22 -2
- package/dist/server.js +137 -12
- package/dist/server.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **hAIve MCP server** — policy-aware briefing and memory tools for MCP-compatible AI coding agents.
|
|
4
4
|
|
|
5
|
-
The MCP server is how agents load team policy before changing code. By default it exposes a small enforcement-oriented tool surface: briefing, relevant memories, failed-attempt capture, anchor verification, code-map lookup, and pre-commit checks.
|
|
5
|
+
The MCP server is how agents load team policy before changing code. By default it exposes a small enforcement-oriented tool surface: briefing, relevant memories, failed-attempt capture, anchor verification, code-map lookup, and pre-commit checks. Larger maintenance and experimental surfaces are opt-in via `HAIVE_TOOL_PROFILE`.
|
|
6
6
|
|
|
7
7
|
hAIve is not just a memory database. The MCP layer participates in enforcement: state-changing hAIve tools require `get_briefing` or `mem_relevant_to` first, so agents cannot silently skip team context while using hAIve.
|
|
8
8
|
|
|
@@ -117,17 +117,26 @@ Default tools:
|
|
|
117
117
|
- `mem_tried`
|
|
118
118
|
- `mem_search`
|
|
119
119
|
- `mem_get`
|
|
120
|
-
- `mem_update`
|
|
121
120
|
- `mem_verify`
|
|
122
121
|
- `code_map`
|
|
123
122
|
- `pre_commit_check`
|
|
123
|
+
- `mem_session_end`
|
|
124
124
|
|
|
125
125
|
Default prompts:
|
|
126
126
|
|
|
127
127
|
- `bootstrap_project`
|
|
128
128
|
- `post_task`
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
### Tool Profiles
|
|
131
|
+
|
|
132
|
+
`HAIVE_TOOL_PROFILE` controls how much hAIve surface an agent sees:
|
|
133
|
+
|
|
134
|
+
- `enforcement` (default): compact repo-native context harness for coding agents.
|
|
135
|
+
- `maintenance`: adds corpus review, lifecycle, distillation, code-search, and project-context maintenance tools.
|
|
136
|
+
- `experimental`: adds exploratory diagnostics such as runtime journal, pattern detection, why-this-file, why-this-decision, and conflict analysis.
|
|
137
|
+
- `full`: legacy alias for `experimental`.
|
|
138
|
+
|
|
139
|
+
Use `maintenance` for human/team stewardship sessions and `experimental` only when you are intentionally working on hAIve's broader research tooling.
|
|
131
140
|
|
|
132
141
|
### `get_briefing` ⭐ Start every task with this
|
|
133
142
|
|
package/dist/index.js
CHANGED
|
@@ -1394,6 +1394,7 @@ import {
|
|
|
1394
1394
|
loadMemoriesFromDir as loadMemoriesFromDir13,
|
|
1395
1395
|
loadUsageIndex as loadUsageIndex7,
|
|
1396
1396
|
memoryMatchesAnchorPaths as memoryMatchesAnchorPaths2,
|
|
1397
|
+
pathsOverlap,
|
|
1397
1398
|
queryCodeMap,
|
|
1398
1399
|
resolveBriefingBudget,
|
|
1399
1400
|
serializeMemory as serializeMemory9,
|
|
@@ -1702,10 +1703,14 @@ ${m.content}`).join("\n\n---\n\n"),
|
|
|
1702
1703
|
const createdAt = loaded?.memory.frontmatter.created_at ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1703
1704
|
if (isDecaying(u, createdAt)) decayWarnings.push(m.id);
|
|
1704
1705
|
}
|
|
1705
|
-
const
|
|
1706
|
+
const formattedMemories = input.format === "compact" ? trimmedMemories.map((m) => ({ ...m, body: compactSummary(m.body) })) : input.format === "actions" ? trimmedMemories.map((m) => ({
|
|
1706
1707
|
...m,
|
|
1707
1708
|
body: extractActionsBriefBody(m.body)
|
|
1708
1709
|
})) : trimmedMemories;
|
|
1710
|
+
const outputMemories = formattedMemories.map((m) => ({
|
|
1711
|
+
...m,
|
|
1712
|
+
why: explainWhySurfaced(m, byId.get(m.id), input.files, inferred)
|
|
1713
|
+
}));
|
|
1709
1714
|
let symbolLocations;
|
|
1710
1715
|
const symbolsToLookup = new Set(input.symbols);
|
|
1711
1716
|
for (const m of outputMemories) {
|
|
@@ -1871,6 +1876,44 @@ function compactSummary(body) {
|
|
|
1871
1876
|
}
|
|
1872
1877
|
return body.slice(0, 120);
|
|
1873
1878
|
}
|
|
1879
|
+
function explainWhySurfaced(memory, loaded, inputFiles, inferredModules) {
|
|
1880
|
+
const why = [];
|
|
1881
|
+
const fm = loaded?.memory.frontmatter;
|
|
1882
|
+
if (memory.reasons.includes("anchor") && fm) {
|
|
1883
|
+
const matching = fm.anchor.paths.filter(
|
|
1884
|
+
(p) => inputFiles.length === 0 || inputFiles.some((file) => pathsOverlap(p, file))
|
|
1885
|
+
);
|
|
1886
|
+
if (matching.length > 0) {
|
|
1887
|
+
why.push(`Anchored to touched path${matching.length === 1 ? "" : "s"}: ${matching.slice(0, 4).join(", ")}`);
|
|
1888
|
+
} else if (fm.anchor.paths.length > 0) {
|
|
1889
|
+
why.push(`Pulled by related anchor: ${fm.anchor.paths.slice(0, 4).join(", ")}`);
|
|
1890
|
+
}
|
|
1891
|
+
if (fm.anchor.symbols.length > 0) {
|
|
1892
|
+
why.push(`Anchor symbol${fm.anchor.symbols.length === 1 ? "" : "s"}: ${fm.anchor.symbols.slice(0, 4).join(", ")}`);
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
if (memory.reasons.includes("module")) {
|
|
1896
|
+
const moduleHints = [
|
|
1897
|
+
...memory.module ? [memory.module] : [],
|
|
1898
|
+
...memory.tags.filter((tag) => inferredModules.includes(tag))
|
|
1899
|
+
];
|
|
1900
|
+
const shown = moduleHints.length > 0 ? [...new Set(moduleHints)].join(", ") : inferredModules.join(", ");
|
|
1901
|
+
why.push(shown ? `Matched inferred module/tag: ${shown}` : "Matched inferred module context.");
|
|
1902
|
+
}
|
|
1903
|
+
if (memory.reasons.includes("domain")) {
|
|
1904
|
+
why.push("Matched inferred domain from the target file paths.");
|
|
1905
|
+
}
|
|
1906
|
+
if (memory.reasons.includes("semantic")) {
|
|
1907
|
+
const score = memory.semantic_score !== void 0 ? ` score=${Math.round(memory.semantic_score * 100) / 100}` : "";
|
|
1908
|
+
why.push(`${memory.match_quality === "exact" ? "Literal task match" : "Semantic/task relevance"}${score}.`);
|
|
1909
|
+
}
|
|
1910
|
+
why.push(`Confidence: ${memory.confidence}; read ${memory.read_count} time${memory.read_count === 1 ? "" : "s"}.`);
|
|
1911
|
+
if (memory.type === "attempt") why.push("Failed-approach record; read before repeating the same path.");
|
|
1912
|
+
if (memory.status === "proposed" || memory.status === "draft") {
|
|
1913
|
+
why.push("Unvalidated record; use cautiously or ask a human before treating it as policy.");
|
|
1914
|
+
}
|
|
1915
|
+
return why;
|
|
1916
|
+
}
|
|
1874
1917
|
async function trySemanticHits(ctx, task, limit) {
|
|
1875
1918
|
let mod;
|
|
1876
1919
|
try {
|
|
@@ -2676,7 +2719,7 @@ import {
|
|
|
2676
2719
|
getUsage as getUsage9,
|
|
2677
2720
|
loadMemoriesFromDir as loadMemoriesFromDir20,
|
|
2678
2721
|
loadUsageIndex as loadUsageIndex11,
|
|
2679
|
-
pathsOverlap,
|
|
2722
|
+
pathsOverlap as pathsOverlap2,
|
|
2680
2723
|
tokenizeQuery as tokenizeQuery5
|
|
2681
2724
|
} from "@hiveai/core";
|
|
2682
2725
|
import { z as z27 } from "zod";
|
|
@@ -2712,7 +2755,7 @@ async function memConflicts(input, ctx) {
|
|
|
2712
2755
|
const otherText = (other.memory.body + " " + fm.tags.join(" ")).toLowerCase();
|
|
2713
2756
|
const reasons = [];
|
|
2714
2757
|
const sim = simScores?.get(fm.id) ?? null;
|
|
2715
|
-
const hasPathOverlap = fm.anchor.paths.some((p) => targetPaths.some((tp) =>
|
|
2758
|
+
const hasPathOverlap = fm.anchor.paths.some((p) => targetPaths.some((tp) => pathsOverlap2(p, tp)));
|
|
2716
2759
|
const otherTokens = new Set(tokenizeQuery5(otherText));
|
|
2717
2760
|
const tokenOverlap = countIntersection(targetTokens, otherTokens);
|
|
2718
2761
|
const isSemanticNeighbor = sim !== null && sim >= input.min_score;
|
|
@@ -2747,7 +2790,7 @@ async function memConflicts(input, ctx) {
|
|
|
2747
2790
|
body_preview: other.memory.body.split("\n").slice(0, 4).join("\n").slice(0, 300),
|
|
2748
2791
|
similarity: sim,
|
|
2749
2792
|
reasons,
|
|
2750
|
-
shared_paths: fm.anchor.paths.filter((p) => targetPaths.some((tp) =>
|
|
2793
|
+
shared_paths: fm.anchor.paths.filter((p) => targetPaths.some((tp) => pathsOverlap2(p, tp)))
|
|
2751
2794
|
});
|
|
2752
2795
|
}
|
|
2753
2796
|
conflicts.sort((a, b) => {
|
|
@@ -2837,10 +2880,13 @@ async function preCommitCheck(input, ctx) {
|
|
|
2837
2880
|
const filesTouching = new Set(relevantMatches.map((m) => m.id));
|
|
2838
2881
|
const staleHits = verifyResult.results.filter((r) => r.stale && filesTouching.has(r.id));
|
|
2839
2882
|
const blockOn = input.block_on;
|
|
2840
|
-
const
|
|
2883
|
+
const classifiedWarnings = apResult.warnings.map(classifyWarning);
|
|
2884
|
+
const blockingWarnings = classifiedWarnings.filter((w) => w.level === "blocking");
|
|
2885
|
+
const reviewWarnings = classifiedWarnings.filter((w) => w.level === "review");
|
|
2886
|
+
const infoWarnings = classifiedWarnings.filter((w) => w.level === "info");
|
|
2841
2887
|
let should_block = false;
|
|
2842
2888
|
if (blockOn !== "never") {
|
|
2843
|
-
if (blockOn === "any" && (
|
|
2889
|
+
if (blockOn === "any" && (blockingWarnings.length > 0 || reviewWarnings.length > 0 || staleHits.length > 0)) should_block = true;
|
|
2844
2890
|
if (blockOn === "high-confidence" && (blockingWarnings.length > 0 || staleHits.length > 0)) should_block = true;
|
|
2845
2891
|
}
|
|
2846
2892
|
const relevant_memories = relevantMatches.slice(0, 8).map((m) => ({
|
|
@@ -2854,10 +2900,12 @@ async function preCommitCheck(input, ctx) {
|
|
|
2854
2900
|
summary: {
|
|
2855
2901
|
anti_patterns: apResult.warnings.length,
|
|
2856
2902
|
blocking_warnings: blockingWarnings.length,
|
|
2903
|
+
review_warnings: reviewWarnings.length,
|
|
2904
|
+
info_warnings: infoWarnings.length,
|
|
2857
2905
|
relevant_memories: relevant_memories.length,
|
|
2858
2906
|
stale_anchors: staleHits.length
|
|
2859
2907
|
},
|
|
2860
|
-
warnings:
|
|
2908
|
+
warnings: classifiedWarnings,
|
|
2861
2909
|
relevant_memories,
|
|
2862
2910
|
stale_anchors: staleHits.map((r) => ({
|
|
2863
2911
|
id: r.id,
|
|
@@ -2867,6 +2915,30 @@ async function preCommitCheck(input, ctx) {
|
|
|
2867
2915
|
}))
|
|
2868
2916
|
};
|
|
2869
2917
|
}
|
|
2918
|
+
function classifyWarning(warning) {
|
|
2919
|
+
if (isBlockingWarning(warning)) {
|
|
2920
|
+
return {
|
|
2921
|
+
...warning,
|
|
2922
|
+
level: "blocking",
|
|
2923
|
+
rationale: "authoritative/trusted memory plus strong semantic match to the diff (score >= 0.65)"
|
|
2924
|
+
};
|
|
2925
|
+
}
|
|
2926
|
+
const hasSemantic = warning.reasons.includes("semantic");
|
|
2927
|
+
const semanticScore = warning.semantic_score ?? 0;
|
|
2928
|
+
const highConfidence = warning.confidence === "authoritative" || warning.confidence === "trusted";
|
|
2929
|
+
if (hasSemantic && semanticScore >= 0.45 || highConfidence && warning.reasons.includes("anchor") && warning.reasons.includes("literal")) {
|
|
2930
|
+
return {
|
|
2931
|
+
...warning,
|
|
2932
|
+
level: "review",
|
|
2933
|
+
rationale: hasSemantic ? "semantic match is plausible but below blocking threshold" : "anchored high-confidence memory also matched diff tokens, but no strong semantic proof"
|
|
2934
|
+
};
|
|
2935
|
+
}
|
|
2936
|
+
return {
|
|
2937
|
+
...warning,
|
|
2938
|
+
level: "info",
|
|
2939
|
+
rationale: "weak signal only (literal/anchor/low semantic evidence); surfaced for audit, hidden in concise CLI output"
|
|
2940
|
+
};
|
|
2941
|
+
}
|
|
2870
2942
|
function isBlockingWarning(warning) {
|
|
2871
2943
|
const highConfidence = warning.confidence === "authoritative" || warning.confidence === "trusted";
|
|
2872
2944
|
if (!highConfidence) return false;
|
|
@@ -3458,7 +3530,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
3458
3530
|
// src/server.ts
|
|
3459
3531
|
import { loadConfigSync } from "@hiveai/core";
|
|
3460
3532
|
var SERVER_NAME = "haive";
|
|
3461
|
-
var SERVER_VERSION = "0.9.
|
|
3533
|
+
var SERVER_VERSION = "0.9.16";
|
|
3462
3534
|
function jsonResult(data) {
|
|
3463
3535
|
return {
|
|
3464
3536
|
content: [
|
|
@@ -3469,15 +3541,58 @@ function jsonResult(data) {
|
|
|
3469
3541
|
]
|
|
3470
3542
|
};
|
|
3471
3543
|
}
|
|
3472
|
-
var ENFORCEMENT_PROFILE_TOOLS =
|
|
3544
|
+
var ENFORCEMENT_PROFILE_TOOLS = [
|
|
3473
3545
|
"get_briefing",
|
|
3474
3546
|
"mem_save",
|
|
3547
|
+
"mem_tried",
|
|
3475
3548
|
"mem_search",
|
|
3549
|
+
"mem_get",
|
|
3476
3550
|
"mem_verify",
|
|
3477
3551
|
"mem_relevant_to",
|
|
3552
|
+
"code_map",
|
|
3478
3553
|
"pre_commit_check",
|
|
3479
3554
|
"mem_session_end"
|
|
3480
|
-
]
|
|
3555
|
+
];
|
|
3556
|
+
var MAINTENANCE_PROFILE_TOOLS = [
|
|
3557
|
+
...ENFORCEMENT_PROFILE_TOOLS,
|
|
3558
|
+
"mem_suggest_topic",
|
|
3559
|
+
"mem_for_files",
|
|
3560
|
+
"mem_list",
|
|
3561
|
+
"get_project_context",
|
|
3562
|
+
"bootstrap_project_save",
|
|
3563
|
+
"mem_resolve_project",
|
|
3564
|
+
"mem_update",
|
|
3565
|
+
"mem_approve",
|
|
3566
|
+
"mem_reject",
|
|
3567
|
+
"mem_pending",
|
|
3568
|
+
"mem_delete",
|
|
3569
|
+
"mem_diff",
|
|
3570
|
+
"get_recap",
|
|
3571
|
+
"code_search",
|
|
3572
|
+
"anti_patterns_check",
|
|
3573
|
+
"mem_distill",
|
|
3574
|
+
"mem_timeline",
|
|
3575
|
+
"mem_conflict_candidates"
|
|
3576
|
+
];
|
|
3577
|
+
var EXPERIMENTAL_PROFILE_TOOLS = [
|
|
3578
|
+
...MAINTENANCE_PROFILE_TOOLS,
|
|
3579
|
+
"mem_observe",
|
|
3580
|
+
"why_this_file",
|
|
3581
|
+
"why_this_decision",
|
|
3582
|
+
"mem_conflicts_with",
|
|
3583
|
+
"pattern_detect",
|
|
3584
|
+
"runtime_journal_append",
|
|
3585
|
+
"runtime_journal_tail"
|
|
3586
|
+
];
|
|
3587
|
+
var TOOL_PROFILES = {
|
|
3588
|
+
enforcement: new Set(ENFORCEMENT_PROFILE_TOOLS),
|
|
3589
|
+
maintenance: new Set(MAINTENANCE_PROFILE_TOOLS),
|
|
3590
|
+
experimental: new Set(EXPERIMENTAL_PROFILE_TOOLS)
|
|
3591
|
+
};
|
|
3592
|
+
function getAllowedToolsForProfile(profile) {
|
|
3593
|
+
if (profile === "full") return TOOL_PROFILES.experimental;
|
|
3594
|
+
return TOOL_PROFILES[profile] ?? TOOL_PROFILES.enforcement;
|
|
3595
|
+
}
|
|
3481
3596
|
var BRIEFING_TOOLS = /* @__PURE__ */ new Set(["get_briefing", "mem_relevant_to"]);
|
|
3482
3597
|
var MUTATING_TOOLS = /* @__PURE__ */ new Set([
|
|
3483
3598
|
"mem_save",
|
|
@@ -3504,7 +3619,8 @@ function createHaiveServer(options = {}) {
|
|
|
3504
3619
|
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
3505
3620
|
{ capabilities: { tools: {}, prompts: {} } }
|
|
3506
3621
|
);
|
|
3507
|
-
const
|
|
3622
|
+
const allowedTools = getAllowedToolsForProfile(toolProfile);
|
|
3623
|
+
const shouldRegisterTool = (name) => allowedTools.has(name);
|
|
3508
3624
|
const registerTool = (name, description, schema, handler) => {
|
|
3509
3625
|
if (!shouldRegisterTool(name)) return;
|
|
3510
3626
|
const tool = server.tool.bind(server);
|
|
@@ -3528,7 +3644,11 @@ function createHaiveServer(options = {}) {
|
|
|
3528
3644
|
}
|
|
3529
3645
|
);
|
|
3530
3646
|
};
|
|
3531
|
-
const shouldRegisterPrompt = (name) =>
|
|
3647
|
+
const shouldRegisterPrompt = (name) => {
|
|
3648
|
+
if (name === "bootstrap_project" || name === "post_task") return true;
|
|
3649
|
+
if (name === "import_docs") return toolProfile !== "enforcement";
|
|
3650
|
+
return toolProfile === "experimental" || toolProfile === "full";
|
|
3651
|
+
};
|
|
3532
3652
|
registerTool(
|
|
3533
3653
|
"mem_save",
|
|
3534
3654
|
[
|