@hiveai/mcp 0.9.16 → 0.9.18
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 +152 -12
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +12 -1
- package/dist/server.js +152 -12
- 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.
|
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.18";
|
|
3532
3672
|
function jsonResult(data) {
|
|
3533
3673
|
return {
|
|
3534
3674
|
content: [
|