@hiveai/mcp 0.2.3 → 0.2.6

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 CHANGED
@@ -129,12 +129,13 @@ import { existsSync as existsSync4 } from "fs";
129
129
  import path3 from "path";
130
130
  import {
131
131
  buildFrontmatter,
132
+ loadMemoriesFromDir as loadMemoriesFromDir2,
132
133
  memoryFilePath,
133
134
  serializeMemory
134
135
  } from "@hiveai/core";
135
136
  import { z as z4 } from "zod";
136
137
  var MemSaveInputSchema = {
137
- type: z4.enum(["convention", "decision", "gotcha", "architecture", "glossary"]).describe("Kind of memory being saved"),
138
+ type: z4.enum(["convention", "decision", "gotcha", "architecture", "glossary", "attempt"]).describe("Kind of memory being saved. Use 'attempt' for failed approaches (auto-validated)."),
138
139
  slug: z4.string().min(1).describe("Short human-readable identifier \u2014 becomes part of the filename"),
139
140
  body: z4.string().describe("Markdown body of the memory"),
140
141
  scope: z4.enum(["personal", "team", "module"]).default("personal").describe("Visibility scope: personal | team | module"),
@@ -174,11 +175,24 @@ async function memSave(input, ctx) {
174
175
  if (existsSync4(file)) {
175
176
  throw new Error(`Memory already exists at ${file}`);
176
177
  }
178
+ let warning;
179
+ if (existsSync4(ctx.paths.memoriesDir)) {
180
+ const existing = await loadMemoriesFromDir2(ctx.paths.memoriesDir);
181
+ const slugTokens = input.slug.toLowerCase().split(/[-_\s]+/).filter(Boolean);
182
+ const similar = existing.filter(({ memory }) => {
183
+ const id = memory.frontmatter.id.toLowerCase();
184
+ return slugTokens.length >= 2 && slugTokens.filter((t) => id.includes(t)).length >= Math.ceil(slugTokens.length * 0.6);
185
+ });
186
+ if (similar.length > 0) {
187
+ warning = `Possible duplicate detected. Similar memories: ${similar.map((m) => m.memory.frontmatter.id).join(", ")}. Consider updating one of these instead.`;
188
+ }
189
+ }
177
190
  await writeFile2(file, serializeMemory({ frontmatter, body: input.body }), "utf8");
178
191
  return {
179
192
  id: frontmatter.id,
180
193
  scope: frontmatter.scope,
181
- file_path: file
194
+ file_path: file,
195
+ ...warning ? { warning } : {}
182
196
  };
183
197
  }
184
198
 
@@ -189,7 +203,8 @@ import {
189
203
  extractSnippet,
190
204
  getUsage,
191
205
  literalMatchesAllTokens,
192
- loadMemoriesFromDir as loadMemoriesFromDir2,
206
+ literalMatchesAnyToken,
207
+ loadMemoriesFromDir as loadMemoriesFromDir3,
193
208
  loadUsageIndex,
194
209
  pickSnippetNeedle,
195
210
  tokenizeQuery,
@@ -199,7 +214,7 @@ import { z as z5 } from "zod";
199
214
  var MemSearchInputSchema = {
200
215
  query: z5.string().describe("Substring matched against id, tags, and body"),
201
216
  scope: z5.enum(["personal", "team", "module"]).optional().describe("Restrict results to a single scope"),
202
- type: z5.enum(["convention", "decision", "gotcha", "architecture", "glossary"]).optional().describe("Restrict results to a memory type"),
217
+ type: z5.enum(["convention", "decision", "gotcha", "architecture", "glossary", "attempt"]).optional().describe("Restrict results to a memory type"),
203
218
  module: z5.string().optional().describe("Restrict results to a module"),
204
219
  status: z5.enum(["draft", "proposed", "validated", "deprecated", "stale", "rejected"]).optional().describe("Filter by a single status. Omit to return all statuses."),
205
220
  exclude_rejected: z5.boolean().default(false).describe("When true, exclude memories with status=rejected from results."),
@@ -214,7 +229,7 @@ async function memSearch(input, ctx) {
214
229
  if (!existsSync5(ctx.paths.memoriesDir)) {
215
230
  return { matches: [], total: 0, mode: input.semantic ? "literal_fallback" : "literal" };
216
231
  }
217
- const all = await loadMemoriesFromDir2(ctx.paths.memoriesDir);
232
+ const all = await loadMemoriesFromDir3(ctx.paths.memoriesDir);
218
233
  const filtered = all.filter(({ memory }) => passesFilters(memory.frontmatter, input));
219
234
  const usage = await loadUsageIndex(ctx.paths);
220
235
  let result;
@@ -250,13 +265,23 @@ function passesFilters(fm, input) {
250
265
  }
251
266
  function buildLiteralResult(input, filtered, usage) {
252
267
  const tokens = tokenizeQuery(input.query);
253
- const matched = filtered.filter(({ memory }) => literalMatchesAllTokens(memory, tokens));
254
268
  const snippetNeedle = pickSnippetNeedle(input.query);
255
- const top = matched.slice(0, input.limit);
269
+ let andMatched = filtered.filter(({ memory }) => literalMatchesAllTokens(memory, tokens));
270
+ if (andMatched.length > 0) {
271
+ const top2 = andMatched.slice(0, input.limit);
272
+ return {
273
+ matches: top2.map((loaded) => toHit(loaded, snippetNeedle, usage)),
274
+ total: andMatched.length,
275
+ mode: "literal"
276
+ };
277
+ }
278
+ const orMatched = filtered.filter(({ memory }) => literalMatchesAnyToken(memory, tokens));
279
+ const top = orMatched.slice(0, input.limit);
256
280
  return {
257
281
  matches: top.map((loaded) => toHit(loaded, snippetNeedle, usage)),
258
- total: matched.length,
259
- mode: "literal"
282
+ total: orMatched.length,
283
+ mode: "literal",
284
+ notice: `No exact match for all tokens. Showing partial matches (OR fallback) \u2014 ${orMatched.length} result${orMatched.length === 1 ? "" : "s"}.`
260
285
  };
261
286
  }
262
287
  async function trySemanticSearch(ctx, input, filtered, usage) {
@@ -320,7 +345,7 @@ function toHit(loaded, needle, usage) {
320
345
  import { writeFile as writeFile3 } from "fs/promises";
321
346
  import { existsSync as existsSync6 } from "fs";
322
347
  import {
323
- loadMemoriesFromDir as loadMemoriesFromDir3,
348
+ loadMemoriesFromDir as loadMemoriesFromDir4,
324
349
  serializeMemory as serializeMemory2,
325
350
  verifyAnchor
326
351
  } from "@hiveai/core";
@@ -336,7 +361,7 @@ async function memVerify(input, ctx) {
336
361
  summary: { checked: 0, fresh: 0, stale: 0, anchorless_skipped: 0, updated: 0 }
337
362
  };
338
363
  }
339
- const all = await loadMemoriesFromDir3(ctx.paths.memoriesDir);
364
+ const all = await loadMemoriesFromDir4(ctx.paths.memoriesDir);
340
365
  const targets = input.id ? all.filter((m) => m.memory.frontmatter.id === input.id) : all;
341
366
  const results = [];
342
367
  let fresh = 0;
@@ -415,7 +440,7 @@ function applyVerification(mem, result) {
415
440
  import { writeFile as writeFile4 } from "fs/promises";
416
441
  import { existsSync as existsSync7 } from "fs";
417
442
  import {
418
- loadMemoriesFromDir as loadMemoriesFromDir4,
443
+ loadMemoriesFromDir as loadMemoriesFromDir5,
419
444
  loadUsageIndex as loadUsageIndex2,
420
445
  recordRejection,
421
446
  saveUsageIndex,
@@ -430,13 +455,17 @@ async function memReject(input, ctx) {
430
455
  if (!existsSync7(ctx.paths.memoriesDir)) {
431
456
  throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
432
457
  }
433
- const memories = await loadMemoriesFromDir4(ctx.paths.memoriesDir);
458
+ const memories = await loadMemoriesFromDir5(ctx.paths.memoriesDir);
434
459
  const loaded = memories.find((m) => m.memory.frontmatter.id === input.id);
435
460
  if (!loaded) throw new Error(`No memory with id "${input.id}".`);
436
461
  await writeFile4(
437
462
  loaded.filePath,
438
463
  serializeMemory3({
439
- frontmatter: { ...loaded.memory.frontmatter, status: "rejected" },
464
+ frontmatter: {
465
+ ...loaded.memory.frontmatter,
466
+ status: "rejected",
467
+ stale_reason: input.reason ?? loaded.memory.frontmatter.stale_reason ?? null
468
+ },
440
469
  body: loaded.memory.body
441
470
  }),
442
471
  "utf8"
@@ -462,7 +491,7 @@ import {
462
491
  deriveConfidence as deriveConfidence2,
463
492
  getUsage as getUsage2,
464
493
  inferModulesFromPaths,
465
- loadMemoriesFromDir as loadMemoriesFromDir5,
494
+ loadMemoriesFromDir as loadMemoriesFromDir6,
466
495
  loadUsageIndex as loadUsageIndex3,
467
496
  memoryMatchesAnchorPaths,
468
497
  trackReads as trackReads2
@@ -484,7 +513,7 @@ async function memForFiles(input, ctx) {
484
513
  module_contexts: await loadModuleContexts(ctx, inferred, input.include_module_contexts)
485
514
  };
486
515
  }
487
- const all = await loadMemoriesFromDir5(ctx.paths.memoriesDir);
516
+ const all = await loadMemoriesFromDir6(ctx.paths.memoriesDir);
488
517
  const usage = await loadUsageIndex3(ctx.paths);
489
518
  const seen = /* @__PURE__ */ new Set();
490
519
  const byAnchor = [];
@@ -563,7 +592,7 @@ import { existsSync as existsSync9 } from "fs";
563
592
  import {
564
593
  deriveConfidence as deriveConfidence3,
565
594
  getUsage as getUsage3,
566
- loadMemoriesFromDir as loadMemoriesFromDir6,
595
+ loadMemoriesFromDir as loadMemoriesFromDir7,
567
596
  loadUsageIndex as loadUsageIndex4
568
597
  } from "@hiveai/core";
569
598
  import { z as z9 } from "zod";
@@ -574,7 +603,7 @@ async function memGet(input, ctx) {
574
603
  if (!existsSync9(ctx.paths.memoriesDir)) {
575
604
  throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
576
605
  }
577
- const all = await loadMemoriesFromDir6(ctx.paths.memoriesDir);
606
+ const all = await loadMemoriesFromDir7(ctx.paths.memoriesDir);
578
607
  const found = all.find((m) => m.memory.frontmatter.id === input.id);
579
608
  if (!found) throw new Error(`No memory with id "${input.id}".`);
580
609
  const fm = found.memory.frontmatter;
@@ -606,7 +635,7 @@ async function memGet(input, ctx) {
606
635
  import { existsSync as existsSync10 } from "fs";
607
636
  import { unlink } from "fs/promises";
608
637
  import {
609
- loadMemoriesFromDir as loadMemoriesFromDir7,
638
+ loadMemoriesFromDir as loadMemoriesFromDir8,
610
639
  loadUsageIndex as loadUsageIndex5,
611
640
  saveUsageIndex as saveUsageIndex2
612
641
  } from "@hiveai/core";
@@ -619,7 +648,7 @@ async function memDelete(input, ctx) {
619
648
  if (!existsSync10(ctx.paths.memoriesDir)) {
620
649
  throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
621
650
  }
622
- const all = await loadMemoriesFromDir7(ctx.paths.memoriesDir);
651
+ const all = await loadMemoriesFromDir8(ctx.paths.memoriesDir);
623
652
  const found = all.find((m) => m.memory.frontmatter.id === input.id);
624
653
  if (!found) throw new Error(`No memory with id "${input.id}".`);
625
654
  await unlink(found.filePath);
@@ -638,7 +667,7 @@ async function memDelete(input, ctx) {
638
667
  // src/tools/mem-update.ts
639
668
  import { writeFile as writeFile5 } from "fs/promises";
640
669
  import { existsSync as existsSync11 } from "fs";
641
- import { loadMemoriesFromDir as loadMemoriesFromDir8, serializeMemory as serializeMemory4 } from "@hiveai/core";
670
+ import { loadMemoriesFromDir as loadMemoriesFromDir9, serializeMemory as serializeMemory4 } from "@hiveai/core";
642
671
  import { z as z11 } from "zod";
643
672
  var MemUpdateInputSchema = {
644
673
  id: z11.string().min(1).describe("Id of the memory to update"),
@@ -654,7 +683,7 @@ async function memUpdate(input, ctx) {
654
683
  if (!existsSync11(ctx.paths.memoriesDir)) {
655
684
  throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
656
685
  }
657
- const memories = await loadMemoriesFromDir8(ctx.paths.memoriesDir);
686
+ const memories = await loadMemoriesFromDir9(ctx.paths.memoriesDir);
658
687
  const loaded = memories.find((m) => m.memory.frontmatter.id === input.id);
659
688
  if (!loaded) throw new Error(`No memory with id "${input.id}".`);
660
689
  const { frontmatter, body } = loaded.memory;
@@ -699,7 +728,7 @@ async function memUpdate(input, ctx) {
699
728
  import { existsSync as existsSync12 } from "fs";
700
729
  import {
701
730
  getUsage as getUsage4,
702
- loadMemoriesFromDir as loadMemoriesFromDir9,
731
+ loadMemoriesFromDir as loadMemoriesFromDir10,
703
732
  loadUsageIndex as loadUsageIndex6
704
733
  } from "@hiveai/core";
705
734
  import { z as z12 } from "zod";
@@ -708,7 +737,7 @@ var MemPendingInputSchema = {
708
737
  };
709
738
  async function memPending(input, ctx) {
710
739
  if (!existsSync12(ctx.paths.memoriesDir)) return { pending: [] };
711
- const all = await loadMemoriesFromDir9(ctx.paths.memoriesDir);
740
+ const all = await loadMemoriesFromDir10(ctx.paths.memoriesDir);
712
741
  const usage = await loadUsageIndex6(ctx.paths);
713
742
  const now = Date.now();
714
743
  const proposed = all.filter(({ memory }) => {
@@ -742,7 +771,7 @@ async function memPending(input, ctx) {
742
771
  import { writeFile as writeFile6 } from "fs/promises";
743
772
  import { existsSync as existsSync13 } from "fs";
744
773
  import {
745
- loadMemoriesFromDir as loadMemoriesFromDir10,
774
+ loadMemoriesFromDir as loadMemoriesFromDir11,
746
775
  serializeMemory as serializeMemory5
747
776
  } from "@hiveai/core";
748
777
  import { z as z13 } from "zod";
@@ -753,7 +782,7 @@ async function memApprove(input, ctx) {
753
782
  if (!existsSync13(ctx.paths.memoriesDir)) {
754
783
  throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
755
784
  }
756
- const all = await loadMemoriesFromDir10(ctx.paths.memoriesDir);
785
+ const all = await loadMemoriesFromDir11(ctx.paths.memoriesDir);
757
786
  const found = all.find((m) => m.memory.frontmatter.id === input.id);
758
787
  if (!found) throw new Error(`No memory with id "${input.id}".`);
759
788
  const previous = found.memory.frontmatter.status;
@@ -770,10 +799,60 @@ async function memApprove(input, ctx) {
770
799
  };
771
800
  }
772
801
 
773
- // src/tools/get-briefing.ts
774
- import { readFile as readFile3, readdir as readdir3 } from "fs/promises";
802
+ // src/tools/mem-tried.ts
803
+ import { mkdir as mkdir3, writeFile as writeFile7 } from "fs/promises";
775
804
  import { existsSync as existsSync14 } from "fs";
776
805
  import path5 from "path";
806
+ import {
807
+ buildFrontmatter as buildFrontmatter2,
808
+ memoryFilePath as memoryFilePath2,
809
+ serializeMemory as serializeMemory6
810
+ } from "@hiveai/core";
811
+ import { z as z14 } from "zod";
812
+ var MemTriedInputSchema = {
813
+ what: z14.string().min(1).describe("Brief description of the approach that was tried"),
814
+ why_failed: z14.string().min(1).describe("Why it failed or why it should NOT be used"),
815
+ instead: z14.string().optional().describe("What to use or do instead (recommended alternative)"),
816
+ scope: z14.enum(["personal", "team", "module"]).default("personal").describe("Visibility scope"),
817
+ module: z14.string().optional().describe("Module name (required when scope=module)"),
818
+ tags: z14.array(z14.string()).default([]).describe("Tags for filtering"),
819
+ paths: z14.array(z14.string()).default([]).describe("Anchor file paths this applies to"),
820
+ author: z14.string().optional().describe("Author handle or email")
821
+ };
822
+ async function memTried(input, ctx) {
823
+ if (!existsSync14(ctx.paths.haiveDir)) {
824
+ throw new Error(`No .ai/ directory at ${ctx.paths.root}. Run 'haive init' first.`);
825
+ }
826
+ const slug = input.what.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().split(/\s+/).slice(0, 5).join("-");
827
+ const baseFm = buildFrontmatter2({
828
+ type: "attempt",
829
+ slug,
830
+ scope: input.scope,
831
+ module: input.module,
832
+ tags: input.tags,
833
+ paths: input.paths,
834
+ author: input.author
835
+ });
836
+ const frontmatter = { ...baseFm, status: "validated" };
837
+ const lines = [`# ${input.what}`, ""];
838
+ lines.push(`**Why it failed / do NOT use:** ${input.why_failed}`);
839
+ if (input.instead) {
840
+ lines.push("", `**Instead, use:** ${input.instead}`);
841
+ }
842
+ const body = lines.join("\n") + "\n";
843
+ const file = memoryFilePath2(ctx.paths, frontmatter.scope, frontmatter.id, frontmatter.module);
844
+ await mkdir3(path5.dirname(file), { recursive: true });
845
+ if (existsSync14(file)) {
846
+ throw new Error(`Memory already exists at ${file}`);
847
+ }
848
+ await writeFile7(file, serializeMemory6({ frontmatter, body }), "utf8");
849
+ return { id: frontmatter.id, scope: frontmatter.scope, file_path: file };
850
+ }
851
+
852
+ // src/tools/get-briefing.ts
853
+ import { readFile as readFile3, readdir as readdir3 } from "fs/promises";
854
+ import { existsSync as existsSync15 } from "fs";
855
+ import path6 from "path";
777
856
  import {
778
857
  allocateBudget,
779
858
  deriveConfidence as deriveConfidence4,
@@ -781,36 +860,43 @@ import {
781
860
  getUsage as getUsage5,
782
861
  inferModulesFromPaths as inferModulesFromPaths2,
783
862
  literalMatchesAllTokens as literalMatchesAllTokens2,
784
- loadMemoriesFromDir as loadMemoriesFromDir11,
863
+ loadMemoriesFromDir as loadMemoriesFromDir12,
785
864
  loadUsageIndex as loadUsageIndex7,
786
865
  memoryMatchesAnchorPaths as memoryMatchesAnchorPaths2,
787
866
  tokenizeQuery as tokenizeQuery2,
788
867
  trackReads as trackReads3,
789
868
  truncateToTokens
790
869
  } from "@hiveai/core";
791
- import { z as z14 } from "zod";
870
+ import { z as z15 } from "zod";
792
871
  var GetBriefingInputSchema = {
793
- task: z14.string().optional().describe(
872
+ task: z15.string().optional().describe(
794
873
  "What you are about to do, in 1\u20132 sentences. Used to rank relevant memories semantically."
795
874
  ),
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(
875
+ files: z15.array(z15.string()).default([]).describe("Project-relative file paths the agent is currently looking at or about to edit"),
876
+ max_tokens: z15.number().int().positive().default(8e3).describe(
798
877
  "Approximate token budget for the entire briefing. Each section is allocated a share and truncated to fit."
799
878
  ),
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(
879
+ max_memories: z15.number().int().positive().default(8).describe("Cap on memories surfaced regardless of token budget"),
880
+ include_project_context: z15.boolean().default(true),
881
+ include_module_contexts: z15.boolean().default(true),
882
+ semantic: z15.boolean().default(true).describe(
804
883
  "Use semantic ranking when a task is provided (requires `haive embeddings index`)."
805
884
  ),
806
- track: z14.boolean().default(true).describe("Increment read_count on returned memories")
885
+ include_stale: z15.boolean().default(false).describe("Include stale memories (excluded by default \u2014 they may be outdated)"),
886
+ track: z15.boolean().default(true).describe("Increment read_count on returned memories")
807
887
  };
808
888
  async function getBriefing(input, ctx) {
809
889
  const inferred = inferModulesFromPaths2(input.files);
810
890
  const memories = [];
811
891
  let searchMode = "literal";
812
- if (existsSync14(ctx.paths.memoriesDir)) {
813
- const allMemories = await loadMemoriesFromDir11(ctx.paths.memoriesDir);
892
+ if (existsSync15(ctx.paths.memoriesDir)) {
893
+ const allLoaded = await loadMemoriesFromDir12(ctx.paths.memoriesDir);
894
+ const allMemories = allLoaded.filter(({ memory }) => {
895
+ const s = memory.frontmatter.status;
896
+ if (s === "rejected" || s === "deprecated") return false;
897
+ if (!input.include_stale && s === "stale") return false;
898
+ return true;
899
+ });
814
900
  const usage = await loadUsageIndex7(ctx.paths);
815
901
  const semanticHits = input.task && input.semantic ? await trySemanticHits(ctx, input.task, allMemories.length * 2) : null;
816
902
  if (input.task && input.semantic) {
@@ -881,10 +967,13 @@ async function getBriefing(input, ctx) {
881
967
  await trackReads3(ctx.paths, memories.map((m) => m.id));
882
968
  }
883
969
  }
884
- const projectContext = input.include_project_context && existsSync14(ctx.paths.projectContext) ? await readFile3(ctx.paths.projectContext, "utf8") : "";
970
+ const projectContext = input.include_project_context && existsSync15(ctx.paths.projectContext) ? await readFile3(ctx.paths.projectContext, "utf8") : "";
885
971
  const moduleContents = input.include_module_contexts ? await loadModuleContexts2(ctx, inferred) : [];
886
- const memoriesText = memories.map((m) => `### ${m.id} (${m.scope}/${m.type}, ${m.confidence})
887
- ${m.body.trim()}`).join("\n\n---\n\n");
972
+ const memoriesText = memories.map((m) => {
973
+ const unverified = m.status === "proposed" ? " [UNVERIFIED \u2014 not yet validated]" : "";
974
+ return `### ${m.id} (${m.scope}/${m.type}, ${m.confidence})${unverified}
975
+ ${m.body.trim()}`;
976
+ }).join("\n\n---\n\n");
888
977
  const slices = allocateBudget(
889
978
  [
890
979
  { key: "project", text: projectContext, weight: 3, mode: "head" },
@@ -952,15 +1041,15 @@ async function trySemanticHits(ctx, task, limit) {
952
1041
  }
953
1042
  async function loadModuleContexts2(ctx, modules) {
954
1043
  if (modules.length === 0) return [];
955
- if (!existsSync14(ctx.paths.modulesContextDir)) return [];
1044
+ if (!existsSync15(ctx.paths.modulesContextDir)) return [];
956
1045
  const available = new Set(
957
1046
  (await readdir3(ctx.paths.modulesContextDir, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => d.name)
958
1047
  );
959
1048
  const out = [];
960
1049
  for (const m of modules) {
961
1050
  if (!available.has(m)) continue;
962
- const file = path5.join(ctx.paths.modulesContextDir, m, "context.md");
963
- if (existsSync14(file)) {
1051
+ const file = path6.join(ctx.paths.modulesContextDir, m, "context.md");
1052
+ if (existsSync15(file)) {
964
1053
  out.push({ name: m, content: await readFile3(file, "utf8") });
965
1054
  }
966
1055
  }
@@ -969,11 +1058,11 @@ async function loadModuleContexts2(ctx, modules) {
969
1058
 
970
1059
  // src/tools/code-map.ts
971
1060
  import { loadCodeMap, queryCodeMap } from "@hiveai/core";
972
- import { z as z15 } from "zod";
1061
+ import { z as z16 } from "zod";
973
1062
  var CodeMapInputSchema = {
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")
1063
+ file: z16.string().optional().describe("Filter to files whose path contains this substring"),
1064
+ symbol: z16.string().optional().describe("Filter to files exporting a symbol whose name contains this substring"),
1065
+ max_files: z16.number().int().positive().default(40).describe("Cap on returned files")
977
1066
  };
978
1067
  async function codeMapTool(input, ctx) {
979
1068
  const map = await loadCodeMap(ctx.paths);
@@ -999,12 +1088,12 @@ async function codeMapTool(input, ctx) {
999
1088
  }
1000
1089
 
1001
1090
  // src/prompts/bootstrap-project.ts
1002
- import { z as z16 } from "zod";
1091
+ import { z as z17 } from "zod";
1003
1092
  var BootstrapProjectArgsSchema = {
1004
- module: z16.string().optional().describe(
1093
+ module: z17.string().optional().describe(
1005
1094
  "Optional module name to scope the analysis to (writes to .ai/modules/<module>/context.md)"
1006
1095
  ),
1007
- focus: z16.string().optional().describe("Optional area to emphasize (e.g. 'data layer', 'API surface')")
1096
+ focus: z17.string().optional().describe("Optional area to emphasize (e.g. 'data layer', 'API surface')")
1008
1097
  };
1009
1098
  var ROOT_TEMPLATE = `# Project context
1010
1099
 
@@ -1087,7 +1176,7 @@ ${template}\`\`\`
1087
1176
 
1088
1177
  // src/server.ts
1089
1178
  var SERVER_NAME = "haive";
1090
- var SERVER_VERSION = "0.2.3";
1179
+ var SERVER_VERSION = "0.2.6";
1091
1180
  function jsonResult(data) {
1092
1181
  return {
1093
1182
  content: [
@@ -1194,6 +1283,12 @@ function createHaiveServer(options = {}) {
1194
1283
  MemApproveInputSchema,
1195
1284
  async (input) => jsonResult(await memApprove(input, context))
1196
1285
  );
1286
+ server.tool(
1287
+ "mem_tried",
1288
+ "Record a failed approach as negative knowledge (type=attempt, auto-validated). Use this whenever you tried something and it didn't work \u2014 saves future agents from repeating the mistake.",
1289
+ MemTriedInputSchema,
1290
+ async (input) => jsonResult(await memTried(input, context))
1291
+ );
1197
1292
  server.prompt(
1198
1293
  "bootstrap_project",
1199
1294
  "Instructions for the AI client to analyze the project and save the context.",