@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/server.d.ts
CHANGED
|
@@ -158,6 +158,14 @@ interface BriefingOutput {
|
|
|
158
158
|
* Clients can use this flag to skip surfacing a near-empty briefing to the model.
|
|
159
159
|
*/
|
|
160
160
|
low_value?: true;
|
|
161
|
+
/**
|
|
162
|
+
* Whether this briefing carries knowledge a capable model could NOT have inferred on its own.
|
|
163
|
+
* - "high": at least one surfaced memory is arbitrary/team-specific (unguessable).
|
|
164
|
+
* - "low": nothing team-specific matched — a generic agent would reach the same answer.
|
|
165
|
+
* When "low" and the project context is still auto-generated/template, the adaptive briefing
|
|
166
|
+
* trims that inferable context to keep the call near-zero-cost (config: adaptiveBriefing).
|
|
167
|
+
*/
|
|
168
|
+
briefing_value?: "high" | "low";
|
|
161
169
|
/**
|
|
162
170
|
* Short, action-oriented hints surfaced to the agent based on the briefing payload.
|
|
163
171
|
* Examples: "haive is uninitialized — use Read/Grep directly", "gotcha memories present — read first".
|
|
@@ -341,15 +349,13 @@ interface WhyThisFileOutput {
|
|
|
341
349
|
*/
|
|
342
350
|
declare function whyThisFile(input: WhyThisFileInput, ctx: HaiveContext): Promise<WhyThisFileOutput>;
|
|
343
351
|
|
|
344
|
-
|
|
345
|
-
diff
|
|
346
|
-
paths:
|
|
347
|
-
limit:
|
|
348
|
-
semantic:
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
[K in keyof typeof AntiPatternsCheckInputSchema]: z.infer<(typeof AntiPatternsCheckInputSchema)[K]>;
|
|
352
|
-
};
|
|
352
|
+
interface AntiPatternsCheckInput {
|
|
353
|
+
diff?: string;
|
|
354
|
+
paths: string[];
|
|
355
|
+
limit: number;
|
|
356
|
+
semantic: boolean;
|
|
357
|
+
min_semantic_score?: number;
|
|
358
|
+
}
|
|
353
359
|
interface AntiPatternsWarning {
|
|
354
360
|
id: string;
|
|
355
361
|
type: "attempt" | "gotcha";
|
|
@@ -693,8 +699,8 @@ declare const SERVER_NAME = "haive";
|
|
|
693
699
|
declare const SERVER_VERSION: string;
|
|
694
700
|
type ToolProfile = "enforcement" | "maintenance" | "experimental" | "full";
|
|
695
701
|
declare const ENFORCEMENT_PROFILE_TOOLS: readonly ["get_briefing", "mem_save", "mem_tried", "mem_search", "mem_get", "mem_verify", "mem_relevant_to", "code_map", "code_search", "pre_commit_check", "mem_session_end"];
|
|
696
|
-
declare const MAINTENANCE_PROFILE_TOOLS: readonly ["get_briefing", "mem_save", "mem_tried", "mem_search", "mem_get", "mem_verify", "mem_relevant_to", "code_map", "code_search", "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", "
|
|
697
|
-
declare const EXPERIMENTAL_PROFILE_TOOLS: readonly ["get_briefing", "mem_save", "mem_tried", "mem_search", "mem_get", "mem_verify", "mem_relevant_to", "code_map", "code_search", "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", "
|
|
702
|
+
declare const MAINTENANCE_PROFILE_TOOLS: readonly ["get_briefing", "mem_save", "mem_tried", "mem_search", "mem_get", "mem_verify", "mem_relevant_to", "code_map", "code_search", "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", "anti_patterns_check", "mem_distill", "mem_timeline", "mem_conflict_candidates"];
|
|
703
|
+
declare const EXPERIMENTAL_PROFILE_TOOLS: readonly ["get_briefing", "mem_save", "mem_tried", "mem_search", "mem_get", "mem_verify", "mem_relevant_to", "code_map", "code_search", "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", "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"];
|
|
698
704
|
declare const TOOL_PROFILES: Record<Exclude<ToolProfile, "full">, ReadonlySet<string>>;
|
|
699
705
|
declare function getAllowedToolsForProfile(profile: ToolProfile): ReadonlySet<string>;
|
|
700
706
|
declare function createHaiveServer(options?: CreateContextOptions): {
|
package/dist/server.js
CHANGED
|
@@ -1074,6 +1074,7 @@ import { existsSync as existsSync15 } from "fs";
|
|
|
1074
1074
|
import path6 from "path";
|
|
1075
1075
|
import {
|
|
1076
1076
|
buildFrontmatter as buildFrontmatter3,
|
|
1077
|
+
isLikelyGuessable,
|
|
1077
1078
|
memoryFilePath as memoryFilePath3,
|
|
1078
1079
|
serializeMemory as serializeMemory7
|
|
1079
1080
|
} from "@hiveai/core";
|
|
@@ -1086,12 +1087,25 @@ var MemObserveInputSchema = {
|
|
|
1086
1087
|
scope: z15.enum(["personal", "team", "module"]).default("team").describe("Visibility scope \u2014 defaults to team since discoveries benefit everyone"),
|
|
1087
1088
|
module: z15.string().optional().describe("Module name (required when scope=module)"),
|
|
1088
1089
|
tags: z15.array(z15.string()).default([]).describe("Tags for filtering"),
|
|
1089
|
-
author: z15.string().optional().describe("Author handle or email")
|
|
1090
|
+
author: z15.string().optional().describe("Author handle or email"),
|
|
1091
|
+
force: z15.boolean().default(false).describe(
|
|
1092
|
+
"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."
|
|
1093
|
+
)
|
|
1090
1094
|
};
|
|
1091
1095
|
async function memObserve(input, ctx) {
|
|
1092
1096
|
if (!existsSync15(ctx.paths.haiveDir)) {
|
|
1093
1097
|
throw new Error(`No .ai/ directory at ${ctx.paths.root}. Run 'haive init' first.`);
|
|
1094
1098
|
}
|
|
1099
|
+
const signalText = [input.what, input.impact, input.fix ?? ""].join(" ");
|
|
1100
|
+
if (!input.force && isLikelyGuessable(signalText)) {
|
|
1101
|
+
return {
|
|
1102
|
+
id: "",
|
|
1103
|
+
scope: input.scope,
|
|
1104
|
+
file_path: "",
|
|
1105
|
+
skipped: true,
|
|
1106
|
+
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."
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1095
1109
|
const slug = input.what.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().split(/\s+/).slice(0, 6).join("-");
|
|
1096
1110
|
const anchorPaths = input.where.split(/[,\n]/).map((s) => s.trim()).filter(Boolean);
|
|
1097
1111
|
const baseFm = buildFrontmatter3({
|
|
@@ -1398,6 +1412,7 @@ import {
|
|
|
1398
1412
|
getUsage as getUsage5,
|
|
1399
1413
|
inferModulesFromPaths as inferModulesFromPaths2,
|
|
1400
1414
|
isGlobPath,
|
|
1415
|
+
isRetiredMemory,
|
|
1401
1416
|
isAutoPromoteEligible,
|
|
1402
1417
|
isDecaying,
|
|
1403
1418
|
isStackPackSeed,
|
|
@@ -1412,6 +1427,8 @@ import {
|
|
|
1412
1427
|
queryCodeMap,
|
|
1413
1428
|
resolveBriefingBudget,
|
|
1414
1429
|
serializeMemory as serializeMemory9,
|
|
1430
|
+
specificityScore,
|
|
1431
|
+
GUESSABLE_THRESHOLD,
|
|
1415
1432
|
tokenizeQuery as tokenizeQuery2,
|
|
1416
1433
|
trackReads as trackReads3,
|
|
1417
1434
|
truncateToTokens,
|
|
@@ -1482,6 +1499,7 @@ async function getBriefing(input, ctx) {
|
|
|
1482
1499
|
const s = memory.frontmatter.status;
|
|
1483
1500
|
if (s === "rejected" || s === "deprecated") return false;
|
|
1484
1501
|
if (!input.include_stale && s === "stale") return false;
|
|
1502
|
+
if (!input.include_stale && isRetiredMemory(memory.frontmatter, memory.body)) return false;
|
|
1485
1503
|
if (memory.frontmatter.type === "session_recap") return false;
|
|
1486
1504
|
return true;
|
|
1487
1505
|
});
|
|
@@ -1837,6 +1855,14 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
1837
1855
|
const memoriesEmpty = outputMemories.length === 0;
|
|
1838
1856
|
const hasMemoriesDir = existsSync18(ctx.paths.memoriesDir);
|
|
1839
1857
|
const isColdStart = isTemplateContext && memoriesEmpty && !lastSession && !autoContextGenerated;
|
|
1858
|
+
const hasUnguessableSignal = outputMemories.some(
|
|
1859
|
+
(m) => (m.priority === "must_read" || m.priority === "useful") && specificityScore(m.body) >= GUESSABLE_THRESHOLD
|
|
1860
|
+
);
|
|
1861
|
+
const briefingValueLow = !hasUnguessableSignal;
|
|
1862
|
+
const adaptiveConfig = await loadConfig3(ctx.paths);
|
|
1863
|
+
const bootstrapUnfilled = /Auto-generated by `haive init/i.test(projectContextRaw) && (projectContextRaw.match(/TODO —/g)?.length ?? 0) >= 2;
|
|
1864
|
+
const contextIsInferable = isTemplateContext || autoContextGenerated || bootstrapUnfilled;
|
|
1865
|
+
const adaptiveTrim = adaptiveConfig.adaptiveBriefing !== false && briefingValueLow && contextIsInferable;
|
|
1840
1866
|
const hints = [];
|
|
1841
1867
|
if (isColdStart) {
|
|
1842
1868
|
hints.push(
|
|
@@ -1869,6 +1895,11 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
1869
1895
|
);
|
|
1870
1896
|
}
|
|
1871
1897
|
}
|
|
1898
|
+
if (adaptiveTrim) {
|
|
1899
|
+
hints.push(
|
|
1900
|
+
"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."
|
|
1901
|
+
);
|
|
1902
|
+
}
|
|
1872
1903
|
if (existsSync18(ctx.paths.haiveDir)) {
|
|
1873
1904
|
await writeBriefingMarker(ctx.paths, {
|
|
1874
1905
|
sessionId: process.env.HAIVE_SESSION_ID,
|
|
@@ -1884,7 +1915,12 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
1884
1915
|
search_mode: searchMode,
|
|
1885
1916
|
inferred_modules: inferred,
|
|
1886
1917
|
...lastSession ? { last_session: lastSession } : {},
|
|
1887
|
-
project_context:
|
|
1918
|
+
project_context: adaptiveTrim ? {
|
|
1919
|
+
content: "(adaptive briefing: auto-generated context omitted \u2014 no team-specific policy matched, so a capable model needs nothing extra here)",
|
|
1920
|
+
truncated: false,
|
|
1921
|
+
...isTemplateContext && !autoContextGenerated ? { is_template: true } : {},
|
|
1922
|
+
...autoContextGenerated ? { auto_generated: true } : {}
|
|
1923
|
+
} : projectContextRaw || autoContextGenerated ? {
|
|
1888
1924
|
content: projectSlice.text,
|
|
1889
1925
|
truncated: projectSlice.truncated,
|
|
1890
1926
|
...isTemplateContext && !autoContextGenerated ? { is_template: true } : {},
|
|
@@ -1898,6 +1934,7 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
1898
1934
|
decay_warnings: decayWarnings,
|
|
1899
1935
|
setup_warnings: setupWarnings,
|
|
1900
1936
|
...isColdStart ? { low_value: true } : {},
|
|
1937
|
+
briefing_value: briefingValueLow ? "low" : "high",
|
|
1901
1938
|
...hints.length > 0 ? { hints } : {},
|
|
1902
1939
|
estimated_tokens: totalTokens,
|
|
1903
1940
|
budget: {
|
|
@@ -2406,6 +2443,7 @@ import { existsSync as existsSync22 } from "fs";
|
|
|
2406
2443
|
import {
|
|
2407
2444
|
deriveConfidence as deriveConfidence6,
|
|
2408
2445
|
getUsage as getUsage7,
|
|
2446
|
+
isRetiredMemory as isRetiredMemory2,
|
|
2409
2447
|
loadMemoriesFromDir as loadMemoriesFromDir17,
|
|
2410
2448
|
loadUsageIndex as loadUsageIndex9,
|
|
2411
2449
|
literalMatchesAnyToken as literalMatchesAnyToken3,
|
|
@@ -2423,6 +2461,9 @@ var AntiPatternsCheckInputSchema = {
|
|
|
2423
2461
|
limit: z24.number().int().positive().max(20).default(8).describe("Cap on returned warnings."),
|
|
2424
2462
|
semantic: z24.boolean().default(true).describe(
|
|
2425
2463
|
"When true, also use semantic search (requires @hiveai/embeddings + memory index) to find related anti-patterns."
|
|
2464
|
+
),
|
|
2465
|
+
min_semantic_score: z24.number().min(0).max(1).default(0.45).describe(
|
|
2466
|
+
"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."
|
|
2426
2467
|
)
|
|
2427
2468
|
};
|
|
2428
2469
|
var CODE_STOPWORDS = /* @__PURE__ */ new Set([
|
|
@@ -2473,8 +2514,12 @@ var CODE_STOPWORDS = /* @__PURE__ */ new Set([
|
|
|
2473
2514
|
"console"
|
|
2474
2515
|
]);
|
|
2475
2516
|
function tokenizeDiffForLiteral(diff) {
|
|
2476
|
-
const
|
|
2477
|
-
const
|
|
2517
|
+
const lines = diff.split("\n");
|
|
2518
|
+
const looksLikeDiff = lines.some((l) => /^[+-]/.test(l));
|
|
2519
|
+
const addedOnly = looksLikeDiff ? lines.filter((l) => l.startsWith("+") && !l.startsWith("+++")).join("\n") : diff;
|
|
2520
|
+
const source = addedOnly.trim().length > 0 ? addedOnly : diff;
|
|
2521
|
+
const wsTokens = tokenizeQuery3(source);
|
|
2522
|
+
const wordTokens = source.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 4 && !CODE_STOPWORDS.has(t));
|
|
2478
2523
|
return [.../* @__PURE__ */ new Set([...wsTokens, ...wordTokens])];
|
|
2479
2524
|
}
|
|
2480
2525
|
async function antiPatternsCheck(input, ctx) {
|
|
@@ -2489,11 +2534,12 @@ async function antiPatternsCheck(input, ctx) {
|
|
|
2489
2534
|
return { scanned: 0, warnings: [], notice: "No .ai/memories directory \u2014 nothing to check against." };
|
|
2490
2535
|
}
|
|
2491
2536
|
const all = await loadMemoriesFromDir17(ctx.paths.memoriesDir);
|
|
2537
|
+
const minSemanticScore = input.min_semantic_score ?? 0.45;
|
|
2492
2538
|
const negative = all.filter(({ memory }) => {
|
|
2493
2539
|
const t = memory.frontmatter.type;
|
|
2494
2540
|
if (t !== "attempt" && t !== "gotcha") return false;
|
|
2495
2541
|
const s = memory.frontmatter.status;
|
|
2496
|
-
return s !== "rejected" && s !== "deprecated" && s !== "stale";
|
|
2542
|
+
return s !== "rejected" && s !== "deprecated" && s !== "stale" && !isRetiredMemory2(memory.frontmatter, memory.body);
|
|
2497
2543
|
});
|
|
2498
2544
|
if (negative.length === 0) {
|
|
2499
2545
|
return { scanned: 0, warnings: [], notice: "No attempt/gotcha memories found yet." };
|
|
@@ -2547,6 +2593,7 @@ async function antiPatternsCheck(input, ctx) {
|
|
|
2547
2593
|
const negativeIds = new Set(negative.map(({ memory }) => memory.frontmatter.id));
|
|
2548
2594
|
for (const hit of result.hits) {
|
|
2549
2595
|
if (!negativeIds.has(hit.id)) continue;
|
|
2596
|
+
if (hit.score < minSemanticScore && !seen.has(hit.id)) continue;
|
|
2550
2597
|
const found = negative.find(({ memory }) => memory.frontmatter.id === hit.id);
|
|
2551
2598
|
if (found) upsert(found.memory.frontmatter, found.memory.body, "semantic", hit.score);
|
|
2552
2599
|
}
|
|
@@ -3825,7 +3872,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
3825
3872
|
// src/server.ts
|
|
3826
3873
|
import { loadConfigSync } from "@hiveai/core";
|
|
3827
3874
|
var SERVER_NAME = "haive";
|
|
3828
|
-
var SERVER_VERSION = "0.
|
|
3875
|
+
var SERVER_VERSION = "0.10.1";
|
|
3829
3876
|
function jsonResult(data) {
|
|
3830
3877
|
return {
|
|
3831
3878
|
content: [
|
|
@@ -3864,7 +3911,6 @@ var MAINTENANCE_PROFILE_TOOLS = [
|
|
|
3864
3911
|
"mem_delete",
|
|
3865
3912
|
"mem_diff",
|
|
3866
3913
|
"get_recap",
|
|
3867
|
-
"code_search",
|
|
3868
3914
|
"anti_patterns_check",
|
|
3869
3915
|
"mem_distill",
|
|
3870
3916
|
"mem_timeline",
|