@hiveai/mcp 0.2.1 → 0.2.3
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 +147 -47
- package/dist/index.js.map +1 -1
- package/dist/server.js +146 -46
- package/dist/server.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -85,7 +85,10 @@ var MemListInputSchema = {
|
|
|
85
85
|
scope: z3.enum(["personal", "team", "module"]).optional(),
|
|
86
86
|
type: z3.enum(["convention", "decision", "gotcha", "architecture", "glossary"]).optional(),
|
|
87
87
|
module: z3.string().optional(),
|
|
88
|
-
tag: z3.string().optional()
|
|
88
|
+
tag: z3.string().optional(),
|
|
89
|
+
status: z3.enum(["draft", "proposed", "validated", "deprecated", "stale", "rejected"]).optional().describe("Filter by a single status. Omit to return all statuses."),
|
|
90
|
+
exclude_rejected: z3.boolean().default(false).describe("When true, exclude memories with status=rejected from results."),
|
|
91
|
+
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.")
|
|
89
92
|
};
|
|
90
93
|
async function memList(input, ctx) {
|
|
91
94
|
if (!existsSync3(ctx.paths.memoriesDir)) {
|
|
@@ -98,10 +101,13 @@ async function memList(input, ctx) {
|
|
|
98
101
|
if (input.type && fm.type !== input.type) return false;
|
|
99
102
|
if (input.module && fm.module !== input.module) return false;
|
|
100
103
|
if (input.tag && !fm.tags.includes(input.tag)) return false;
|
|
104
|
+
if (input.status && fm.status !== input.status) return false;
|
|
105
|
+
if (input.exclude_rejected && fm.status === "rejected") return false;
|
|
101
106
|
return true;
|
|
102
107
|
});
|
|
103
108
|
const memories = filtered.map(({ memory, filePath }) => {
|
|
104
109
|
const fm = memory.frontmatter;
|
|
110
|
+
const snippet = memory.body.replace(/\s+/g, " ").trim().slice(0, 120);
|
|
105
111
|
return {
|
|
106
112
|
id: fm.id,
|
|
107
113
|
scope: fm.scope,
|
|
@@ -109,7 +115,9 @@ async function memList(input, ctx) {
|
|
|
109
115
|
...fm.module ? { module: fm.module } : {},
|
|
110
116
|
status: fm.status,
|
|
111
117
|
tags: fm.tags,
|
|
112
|
-
|
|
118
|
+
snippet,
|
|
119
|
+
file_path: filePath,
|
|
120
|
+
...input.include_body ? { body: memory.body } : {}
|
|
113
121
|
};
|
|
114
122
|
});
|
|
115
123
|
return { memories };
|
|
@@ -193,6 +201,8 @@ var MemSearchInputSchema = {
|
|
|
193
201
|
scope: z5.enum(["personal", "team", "module"]).optional().describe("Restrict results to a single scope"),
|
|
194
202
|
type: z5.enum(["convention", "decision", "gotcha", "architecture", "glossary"]).optional().describe("Restrict results to a memory type"),
|
|
195
203
|
module: z5.string().optional().describe("Restrict results to a module"),
|
|
204
|
+
status: z5.enum(["draft", "proposed", "validated", "deprecated", "stale", "rejected"]).optional().describe("Filter by a single status. Omit to return all statuses."),
|
|
205
|
+
exclude_rejected: z5.boolean().default(false).describe("When true, exclude memories with status=rejected from results."),
|
|
196
206
|
limit: z5.number().int().positive().max(100).default(20).describe("Max results"),
|
|
197
207
|
semantic: z5.boolean().default(false).describe(
|
|
198
208
|
"Use semantic similarity from the embeddings index (requires `haive embeddings index`)."
|
|
@@ -234,6 +244,8 @@ function passesFilters(fm, input) {
|
|
|
234
244
|
if (input.scope && fm.scope !== input.scope) return false;
|
|
235
245
|
if (input.type && fm.type !== input.type) return false;
|
|
236
246
|
if (input.module && fm.module !== input.module) return false;
|
|
247
|
+
if (input.status && fm.status !== input.status) return false;
|
|
248
|
+
if (input.exclude_rejected && fm.status === "rejected") return false;
|
|
237
249
|
return true;
|
|
238
250
|
}
|
|
239
251
|
function buildLiteralResult(input, filtered, usage) {
|
|
@@ -335,6 +347,14 @@ async function memVerify(input, ctx) {
|
|
|
335
347
|
const isAnchored = memory.frontmatter.anchor.paths.length > 0 || memory.frontmatter.anchor.symbols.length > 0;
|
|
336
348
|
if (!isAnchored) {
|
|
337
349
|
anchorless++;
|
|
350
|
+
results.push({
|
|
351
|
+
id: memory.frontmatter.id,
|
|
352
|
+
file_path: filePath,
|
|
353
|
+
stale: false,
|
|
354
|
+
reason: null,
|
|
355
|
+
status_after: memory.frontmatter.status,
|
|
356
|
+
skipped: true
|
|
357
|
+
});
|
|
338
358
|
continue;
|
|
339
359
|
}
|
|
340
360
|
const result = await verifyAnchor(memory, { projectRoot: ctx.paths.root });
|
|
@@ -392,12 +412,14 @@ function applyVerification(mem, result) {
|
|
|
392
412
|
}
|
|
393
413
|
|
|
394
414
|
// src/tools/mem-reject.ts
|
|
415
|
+
import { writeFile as writeFile4 } from "fs/promises";
|
|
395
416
|
import { existsSync as existsSync7 } from "fs";
|
|
396
417
|
import {
|
|
397
418
|
loadMemoriesFromDir as loadMemoriesFromDir4,
|
|
398
419
|
loadUsageIndex as loadUsageIndex2,
|
|
399
420
|
recordRejection,
|
|
400
|
-
saveUsageIndex
|
|
421
|
+
saveUsageIndex,
|
|
422
|
+
serializeMemory as serializeMemory3
|
|
401
423
|
} from "@hiveai/core";
|
|
402
424
|
import { z as z7 } from "zod";
|
|
403
425
|
var MemRejectInputSchema = {
|
|
@@ -409,16 +431,23 @@ async function memReject(input, ctx) {
|
|
|
409
431
|
throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
|
|
410
432
|
}
|
|
411
433
|
const memories = await loadMemoriesFromDir4(ctx.paths.memoriesDir);
|
|
412
|
-
const
|
|
413
|
-
if (!
|
|
414
|
-
|
|
415
|
-
|
|
434
|
+
const loaded = memories.find((m) => m.memory.frontmatter.id === input.id);
|
|
435
|
+
if (!loaded) throw new Error(`No memory with id "${input.id}".`);
|
|
436
|
+
await writeFile4(
|
|
437
|
+
loaded.filePath,
|
|
438
|
+
serializeMemory3({
|
|
439
|
+
frontmatter: { ...loaded.memory.frontmatter, status: "rejected" },
|
|
440
|
+
body: loaded.memory.body
|
|
441
|
+
}),
|
|
442
|
+
"utf8"
|
|
443
|
+
);
|
|
416
444
|
const idx = await loadUsageIndex2(ctx.paths);
|
|
417
445
|
recordRejection(idx, input.id, input.reason ?? null);
|
|
418
446
|
await saveUsageIndex(ctx.paths, idx);
|
|
419
447
|
const u = idx.by_id[input.id];
|
|
420
448
|
return {
|
|
421
449
|
id: input.id,
|
|
450
|
+
status: "rejected",
|
|
422
451
|
rejected_count: u?.rejected_count ?? 0,
|
|
423
452
|
last_rejected_at: u?.last_rejected_at ?? null,
|
|
424
453
|
rejection_reason: u?.rejection_reason ?? null
|
|
@@ -606,20 +635,80 @@ async function memDelete(input, ctx) {
|
|
|
606
635
|
return { id: input.id, deleted_file: found.filePath, usage_removed: usageRemoved };
|
|
607
636
|
}
|
|
608
637
|
|
|
609
|
-
// src/tools/mem-
|
|
638
|
+
// src/tools/mem-update.ts
|
|
639
|
+
import { writeFile as writeFile5 } from "fs/promises";
|
|
610
640
|
import { existsSync as existsSync11 } from "fs";
|
|
641
|
+
import { loadMemoriesFromDir as loadMemoriesFromDir8, serializeMemory as serializeMemory4 } from "@hiveai/core";
|
|
642
|
+
import { z as z11 } from "zod";
|
|
643
|
+
var MemUpdateInputSchema = {
|
|
644
|
+
id: z11.string().min(1).describe("Id of the memory to update"),
|
|
645
|
+
body: z11.string().optional().describe("New Markdown body \u2014 replaces the existing body"),
|
|
646
|
+
tags: z11.array(z11.string()).optional().describe("New tags array \u2014 fully replaces existing tags"),
|
|
647
|
+
paths: z11.array(z11.string()).optional().describe("New anchor paths \u2014 fully replaces existing anchor.paths"),
|
|
648
|
+
symbols: z11.array(z11.string()).optional().describe("New anchor symbols \u2014 fully replaces existing anchor.symbols"),
|
|
649
|
+
commit: z11.string().optional().describe("New anchor commit SHA"),
|
|
650
|
+
domain: z11.string().optional().describe("New domain label"),
|
|
651
|
+
author: z11.string().optional().describe("New author handle or email")
|
|
652
|
+
};
|
|
653
|
+
async function memUpdate(input, ctx) {
|
|
654
|
+
if (!existsSync11(ctx.paths.memoriesDir)) {
|
|
655
|
+
throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
|
|
656
|
+
}
|
|
657
|
+
const memories = await loadMemoriesFromDir8(ctx.paths.memoriesDir);
|
|
658
|
+
const loaded = memories.find((m) => m.memory.frontmatter.id === input.id);
|
|
659
|
+
if (!loaded) throw new Error(`No memory with id "${input.id}".`);
|
|
660
|
+
const { frontmatter, body } = loaded.memory;
|
|
661
|
+
const updated_fields = [];
|
|
662
|
+
const newAnchor = { ...frontmatter.anchor };
|
|
663
|
+
if (input.paths !== void 0) {
|
|
664
|
+
newAnchor.paths = input.paths;
|
|
665
|
+
updated_fields.push("anchor.paths");
|
|
666
|
+
}
|
|
667
|
+
if (input.symbols !== void 0) {
|
|
668
|
+
newAnchor.symbols = input.symbols;
|
|
669
|
+
updated_fields.push("anchor.symbols");
|
|
670
|
+
}
|
|
671
|
+
if (input.commit !== void 0) {
|
|
672
|
+
newAnchor.commit = input.commit;
|
|
673
|
+
updated_fields.push("anchor.commit");
|
|
674
|
+
}
|
|
675
|
+
const newFrontmatter = {
|
|
676
|
+
...frontmatter,
|
|
677
|
+
anchor: newAnchor,
|
|
678
|
+
...input.tags !== void 0 ? { tags: input.tags } : {},
|
|
679
|
+
...input.domain !== void 0 ? { domain: input.domain } : {},
|
|
680
|
+
...input.author !== void 0 ? { author: input.author } : {}
|
|
681
|
+
};
|
|
682
|
+
if (input.tags !== void 0) updated_fields.push("tags");
|
|
683
|
+
if (input.domain !== void 0) updated_fields.push("domain");
|
|
684
|
+
if (input.author !== void 0) updated_fields.push("author");
|
|
685
|
+
const newBody = input.body !== void 0 ? input.body : body;
|
|
686
|
+
if (input.body !== void 0) updated_fields.push("body");
|
|
687
|
+
if (updated_fields.length === 0) {
|
|
688
|
+
throw new Error("No fields to update \u2014 provide at least one of: body, tags, paths, symbols, commit, domain, author.");
|
|
689
|
+
}
|
|
690
|
+
await writeFile5(
|
|
691
|
+
loaded.filePath,
|
|
692
|
+
serializeMemory4({ frontmatter: newFrontmatter, body: newBody }),
|
|
693
|
+
"utf8"
|
|
694
|
+
);
|
|
695
|
+
return { id: input.id, file_path: loaded.filePath, updated_fields };
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// src/tools/mem-pending.ts
|
|
699
|
+
import { existsSync as existsSync12 } from "fs";
|
|
611
700
|
import {
|
|
612
701
|
getUsage as getUsage4,
|
|
613
|
-
loadMemoriesFromDir as
|
|
702
|
+
loadMemoriesFromDir as loadMemoriesFromDir9,
|
|
614
703
|
loadUsageIndex as loadUsageIndex6
|
|
615
704
|
} from "@hiveai/core";
|
|
616
|
-
import { z as
|
|
705
|
+
import { z as z12 } from "zod";
|
|
617
706
|
var MemPendingInputSchema = {
|
|
618
|
-
scope:
|
|
707
|
+
scope: z12.enum(["personal", "team", "module"]).optional()
|
|
619
708
|
};
|
|
620
709
|
async function memPending(input, ctx) {
|
|
621
|
-
if (!
|
|
622
|
-
const all = await
|
|
710
|
+
if (!existsSync12(ctx.paths.memoriesDir)) return { pending: [] };
|
|
711
|
+
const all = await loadMemoriesFromDir9(ctx.paths.memoriesDir);
|
|
623
712
|
const usage = await loadUsageIndex6(ctx.paths);
|
|
624
713
|
const now = Date.now();
|
|
625
714
|
const proposed = all.filter(({ memory }) => {
|
|
@@ -650,21 +739,21 @@ async function memPending(input, ctx) {
|
|
|
650
739
|
}
|
|
651
740
|
|
|
652
741
|
// src/tools/mem-approve.ts
|
|
653
|
-
import { writeFile as
|
|
654
|
-
import { existsSync as
|
|
742
|
+
import { writeFile as writeFile6 } from "fs/promises";
|
|
743
|
+
import { existsSync as existsSync13 } from "fs";
|
|
655
744
|
import {
|
|
656
|
-
loadMemoriesFromDir as
|
|
657
|
-
serializeMemory as
|
|
745
|
+
loadMemoriesFromDir as loadMemoriesFromDir10,
|
|
746
|
+
serializeMemory as serializeMemory5
|
|
658
747
|
} from "@hiveai/core";
|
|
659
|
-
import { z as
|
|
748
|
+
import { z as z13 } from "zod";
|
|
660
749
|
var MemApproveInputSchema = {
|
|
661
|
-
id:
|
|
750
|
+
id: z13.string().min(1).describe("Memory id to approve (sets status=validated immediately)")
|
|
662
751
|
};
|
|
663
752
|
async function memApprove(input, ctx) {
|
|
664
|
-
if (!
|
|
753
|
+
if (!existsSync13(ctx.paths.memoriesDir)) {
|
|
665
754
|
throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
|
|
666
755
|
}
|
|
667
|
-
const all = await
|
|
756
|
+
const all = await loadMemoriesFromDir10(ctx.paths.memoriesDir);
|
|
668
757
|
const found = all.find((m) => m.memory.frontmatter.id === input.id);
|
|
669
758
|
if (!found) throw new Error(`No memory with id "${input.id}".`);
|
|
670
759
|
const previous = found.memory.frontmatter.status;
|
|
@@ -672,7 +761,7 @@ async function memApprove(input, ctx) {
|
|
|
672
761
|
frontmatter: { ...found.memory.frontmatter, status: "validated" },
|
|
673
762
|
body: found.memory.body
|
|
674
763
|
};
|
|
675
|
-
await
|
|
764
|
+
await writeFile6(found.filePath, serializeMemory5(next), "utf8");
|
|
676
765
|
return {
|
|
677
766
|
id: input.id,
|
|
678
767
|
previous_status: previous,
|
|
@@ -683,7 +772,7 @@ async function memApprove(input, ctx) {
|
|
|
683
772
|
|
|
684
773
|
// src/tools/get-briefing.ts
|
|
685
774
|
import { readFile as readFile3, readdir as readdir3 } from "fs/promises";
|
|
686
|
-
import { existsSync as
|
|
775
|
+
import { existsSync as existsSync14 } from "fs";
|
|
687
776
|
import path5 from "path";
|
|
688
777
|
import {
|
|
689
778
|
allocateBudget,
|
|
@@ -692,37 +781,41 @@ import {
|
|
|
692
781
|
getUsage as getUsage5,
|
|
693
782
|
inferModulesFromPaths as inferModulesFromPaths2,
|
|
694
783
|
literalMatchesAllTokens as literalMatchesAllTokens2,
|
|
695
|
-
loadMemoriesFromDir as
|
|
784
|
+
loadMemoriesFromDir as loadMemoriesFromDir11,
|
|
696
785
|
loadUsageIndex as loadUsageIndex7,
|
|
697
786
|
memoryMatchesAnchorPaths as memoryMatchesAnchorPaths2,
|
|
698
787
|
tokenizeQuery as tokenizeQuery2,
|
|
699
788
|
trackReads as trackReads3,
|
|
700
789
|
truncateToTokens
|
|
701
790
|
} from "@hiveai/core";
|
|
702
|
-
import { z as
|
|
791
|
+
import { z as z14 } from "zod";
|
|
703
792
|
var GetBriefingInputSchema = {
|
|
704
|
-
task:
|
|
793
|
+
task: z14.string().optional().describe(
|
|
705
794
|
"What you are about to do, in 1\u20132 sentences. Used to rank relevant memories semantically."
|
|
706
795
|
),
|
|
707
|
-
files:
|
|
708
|
-
max_tokens:
|
|
796
|
+
files: z14.array(z14.string()).default([]).describe("Project-relative file paths the agent is currently looking at or about to edit"),
|
|
797
|
+
max_tokens: z14.number().int().positive().default(8e3).describe(
|
|
709
798
|
"Approximate token budget for the entire briefing. Each section is allocated a share and truncated to fit."
|
|
710
799
|
),
|
|
711
|
-
max_memories:
|
|
712
|
-
include_project_context:
|
|
713
|
-
include_module_contexts:
|
|
714
|
-
semantic:
|
|
800
|
+
max_memories: z14.number().int().positive().default(8).describe("Cap on memories surfaced regardless of token budget"),
|
|
801
|
+
include_project_context: z14.boolean().default(true),
|
|
802
|
+
include_module_contexts: z14.boolean().default(true),
|
|
803
|
+
semantic: z14.boolean().default(true).describe(
|
|
715
804
|
"Use semantic ranking when a task is provided (requires `haive embeddings index`)."
|
|
716
805
|
),
|
|
717
|
-
track:
|
|
806
|
+
track: z14.boolean().default(true).describe("Increment read_count on returned memories")
|
|
718
807
|
};
|
|
719
808
|
async function getBriefing(input, ctx) {
|
|
720
809
|
const inferred = inferModulesFromPaths2(input.files);
|
|
721
810
|
const memories = [];
|
|
722
|
-
|
|
723
|
-
|
|
811
|
+
let searchMode = "literal";
|
|
812
|
+
if (existsSync14(ctx.paths.memoriesDir)) {
|
|
813
|
+
const allMemories = await loadMemoriesFromDir11(ctx.paths.memoriesDir);
|
|
724
814
|
const usage = await loadUsageIndex7(ctx.paths);
|
|
725
815
|
const semanticHits = input.task && input.semantic ? await trySemanticHits(ctx, input.task, allMemories.length * 2) : null;
|
|
816
|
+
if (input.task && input.semantic) {
|
|
817
|
+
searchMode = semanticHits ? "semantic" : "literal_fallback";
|
|
818
|
+
}
|
|
726
819
|
const seen = /* @__PURE__ */ new Map();
|
|
727
820
|
const addOrUpdate = (loaded, reason, score) => {
|
|
728
821
|
const fm = loaded.memory.frontmatter;
|
|
@@ -788,7 +881,7 @@ async function getBriefing(input, ctx) {
|
|
|
788
881
|
await trackReads3(ctx.paths, memories.map((m) => m.id));
|
|
789
882
|
}
|
|
790
883
|
}
|
|
791
|
-
const projectContext = input.include_project_context &&
|
|
884
|
+
const projectContext = input.include_project_context && existsSync14(ctx.paths.projectContext) ? await readFile3(ctx.paths.projectContext, "utf8") : "";
|
|
792
885
|
const moduleContents = input.include_module_contexts ? await loadModuleContexts2(ctx, inferred) : [];
|
|
793
886
|
const memoriesText = memories.map((m) => `### ${m.id} (${m.scope}/${m.type}, ${m.confidence})
|
|
794
887
|
${m.body.trim()}`).join("\n\n---\n\n");
|
|
@@ -830,6 +923,7 @@ ${m.content}`).join("\n\n---\n\n"),
|
|
|
830
923
|
const totalTokens = projectSlice.estimatedTokens + modulesSlice.estimatedTokens + memoriesSlice.estimatedTokens;
|
|
831
924
|
return {
|
|
832
925
|
...input.task ? { task: input.task } : {},
|
|
926
|
+
search_mode: searchMode,
|
|
833
927
|
inferred_modules: inferred,
|
|
834
928
|
project_context: projectContext ? { content: projectSlice.text, truncated: projectSlice.truncated } : null,
|
|
835
929
|
module_contexts: trimmedModules,
|
|
@@ -858,7 +952,7 @@ async function trySemanticHits(ctx, task, limit) {
|
|
|
858
952
|
}
|
|
859
953
|
async function loadModuleContexts2(ctx, modules) {
|
|
860
954
|
if (modules.length === 0) return [];
|
|
861
|
-
if (!
|
|
955
|
+
if (!existsSync14(ctx.paths.modulesContextDir)) return [];
|
|
862
956
|
const available = new Set(
|
|
863
957
|
(await readdir3(ctx.paths.modulesContextDir, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => d.name)
|
|
864
958
|
);
|
|
@@ -866,7 +960,7 @@ async function loadModuleContexts2(ctx, modules) {
|
|
|
866
960
|
for (const m of modules) {
|
|
867
961
|
if (!available.has(m)) continue;
|
|
868
962
|
const file = path5.join(ctx.paths.modulesContextDir, m, "context.md");
|
|
869
|
-
if (
|
|
963
|
+
if (existsSync14(file)) {
|
|
870
964
|
out.push({ name: m, content: await readFile3(file, "utf8") });
|
|
871
965
|
}
|
|
872
966
|
}
|
|
@@ -875,11 +969,11 @@ async function loadModuleContexts2(ctx, modules) {
|
|
|
875
969
|
|
|
876
970
|
// src/tools/code-map.ts
|
|
877
971
|
import { loadCodeMap, queryCodeMap } from "@hiveai/core";
|
|
878
|
-
import { z as
|
|
972
|
+
import { z as z15 } from "zod";
|
|
879
973
|
var CodeMapInputSchema = {
|
|
880
|
-
file:
|
|
881
|
-
symbol:
|
|
882
|
-
max_files:
|
|
974
|
+
file: z15.string().optional().describe("Filter to files whose path contains this substring"),
|
|
975
|
+
symbol: z15.string().optional().describe("Filter to files exporting a symbol whose name contains this substring"),
|
|
976
|
+
max_files: z15.number().int().positive().default(40).describe("Cap on returned files")
|
|
883
977
|
};
|
|
884
978
|
async function codeMapTool(input, ctx) {
|
|
885
979
|
const map = await loadCodeMap(ctx.paths);
|
|
@@ -905,12 +999,12 @@ async function codeMapTool(input, ctx) {
|
|
|
905
999
|
}
|
|
906
1000
|
|
|
907
1001
|
// src/prompts/bootstrap-project.ts
|
|
908
|
-
import { z as
|
|
1002
|
+
import { z as z16 } from "zod";
|
|
909
1003
|
var BootstrapProjectArgsSchema = {
|
|
910
|
-
module:
|
|
1004
|
+
module: z16.string().optional().describe(
|
|
911
1005
|
"Optional module name to scope the analysis to (writes to .ai/modules/<module>/context.md)"
|
|
912
1006
|
),
|
|
913
|
-
focus:
|
|
1007
|
+
focus: z16.string().optional().describe("Optional area to emphasize (e.g. 'data layer', 'API surface')")
|
|
914
1008
|
};
|
|
915
1009
|
var ROOT_TEMPLATE = `# Project context
|
|
916
1010
|
|
|
@@ -993,7 +1087,7 @@ ${template}\`\`\`
|
|
|
993
1087
|
|
|
994
1088
|
// src/server.ts
|
|
995
1089
|
var SERVER_NAME = "haive";
|
|
996
|
-
var SERVER_VERSION = "0.2.
|
|
1090
|
+
var SERVER_VERSION = "0.2.3";
|
|
997
1091
|
function jsonResult(data) {
|
|
998
1092
|
return {
|
|
999
1093
|
content: [
|
|
@@ -1082,6 +1176,12 @@ function createHaiveServer(options = {}) {
|
|
|
1082
1176
|
MemDeleteInputSchema,
|
|
1083
1177
|
async (input) => jsonResult(await memDelete(input, context))
|
|
1084
1178
|
);
|
|
1179
|
+
server.tool(
|
|
1180
|
+
"mem_update",
|
|
1181
|
+
"Update the body, tags, or anchor of an existing memory without changing its id or losing usage history.",
|
|
1182
|
+
MemUpdateInputSchema,
|
|
1183
|
+
async (input) => jsonResult(await memUpdate(input, context))
|
|
1184
|
+
);
|
|
1085
1185
|
server.tool(
|
|
1086
1186
|
"mem_pending",
|
|
1087
1187
|
"List 'proposed' memories awaiting review, sorted by reads (most-read first).",
|
|
@@ -1120,7 +1220,7 @@ async function main() {
|
|
|
1120
1220
|
const { root } = parseArgs(process.argv);
|
|
1121
1221
|
const { server, context } = createHaiveServer({ root });
|
|
1122
1222
|
console.error(
|
|
1123
|
-
`[haive-mcp] starting server
|
|
1223
|
+
`[haive-mcp] starting server v${SERVER_VERSION} (project root: ${context.paths.root})`
|
|
1124
1224
|
);
|
|
1125
1225
|
const transport = new StdioServerTransport();
|
|
1126
1226
|
await server.connect(transport);
|