@hiveai/mcp 0.21.0 → 0.24.0
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 +69 -29
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +21 -2
- package/dist/server.js +69 -29
- package/dist/server.js.map +1 -1
- package/package.json +3 -3
package/dist/server.d.ts
CHANGED
|
@@ -670,6 +670,13 @@ declare function memTimeline(input: MemTimelineInput, ctx: HaiveContext): Promis
|
|
|
670
670
|
notice: string | undefined;
|
|
671
671
|
}>;
|
|
672
672
|
|
|
673
|
+
interface SuggestedResolution {
|
|
674
|
+
keep_id: string;
|
|
675
|
+
supersede_id: string;
|
|
676
|
+
reason: string;
|
|
677
|
+
/** Copy-paste command that APPLIES the guided supersede (promotes winner, deprecates loser). */
|
|
678
|
+
command: string;
|
|
679
|
+
}
|
|
673
680
|
declare const MemConflictCandidatesInputSchema: {
|
|
674
681
|
since_days: z.ZodDefault<z.ZodNumber>;
|
|
675
682
|
types: z.ZodDefault<z.ZodArray<z.ZodEnum<["decision", "architecture", "convention", "gotcha"]>, "many">>;
|
|
@@ -682,8 +689,20 @@ type MemConflictCandidatesInput = {
|
|
|
682
689
|
[K in keyof typeof MemConflictCandidatesInputSchema]: z.infer<(typeof MemConflictCandidatesInputSchema)[K]>;
|
|
683
690
|
};
|
|
684
691
|
declare function memConflictCandidates(input: MemConflictCandidatesInput, ctx: HaiveContext): Promise<{
|
|
685
|
-
pairs:
|
|
686
|
-
|
|
692
|
+
pairs: {
|
|
693
|
+
suggested_resolution: SuggestedResolution | null;
|
|
694
|
+
id_a: string;
|
|
695
|
+
id_b: string;
|
|
696
|
+
jaccard: number;
|
|
697
|
+
}[];
|
|
698
|
+
topic_status_pairs: {
|
|
699
|
+
suggested_resolution: SuggestedResolution | null;
|
|
700
|
+
id_a: string;
|
|
701
|
+
id_b: string;
|
|
702
|
+
topic: string;
|
|
703
|
+
status_a: string;
|
|
704
|
+
status_b: string;
|
|
705
|
+
}[];
|
|
687
706
|
scanned: number;
|
|
688
707
|
truncated: boolean;
|
|
689
708
|
notice: string | undefined;
|
package/dist/server.js
CHANGED
|
@@ -1149,7 +1149,15 @@ async function memTried(input, ctx) {
|
|
|
1149
1149
|
throw new Error(`Memory already exists at ${file}`);
|
|
1150
1150
|
}
|
|
1151
1151
|
await writeFile8(file, serializeMemory7({ frontmatter, body }), "utf8");
|
|
1152
|
-
|
|
1152
|
+
const sensorGenerated = Boolean(sensor);
|
|
1153
|
+
const hint = sensorGenerated ? void 0 : input.paths.length === 0 ? "No sensor was generated (no `paths` given), so this lesson is feedforward-only \u2014 it will be briefed but the gate cannot block the repeat. Re-run with `paths` set to the file(s) where the mistake lives to close the loop." : "No sensor could be derived from the wording (no distinctive code token). The lesson is briefed but not enforced; add a concrete forbidden token/value, or attach a sensor manually, to make the gate block the repeat.";
|
|
1154
|
+
return {
|
|
1155
|
+
id: frontmatter.id,
|
|
1156
|
+
scope: frontmatter.scope,
|
|
1157
|
+
file_path: file,
|
|
1158
|
+
sensor_generated: sensorGenerated,
|
|
1159
|
+
...hint ? { hint } : {}
|
|
1160
|
+
};
|
|
1153
1161
|
}
|
|
1154
1162
|
|
|
1155
1163
|
// src/tools/ingest-findings.ts
|
|
@@ -1577,6 +1585,7 @@ async function memSessionEnd(input, ctx) {
|
|
|
1577
1585
|
// src/tools/get-briefing.ts
|
|
1578
1586
|
import { readFile as readFile5, writeFile as writeFile13 } from "fs/promises";
|
|
1579
1587
|
import { existsSync as existsSync21 } from "fs";
|
|
1588
|
+
import path11 from "path";
|
|
1580
1589
|
import {
|
|
1581
1590
|
allocateBudget,
|
|
1582
1591
|
briefingProofLine,
|
|
@@ -2020,6 +2029,7 @@ async function getBriefing(input, ctx) {
|
|
|
2020
2029
|
const topSymbols = Object.entries(codeMap.files).flatMap(
|
|
2021
2030
|
([fp, entry]) => entry.exports.slice(0, 3).map((e) => `${e.name} (${fp.split("/").slice(-2).join("/")})`)
|
|
2022
2031
|
).slice(0, 15).join(", ");
|
|
2032
|
+
const commands = await detectRunCommands(ctx.paths.root);
|
|
2023
2033
|
projectContext = `# Project context (auto-generated by hAIve)
|
|
2024
2034
|
|
|
2025
2035
|
> \u26A0 This is a minimal auto-generated context based on the code-map. Invoke the \`bootstrap_project\` MCP prompt to replace it with a full analysis.
|
|
@@ -2029,7 +2039,10 @@ async function getBriefing(input, ctx) {
|
|
|
2029
2039
|
- **Main file types:** ${topExts}
|
|
2030
2040
|
- **Generated at:** ${codeMap.generated_at}
|
|
2031
2041
|
|
|
2032
|
-
|
|
2042
|
+
` + (commands ? `## Commands
|
|
2043
|
+
${commands}
|
|
2044
|
+
|
|
2045
|
+
` : "") + `## Key exports (sample)
|
|
2033
2046
|
` + topSymbols + "\n";
|
|
2034
2047
|
autoContextGenerated = true;
|
|
2035
2048
|
setupWarnings.push(
|
|
@@ -2309,6 +2322,19 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
2309
2322
|
}
|
|
2310
2323
|
};
|
|
2311
2324
|
}
|
|
2325
|
+
async function detectRunCommands(root) {
|
|
2326
|
+
const pkgPath = path11.join(root, "package.json");
|
|
2327
|
+
if (!existsSync21(pkgPath)) return null;
|
|
2328
|
+
try {
|
|
2329
|
+
const pkg = JSON.parse(await readFile5(pkgPath, "utf8"));
|
|
2330
|
+
const scripts = pkg.scripts ?? {};
|
|
2331
|
+
const order = ["test", "build", "lint", "typecheck", "type-check", "dev", "start"];
|
|
2332
|
+
const lines = order.filter((name) => typeof scripts[name] === "string" && scripts[name].trim() !== "").map((name) => `- \`${name}\`: \`${scripts[name]}\``);
|
|
2333
|
+
return lines.length > 0 ? lines.join("\n") : null;
|
|
2334
|
+
} catch {
|
|
2335
|
+
return null;
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2312
2338
|
|
|
2313
2339
|
// src/tools/code-map.ts
|
|
2314
2340
|
import { estimateTokens as estimateTokens2, loadCodeMap as loadCodeMap2, queryCodeMap as queryCodeMap2 } from "@hiveai/core";
|
|
@@ -2548,7 +2574,7 @@ async function codeSearch(input, ctx) {
|
|
|
2548
2574
|
// src/tools/why-this-file.ts
|
|
2549
2575
|
import { existsSync as existsSync24 } from "fs";
|
|
2550
2576
|
import { spawn } from "child_process";
|
|
2551
|
-
import
|
|
2577
|
+
import path12 from "path";
|
|
2552
2578
|
import {
|
|
2553
2579
|
deriveConfidence as deriveConfidence5,
|
|
2554
2580
|
getUsage as getUsage7,
|
|
@@ -2566,7 +2592,7 @@ var WhyThisFileInputSchema = {
|
|
|
2566
2592
|
memory_limit: z25.number().int().positive().max(20).default(5).describe("Cap on memories anchored to this path.")
|
|
2567
2593
|
};
|
|
2568
2594
|
async function whyThisFile(input, ctx) {
|
|
2569
|
-
const fileExists = existsSync24(
|
|
2595
|
+
const fileExists = existsSync24(path12.join(ctx.paths.root, input.path));
|
|
2570
2596
|
const [commits, memories, codeMap] = await Promise.all([
|
|
2571
2597
|
runGitLog(ctx.paths.root, input.path, input.git_log_limit).catch(() => []),
|
|
2572
2598
|
collectAnchoredMemories(ctx, input.path, input.memory_limit),
|
|
@@ -2665,7 +2691,6 @@ function runCommand(cmd, args, cwd) {
|
|
|
2665
2691
|
import { existsSync as existsSync25 } from "fs";
|
|
2666
2692
|
import {
|
|
2667
2693
|
addedLinesFromDiff,
|
|
2668
|
-
appendPreventionEvent,
|
|
2669
2694
|
BRIDGE_TARGET_PATH,
|
|
2670
2695
|
buildDocFrequency,
|
|
2671
2696
|
CODE_STOPWORDS,
|
|
@@ -2677,9 +2702,8 @@ import {
|
|
|
2677
2702
|
loadUsageIndex as loadUsageIndex10,
|
|
2678
2703
|
literalMatchesAnyToken as literalMatchesAnyToken3,
|
|
2679
2704
|
memoryMatchesAnchorPaths as memoryMatchesAnchorPaths4,
|
|
2680
|
-
|
|
2705
|
+
recordPreventionHits,
|
|
2681
2706
|
runSensors,
|
|
2682
|
-
saveUsageIndex as saveUsageIndex4,
|
|
2683
2707
|
sensorTargetsFromDiff,
|
|
2684
2708
|
tokenizeQuery as tokenizeQuery3
|
|
2685
2709
|
} from "@hiveai/core";
|
|
@@ -2864,19 +2888,7 @@ async function antiPatternsCheck(input, ctx) {
|
|
|
2864
2888
|
const strongCatches = warnings.filter(
|
|
2865
2889
|
(w) => w.reasons.includes("sensor") || w.reasons.includes("anchor") && w.reasons.includes("literal")
|
|
2866
2890
|
);
|
|
2867
|
-
|
|
2868
|
-
const recordedIds = [];
|
|
2869
|
-
for (const w of strongCatches) if (recordPrevention(usage, w.id)) recordedIds.push(w.id);
|
|
2870
|
-
if (recordedIds.length > 0) {
|
|
2871
|
-
await saveUsageIndex4(ctx.paths, usage).catch(() => {
|
|
2872
|
-
});
|
|
2873
|
-
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
2874
|
-
for (const id of recordedIds) {
|
|
2875
|
-
await appendPreventionEvent(ctx.paths, { at, id, source: "anti-pattern" }).catch(() => {
|
|
2876
|
-
});
|
|
2877
|
-
}
|
|
2878
|
-
}
|
|
2879
|
-
}
|
|
2891
|
+
await recordPreventionHits(ctx.paths, strongCatches.map((w) => w.id), "anti-pattern");
|
|
2880
2892
|
return {
|
|
2881
2893
|
scanned: negative.length,
|
|
2882
2894
|
warnings
|
|
@@ -3633,7 +3645,7 @@ function repairTargetPathForWarning(warning, paths) {
|
|
|
3633
3645
|
// src/tools/pattern-detect.ts
|
|
3634
3646
|
import { mkdir as mkdir8, writeFile as writeFile14 } from "fs/promises";
|
|
3635
3647
|
import { existsSync as existsSync29 } from "fs";
|
|
3636
|
-
import
|
|
3648
|
+
import path13 from "path";
|
|
3637
3649
|
import { execSync as execSync2 } from "child_process";
|
|
3638
3650
|
import {
|
|
3639
3651
|
buildFrontmatter as buildFrontmatter5,
|
|
@@ -3682,13 +3694,13 @@ async function patternDetect(input, ctx) {
|
|
|
3682
3694
|
try {
|
|
3683
3695
|
const changedFiles = gitChangedFiles(ctx.paths.root, input.since_days);
|
|
3684
3696
|
const configFiles = changedFiles.filter(
|
|
3685
|
-
(f) => CONFIG_PATTERNS.some((p) =>
|
|
3697
|
+
(f) => CONFIG_PATTERNS.some((p) => path13.basename(f.toLowerCase()).includes(p))
|
|
3686
3698
|
);
|
|
3687
3699
|
for (const file of configFiles.slice(0, 5)) {
|
|
3688
3700
|
const diff = gitFileDiff(ctx.paths.root, file, input.since_days);
|
|
3689
3701
|
if (!diff) continue;
|
|
3690
|
-
const parentDir =
|
|
3691
|
-
const baseName =
|
|
3702
|
+
const parentDir = path13.basename(path13.dirname(file));
|
|
3703
|
+
const baseName = path13.basename(file).replace(/\.[^.]+$/, "");
|
|
3692
3704
|
const slug = `${parentDir}-${baseName}`.replace(/[^a-z0-9]/gi, "-").toLowerCase().slice(0, 40);
|
|
3693
3705
|
matches.push({
|
|
3694
3706
|
kind: "config_change",
|
|
@@ -3752,7 +3764,7 @@ async function patternDetect(input, ctx) {
|
|
|
3752
3764
|
for (const [p, { count, tools }] of pathCounts) {
|
|
3753
3765
|
if (count < HOT_FILE_MIN) continue;
|
|
3754
3766
|
if (tools.has("mem_tried") || tools.has("mem_observe")) continue;
|
|
3755
|
-
if (CONFIG_PATTERNS.some((cp) =>
|
|
3767
|
+
if (CONFIG_PATTERNS.some((cp) => path13.basename(p).includes(cp))) continue;
|
|
3756
3768
|
const slug = p.replace(/[^a-z0-9]/g, "-").replace(/-+/g, "-").slice(0, 40);
|
|
3757
3769
|
matches.push({
|
|
3758
3770
|
kind: "hot_file",
|
|
@@ -3799,7 +3811,7 @@ async function patternDetect(input, ctx) {
|
|
|
3799
3811
|
void 0
|
|
3800
3812
|
);
|
|
3801
3813
|
if (existsSync29(file)) continue;
|
|
3802
|
-
await mkdir8(
|
|
3814
|
+
await mkdir8(path13.dirname(file), { recursive: true });
|
|
3803
3815
|
await writeFile14(
|
|
3804
3816
|
file,
|
|
3805
3817
|
serializeMemory12({ frontmatter: fm, body: match.proposed_body }),
|
|
@@ -3848,9 +3860,22 @@ import { existsSync as existsSync30 } from "fs";
|
|
|
3848
3860
|
import {
|
|
3849
3861
|
findLexicalConflictPairs,
|
|
3850
3862
|
findTopicStatusConflictPairs,
|
|
3851
|
-
loadMemoriesFromDir as loadMemoriesFromDir23
|
|
3863
|
+
loadMemoriesFromDir as loadMemoriesFromDir23,
|
|
3864
|
+
planConflictResolution
|
|
3852
3865
|
} from "@hiveai/core";
|
|
3853
3866
|
import { z as z32 } from "zod";
|
|
3867
|
+
function suggestResolution(byId, idA, idB) {
|
|
3868
|
+
const a = byId.get(idA);
|
|
3869
|
+
const b = byId.get(idB);
|
|
3870
|
+
if (!a || !b) return null;
|
|
3871
|
+
const plan = planConflictResolution(a, b);
|
|
3872
|
+
return {
|
|
3873
|
+
keep_id: plan.keep_id,
|
|
3874
|
+
supersede_id: plan.supersede_id,
|
|
3875
|
+
reason: plan.reason,
|
|
3876
|
+
command: `haive memory resolve-conflict ${plan.keep_id} ${plan.supersede_id} --yes`
|
|
3877
|
+
};
|
|
3878
|
+
}
|
|
3854
3879
|
var MemConflictCandidatesInputSchema = {
|
|
3855
3880
|
since_days: z32.number().int().positive().max(3650).default(365).describe("Only memories created since N days ago"),
|
|
3856
3881
|
types: z32.array(z32.enum(["decision", "architecture", "convention", "gotcha"])).default(["decision", "architecture"]).describe("Memory types scanned for pairwise lexical overlap"),
|
|
@@ -3872,6 +3897,7 @@ async function memConflictCandidates(input, ctx) {
|
|
|
3872
3897
|
};
|
|
3873
3898
|
}
|
|
3874
3899
|
const all = await loadMemoriesFromDir23(ctx.paths.memoriesDir);
|
|
3900
|
+
const byId = new Map(all.map((m) => [m.memory.frontmatter.id, m]));
|
|
3875
3901
|
const { pairs, scanned, truncated } = findLexicalConflictPairs(all, {
|
|
3876
3902
|
sinceDays: input.since_days,
|
|
3877
3903
|
types: input.types,
|
|
@@ -3880,8 +3906,22 @@ async function memConflictCandidates(input, ctx) {
|
|
|
3880
3906
|
maxScan: input.max_scan
|
|
3881
3907
|
});
|
|
3882
3908
|
const topicStatusPairs = findTopicStatusConflictPairs(all, input.max_topic_pairs);
|
|
3909
|
+
const enrichedPairs = pairs.map((p) => ({
|
|
3910
|
+
...p,
|
|
3911
|
+
suggested_resolution: suggestResolution(byId, p.id_a, p.id_b)
|
|
3912
|
+
}));
|
|
3913
|
+
const enrichedTopicStatusPairs = topicStatusPairs.map((p) => ({
|
|
3914
|
+
...p,
|
|
3915
|
+
suggested_resolution: suggestResolution(byId, p.id_a, p.id_b)
|
|
3916
|
+
}));
|
|
3883
3917
|
const notice = pairs.length === 0 && topicStatusPairs.length === 0 ? "No lexical or topic-status candidates \u2014 widen since_days/types or lower min_jaccard." : void 0;
|
|
3884
|
-
return {
|
|
3918
|
+
return {
|
|
3919
|
+
pairs: enrichedPairs,
|
|
3920
|
+
topic_status_pairs: enrichedTopicStatusPairs,
|
|
3921
|
+
scanned,
|
|
3922
|
+
truncated,
|
|
3923
|
+
notice
|
|
3924
|
+
};
|
|
3885
3925
|
}
|
|
3886
3926
|
|
|
3887
3927
|
// src/tools/mem-resolve-project.ts
|
|
@@ -4228,7 +4268,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
4228
4268
|
// src/server.ts
|
|
4229
4269
|
import { hasRecentBriefingMarker, loadConfigSync } from "@hiveai/core";
|
|
4230
4270
|
var SERVER_NAME = "haive";
|
|
4231
|
-
var SERVER_VERSION = "0.
|
|
4271
|
+
var SERVER_VERSION = "0.24.0";
|
|
4232
4272
|
function jsonResult(data) {
|
|
4233
4273
|
return {
|
|
4234
4274
|
content: [
|