@hiveai/mcp 0.9.15 → 0.9.17
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 +201 -16
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +19 -2
- package/dist/server.js +206 -16
- package/dist/server.js.map +1 -1
- package/package.json +3 -3
package/dist/server.d.ts
CHANGED
|
@@ -69,6 +69,11 @@ declare const GetBriefingZod: z.ZodObject<{
|
|
|
69
69
|
budget_preset?: "quick" | "balanced" | "deep" | undefined;
|
|
70
70
|
}>;
|
|
71
71
|
type GetBriefingInput = z.infer<typeof GetBriefingZod>;
|
|
72
|
+
type BriefingMemoryPriority = "must_read" | "useful" | "background";
|
|
73
|
+
interface BriefingQuality {
|
|
74
|
+
level: "strong" | "thin" | "noisy";
|
|
75
|
+
reasons: string[];
|
|
76
|
+
}
|
|
72
77
|
interface BriefingMemory {
|
|
73
78
|
id: string;
|
|
74
79
|
scope: string;
|
|
@@ -80,9 +85,11 @@ interface BriefingMemory {
|
|
|
80
85
|
/** Present when confidence is 'low' or 'unverified' — AI should weight this memory cautiously. */
|
|
81
86
|
unverified?: true;
|
|
82
87
|
read_count: number;
|
|
83
|
-
reasons: Array<"anchor" | "module" | "domain" | "semantic">;
|
|
88
|
+
reasons: Array<"anchor" | "module" | "domain" | "semantic" | "symbol">;
|
|
84
89
|
match_quality: "exact" | "partial" | "semantic";
|
|
85
90
|
semantic_score?: number;
|
|
91
|
+
/** Relevance tier for the current task. `must_read` should be consumed before edits. */
|
|
92
|
+
priority: BriefingMemoryPriority;
|
|
86
93
|
/** Human/agent-readable explanation for why this record was surfaced. */
|
|
87
94
|
why?: string[];
|
|
88
95
|
body: string;
|
|
@@ -132,6 +139,7 @@ interface BriefingOutput {
|
|
|
132
139
|
truncated: boolean;
|
|
133
140
|
}>;
|
|
134
141
|
memories: BriefingMemory[];
|
|
142
|
+
briefing_quality: BriefingQuality;
|
|
135
143
|
symbol_locations?: CodeMapSymbolHit[];
|
|
136
144
|
/**
|
|
137
145
|
* Memories that require explicit human confirmation before any code action.
|
|
@@ -249,6 +257,7 @@ interface MemRelevantToOutput {
|
|
|
249
257
|
task: string;
|
|
250
258
|
search_mode: "semantic" | "literal_fallback" | "literal";
|
|
251
259
|
memories: BriefingMemory[];
|
|
260
|
+
briefing_quality: BriefingQuality;
|
|
252
261
|
hints?: string[];
|
|
253
262
|
/**
|
|
254
263
|
* True when the search returned zero memories — clients can skip surfacing
|
|
@@ -549,6 +558,8 @@ interface ClassifiedAntiPatternsWarning extends AntiPatternsWarning {
|
|
|
549
558
|
*/
|
|
550
559
|
level: AntiPatternLevel;
|
|
551
560
|
rationale: string;
|
|
561
|
+
affected_files: string[];
|
|
562
|
+
repair_command: string;
|
|
552
563
|
}
|
|
553
564
|
/**
|
|
554
565
|
* One-shot "should I block this commit?" check.
|
|
@@ -675,6 +686,12 @@ declare function runtimeJournalTail(input: RuntimeJournalTailInput, ctx: HaiveCo
|
|
|
675
686
|
|
|
676
687
|
declare const SERVER_NAME = "haive";
|
|
677
688
|
declare const SERVER_VERSION: string;
|
|
689
|
+
type ToolProfile = "enforcement" | "maintenance" | "experimental" | "full";
|
|
690
|
+
declare const ENFORCEMENT_PROFILE_TOOLS: readonly ["get_briefing", "mem_save", "mem_tried", "mem_search", "mem_get", "mem_verify", "mem_relevant_to", "code_map", "pre_commit_check", "mem_session_end"];
|
|
691
|
+
declare const MAINTENANCE_PROFILE_TOOLS: readonly ["get_briefing", "mem_save", "mem_tried", "mem_search", "mem_get", "mem_verify", "mem_relevant_to", "code_map", "pre_commit_check", "mem_session_end", "mem_suggest_topic", "mem_for_files", "mem_list", "get_project_context", "bootstrap_project_save", "mem_resolve_project", "mem_update", "mem_approve", "mem_reject", "mem_pending", "mem_delete", "mem_diff", "get_recap", "code_search", "anti_patterns_check", "mem_distill", "mem_timeline", "mem_conflict_candidates"];
|
|
692
|
+
declare const EXPERIMENTAL_PROFILE_TOOLS: readonly ["get_briefing", "mem_save", "mem_tried", "mem_search", "mem_get", "mem_verify", "mem_relevant_to", "code_map", "pre_commit_check", "mem_session_end", "mem_suggest_topic", "mem_for_files", "mem_list", "get_project_context", "bootstrap_project_save", "mem_resolve_project", "mem_update", "mem_approve", "mem_reject", "mem_pending", "mem_delete", "mem_diff", "get_recap", "code_search", "anti_patterns_check", "mem_distill", "mem_timeline", "mem_conflict_candidates", "mem_observe", "why_this_file", "why_this_decision", "mem_conflicts_with", "pattern_detect", "runtime_journal_append", "runtime_journal_tail"];
|
|
693
|
+
declare const TOOL_PROFILES: Record<Exclude<ToolProfile, "full">, ReadonlySet<string>>;
|
|
694
|
+
declare function getAllowedToolsForProfile(profile: ToolProfile): ReadonlySet<string>;
|
|
678
695
|
declare function createHaiveServer(options?: CreateContextOptions): {
|
|
679
696
|
server: McpServer;
|
|
680
697
|
context: HaiveContext;
|
|
@@ -695,4 +712,4 @@ declare function runHaiveMcpStdio(options: {
|
|
|
695
712
|
root?: string;
|
|
696
713
|
}): Promise<void>;
|
|
697
714
|
|
|
698
|
-
export { type AntiPatternsCheckInput, type AntiPatternsCheckOutput, type BriefingOutput, type CodeMapInput, type CodeMapToolOutput, type CodeSearchInput, type CodeSearchOutput, type GetBriefingInput, type GetRecapInput, type GetRecapOutput, type MemConflictCandidatesInput, type MemConflictsInput, type MemConflictsOutput, type MemDistillInput, type MemDistillOutput, type MemRelevantToInput, type MemRelevantToOutput, type MemResolveProjectInput, type MemSuggestTopicInput, type MemTimelineInput, type PatternDetectInput, type PatternDetectOutput, type PreCommitCheckInput, type PreCommitCheckOutput, type RuntimeJournalAppendInput, type RuntimeJournalTailInput, SERVER_NAME, SERVER_VERSION, type WhyThisDecisionInput, type WhyThisDecisionOutput, type WhyThisFileInput, type WhyThisFileOutput, antiPatternsCheck, codeMapTool, codeSearch, createHaiveServer, getBriefing, getRecap, memConflictCandidates, memConflicts, memDistill, memRelevantTo, memResolveProject, memSuggestTopic, memTimeline, parseMcpCliArgs, patternDetect, preCommitCheck, printHaiveMcpVersion, runHaiveMcpStdio, runtimeJournalAppend, runtimeJournalTail, whyThisDecision, whyThisFile };
|
|
715
|
+
export { type AntiPatternsCheckInput, type AntiPatternsCheckOutput, type BriefingOutput, type CodeMapInput, type CodeMapToolOutput, type CodeSearchInput, type CodeSearchOutput, ENFORCEMENT_PROFILE_TOOLS, EXPERIMENTAL_PROFILE_TOOLS, type GetBriefingInput, type GetRecapInput, type GetRecapOutput, MAINTENANCE_PROFILE_TOOLS, type MemConflictCandidatesInput, type MemConflictsInput, type MemConflictsOutput, type MemDistillInput, type MemDistillOutput, type MemRelevantToInput, type MemRelevantToOutput, type MemResolveProjectInput, type MemSuggestTopicInput, type MemTimelineInput, type PatternDetectInput, type PatternDetectOutput, type PreCommitCheckInput, type PreCommitCheckOutput, type RuntimeJournalAppendInput, type RuntimeJournalTailInput, SERVER_NAME, SERVER_VERSION, TOOL_PROFILES, type ToolProfile, type WhyThisDecisionInput, type WhyThisDecisionOutput, type WhyThisFileInput, type WhyThisFileOutput, antiPatternsCheck, codeMapTool, codeSearch, createHaiveServer, getAllowedToolsForProfile, getBriefing, getRecap, memConflictCandidates, memConflicts, memDistill, memRelevantTo, memResolveProject, memSuggestTopic, memTimeline, parseMcpCliArgs, patternDetect, preCommitCheck, printHaiveMcpVersion, runHaiveMcpStdio, runtimeJournalAppend, runtimeJournalTail, whyThisDecision, whyThisFile };
|
package/dist/server.js
CHANGED
|
@@ -222,7 +222,6 @@ async function memSave(input, ctx) {
|
|
|
222
222
|
const { similarityWarning: simW, body_similar: bs } = bodySimilarWarnings(/* @__PURE__ */ new Set([fm.id]));
|
|
223
223
|
const newFrontmatter = {
|
|
224
224
|
...fm,
|
|
225
|
-
body: input.body,
|
|
226
225
|
tags: input.tags.length ? input.tags : fm.tags,
|
|
227
226
|
revision_count: (fm.revision_count ?? 0) + 1,
|
|
228
227
|
anchor: {
|
|
@@ -238,6 +237,7 @@ async function memSave(input, ctx) {
|
|
|
238
237
|
);
|
|
239
238
|
const mergedTw = [
|
|
240
239
|
invalidPaths.length > 0 ? `Anchor path(s) not found in project: ${invalidPaths.join(", ")}. They will be marked stale by haive sync.` : null,
|
|
240
|
+
criticalAnchorWarning(input.type, fm.status, newFrontmatter.anchor.paths, newFrontmatter.anchor.symbols),
|
|
241
241
|
simW ?? null
|
|
242
242
|
].filter(Boolean).join(" \u2014 ") || void 0;
|
|
243
243
|
return {
|
|
@@ -293,6 +293,7 @@ async function memSave(input, ctx) {
|
|
|
293
293
|
const { similarityWarning: simWarnNew, body_similar: bsNew } = bodySimilarWarnings();
|
|
294
294
|
const finalWarning = [
|
|
295
295
|
invalidPaths.length > 0 ? `Anchor path(s) not found in project: ${invalidPaths.join(", ")}. They will be marked stale by \`haive sync\`.` : null,
|
|
296
|
+
criticalAnchorWarning(frontmatter.type, frontmatter.status, frontmatter.anchor.paths, frontmatter.anchor.symbols),
|
|
296
297
|
warning ?? null,
|
|
297
298
|
simWarnNew ?? null
|
|
298
299
|
].filter(Boolean).join(" \u2014 ") || void 0;
|
|
@@ -307,6 +308,12 @@ async function memSave(input, ctx) {
|
|
|
307
308
|
...invalidPaths.length > 0 ? { invalid_paths: invalidPaths } : {}
|
|
308
309
|
};
|
|
309
310
|
}
|
|
311
|
+
function criticalAnchorWarning(type, status, paths, symbols) {
|
|
312
|
+
if (!["decision", "gotcha", "architecture"].includes(type)) return null;
|
|
313
|
+
if (status !== "validated") return null;
|
|
314
|
+
if (paths.length > 0 || symbols.length > 0) return null;
|
|
315
|
+
return `${type} is validated without paths or symbols; add anchors so hAIve can detect drift.`;
|
|
316
|
+
}
|
|
310
317
|
|
|
311
318
|
// src/tools/mem-search.ts
|
|
312
319
|
import { existsSync as existsSync5 } from "fs";
|
|
@@ -1383,6 +1390,7 @@ import {
|
|
|
1383
1390
|
extractActionsBriefBody,
|
|
1384
1391
|
getUsage as getUsage5,
|
|
1385
1392
|
inferModulesFromPaths as inferModulesFromPaths2,
|
|
1393
|
+
isGlobPath,
|
|
1386
1394
|
isAutoPromoteEligible,
|
|
1387
1395
|
isDecaying,
|
|
1388
1396
|
literalMatchesAllTokens as literalMatchesAllTokens2,
|
|
@@ -1504,6 +1512,7 @@ async function getBriefing(input, ctx) {
|
|
|
1504
1512
|
reasons: [reason],
|
|
1505
1513
|
match_quality: matchQuality ?? "partial",
|
|
1506
1514
|
...score !== void 0 ? { semantic_score: score } : {},
|
|
1515
|
+
priority: "background",
|
|
1507
1516
|
body: loaded.memory.body,
|
|
1508
1517
|
file_path: loaded.filePath
|
|
1509
1518
|
});
|
|
@@ -1519,6 +1528,13 @@ async function getBriefing(input, ctx) {
|
|
|
1519
1528
|
if (fm.tags.some((t) => inferred.includes(t))) addOrUpdate(loaded, "module", void 0, "partial");
|
|
1520
1529
|
}
|
|
1521
1530
|
}
|
|
1531
|
+
if (input.symbols.length > 0) {
|
|
1532
|
+
const wanted = new Set(input.symbols.map((s) => s.toLowerCase()));
|
|
1533
|
+
for (const loaded of allMemories) {
|
|
1534
|
+
const symbols = loaded.memory.frontmatter.anchor.symbols.map((s) => s.toLowerCase());
|
|
1535
|
+
if (symbols.some((s) => wanted.has(s))) addOrUpdate(loaded, "symbol", void 0, "exact");
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1522
1538
|
if (input.task) {
|
|
1523
1539
|
const tokens = tokenizeQuery2(input.task);
|
|
1524
1540
|
const andHits = allMemories.filter((m) => literalMatchesAllTokens2(m.memory, tokens));
|
|
@@ -1544,11 +1560,12 @@ async function getBriefing(input, ctx) {
|
|
|
1544
1560
|
}
|
|
1545
1561
|
}
|
|
1546
1562
|
const ranked = [...seen.values()].sort((a, b) => {
|
|
1563
|
+
const priorityScore = (m) => priorityRank(classifyMemoryPriority(m, byId.get(m.id), input.files, input.symbols));
|
|
1547
1564
|
const reasonScore = (m) => (m.type === "attempt" ? 3 : 0) + // attempt = negative knowledge, surface first to prevent repeating mistakes
|
|
1548
|
-
(m.reasons.includes("anchor") ? 4 : 0) + (m.reasons.includes("module") ? 2 : 0) + (m.reasons.includes("semantic") ? 2 : 0) + (m.reasons.includes("domain") ? 1 : 0);
|
|
1565
|
+
(m.reasons.includes("anchor") ? 4 : 0) + (m.reasons.includes("symbol") ? 4 : 0) + (m.reasons.includes("module") ? 2 : 0) + (m.reasons.includes("semantic") ? 2 : 0) + (m.reasons.includes("domain") ? 1 : 0);
|
|
1549
1566
|
const confidenceScore = (m) => m.confidence === "authoritative" ? 4 : m.confidence === "trusted" ? 3 : m.confidence === "low" ? 1 : m.confidence === "stale" ? -2 : 0;
|
|
1550
|
-
const sa = reasonScore(a) + confidenceScore(a) + (a.semantic_score ?? 0);
|
|
1551
|
-
const sb = reasonScore(b) + confidenceScore(b) + (b.semantic_score ?? 0);
|
|
1567
|
+
const sa = priorityScore(a) * 100 + reasonScore(a) + confidenceScore(a) + (a.semantic_score ?? 0);
|
|
1568
|
+
const sb = priorityScore(b) * 100 + reasonScore(b) + confidenceScore(b) + (b.semantic_score ?? 0);
|
|
1552
1569
|
return sb - sa;
|
|
1553
1570
|
});
|
|
1554
1571
|
for (const mem of ranked.slice(0, briefingMaxMemories)) {
|
|
@@ -1707,8 +1724,15 @@ ${m.content}`).join("\n\n---\n\n"),
|
|
|
1707
1724
|
})) : trimmedMemories;
|
|
1708
1725
|
const outputMemories = formattedMemories.map((m) => ({
|
|
1709
1726
|
...m,
|
|
1727
|
+
priority: classifyMemoryPriority(m, byId.get(m.id), input.files, input.symbols),
|
|
1710
1728
|
why: explainWhySurfaced(m, byId.get(m.id), input.files, inferred)
|
|
1711
1729
|
}));
|
|
1730
|
+
const briefingQuality = classifyBriefingQuality(outputMemories, {
|
|
1731
|
+
isTemplateContext,
|
|
1732
|
+
autoContextGenerated,
|
|
1733
|
+
hasLastSession: Boolean(lastSession),
|
|
1734
|
+
searchMode
|
|
1735
|
+
});
|
|
1712
1736
|
let symbolLocations;
|
|
1713
1737
|
const symbolsToLookup = new Set(input.symbols);
|
|
1714
1738
|
for (const m of outputMemories) {
|
|
@@ -1849,6 +1873,7 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
1849
1873
|
} : null,
|
|
1850
1874
|
module_contexts: trimmedModules,
|
|
1851
1875
|
memories: outputMemories,
|
|
1876
|
+
briefing_quality: briefingQuality,
|
|
1852
1877
|
...symbolLocations ? { symbol_locations: symbolLocations } : {},
|
|
1853
1878
|
action_required: actionRequired,
|
|
1854
1879
|
decay_warnings: decayWarnings,
|
|
@@ -1874,6 +1899,53 @@ function compactSummary(body) {
|
|
|
1874
1899
|
}
|
|
1875
1900
|
return body.slice(0, 120);
|
|
1876
1901
|
}
|
|
1902
|
+
function classifyMemoryPriority(memory, loaded, inputFiles, inputSymbols) {
|
|
1903
|
+
const fm = loaded?.memory.frontmatter;
|
|
1904
|
+
const directAnchor = Boolean(
|
|
1905
|
+
fm && inputFiles.length > 0 && fm.anchor.paths.some((p) => inputFiles.some((file) => pathsOverlap(p, file)))
|
|
1906
|
+
);
|
|
1907
|
+
const directSymbol = Boolean(
|
|
1908
|
+
fm && inputSymbols.length > 0 && fm.anchor.symbols.some(
|
|
1909
|
+
(sym) => inputSymbols.some((wanted) => wanted.toLowerCase() === sym.toLowerCase())
|
|
1910
|
+
)
|
|
1911
|
+
);
|
|
1912
|
+
const strongSemantic = (memory.semantic_score ?? 0) >= 0.65;
|
|
1913
|
+
const usefulSemantic = (memory.semantic_score ?? 0) >= 0.35;
|
|
1914
|
+
if (fm?.requires_human_approval || directAnchor || directSymbol || memory.type === "attempt" && (memory.match_quality === "exact" || strongSemantic)) {
|
|
1915
|
+
return "must_read";
|
|
1916
|
+
}
|
|
1917
|
+
if (memory.reasons.includes("module") || memory.reasons.includes("domain") || memory.match_quality === "exact" || usefulSemantic) {
|
|
1918
|
+
return "useful";
|
|
1919
|
+
}
|
|
1920
|
+
return "background";
|
|
1921
|
+
}
|
|
1922
|
+
function priorityRank(priority) {
|
|
1923
|
+
return priority === "must_read" ? 3 : priority === "useful" ? 2 : 1;
|
|
1924
|
+
}
|
|
1925
|
+
function classifyBriefingQuality(memories, context) {
|
|
1926
|
+
const mustRead = memories.filter((m) => m.priority === "must_read").length;
|
|
1927
|
+
const useful = memories.filter((m) => m.priority === "useful").length;
|
|
1928
|
+
const background = memories.filter((m) => m.priority === "background").length;
|
|
1929
|
+
const weakSemantic = memories.filter(
|
|
1930
|
+
(m) => m.reasons.length === 1 && m.reasons.includes("semantic") && (m.semantic_score ?? 0) > 0 && (m.semantic_score ?? 0) < 0.35
|
|
1931
|
+
).length;
|
|
1932
|
+
const reasons = [];
|
|
1933
|
+
if (memories.length === 0) reasons.push("no memories matched the task or files");
|
|
1934
|
+
if (context.isTemplateContext && !context.autoContextGenerated) reasons.push("project context is still a template");
|
|
1935
|
+
if (!context.hasLastSession) reasons.push("no previous session recap");
|
|
1936
|
+
if (mustRead > 0) reasons.push(`${mustRead} must_read memor${mustRead === 1 ? "y" : "ies"} matched directly`);
|
|
1937
|
+
if (useful > 0) reasons.push(`${useful} useful memor${useful === 1 ? "y" : "ies"} matched`);
|
|
1938
|
+
if (background > useful + mustRead && background > 2) reasons.push(`${background} background memories dominate the result`);
|
|
1939
|
+
if (weakSemantic > 0) reasons.push(`${weakSemantic} weak semantic-only match${weakSemantic === 1 ? "" : "es"}`);
|
|
1940
|
+
if (context.searchMode === "literal_fallback") reasons.push("semantic index unavailable or empty; literal fallback used");
|
|
1941
|
+
if (memories.length === 0 || mustRead === 0 && useful === 0) {
|
|
1942
|
+
return { level: "thin", reasons };
|
|
1943
|
+
}
|
|
1944
|
+
if (background > useful + mustRead && background > 2) {
|
|
1945
|
+
return { level: "noisy", reasons };
|
|
1946
|
+
}
|
|
1947
|
+
return { level: "strong", reasons };
|
|
1948
|
+
}
|
|
1877
1949
|
function explainWhySurfaced(memory, loaded, inputFiles, inferredModules) {
|
|
1878
1950
|
const why = [];
|
|
1879
1951
|
const fm = loaded?.memory.frontmatter;
|
|
@@ -1882,7 +1954,19 @@ function explainWhySurfaced(memory, loaded, inputFiles, inferredModules) {
|
|
|
1882
1954
|
(p) => inputFiles.length === 0 || inputFiles.some((file) => pathsOverlap(p, file))
|
|
1883
1955
|
);
|
|
1884
1956
|
if (matching.length > 0) {
|
|
1885
|
-
|
|
1957
|
+
const exact = matching.filter(
|
|
1958
|
+
(p) => !isGlobPath(p) && inputFiles.some((file) => p === file || pathsOverlap(p, file))
|
|
1959
|
+
);
|
|
1960
|
+
const glob = matching.filter((p) => isGlobPath(p));
|
|
1961
|
+
if (exact.length > 0) {
|
|
1962
|
+
why.push(`Exact/file anchor match: ${exact.slice(0, 4).join(", ")}`);
|
|
1963
|
+
}
|
|
1964
|
+
if (glob.length > 0) {
|
|
1965
|
+
why.push(`Glob anchor match: ${glob.slice(0, 4).join(", ")}`);
|
|
1966
|
+
}
|
|
1967
|
+
if (exact.length === 0 && glob.length === 0) {
|
|
1968
|
+
why.push(`Anchored to touched path${matching.length === 1 ? "" : "s"}: ${matching.slice(0, 4).join(", ")}`);
|
|
1969
|
+
}
|
|
1886
1970
|
} else if (fm.anchor.paths.length > 0) {
|
|
1887
1971
|
why.push(`Pulled by related anchor: ${fm.anchor.paths.slice(0, 4).join(", ")}`);
|
|
1888
1972
|
}
|
|
@@ -1890,6 +1974,9 @@ function explainWhySurfaced(memory, loaded, inputFiles, inferredModules) {
|
|
|
1890
1974
|
why.push(`Anchor symbol${fm.anchor.symbols.length === 1 ? "" : "s"}: ${fm.anchor.symbols.slice(0, 4).join(", ")}`);
|
|
1891
1975
|
}
|
|
1892
1976
|
}
|
|
1977
|
+
if (memory.reasons.includes("symbol") && fm) {
|
|
1978
|
+
why.push(`Explicit symbol match: ${fm.anchor.symbols.slice(0, 4).join(", ")}`);
|
|
1979
|
+
}
|
|
1893
1980
|
if (memory.reasons.includes("module")) {
|
|
1894
1981
|
const moduleHints = [
|
|
1895
1982
|
...memory.module ? [memory.module] : [],
|
|
@@ -2131,7 +2218,8 @@ async function memRelevantTo(input, ctx) {
|
|
|
2131
2218
|
const out = {
|
|
2132
2219
|
task: input.task,
|
|
2133
2220
|
search_mode: briefing.search_mode,
|
|
2134
|
-
memories: briefing.memories
|
|
2221
|
+
memories: briefing.memories,
|
|
2222
|
+
briefing_quality: briefing.briefing_quality
|
|
2135
2223
|
};
|
|
2136
2224
|
if (briefing.hints && briefing.hints.length > 0) out.hints = briefing.hints;
|
|
2137
2225
|
if (briefing.memories.length === 0) out.empty = true;
|
|
@@ -2878,7 +2966,7 @@ async function preCommitCheck(input, ctx) {
|
|
|
2878
2966
|
const filesTouching = new Set(relevantMatches.map((m) => m.id));
|
|
2879
2967
|
const staleHits = verifyResult.results.filter((r) => r.stale && filesTouching.has(r.id));
|
|
2880
2968
|
const blockOn = input.block_on;
|
|
2881
|
-
const classifiedWarnings = apResult.warnings.map(classifyWarning);
|
|
2969
|
+
const classifiedWarnings = apResult.warnings.map((warning) => classifyWarning(warning, input.paths));
|
|
2882
2970
|
const blockingWarnings = classifiedWarnings.filter((w) => w.level === "blocking");
|
|
2883
2971
|
const reviewWarnings = classifiedWarnings.filter((w) => w.level === "review");
|
|
2884
2972
|
const infoWarnings = classifiedWarnings.filter((w) => w.level === "info");
|
|
@@ -2913,12 +3001,26 @@ async function preCommitCheck(input, ctx) {
|
|
|
2913
3001
|
}))
|
|
2914
3002
|
};
|
|
2915
3003
|
}
|
|
2916
|
-
function classifyWarning(warning) {
|
|
3004
|
+
function classifyWarning(warning, paths) {
|
|
3005
|
+
const affectedFiles = paths.filter((p) => !p.startsWith(".ai/.usage/"));
|
|
3006
|
+
const repairCommand = repairCommandForWarning(warning, affectedFiles);
|
|
3007
|
+
const fileDowngrade = fileTypeDowngradeReason(warning, affectedFiles);
|
|
3008
|
+
if (fileDowngrade) {
|
|
3009
|
+
return {
|
|
3010
|
+
...warning,
|
|
3011
|
+
level: "info",
|
|
3012
|
+
rationale: fileDowngrade,
|
|
3013
|
+
affected_files: affectedFiles,
|
|
3014
|
+
repair_command: repairCommand
|
|
3015
|
+
};
|
|
3016
|
+
}
|
|
2917
3017
|
if (isBlockingWarning(warning)) {
|
|
2918
3018
|
return {
|
|
2919
3019
|
...warning,
|
|
2920
3020
|
level: "blocking",
|
|
2921
|
-
rationale: "authoritative/trusted memory plus strong semantic match to the diff (score >= 0.65)"
|
|
3021
|
+
rationale: "authoritative/trusted memory plus strong semantic match to the diff (score >= 0.65)",
|
|
3022
|
+
affected_files: affectedFiles,
|
|
3023
|
+
repair_command: repairCommand
|
|
2922
3024
|
};
|
|
2923
3025
|
}
|
|
2924
3026
|
const hasSemantic = warning.reasons.includes("semantic");
|
|
@@ -2928,13 +3030,17 @@ function classifyWarning(warning) {
|
|
|
2928
3030
|
return {
|
|
2929
3031
|
...warning,
|
|
2930
3032
|
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"
|
|
3033
|
+
rationale: hasSemantic ? "semantic match is plausible but below blocking threshold" : "anchored high-confidence memory also matched diff tokens, but no strong semantic proof",
|
|
3034
|
+
affected_files: affectedFiles,
|
|
3035
|
+
repair_command: repairCommand
|
|
2932
3036
|
};
|
|
2933
3037
|
}
|
|
2934
3038
|
return {
|
|
2935
3039
|
...warning,
|
|
2936
3040
|
level: "info",
|
|
2937
|
-
rationale: "weak signal only (literal/anchor/low semantic evidence); surfaced for audit, hidden in concise CLI output"
|
|
3041
|
+
rationale: "weak signal only (literal/anchor/low semantic evidence); surfaced for audit, hidden in concise CLI output",
|
|
3042
|
+
affected_files: affectedFiles,
|
|
3043
|
+
repair_command: repairCommand
|
|
2938
3044
|
};
|
|
2939
3045
|
}
|
|
2940
3046
|
function isBlockingWarning(warning) {
|
|
@@ -2942,6 +3048,40 @@ function isBlockingWarning(warning) {
|
|
|
2942
3048
|
if (!highConfidence) return false;
|
|
2943
3049
|
return warning.reasons.includes("semantic") && (warning.semantic_score ?? 0) >= 0.65;
|
|
2944
3050
|
}
|
|
3051
|
+
function fileTypeDowngradeReason(warning, paths) {
|
|
3052
|
+
if (paths.length === 0) return null;
|
|
3053
|
+
if (paths.every((p) => p.startsWith(".ai/.usage/") || p === ".ai/.usage/tool-usage.jsonl")) {
|
|
3054
|
+
return ".ai usage logs are local telemetry and never block commits.";
|
|
3055
|
+
}
|
|
3056
|
+
const docsOnly = paths.every(isDocLikePath);
|
|
3057
|
+
if (docsOnly && !hasStrongSemantic(warning)) {
|
|
3058
|
+
return "docs/changelog-only change; anti-pattern is downgraded unless semantic evidence is strong.";
|
|
3059
|
+
}
|
|
3060
|
+
const configOnly = paths.every(isPackageOrConfigPath);
|
|
3061
|
+
if (configOnly && looksRuntimeSpecific(warning) && !warning.reasons.includes("anchor") && !hasStrongSemantic(warning)) {
|
|
3062
|
+
return "package/config-only change; runtime-specific gotcha is not anchored or semantically strong.";
|
|
3063
|
+
}
|
|
3064
|
+
return null;
|
|
3065
|
+
}
|
|
3066
|
+
function hasStrongSemantic(warning) {
|
|
3067
|
+
return warning.reasons.includes("semantic") && (warning.semantic_score ?? 0) >= 0.65;
|
|
3068
|
+
}
|
|
3069
|
+
function isDocLikePath(file) {
|
|
3070
|
+
const lower = file.toLowerCase();
|
|
3071
|
+
return lower.endsWith(".md") || lower.includes("changelog") || lower.startsWith("docs/") || lower.startsWith(".github/") && lower.endsWith(".md");
|
|
3072
|
+
}
|
|
3073
|
+
function isPackageOrConfigPath(file) {
|
|
3074
|
+
const lower = file.toLowerCase();
|
|
3075
|
+
return lower.endsWith("package.json") || lower.endsWith("package-lock.json") || lower.endsWith("pnpm-lock.yaml") || lower.endsWith("yarn.lock") || lower.endsWith("bun.lockb") || lower.endsWith(".config.ts") || lower.endsWith(".config.js") || lower.endsWith(".json") || lower.endsWith(".yml") || lower.endsWith(".yaml") || lower.startsWith(".github/workflows/");
|
|
3076
|
+
}
|
|
3077
|
+
function looksRuntimeSpecific(warning) {
|
|
3078
|
+
const text = `${warning.body_preview} ${warning.id}`.toLowerCase();
|
|
3079
|
+
return /\b(runtime|controller|request|response|database|transaction|auth|cache|production|service|api|endpoint)\b/.test(text);
|
|
3080
|
+
}
|
|
3081
|
+
function repairCommandForWarning(warning, paths) {
|
|
3082
|
+
const firstPath = paths[0];
|
|
3083
|
+
return firstPath ? `haive briefing --files "${firstPath}" --task "review ${warning.id}"` : `haive memory show ${warning.id}`;
|
|
3084
|
+
}
|
|
2945
3085
|
|
|
2946
3086
|
// src/tools/pattern-detect.ts
|
|
2947
3087
|
import { mkdir as mkdir7, writeFile as writeFile12 } from "fs/promises";
|
|
@@ -3528,7 +3668,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
3528
3668
|
// src/server.ts
|
|
3529
3669
|
import { loadConfigSync } from "@hiveai/core";
|
|
3530
3670
|
var SERVER_NAME = "haive";
|
|
3531
|
-
var SERVER_VERSION = "0.9.
|
|
3671
|
+
var SERVER_VERSION = "0.9.17";
|
|
3532
3672
|
function jsonResult(data) {
|
|
3533
3673
|
return {
|
|
3534
3674
|
content: [
|
|
@@ -3539,7 +3679,7 @@ function jsonResult(data) {
|
|
|
3539
3679
|
]
|
|
3540
3680
|
};
|
|
3541
3681
|
}
|
|
3542
|
-
var ENFORCEMENT_PROFILE_TOOLS =
|
|
3682
|
+
var ENFORCEMENT_PROFILE_TOOLS = [
|
|
3543
3683
|
"get_briefing",
|
|
3544
3684
|
"mem_save",
|
|
3545
3685
|
"mem_tried",
|
|
@@ -3550,7 +3690,47 @@ var ENFORCEMENT_PROFILE_TOOLS = /* @__PURE__ */ new Set([
|
|
|
3550
3690
|
"code_map",
|
|
3551
3691
|
"pre_commit_check",
|
|
3552
3692
|
"mem_session_end"
|
|
3553
|
-
]
|
|
3693
|
+
];
|
|
3694
|
+
var MAINTENANCE_PROFILE_TOOLS = [
|
|
3695
|
+
...ENFORCEMENT_PROFILE_TOOLS,
|
|
3696
|
+
"mem_suggest_topic",
|
|
3697
|
+
"mem_for_files",
|
|
3698
|
+
"mem_list",
|
|
3699
|
+
"get_project_context",
|
|
3700
|
+
"bootstrap_project_save",
|
|
3701
|
+
"mem_resolve_project",
|
|
3702
|
+
"mem_update",
|
|
3703
|
+
"mem_approve",
|
|
3704
|
+
"mem_reject",
|
|
3705
|
+
"mem_pending",
|
|
3706
|
+
"mem_delete",
|
|
3707
|
+
"mem_diff",
|
|
3708
|
+
"get_recap",
|
|
3709
|
+
"code_search",
|
|
3710
|
+
"anti_patterns_check",
|
|
3711
|
+
"mem_distill",
|
|
3712
|
+
"mem_timeline",
|
|
3713
|
+
"mem_conflict_candidates"
|
|
3714
|
+
];
|
|
3715
|
+
var EXPERIMENTAL_PROFILE_TOOLS = [
|
|
3716
|
+
...MAINTENANCE_PROFILE_TOOLS,
|
|
3717
|
+
"mem_observe",
|
|
3718
|
+
"why_this_file",
|
|
3719
|
+
"why_this_decision",
|
|
3720
|
+
"mem_conflicts_with",
|
|
3721
|
+
"pattern_detect",
|
|
3722
|
+
"runtime_journal_append",
|
|
3723
|
+
"runtime_journal_tail"
|
|
3724
|
+
];
|
|
3725
|
+
var TOOL_PROFILES = {
|
|
3726
|
+
enforcement: new Set(ENFORCEMENT_PROFILE_TOOLS),
|
|
3727
|
+
maintenance: new Set(MAINTENANCE_PROFILE_TOOLS),
|
|
3728
|
+
experimental: new Set(EXPERIMENTAL_PROFILE_TOOLS)
|
|
3729
|
+
};
|
|
3730
|
+
function getAllowedToolsForProfile(profile) {
|
|
3731
|
+
if (profile === "full") return TOOL_PROFILES.experimental;
|
|
3732
|
+
return TOOL_PROFILES[profile] ?? TOOL_PROFILES.enforcement;
|
|
3733
|
+
}
|
|
3554
3734
|
var BRIEFING_TOOLS = /* @__PURE__ */ new Set(["get_briefing", "mem_relevant_to"]);
|
|
3555
3735
|
var MUTATING_TOOLS = /* @__PURE__ */ new Set([
|
|
3556
3736
|
"mem_save",
|
|
@@ -3577,7 +3757,8 @@ function createHaiveServer(options = {}) {
|
|
|
3577
3757
|
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
3578
3758
|
{ capabilities: { tools: {}, prompts: {} } }
|
|
3579
3759
|
);
|
|
3580
|
-
const
|
|
3760
|
+
const allowedTools = getAllowedToolsForProfile(toolProfile);
|
|
3761
|
+
const shouldRegisterTool = (name) => allowedTools.has(name);
|
|
3581
3762
|
const registerTool = (name, description, schema, handler) => {
|
|
3582
3763
|
if (!shouldRegisterTool(name)) return;
|
|
3583
3764
|
const tool = server.tool.bind(server);
|
|
@@ -3601,7 +3782,11 @@ function createHaiveServer(options = {}) {
|
|
|
3601
3782
|
}
|
|
3602
3783
|
);
|
|
3603
3784
|
};
|
|
3604
|
-
const shouldRegisterPrompt = (name) =>
|
|
3785
|
+
const shouldRegisterPrompt = (name) => {
|
|
3786
|
+
if (name === "bootstrap_project" || name === "post_task") return true;
|
|
3787
|
+
if (name === "import_docs") return toolProfile !== "enforcement";
|
|
3788
|
+
return toolProfile === "experimental" || toolProfile === "full";
|
|
3789
|
+
};
|
|
3605
3790
|
registerTool(
|
|
3606
3791
|
"mem_save",
|
|
3607
3792
|
[
|
|
@@ -4454,12 +4639,17 @@ async function runHaiveMcpStdio(options) {
|
|
|
4454
4639
|
await server.connect(new StdioServerTransport());
|
|
4455
4640
|
}
|
|
4456
4641
|
export {
|
|
4642
|
+
ENFORCEMENT_PROFILE_TOOLS,
|
|
4643
|
+
EXPERIMENTAL_PROFILE_TOOLS,
|
|
4644
|
+
MAINTENANCE_PROFILE_TOOLS,
|
|
4457
4645
|
SERVER_NAME,
|
|
4458
4646
|
SERVER_VERSION,
|
|
4647
|
+
TOOL_PROFILES,
|
|
4459
4648
|
antiPatternsCheck,
|
|
4460
4649
|
codeMapTool,
|
|
4461
4650
|
codeSearch,
|
|
4462
4651
|
createHaiveServer,
|
|
4652
|
+
getAllowedToolsForProfile,
|
|
4463
4653
|
getBriefing,
|
|
4464
4654
|
getRecap,
|
|
4465
4655
|
memConflictCandidates,
|