@hiveai/mcp 0.9.31 → 0.10.1
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 +53 -7
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +17 -11
- package/dist/server.js +53 -7
- package/dist/server.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1076,6 +1076,7 @@ import { existsSync as existsSync15 } from "fs";
|
|
|
1076
1076
|
import path6 from "path";
|
|
1077
1077
|
import {
|
|
1078
1078
|
buildFrontmatter as buildFrontmatter3,
|
|
1079
|
+
isLikelyGuessable,
|
|
1079
1080
|
memoryFilePath as memoryFilePath3,
|
|
1080
1081
|
serializeMemory as serializeMemory7
|
|
1081
1082
|
} from "@hiveai/core";
|
|
@@ -1088,12 +1089,25 @@ var MemObserveInputSchema = {
|
|
|
1088
1089
|
scope: z15.enum(["personal", "team", "module"]).default("team").describe("Visibility scope \u2014 defaults to team since discoveries benefit everyone"),
|
|
1089
1090
|
module: z15.string().optional().describe("Module name (required when scope=module)"),
|
|
1090
1091
|
tags: z15.array(z15.string()).default([]).describe("Tags for filtering"),
|
|
1091
|
-
author: z15.string().optional().describe("Author handle or email")
|
|
1092
|
+
author: z15.string().optional().describe("Author handle or email"),
|
|
1093
|
+
force: z15.boolean().default(false).describe(
|
|
1094
|
+
"Save even if the observation looks like generic, guessable knowledge. By default, low-specificity observations (things a capable model already knows) are SKIPPED to keep the corpus high-signal \u2014 only unguessable, team-specific discoveries are worth storing."
|
|
1095
|
+
)
|
|
1092
1096
|
};
|
|
1093
1097
|
async function memObserve(input, ctx) {
|
|
1094
1098
|
if (!existsSync15(ctx.paths.haiveDir)) {
|
|
1095
1099
|
throw new Error(`No .ai/ directory at ${ctx.paths.root}. Run 'haive init' first.`);
|
|
1096
1100
|
}
|
|
1101
|
+
const signalText = [input.what, input.impact, input.fix ?? ""].join(" ");
|
|
1102
|
+
if (!input.force && isLikelyGuessable(signalText)) {
|
|
1103
|
+
return {
|
|
1104
|
+
id: "",
|
|
1105
|
+
scope: input.scope,
|
|
1106
|
+
file_path: "",
|
|
1107
|
+
skipped: true,
|
|
1108
|
+
reason: "Observation looks like generic, guessable knowledge (low specificity) \u2014 not saved. Capture only arbitrary, team-specific facts (exact names, values, formats). Pass force=true to override."
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1097
1111
|
const slug = input.what.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().split(/\s+/).slice(0, 6).join("-");
|
|
1098
1112
|
const anchorPaths = input.where.split(/[,\n]/).map((s) => s.trim()).filter(Boolean);
|
|
1099
1113
|
const baseFm = buildFrontmatter3({
|
|
@@ -1400,6 +1414,7 @@ import {
|
|
|
1400
1414
|
getUsage as getUsage5,
|
|
1401
1415
|
inferModulesFromPaths as inferModulesFromPaths2,
|
|
1402
1416
|
isGlobPath,
|
|
1417
|
+
isRetiredMemory,
|
|
1403
1418
|
isAutoPromoteEligible,
|
|
1404
1419
|
isDecaying,
|
|
1405
1420
|
isStackPackSeed,
|
|
@@ -1414,6 +1429,8 @@ import {
|
|
|
1414
1429
|
queryCodeMap,
|
|
1415
1430
|
resolveBriefingBudget,
|
|
1416
1431
|
serializeMemory as serializeMemory9,
|
|
1432
|
+
specificityScore,
|
|
1433
|
+
GUESSABLE_THRESHOLD,
|
|
1417
1434
|
tokenizeQuery as tokenizeQuery2,
|
|
1418
1435
|
trackReads as trackReads3,
|
|
1419
1436
|
truncateToTokens,
|
|
@@ -1484,6 +1501,7 @@ async function getBriefing(input, ctx) {
|
|
|
1484
1501
|
const s = memory.frontmatter.status;
|
|
1485
1502
|
if (s === "rejected" || s === "deprecated") return false;
|
|
1486
1503
|
if (!input.include_stale && s === "stale") return false;
|
|
1504
|
+
if (!input.include_stale && isRetiredMemory(memory.frontmatter, memory.body)) return false;
|
|
1487
1505
|
if (memory.frontmatter.type === "session_recap") return false;
|
|
1488
1506
|
return true;
|
|
1489
1507
|
});
|
|
@@ -1839,6 +1857,14 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
1839
1857
|
const memoriesEmpty = outputMemories.length === 0;
|
|
1840
1858
|
const hasMemoriesDir = existsSync18(ctx.paths.memoriesDir);
|
|
1841
1859
|
const isColdStart = isTemplateContext && memoriesEmpty && !lastSession && !autoContextGenerated;
|
|
1860
|
+
const hasUnguessableSignal = outputMemories.some(
|
|
1861
|
+
(m) => (m.priority === "must_read" || m.priority === "useful") && specificityScore(m.body) >= GUESSABLE_THRESHOLD
|
|
1862
|
+
);
|
|
1863
|
+
const briefingValueLow = !hasUnguessableSignal;
|
|
1864
|
+
const adaptiveConfig = await loadConfig3(ctx.paths);
|
|
1865
|
+
const bootstrapUnfilled = /Auto-generated by `haive init/i.test(projectContextRaw) && (projectContextRaw.match(/TODO —/g)?.length ?? 0) >= 2;
|
|
1866
|
+
const contextIsInferable = isTemplateContext || autoContextGenerated || bootstrapUnfilled;
|
|
1867
|
+
const adaptiveTrim = adaptiveConfig.adaptiveBriefing !== false && briefingValueLow && contextIsInferable;
|
|
1842
1868
|
const hints = [];
|
|
1843
1869
|
if (isColdStart) {
|
|
1844
1870
|
hints.push(
|
|
@@ -1871,6 +1897,11 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
1871
1897
|
);
|
|
1872
1898
|
}
|
|
1873
1899
|
}
|
|
1900
|
+
if (adaptiveTrim) {
|
|
1901
|
+
hints.push(
|
|
1902
|
+
"No team-specific policy matched these files/task \u2014 nothing here a capable model can't infer. The auto-generated project context was trimmed to keep this briefing near-zero-cost; proceed with normal Read/Grep."
|
|
1903
|
+
);
|
|
1904
|
+
}
|
|
1874
1905
|
if (existsSync18(ctx.paths.haiveDir)) {
|
|
1875
1906
|
await writeBriefingMarker(ctx.paths, {
|
|
1876
1907
|
sessionId: process.env.HAIVE_SESSION_ID,
|
|
@@ -1886,7 +1917,12 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
1886
1917
|
search_mode: searchMode,
|
|
1887
1918
|
inferred_modules: inferred,
|
|
1888
1919
|
...lastSession ? { last_session: lastSession } : {},
|
|
1889
|
-
project_context:
|
|
1920
|
+
project_context: adaptiveTrim ? {
|
|
1921
|
+
content: "(adaptive briefing: auto-generated context omitted \u2014 no team-specific policy matched, so a capable model needs nothing extra here)",
|
|
1922
|
+
truncated: false,
|
|
1923
|
+
...isTemplateContext && !autoContextGenerated ? { is_template: true } : {},
|
|
1924
|
+
...autoContextGenerated ? { auto_generated: true } : {}
|
|
1925
|
+
} : projectContextRaw || autoContextGenerated ? {
|
|
1890
1926
|
content: projectSlice.text,
|
|
1891
1927
|
truncated: projectSlice.truncated,
|
|
1892
1928
|
...isTemplateContext && !autoContextGenerated ? { is_template: true } : {},
|
|
@@ -1900,6 +1936,7 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
1900
1936
|
decay_warnings: decayWarnings,
|
|
1901
1937
|
setup_warnings: setupWarnings,
|
|
1902
1938
|
...isColdStart ? { low_value: true } : {},
|
|
1939
|
+
briefing_value: briefingValueLow ? "low" : "high",
|
|
1903
1940
|
...hints.length > 0 ? { hints } : {},
|
|
1904
1941
|
estimated_tokens: totalTokens,
|
|
1905
1942
|
budget: {
|
|
@@ -2408,6 +2445,7 @@ import { existsSync as existsSync22 } from "fs";
|
|
|
2408
2445
|
import {
|
|
2409
2446
|
deriveConfidence as deriveConfidence6,
|
|
2410
2447
|
getUsage as getUsage7,
|
|
2448
|
+
isRetiredMemory as isRetiredMemory2,
|
|
2411
2449
|
loadMemoriesFromDir as loadMemoriesFromDir17,
|
|
2412
2450
|
loadUsageIndex as loadUsageIndex9,
|
|
2413
2451
|
literalMatchesAnyToken as literalMatchesAnyToken3,
|
|
@@ -2425,6 +2463,9 @@ var AntiPatternsCheckInputSchema = {
|
|
|
2425
2463
|
limit: z24.number().int().positive().max(20).default(8).describe("Cap on returned warnings."),
|
|
2426
2464
|
semantic: z24.boolean().default(true).describe(
|
|
2427
2465
|
"When true, also use semantic search (requires @hiveai/embeddings + memory index) to find related anti-patterns."
|
|
2466
|
+
),
|
|
2467
|
+
min_semantic_score: z24.number().min(0).max(1).default(0.45).describe(
|
|
2468
|
+
"Minimum cosine score for semantic-only anti-pattern hits. Anchor/literal matches still surface. Default 0.45 keeps broad, weakly-related memories out of review noise."
|
|
2428
2469
|
)
|
|
2429
2470
|
};
|
|
2430
2471
|
var CODE_STOPWORDS = /* @__PURE__ */ new Set([
|
|
@@ -2475,8 +2516,12 @@ var CODE_STOPWORDS = /* @__PURE__ */ new Set([
|
|
|
2475
2516
|
"console"
|
|
2476
2517
|
]);
|
|
2477
2518
|
function tokenizeDiffForLiteral(diff) {
|
|
2478
|
-
const
|
|
2479
|
-
const
|
|
2519
|
+
const lines = diff.split("\n");
|
|
2520
|
+
const looksLikeDiff = lines.some((l) => /^[+-]/.test(l));
|
|
2521
|
+
const addedOnly = looksLikeDiff ? lines.filter((l) => l.startsWith("+") && !l.startsWith("+++")).join("\n") : diff;
|
|
2522
|
+
const source = addedOnly.trim().length > 0 ? addedOnly : diff;
|
|
2523
|
+
const wsTokens = tokenizeQuery3(source);
|
|
2524
|
+
const wordTokens = source.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 4 && !CODE_STOPWORDS.has(t));
|
|
2480
2525
|
return [.../* @__PURE__ */ new Set([...wsTokens, ...wordTokens])];
|
|
2481
2526
|
}
|
|
2482
2527
|
async function antiPatternsCheck(input, ctx) {
|
|
@@ -2491,11 +2536,12 @@ async function antiPatternsCheck(input, ctx) {
|
|
|
2491
2536
|
return { scanned: 0, warnings: [], notice: "No .ai/memories directory \u2014 nothing to check against." };
|
|
2492
2537
|
}
|
|
2493
2538
|
const all = await loadMemoriesFromDir17(ctx.paths.memoriesDir);
|
|
2539
|
+
const minSemanticScore = input.min_semantic_score ?? 0.45;
|
|
2494
2540
|
const negative = all.filter(({ memory }) => {
|
|
2495
2541
|
const t = memory.frontmatter.type;
|
|
2496
2542
|
if (t !== "attempt" && t !== "gotcha") return false;
|
|
2497
2543
|
const s = memory.frontmatter.status;
|
|
2498
|
-
return s !== "rejected" && s !== "deprecated" && s !== "stale";
|
|
2544
|
+
return s !== "rejected" && s !== "deprecated" && s !== "stale" && !isRetiredMemory2(memory.frontmatter, memory.body);
|
|
2499
2545
|
});
|
|
2500
2546
|
if (negative.length === 0) {
|
|
2501
2547
|
return { scanned: 0, warnings: [], notice: "No attempt/gotcha memories found yet." };
|
|
@@ -2549,6 +2595,7 @@ async function antiPatternsCheck(input, ctx) {
|
|
|
2549
2595
|
const negativeIds = new Set(negative.map(({ memory }) => memory.frontmatter.id));
|
|
2550
2596
|
for (const hit of result.hits) {
|
|
2551
2597
|
if (!negativeIds.has(hit.id)) continue;
|
|
2598
|
+
if (hit.score < minSemanticScore && !seen.has(hit.id)) continue;
|
|
2552
2599
|
const found = negative.find(({ memory }) => memory.frontmatter.id === hit.id);
|
|
2553
2600
|
if (found) upsert(found.memory.frontmatter, found.memory.body, "semantic", hit.score);
|
|
2554
2601
|
}
|
|
@@ -3827,7 +3874,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
3827
3874
|
// src/server.ts
|
|
3828
3875
|
import { loadConfigSync } from "@hiveai/core";
|
|
3829
3876
|
var SERVER_NAME = "haive";
|
|
3830
|
-
var SERVER_VERSION = "0.
|
|
3877
|
+
var SERVER_VERSION = "0.10.1";
|
|
3831
3878
|
function jsonResult(data) {
|
|
3832
3879
|
return {
|
|
3833
3880
|
content: [
|
|
@@ -3866,7 +3913,6 @@ var MAINTENANCE_PROFILE_TOOLS = [
|
|
|
3866
3913
|
"mem_delete",
|
|
3867
3914
|
"mem_diff",
|
|
3868
3915
|
"get_recap",
|
|
3869
|
-
"code_search",
|
|
3870
3916
|
"anti_patterns_check",
|
|
3871
3917
|
"mem_distill",
|
|
3872
3918
|
"mem_timeline",
|