@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/index.js
CHANGED
|
@@ -1151,7 +1151,15 @@ async function memTried(input, ctx) {
|
|
|
1151
1151
|
throw new Error(`Memory already exists at ${file}`);
|
|
1152
1152
|
}
|
|
1153
1153
|
await writeFile8(file, serializeMemory7({ frontmatter, body }), "utf8");
|
|
1154
|
-
|
|
1154
|
+
const sensorGenerated = Boolean(sensor);
|
|
1155
|
+
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.";
|
|
1156
|
+
return {
|
|
1157
|
+
id: frontmatter.id,
|
|
1158
|
+
scope: frontmatter.scope,
|
|
1159
|
+
file_path: file,
|
|
1160
|
+
sensor_generated: sensorGenerated,
|
|
1161
|
+
...hint ? { hint } : {}
|
|
1162
|
+
};
|
|
1155
1163
|
}
|
|
1156
1164
|
|
|
1157
1165
|
// src/tools/ingest-findings.ts
|
|
@@ -1579,6 +1587,7 @@ async function memSessionEnd(input, ctx) {
|
|
|
1579
1587
|
// src/tools/get-briefing.ts
|
|
1580
1588
|
import { readFile as readFile5, writeFile as writeFile13 } from "fs/promises";
|
|
1581
1589
|
import { existsSync as existsSync21 } from "fs";
|
|
1590
|
+
import path11 from "path";
|
|
1582
1591
|
import {
|
|
1583
1592
|
allocateBudget,
|
|
1584
1593
|
briefingProofLine,
|
|
@@ -2022,6 +2031,7 @@ async function getBriefing(input, ctx) {
|
|
|
2022
2031
|
const topSymbols = Object.entries(codeMap.files).flatMap(
|
|
2023
2032
|
([fp, entry]) => entry.exports.slice(0, 3).map((e) => `${e.name} (${fp.split("/").slice(-2).join("/")})`)
|
|
2024
2033
|
).slice(0, 15).join(", ");
|
|
2034
|
+
const commands = await detectRunCommands(ctx.paths.root);
|
|
2025
2035
|
projectContext = `# Project context (auto-generated by hAIve)
|
|
2026
2036
|
|
|
2027
2037
|
> \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.
|
|
@@ -2031,7 +2041,10 @@ async function getBriefing(input, ctx) {
|
|
|
2031
2041
|
- **Main file types:** ${topExts}
|
|
2032
2042
|
- **Generated at:** ${codeMap.generated_at}
|
|
2033
2043
|
|
|
2034
|
-
|
|
2044
|
+
` + (commands ? `## Commands
|
|
2045
|
+
${commands}
|
|
2046
|
+
|
|
2047
|
+
` : "") + `## Key exports (sample)
|
|
2035
2048
|
` + topSymbols + "\n";
|
|
2036
2049
|
autoContextGenerated = true;
|
|
2037
2050
|
setupWarnings.push(
|
|
@@ -2311,6 +2324,19 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
2311
2324
|
}
|
|
2312
2325
|
};
|
|
2313
2326
|
}
|
|
2327
|
+
async function detectRunCommands(root) {
|
|
2328
|
+
const pkgPath = path11.join(root, "package.json");
|
|
2329
|
+
if (!existsSync21(pkgPath)) return null;
|
|
2330
|
+
try {
|
|
2331
|
+
const pkg = JSON.parse(await readFile5(pkgPath, "utf8"));
|
|
2332
|
+
const scripts = pkg.scripts ?? {};
|
|
2333
|
+
const order = ["test", "build", "lint", "typecheck", "type-check", "dev", "start"];
|
|
2334
|
+
const lines = order.filter((name) => typeof scripts[name] === "string" && scripts[name].trim() !== "").map((name) => `- \`${name}\`: \`${scripts[name]}\``);
|
|
2335
|
+
return lines.length > 0 ? lines.join("\n") : null;
|
|
2336
|
+
} catch {
|
|
2337
|
+
return null;
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2314
2340
|
|
|
2315
2341
|
// src/tools/code-map.ts
|
|
2316
2342
|
import { estimateTokens as estimateTokens2, loadCodeMap as loadCodeMap2, queryCodeMap as queryCodeMap2 } from "@hiveai/core";
|
|
@@ -2550,7 +2576,7 @@ async function codeSearch(input, ctx) {
|
|
|
2550
2576
|
// src/tools/why-this-file.ts
|
|
2551
2577
|
import { existsSync as existsSync24 } from "fs";
|
|
2552
2578
|
import { spawn } from "child_process";
|
|
2553
|
-
import
|
|
2579
|
+
import path12 from "path";
|
|
2554
2580
|
import {
|
|
2555
2581
|
deriveConfidence as deriveConfidence5,
|
|
2556
2582
|
getUsage as getUsage7,
|
|
@@ -2568,7 +2594,7 @@ var WhyThisFileInputSchema = {
|
|
|
2568
2594
|
memory_limit: z25.number().int().positive().max(20).default(5).describe("Cap on memories anchored to this path.")
|
|
2569
2595
|
};
|
|
2570
2596
|
async function whyThisFile(input, ctx) {
|
|
2571
|
-
const fileExists = existsSync24(
|
|
2597
|
+
const fileExists = existsSync24(path12.join(ctx.paths.root, input.path));
|
|
2572
2598
|
const [commits, memories, codeMap] = await Promise.all([
|
|
2573
2599
|
runGitLog(ctx.paths.root, input.path, input.git_log_limit).catch(() => []),
|
|
2574
2600
|
collectAnchoredMemories(ctx, input.path, input.memory_limit),
|
|
@@ -2667,7 +2693,6 @@ function runCommand(cmd, args, cwd) {
|
|
|
2667
2693
|
import { existsSync as existsSync25 } from "fs";
|
|
2668
2694
|
import {
|
|
2669
2695
|
addedLinesFromDiff,
|
|
2670
|
-
appendPreventionEvent,
|
|
2671
2696
|
BRIDGE_TARGET_PATH,
|
|
2672
2697
|
buildDocFrequency,
|
|
2673
2698
|
CODE_STOPWORDS,
|
|
@@ -2679,9 +2704,8 @@ import {
|
|
|
2679
2704
|
loadUsageIndex as loadUsageIndex10,
|
|
2680
2705
|
literalMatchesAnyToken as literalMatchesAnyToken3,
|
|
2681
2706
|
memoryMatchesAnchorPaths as memoryMatchesAnchorPaths4,
|
|
2682
|
-
|
|
2707
|
+
recordPreventionHits,
|
|
2683
2708
|
runSensors,
|
|
2684
|
-
saveUsageIndex as saveUsageIndex4,
|
|
2685
2709
|
sensorTargetsFromDiff,
|
|
2686
2710
|
tokenizeQuery as tokenizeQuery3
|
|
2687
2711
|
} from "@hiveai/core";
|
|
@@ -2866,19 +2890,7 @@ async function antiPatternsCheck(input, ctx) {
|
|
|
2866
2890
|
const strongCatches = warnings.filter(
|
|
2867
2891
|
(w) => w.reasons.includes("sensor") || w.reasons.includes("anchor") && w.reasons.includes("literal")
|
|
2868
2892
|
);
|
|
2869
|
-
|
|
2870
|
-
const recordedIds = [];
|
|
2871
|
-
for (const w of strongCatches) if (recordPrevention(usage, w.id)) recordedIds.push(w.id);
|
|
2872
|
-
if (recordedIds.length > 0) {
|
|
2873
|
-
await saveUsageIndex4(ctx.paths, usage).catch(() => {
|
|
2874
|
-
});
|
|
2875
|
-
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
2876
|
-
for (const id of recordedIds) {
|
|
2877
|
-
await appendPreventionEvent(ctx.paths, { at, id, source: "anti-pattern" }).catch(() => {
|
|
2878
|
-
});
|
|
2879
|
-
}
|
|
2880
|
-
}
|
|
2881
|
-
}
|
|
2893
|
+
await recordPreventionHits(ctx.paths, strongCatches.map((w) => w.id), "anti-pattern");
|
|
2882
2894
|
return {
|
|
2883
2895
|
scanned: negative.length,
|
|
2884
2896
|
warnings
|
|
@@ -3635,7 +3647,7 @@ function repairTargetPathForWarning(warning, paths) {
|
|
|
3635
3647
|
// src/tools/pattern-detect.ts
|
|
3636
3648
|
import { mkdir as mkdir8, writeFile as writeFile14 } from "fs/promises";
|
|
3637
3649
|
import { existsSync as existsSync29 } from "fs";
|
|
3638
|
-
import
|
|
3650
|
+
import path13 from "path";
|
|
3639
3651
|
import { execSync as execSync2 } from "child_process";
|
|
3640
3652
|
import {
|
|
3641
3653
|
buildFrontmatter as buildFrontmatter5,
|
|
@@ -3684,13 +3696,13 @@ async function patternDetect(input, ctx) {
|
|
|
3684
3696
|
try {
|
|
3685
3697
|
const changedFiles = gitChangedFiles(ctx.paths.root, input.since_days);
|
|
3686
3698
|
const configFiles = changedFiles.filter(
|
|
3687
|
-
(f) => CONFIG_PATTERNS.some((p) =>
|
|
3699
|
+
(f) => CONFIG_PATTERNS.some((p) => path13.basename(f.toLowerCase()).includes(p))
|
|
3688
3700
|
);
|
|
3689
3701
|
for (const file of configFiles.slice(0, 5)) {
|
|
3690
3702
|
const diff = gitFileDiff(ctx.paths.root, file, input.since_days);
|
|
3691
3703
|
if (!diff) continue;
|
|
3692
|
-
const parentDir =
|
|
3693
|
-
const baseName =
|
|
3704
|
+
const parentDir = path13.basename(path13.dirname(file));
|
|
3705
|
+
const baseName = path13.basename(file).replace(/\.[^.]+$/, "");
|
|
3694
3706
|
const slug = `${parentDir}-${baseName}`.replace(/[^a-z0-9]/gi, "-").toLowerCase().slice(0, 40);
|
|
3695
3707
|
matches.push({
|
|
3696
3708
|
kind: "config_change",
|
|
@@ -3754,7 +3766,7 @@ async function patternDetect(input, ctx) {
|
|
|
3754
3766
|
for (const [p, { count, tools }] of pathCounts) {
|
|
3755
3767
|
if (count < HOT_FILE_MIN) continue;
|
|
3756
3768
|
if (tools.has("mem_tried") || tools.has("mem_observe")) continue;
|
|
3757
|
-
if (CONFIG_PATTERNS.some((cp) =>
|
|
3769
|
+
if (CONFIG_PATTERNS.some((cp) => path13.basename(p).includes(cp))) continue;
|
|
3758
3770
|
const slug = p.replace(/[^a-z0-9]/g, "-").replace(/-+/g, "-").slice(0, 40);
|
|
3759
3771
|
matches.push({
|
|
3760
3772
|
kind: "hot_file",
|
|
@@ -3801,7 +3813,7 @@ async function patternDetect(input, ctx) {
|
|
|
3801
3813
|
void 0
|
|
3802
3814
|
);
|
|
3803
3815
|
if (existsSync29(file)) continue;
|
|
3804
|
-
await mkdir8(
|
|
3816
|
+
await mkdir8(path13.dirname(file), { recursive: true });
|
|
3805
3817
|
await writeFile14(
|
|
3806
3818
|
file,
|
|
3807
3819
|
serializeMemory12({ frontmatter: fm, body: match.proposed_body }),
|
|
@@ -3850,9 +3862,22 @@ import { existsSync as existsSync30 } from "fs";
|
|
|
3850
3862
|
import {
|
|
3851
3863
|
findLexicalConflictPairs,
|
|
3852
3864
|
findTopicStatusConflictPairs,
|
|
3853
|
-
loadMemoriesFromDir as loadMemoriesFromDir23
|
|
3865
|
+
loadMemoriesFromDir as loadMemoriesFromDir23,
|
|
3866
|
+
planConflictResolution
|
|
3854
3867
|
} from "@hiveai/core";
|
|
3855
3868
|
import { z as z32 } from "zod";
|
|
3869
|
+
function suggestResolution(byId, idA, idB) {
|
|
3870
|
+
const a = byId.get(idA);
|
|
3871
|
+
const b = byId.get(idB);
|
|
3872
|
+
if (!a || !b) return null;
|
|
3873
|
+
const plan = planConflictResolution(a, b);
|
|
3874
|
+
return {
|
|
3875
|
+
keep_id: plan.keep_id,
|
|
3876
|
+
supersede_id: plan.supersede_id,
|
|
3877
|
+
reason: plan.reason,
|
|
3878
|
+
command: `haive memory resolve-conflict ${plan.keep_id} ${plan.supersede_id} --yes`
|
|
3879
|
+
};
|
|
3880
|
+
}
|
|
3856
3881
|
var MemConflictCandidatesInputSchema = {
|
|
3857
3882
|
since_days: z32.number().int().positive().max(3650).default(365).describe("Only memories created since N days ago"),
|
|
3858
3883
|
types: z32.array(z32.enum(["decision", "architecture", "convention", "gotcha"])).default(["decision", "architecture"]).describe("Memory types scanned for pairwise lexical overlap"),
|
|
@@ -3874,6 +3899,7 @@ async function memConflictCandidates(input, ctx) {
|
|
|
3874
3899
|
};
|
|
3875
3900
|
}
|
|
3876
3901
|
const all = await loadMemoriesFromDir23(ctx.paths.memoriesDir);
|
|
3902
|
+
const byId = new Map(all.map((m) => [m.memory.frontmatter.id, m]));
|
|
3877
3903
|
const { pairs, scanned, truncated } = findLexicalConflictPairs(all, {
|
|
3878
3904
|
sinceDays: input.since_days,
|
|
3879
3905
|
types: input.types,
|
|
@@ -3882,8 +3908,22 @@ async function memConflictCandidates(input, ctx) {
|
|
|
3882
3908
|
maxScan: input.max_scan
|
|
3883
3909
|
});
|
|
3884
3910
|
const topicStatusPairs = findTopicStatusConflictPairs(all, input.max_topic_pairs);
|
|
3911
|
+
const enrichedPairs = pairs.map((p) => ({
|
|
3912
|
+
...p,
|
|
3913
|
+
suggested_resolution: suggestResolution(byId, p.id_a, p.id_b)
|
|
3914
|
+
}));
|
|
3915
|
+
const enrichedTopicStatusPairs = topicStatusPairs.map((p) => ({
|
|
3916
|
+
...p,
|
|
3917
|
+
suggested_resolution: suggestResolution(byId, p.id_a, p.id_b)
|
|
3918
|
+
}));
|
|
3885
3919
|
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;
|
|
3886
|
-
return {
|
|
3920
|
+
return {
|
|
3921
|
+
pairs: enrichedPairs,
|
|
3922
|
+
topic_status_pairs: enrichedTopicStatusPairs,
|
|
3923
|
+
scanned,
|
|
3924
|
+
truncated,
|
|
3925
|
+
notice
|
|
3926
|
+
};
|
|
3887
3927
|
}
|
|
3888
3928
|
|
|
3889
3929
|
// src/tools/mem-resolve-project.ts
|
|
@@ -4230,7 +4270,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
4230
4270
|
// src/server.ts
|
|
4231
4271
|
import { hasRecentBriefingMarker, loadConfigSync } from "@hiveai/core";
|
|
4232
4272
|
var SERVER_NAME = "haive";
|
|
4233
|
-
var SERVER_VERSION = "0.
|
|
4273
|
+
var SERVER_VERSION = "0.24.0";
|
|
4234
4274
|
function jsonResult(data) {
|
|
4235
4275
|
return {
|
|
4236
4276
|
content: [
|