@hiveai/mcp 0.2.0 → 0.2.2
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 +139 -47
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +138 -46
- package/dist/server.js.map +1 -1
- package/package.json +5 -4
package/dist/server.js
CHANGED
|
@@ -80,7 +80,8 @@ var MemListInputSchema = {
|
|
|
80
80
|
scope: z3.enum(["personal", "team", "module"]).optional(),
|
|
81
81
|
type: z3.enum(["convention", "decision", "gotcha", "architecture", "glossary"]).optional(),
|
|
82
82
|
module: z3.string().optional(),
|
|
83
|
-
tag: z3.string().optional()
|
|
83
|
+
tag: z3.string().optional(),
|
|
84
|
+
include_body: z3.boolean().default(false).describe("Include full body text. Default false to save tokens \u2014 use mem_get for a single memory's full content.")
|
|
84
85
|
};
|
|
85
86
|
async function memList(input, ctx) {
|
|
86
87
|
if (!existsSync3(ctx.paths.memoriesDir)) {
|
|
@@ -97,6 +98,7 @@ async function memList(input, ctx) {
|
|
|
97
98
|
});
|
|
98
99
|
const memories = filtered.map(({ memory, filePath }) => {
|
|
99
100
|
const fm = memory.frontmatter;
|
|
101
|
+
const snippet = memory.body.replace(/\s+/g, " ").trim().slice(0, 120);
|
|
100
102
|
return {
|
|
101
103
|
id: fm.id,
|
|
102
104
|
scope: fm.scope,
|
|
@@ -104,7 +106,9 @@ async function memList(input, ctx) {
|
|
|
104
106
|
...fm.module ? { module: fm.module } : {},
|
|
105
107
|
status: fm.status,
|
|
106
108
|
tags: fm.tags,
|
|
107
|
-
|
|
109
|
+
snippet,
|
|
110
|
+
file_path: filePath,
|
|
111
|
+
...input.include_body ? { body: memory.body } : {}
|
|
108
112
|
};
|
|
109
113
|
});
|
|
110
114
|
return { memories };
|
|
@@ -330,6 +334,14 @@ async function memVerify(input, ctx) {
|
|
|
330
334
|
const isAnchored = memory.frontmatter.anchor.paths.length > 0 || memory.frontmatter.anchor.symbols.length > 0;
|
|
331
335
|
if (!isAnchored) {
|
|
332
336
|
anchorless++;
|
|
337
|
+
results.push({
|
|
338
|
+
id: memory.frontmatter.id,
|
|
339
|
+
file_path: filePath,
|
|
340
|
+
stale: false,
|
|
341
|
+
reason: null,
|
|
342
|
+
status_after: memory.frontmatter.status,
|
|
343
|
+
skipped: true
|
|
344
|
+
});
|
|
333
345
|
continue;
|
|
334
346
|
}
|
|
335
347
|
const result = await verifyAnchor(memory, { projectRoot: ctx.paths.root });
|
|
@@ -387,12 +399,14 @@ function applyVerification(mem, result) {
|
|
|
387
399
|
}
|
|
388
400
|
|
|
389
401
|
// src/tools/mem-reject.ts
|
|
402
|
+
import { writeFile as writeFile4 } from "fs/promises";
|
|
390
403
|
import { existsSync as existsSync7 } from "fs";
|
|
391
404
|
import {
|
|
392
405
|
loadMemoriesFromDir as loadMemoriesFromDir4,
|
|
393
406
|
loadUsageIndex as loadUsageIndex2,
|
|
394
407
|
recordRejection,
|
|
395
|
-
saveUsageIndex
|
|
408
|
+
saveUsageIndex,
|
|
409
|
+
serializeMemory as serializeMemory3
|
|
396
410
|
} from "@hiveai/core";
|
|
397
411
|
import { z as z7 } from "zod";
|
|
398
412
|
var MemRejectInputSchema = {
|
|
@@ -404,16 +418,23 @@ async function memReject(input, ctx) {
|
|
|
404
418
|
throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
|
|
405
419
|
}
|
|
406
420
|
const memories = await loadMemoriesFromDir4(ctx.paths.memoriesDir);
|
|
407
|
-
const
|
|
408
|
-
if (!
|
|
409
|
-
|
|
410
|
-
|
|
421
|
+
const loaded = memories.find((m) => m.memory.frontmatter.id === input.id);
|
|
422
|
+
if (!loaded) throw new Error(`No memory with id "${input.id}".`);
|
|
423
|
+
await writeFile4(
|
|
424
|
+
loaded.filePath,
|
|
425
|
+
serializeMemory3({
|
|
426
|
+
frontmatter: { ...loaded.memory.frontmatter, status: "rejected" },
|
|
427
|
+
body: loaded.memory.body
|
|
428
|
+
}),
|
|
429
|
+
"utf8"
|
|
430
|
+
);
|
|
411
431
|
const idx = await loadUsageIndex2(ctx.paths);
|
|
412
432
|
recordRejection(idx, input.id, input.reason ?? null);
|
|
413
433
|
await saveUsageIndex(ctx.paths, idx);
|
|
414
434
|
const u = idx.by_id[input.id];
|
|
415
435
|
return {
|
|
416
436
|
id: input.id,
|
|
437
|
+
status: "rejected",
|
|
417
438
|
rejected_count: u?.rejected_count ?? 0,
|
|
418
439
|
last_rejected_at: u?.last_rejected_at ?? null,
|
|
419
440
|
rejection_reason: u?.rejection_reason ?? null
|
|
@@ -601,20 +622,80 @@ async function memDelete(input, ctx) {
|
|
|
601
622
|
return { id: input.id, deleted_file: found.filePath, usage_removed: usageRemoved };
|
|
602
623
|
}
|
|
603
624
|
|
|
604
|
-
// src/tools/mem-
|
|
625
|
+
// src/tools/mem-update.ts
|
|
626
|
+
import { writeFile as writeFile5 } from "fs/promises";
|
|
605
627
|
import { existsSync as existsSync11 } from "fs";
|
|
628
|
+
import { loadMemoriesFromDir as loadMemoriesFromDir8, serializeMemory as serializeMemory4 } from "@hiveai/core";
|
|
629
|
+
import { z as z11 } from "zod";
|
|
630
|
+
var MemUpdateInputSchema = {
|
|
631
|
+
id: z11.string().min(1).describe("Id of the memory to update"),
|
|
632
|
+
body: z11.string().optional().describe("New Markdown body \u2014 replaces the existing body"),
|
|
633
|
+
tags: z11.array(z11.string()).optional().describe("New tags array \u2014 fully replaces existing tags"),
|
|
634
|
+
paths: z11.array(z11.string()).optional().describe("New anchor paths \u2014 fully replaces existing anchor.paths"),
|
|
635
|
+
symbols: z11.array(z11.string()).optional().describe("New anchor symbols \u2014 fully replaces existing anchor.symbols"),
|
|
636
|
+
commit: z11.string().optional().describe("New anchor commit SHA"),
|
|
637
|
+
domain: z11.string().optional().describe("New domain label"),
|
|
638
|
+
author: z11.string().optional().describe("New author handle or email")
|
|
639
|
+
};
|
|
640
|
+
async function memUpdate(input, ctx) {
|
|
641
|
+
if (!existsSync11(ctx.paths.memoriesDir)) {
|
|
642
|
+
throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
|
|
643
|
+
}
|
|
644
|
+
const memories = await loadMemoriesFromDir8(ctx.paths.memoriesDir);
|
|
645
|
+
const loaded = memories.find((m) => m.memory.frontmatter.id === input.id);
|
|
646
|
+
if (!loaded) throw new Error(`No memory with id "${input.id}".`);
|
|
647
|
+
const { frontmatter, body } = loaded.memory;
|
|
648
|
+
const updated_fields = [];
|
|
649
|
+
const newAnchor = { ...frontmatter.anchor };
|
|
650
|
+
if (input.paths !== void 0) {
|
|
651
|
+
newAnchor.paths = input.paths;
|
|
652
|
+
updated_fields.push("anchor.paths");
|
|
653
|
+
}
|
|
654
|
+
if (input.symbols !== void 0) {
|
|
655
|
+
newAnchor.symbols = input.symbols;
|
|
656
|
+
updated_fields.push("anchor.symbols");
|
|
657
|
+
}
|
|
658
|
+
if (input.commit !== void 0) {
|
|
659
|
+
newAnchor.commit = input.commit;
|
|
660
|
+
updated_fields.push("anchor.commit");
|
|
661
|
+
}
|
|
662
|
+
const newFrontmatter = {
|
|
663
|
+
...frontmatter,
|
|
664
|
+
anchor: newAnchor,
|
|
665
|
+
...input.tags !== void 0 ? { tags: input.tags } : {},
|
|
666
|
+
...input.domain !== void 0 ? { domain: input.domain } : {},
|
|
667
|
+
...input.author !== void 0 ? { author: input.author } : {}
|
|
668
|
+
};
|
|
669
|
+
if (input.tags !== void 0) updated_fields.push("tags");
|
|
670
|
+
if (input.domain !== void 0) updated_fields.push("domain");
|
|
671
|
+
if (input.author !== void 0) updated_fields.push("author");
|
|
672
|
+
const newBody = input.body !== void 0 ? input.body : body;
|
|
673
|
+
if (input.body !== void 0) updated_fields.push("body");
|
|
674
|
+
if (updated_fields.length === 0) {
|
|
675
|
+
throw new Error("No fields to update \u2014 provide at least one of: body, tags, paths, symbols, commit, domain, author.");
|
|
676
|
+
}
|
|
677
|
+
await writeFile5(
|
|
678
|
+
loaded.filePath,
|
|
679
|
+
serializeMemory4({ frontmatter: newFrontmatter, body: newBody }),
|
|
680
|
+
"utf8"
|
|
681
|
+
);
|
|
682
|
+
return { id: input.id, file_path: loaded.filePath, updated_fields };
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// src/tools/mem-pending.ts
|
|
686
|
+
import { existsSync as existsSync12 } from "fs";
|
|
606
687
|
import {
|
|
607
688
|
getUsage as getUsage4,
|
|
608
|
-
loadMemoriesFromDir as
|
|
689
|
+
loadMemoriesFromDir as loadMemoriesFromDir9,
|
|
609
690
|
loadUsageIndex as loadUsageIndex6
|
|
610
691
|
} from "@hiveai/core";
|
|
611
|
-
import { z as
|
|
692
|
+
import { z as z12 } from "zod";
|
|
612
693
|
var MemPendingInputSchema = {
|
|
613
|
-
scope:
|
|
694
|
+
scope: z12.enum(["personal", "team", "module"]).optional()
|
|
614
695
|
};
|
|
615
696
|
async function memPending(input, ctx) {
|
|
616
|
-
if (!
|
|
617
|
-
const all = await
|
|
697
|
+
if (!existsSync12(ctx.paths.memoriesDir)) return { pending: [] };
|
|
698
|
+
const all = await loadMemoriesFromDir9(ctx.paths.memoriesDir);
|
|
618
699
|
const usage = await loadUsageIndex6(ctx.paths);
|
|
619
700
|
const now = Date.now();
|
|
620
701
|
const proposed = all.filter(({ memory }) => {
|
|
@@ -645,21 +726,21 @@ async function memPending(input, ctx) {
|
|
|
645
726
|
}
|
|
646
727
|
|
|
647
728
|
// src/tools/mem-approve.ts
|
|
648
|
-
import { writeFile as
|
|
649
|
-
import { existsSync as
|
|
729
|
+
import { writeFile as writeFile6 } from "fs/promises";
|
|
730
|
+
import { existsSync as existsSync13 } from "fs";
|
|
650
731
|
import {
|
|
651
|
-
loadMemoriesFromDir as
|
|
652
|
-
serializeMemory as
|
|
732
|
+
loadMemoriesFromDir as loadMemoriesFromDir10,
|
|
733
|
+
serializeMemory as serializeMemory5
|
|
653
734
|
} from "@hiveai/core";
|
|
654
|
-
import { z as
|
|
735
|
+
import { z as z13 } from "zod";
|
|
655
736
|
var MemApproveInputSchema = {
|
|
656
|
-
id:
|
|
737
|
+
id: z13.string().min(1).describe("Memory id to approve (sets status=validated immediately)")
|
|
657
738
|
};
|
|
658
739
|
async function memApprove(input, ctx) {
|
|
659
|
-
if (!
|
|
740
|
+
if (!existsSync13(ctx.paths.memoriesDir)) {
|
|
660
741
|
throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
|
|
661
742
|
}
|
|
662
|
-
const all = await
|
|
743
|
+
const all = await loadMemoriesFromDir10(ctx.paths.memoriesDir);
|
|
663
744
|
const found = all.find((m) => m.memory.frontmatter.id === input.id);
|
|
664
745
|
if (!found) throw new Error(`No memory with id "${input.id}".`);
|
|
665
746
|
const previous = found.memory.frontmatter.status;
|
|
@@ -667,7 +748,7 @@ async function memApprove(input, ctx) {
|
|
|
667
748
|
frontmatter: { ...found.memory.frontmatter, status: "validated" },
|
|
668
749
|
body: found.memory.body
|
|
669
750
|
};
|
|
670
|
-
await
|
|
751
|
+
await writeFile6(found.filePath, serializeMemory5(next), "utf8");
|
|
671
752
|
return {
|
|
672
753
|
id: input.id,
|
|
673
754
|
previous_status: previous,
|
|
@@ -678,7 +759,7 @@ async function memApprove(input, ctx) {
|
|
|
678
759
|
|
|
679
760
|
// src/tools/get-briefing.ts
|
|
680
761
|
import { readFile as readFile3, readdir as readdir3 } from "fs/promises";
|
|
681
|
-
import { existsSync as
|
|
762
|
+
import { existsSync as existsSync14 } from "fs";
|
|
682
763
|
import path5 from "path";
|
|
683
764
|
import {
|
|
684
765
|
allocateBudget,
|
|
@@ -687,37 +768,41 @@ import {
|
|
|
687
768
|
getUsage as getUsage5,
|
|
688
769
|
inferModulesFromPaths as inferModulesFromPaths2,
|
|
689
770
|
literalMatchesAllTokens as literalMatchesAllTokens2,
|
|
690
|
-
loadMemoriesFromDir as
|
|
771
|
+
loadMemoriesFromDir as loadMemoriesFromDir11,
|
|
691
772
|
loadUsageIndex as loadUsageIndex7,
|
|
692
773
|
memoryMatchesAnchorPaths as memoryMatchesAnchorPaths2,
|
|
693
774
|
tokenizeQuery as tokenizeQuery2,
|
|
694
775
|
trackReads as trackReads3,
|
|
695
776
|
truncateToTokens
|
|
696
777
|
} from "@hiveai/core";
|
|
697
|
-
import { z as
|
|
778
|
+
import { z as z14 } from "zod";
|
|
698
779
|
var GetBriefingInputSchema = {
|
|
699
|
-
task:
|
|
780
|
+
task: z14.string().optional().describe(
|
|
700
781
|
"What you are about to do, in 1\u20132 sentences. Used to rank relevant memories semantically."
|
|
701
782
|
),
|
|
702
|
-
files:
|
|
703
|
-
max_tokens:
|
|
783
|
+
files: z14.array(z14.string()).default([]).describe("Project-relative file paths the agent is currently looking at or about to edit"),
|
|
784
|
+
max_tokens: z14.number().int().positive().default(8e3).describe(
|
|
704
785
|
"Approximate token budget for the entire briefing. Each section is allocated a share and truncated to fit."
|
|
705
786
|
),
|
|
706
|
-
max_memories:
|
|
707
|
-
include_project_context:
|
|
708
|
-
include_module_contexts:
|
|
709
|
-
semantic:
|
|
787
|
+
max_memories: z14.number().int().positive().default(8).describe("Cap on memories surfaced regardless of token budget"),
|
|
788
|
+
include_project_context: z14.boolean().default(true),
|
|
789
|
+
include_module_contexts: z14.boolean().default(true),
|
|
790
|
+
semantic: z14.boolean().default(true).describe(
|
|
710
791
|
"Use semantic ranking when a task is provided (requires `haive embeddings index`)."
|
|
711
792
|
),
|
|
712
|
-
track:
|
|
793
|
+
track: z14.boolean().default(true).describe("Increment read_count on returned memories")
|
|
713
794
|
};
|
|
714
795
|
async function getBriefing(input, ctx) {
|
|
715
796
|
const inferred = inferModulesFromPaths2(input.files);
|
|
716
797
|
const memories = [];
|
|
717
|
-
|
|
718
|
-
|
|
798
|
+
let searchMode = "literal";
|
|
799
|
+
if (existsSync14(ctx.paths.memoriesDir)) {
|
|
800
|
+
const allMemories = await loadMemoriesFromDir11(ctx.paths.memoriesDir);
|
|
719
801
|
const usage = await loadUsageIndex7(ctx.paths);
|
|
720
802
|
const semanticHits = input.task && input.semantic ? await trySemanticHits(ctx, input.task, allMemories.length * 2) : null;
|
|
803
|
+
if (input.task && input.semantic) {
|
|
804
|
+
searchMode = semanticHits ? "semantic" : "literal_fallback";
|
|
805
|
+
}
|
|
721
806
|
const seen = /* @__PURE__ */ new Map();
|
|
722
807
|
const addOrUpdate = (loaded, reason, score) => {
|
|
723
808
|
const fm = loaded.memory.frontmatter;
|
|
@@ -783,7 +868,7 @@ async function getBriefing(input, ctx) {
|
|
|
783
868
|
await trackReads3(ctx.paths, memories.map((m) => m.id));
|
|
784
869
|
}
|
|
785
870
|
}
|
|
786
|
-
const projectContext = input.include_project_context &&
|
|
871
|
+
const projectContext = input.include_project_context && existsSync14(ctx.paths.projectContext) ? await readFile3(ctx.paths.projectContext, "utf8") : "";
|
|
787
872
|
const moduleContents = input.include_module_contexts ? await loadModuleContexts2(ctx, inferred) : [];
|
|
788
873
|
const memoriesText = memories.map((m) => `### ${m.id} (${m.scope}/${m.type}, ${m.confidence})
|
|
789
874
|
${m.body.trim()}`).join("\n\n---\n\n");
|
|
@@ -825,6 +910,7 @@ ${m.content}`).join("\n\n---\n\n"),
|
|
|
825
910
|
const totalTokens = projectSlice.estimatedTokens + modulesSlice.estimatedTokens + memoriesSlice.estimatedTokens;
|
|
826
911
|
return {
|
|
827
912
|
...input.task ? { task: input.task } : {},
|
|
913
|
+
search_mode: searchMode,
|
|
828
914
|
inferred_modules: inferred,
|
|
829
915
|
project_context: projectContext ? { content: projectSlice.text, truncated: projectSlice.truncated } : null,
|
|
830
916
|
module_contexts: trimmedModules,
|
|
@@ -853,7 +939,7 @@ async function trySemanticHits(ctx, task, limit) {
|
|
|
853
939
|
}
|
|
854
940
|
async function loadModuleContexts2(ctx, modules) {
|
|
855
941
|
if (modules.length === 0) return [];
|
|
856
|
-
if (!
|
|
942
|
+
if (!existsSync14(ctx.paths.modulesContextDir)) return [];
|
|
857
943
|
const available = new Set(
|
|
858
944
|
(await readdir3(ctx.paths.modulesContextDir, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => d.name)
|
|
859
945
|
);
|
|
@@ -861,7 +947,7 @@ async function loadModuleContexts2(ctx, modules) {
|
|
|
861
947
|
for (const m of modules) {
|
|
862
948
|
if (!available.has(m)) continue;
|
|
863
949
|
const file = path5.join(ctx.paths.modulesContextDir, m, "context.md");
|
|
864
|
-
if (
|
|
950
|
+
if (existsSync14(file)) {
|
|
865
951
|
out.push({ name: m, content: await readFile3(file, "utf8") });
|
|
866
952
|
}
|
|
867
953
|
}
|
|
@@ -870,11 +956,11 @@ async function loadModuleContexts2(ctx, modules) {
|
|
|
870
956
|
|
|
871
957
|
// src/tools/code-map.ts
|
|
872
958
|
import { loadCodeMap, queryCodeMap } from "@hiveai/core";
|
|
873
|
-
import { z as
|
|
959
|
+
import { z as z15 } from "zod";
|
|
874
960
|
var CodeMapInputSchema = {
|
|
875
|
-
file:
|
|
876
|
-
symbol:
|
|
877
|
-
max_files:
|
|
961
|
+
file: z15.string().optional().describe("Filter to files whose path contains this substring"),
|
|
962
|
+
symbol: z15.string().optional().describe("Filter to files exporting a symbol whose name contains this substring"),
|
|
963
|
+
max_files: z15.number().int().positive().default(40).describe("Cap on returned files")
|
|
878
964
|
};
|
|
879
965
|
async function codeMapTool(input, ctx) {
|
|
880
966
|
const map = await loadCodeMap(ctx.paths);
|
|
@@ -900,12 +986,12 @@ async function codeMapTool(input, ctx) {
|
|
|
900
986
|
}
|
|
901
987
|
|
|
902
988
|
// src/prompts/bootstrap-project.ts
|
|
903
|
-
import { z as
|
|
989
|
+
import { z as z16 } from "zod";
|
|
904
990
|
var BootstrapProjectArgsSchema = {
|
|
905
|
-
module:
|
|
991
|
+
module: z16.string().optional().describe(
|
|
906
992
|
"Optional module name to scope the analysis to (writes to .ai/modules/<module>/context.md)"
|
|
907
993
|
),
|
|
908
|
-
focus:
|
|
994
|
+
focus: z16.string().optional().describe("Optional area to emphasize (e.g. 'data layer', 'API surface')")
|
|
909
995
|
};
|
|
910
996
|
var ROOT_TEMPLATE = `# Project context
|
|
911
997
|
|
|
@@ -988,7 +1074,7 @@ ${template}\`\`\`
|
|
|
988
1074
|
|
|
989
1075
|
// src/server.ts
|
|
990
1076
|
var SERVER_NAME = "haive";
|
|
991
|
-
var SERVER_VERSION = "0.
|
|
1077
|
+
var SERVER_VERSION = "0.2.2";
|
|
992
1078
|
function jsonResult(data) {
|
|
993
1079
|
return {
|
|
994
1080
|
content: [
|
|
@@ -1077,6 +1163,12 @@ function createHaiveServer(options = {}) {
|
|
|
1077
1163
|
MemDeleteInputSchema,
|
|
1078
1164
|
async (input) => jsonResult(await memDelete(input, context))
|
|
1079
1165
|
);
|
|
1166
|
+
server.tool(
|
|
1167
|
+
"mem_update",
|
|
1168
|
+
"Update the body, tags, or anchor of an existing memory without changing its id or losing usage history.",
|
|
1169
|
+
MemUpdateInputSchema,
|
|
1170
|
+
async (input) => jsonResult(await memUpdate(input, context))
|
|
1171
|
+
);
|
|
1080
1172
|
server.tool(
|
|
1081
1173
|
"mem_pending",
|
|
1082
1174
|
"List 'proposed' memories awaiting review, sorted by reads (most-read first).",
|