@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/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
- file_path: filePath
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 exists = memories.some((m) => m.memory.frontmatter.id === input.id);
408
- if (!exists) {
409
- throw new Error(`No memory with id "${input.id}".`);
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-pending.ts
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 loadMemoriesFromDir8,
689
+ loadMemoriesFromDir as loadMemoriesFromDir9,
609
690
  loadUsageIndex as loadUsageIndex6
610
691
  } from "@hiveai/core";
611
- import { z as z11 } from "zod";
692
+ import { z as z12 } from "zod";
612
693
  var MemPendingInputSchema = {
613
- scope: z11.enum(["personal", "team", "module"]).optional()
694
+ scope: z12.enum(["personal", "team", "module"]).optional()
614
695
  };
615
696
  async function memPending(input, ctx) {
616
- if (!existsSync11(ctx.paths.memoriesDir)) return { pending: [] };
617
- const all = await loadMemoriesFromDir8(ctx.paths.memoriesDir);
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 writeFile4 } from "fs/promises";
649
- import { existsSync as existsSync12 } from "fs";
729
+ import { writeFile as writeFile6 } from "fs/promises";
730
+ import { existsSync as existsSync13 } from "fs";
650
731
  import {
651
- loadMemoriesFromDir as loadMemoriesFromDir9,
652
- serializeMemory as serializeMemory3
732
+ loadMemoriesFromDir as loadMemoriesFromDir10,
733
+ serializeMemory as serializeMemory5
653
734
  } from "@hiveai/core";
654
- import { z as z12 } from "zod";
735
+ import { z as z13 } from "zod";
655
736
  var MemApproveInputSchema = {
656
- id: z12.string().min(1).describe("Memory id to approve (sets status=validated immediately)")
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 (!existsSync12(ctx.paths.memoriesDir)) {
740
+ if (!existsSync13(ctx.paths.memoriesDir)) {
660
741
  throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
661
742
  }
662
- const all = await loadMemoriesFromDir9(ctx.paths.memoriesDir);
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 writeFile4(found.filePath, serializeMemory3(next), "utf8");
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 existsSync13 } from "fs";
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 loadMemoriesFromDir10,
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 z13 } from "zod";
778
+ import { z as z14 } from "zod";
698
779
  var GetBriefingInputSchema = {
699
- task: z13.string().optional().describe(
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: z13.array(z13.string()).default([]).describe("Project-relative file paths the agent is currently looking at or about to edit"),
703
- max_tokens: z13.number().int().positive().default(8e3).describe(
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: z13.number().int().positive().default(8).describe("Cap on memories surfaced regardless of token budget"),
707
- include_project_context: z13.boolean().default(true),
708
- include_module_contexts: z13.boolean().default(true),
709
- semantic: z13.boolean().default(true).describe(
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: z13.boolean().default(true).describe("Increment read_count on returned memories")
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
- if (existsSync13(ctx.paths.memoriesDir)) {
718
- const allMemories = await loadMemoriesFromDir10(ctx.paths.memoriesDir);
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 && existsSync13(ctx.paths.projectContext) ? await readFile3(ctx.paths.projectContext, "utf8") : "";
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 (!existsSync13(ctx.paths.modulesContextDir)) return [];
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 (existsSync13(file)) {
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 z14 } from "zod";
959
+ import { z as z15 } from "zod";
874
960
  var CodeMapInputSchema = {
875
- file: z14.string().optional().describe("Filter to files whose path contains this substring"),
876
- symbol: z14.string().optional().describe("Filter to files exporting a symbol whose name contains this substring"),
877
- max_files: z14.number().int().positive().default(40).describe("Cap on returned 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 z15 } from "zod";
989
+ import { z as z16 } from "zod";
904
990
  var BootstrapProjectArgsSchema = {
905
- module: z15.string().optional().describe(
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: z15.string().optional().describe("Optional area to emphasize (e.g. 'data layer', 'API surface')")
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.1.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).",