@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 +149 -54
- package/dist/index.js.map +1 -1
- package/dist/server.js +149 -54
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -124,12 +124,13 @@ import { existsSync as existsSync4 } from "fs";
|
|
|
124
124
|
import path3 from "path";
|
|
125
125
|
import {
|
|
126
126
|
buildFrontmatter,
|
|
127
|
+
loadMemoriesFromDir as loadMemoriesFromDir2,
|
|
127
128
|
memoryFilePath,
|
|
128
129
|
serializeMemory
|
|
129
130
|
} from "@hiveai/core";
|
|
130
131
|
import { z as z4 } from "zod";
|
|
131
132
|
var MemSaveInputSchema = {
|
|
132
|
-
type: z4.enum(["convention", "decision", "gotcha", "architecture", "glossary"]).describe("Kind of memory being saved"),
|
|
133
|
+
type: z4.enum(["convention", "decision", "gotcha", "architecture", "glossary", "attempt"]).describe("Kind of memory being saved. Use 'attempt' for failed approaches (auto-validated)."),
|
|
133
134
|
slug: z4.string().min(1).describe("Short human-readable identifier \u2014 becomes part of the filename"),
|
|
134
135
|
body: z4.string().describe("Markdown body of the memory"),
|
|
135
136
|
scope: z4.enum(["personal", "team", "module"]).default("personal").describe("Visibility scope: personal | team | module"),
|
|
@@ -169,11 +170,24 @@ async function memSave(input, ctx) {
|
|
|
169
170
|
if (existsSync4(file)) {
|
|
170
171
|
throw new Error(`Memory already exists at ${file}`);
|
|
171
172
|
}
|
|
173
|
+
let warning;
|
|
174
|
+
if (existsSync4(ctx.paths.memoriesDir)) {
|
|
175
|
+
const existing = await loadMemoriesFromDir2(ctx.paths.memoriesDir);
|
|
176
|
+
const slugTokens = input.slug.toLowerCase().split(/[-_\s]+/).filter(Boolean);
|
|
177
|
+
const similar = existing.filter(({ memory }) => {
|
|
178
|
+
const id = memory.frontmatter.id.toLowerCase();
|
|
179
|
+
return slugTokens.length >= 2 && slugTokens.filter((t) => id.includes(t)).length >= Math.ceil(slugTokens.length * 0.6);
|
|
180
|
+
});
|
|
181
|
+
if (similar.length > 0) {
|
|
182
|
+
warning = `Possible duplicate detected. Similar memories: ${similar.map((m) => m.memory.frontmatter.id).join(", ")}. Consider updating one of these instead.`;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
172
185
|
await writeFile2(file, serializeMemory({ frontmatter, body: input.body }), "utf8");
|
|
173
186
|
return {
|
|
174
187
|
id: frontmatter.id,
|
|
175
188
|
scope: frontmatter.scope,
|
|
176
|
-
file_path: file
|
|
189
|
+
file_path: file,
|
|
190
|
+
...warning ? { warning } : {}
|
|
177
191
|
};
|
|
178
192
|
}
|
|
179
193
|
|
|
@@ -184,7 +198,8 @@ import {
|
|
|
184
198
|
extractSnippet,
|
|
185
199
|
getUsage,
|
|
186
200
|
literalMatchesAllTokens,
|
|
187
|
-
|
|
201
|
+
literalMatchesAnyToken,
|
|
202
|
+
loadMemoriesFromDir as loadMemoriesFromDir3,
|
|
188
203
|
loadUsageIndex,
|
|
189
204
|
pickSnippetNeedle,
|
|
190
205
|
tokenizeQuery,
|
|
@@ -194,7 +209,7 @@ import { z as z5 } from "zod";
|
|
|
194
209
|
var MemSearchInputSchema = {
|
|
195
210
|
query: z5.string().describe("Substring matched against id, tags, and body"),
|
|
196
211
|
scope: z5.enum(["personal", "team", "module"]).optional().describe("Restrict results to a single scope"),
|
|
197
|
-
type: z5.enum(["convention", "decision", "gotcha", "architecture", "glossary"]).optional().describe("Restrict results to a memory type"),
|
|
212
|
+
type: z5.enum(["convention", "decision", "gotcha", "architecture", "glossary", "attempt"]).optional().describe("Restrict results to a memory type"),
|
|
198
213
|
module: z5.string().optional().describe("Restrict results to a module"),
|
|
199
214
|
status: z5.enum(["draft", "proposed", "validated", "deprecated", "stale", "rejected"]).optional().describe("Filter by a single status. Omit to return all statuses."),
|
|
200
215
|
exclude_rejected: z5.boolean().default(false).describe("When true, exclude memories with status=rejected from results."),
|
|
@@ -209,7 +224,7 @@ async function memSearch(input, ctx) {
|
|
|
209
224
|
if (!existsSync5(ctx.paths.memoriesDir)) {
|
|
210
225
|
return { matches: [], total: 0, mode: input.semantic ? "literal_fallback" : "literal" };
|
|
211
226
|
}
|
|
212
|
-
const all = await
|
|
227
|
+
const all = await loadMemoriesFromDir3(ctx.paths.memoriesDir);
|
|
213
228
|
const filtered = all.filter(({ memory }) => passesFilters(memory.frontmatter, input));
|
|
214
229
|
const usage = await loadUsageIndex(ctx.paths);
|
|
215
230
|
let result;
|
|
@@ -245,13 +260,23 @@ function passesFilters(fm, input) {
|
|
|
245
260
|
}
|
|
246
261
|
function buildLiteralResult(input, filtered, usage) {
|
|
247
262
|
const tokens = tokenizeQuery(input.query);
|
|
248
|
-
const matched = filtered.filter(({ memory }) => literalMatchesAllTokens(memory, tokens));
|
|
249
263
|
const snippetNeedle = pickSnippetNeedle(input.query);
|
|
250
|
-
|
|
264
|
+
let andMatched = filtered.filter(({ memory }) => literalMatchesAllTokens(memory, tokens));
|
|
265
|
+
if (andMatched.length > 0) {
|
|
266
|
+
const top2 = andMatched.slice(0, input.limit);
|
|
267
|
+
return {
|
|
268
|
+
matches: top2.map((loaded) => toHit(loaded, snippetNeedle, usage)),
|
|
269
|
+
total: andMatched.length,
|
|
270
|
+
mode: "literal"
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
const orMatched = filtered.filter(({ memory }) => literalMatchesAnyToken(memory, tokens));
|
|
274
|
+
const top = orMatched.slice(0, input.limit);
|
|
251
275
|
return {
|
|
252
276
|
matches: top.map((loaded) => toHit(loaded, snippetNeedle, usage)),
|
|
253
|
-
total:
|
|
254
|
-
mode: "literal"
|
|
277
|
+
total: orMatched.length,
|
|
278
|
+
mode: "literal",
|
|
279
|
+
notice: `No exact match for all tokens. Showing partial matches (OR fallback) \u2014 ${orMatched.length} result${orMatched.length === 1 ? "" : "s"}.`
|
|
255
280
|
};
|
|
256
281
|
}
|
|
257
282
|
async function trySemanticSearch(ctx, input, filtered, usage) {
|
|
@@ -315,7 +340,7 @@ function toHit(loaded, needle, usage) {
|
|
|
315
340
|
import { writeFile as writeFile3 } from "fs/promises";
|
|
316
341
|
import { existsSync as existsSync6 } from "fs";
|
|
317
342
|
import {
|
|
318
|
-
loadMemoriesFromDir as
|
|
343
|
+
loadMemoriesFromDir as loadMemoriesFromDir4,
|
|
319
344
|
serializeMemory as serializeMemory2,
|
|
320
345
|
verifyAnchor
|
|
321
346
|
} from "@hiveai/core";
|
|
@@ -331,7 +356,7 @@ async function memVerify(input, ctx) {
|
|
|
331
356
|
summary: { checked: 0, fresh: 0, stale: 0, anchorless_skipped: 0, updated: 0 }
|
|
332
357
|
};
|
|
333
358
|
}
|
|
334
|
-
const all = await
|
|
359
|
+
const all = await loadMemoriesFromDir4(ctx.paths.memoriesDir);
|
|
335
360
|
const targets = input.id ? all.filter((m) => m.memory.frontmatter.id === input.id) : all;
|
|
336
361
|
const results = [];
|
|
337
362
|
let fresh = 0;
|
|
@@ -410,7 +435,7 @@ function applyVerification(mem, result) {
|
|
|
410
435
|
import { writeFile as writeFile4 } from "fs/promises";
|
|
411
436
|
import { existsSync as existsSync7 } from "fs";
|
|
412
437
|
import {
|
|
413
|
-
loadMemoriesFromDir as
|
|
438
|
+
loadMemoriesFromDir as loadMemoriesFromDir5,
|
|
414
439
|
loadUsageIndex as loadUsageIndex2,
|
|
415
440
|
recordRejection,
|
|
416
441
|
saveUsageIndex,
|
|
@@ -425,13 +450,17 @@ async function memReject(input, ctx) {
|
|
|
425
450
|
if (!existsSync7(ctx.paths.memoriesDir)) {
|
|
426
451
|
throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
|
|
427
452
|
}
|
|
428
|
-
const memories = await
|
|
453
|
+
const memories = await loadMemoriesFromDir5(ctx.paths.memoriesDir);
|
|
429
454
|
const loaded = memories.find((m) => m.memory.frontmatter.id === input.id);
|
|
430
455
|
if (!loaded) throw new Error(`No memory with id "${input.id}".`);
|
|
431
456
|
await writeFile4(
|
|
432
457
|
loaded.filePath,
|
|
433
458
|
serializeMemory3({
|
|
434
|
-
frontmatter: {
|
|
459
|
+
frontmatter: {
|
|
460
|
+
...loaded.memory.frontmatter,
|
|
461
|
+
status: "rejected",
|
|
462
|
+
stale_reason: input.reason ?? loaded.memory.frontmatter.stale_reason ?? null
|
|
463
|
+
},
|
|
435
464
|
body: loaded.memory.body
|
|
436
465
|
}),
|
|
437
466
|
"utf8"
|
|
@@ -457,7 +486,7 @@ import {
|
|
|
457
486
|
deriveConfidence as deriveConfidence2,
|
|
458
487
|
getUsage as getUsage2,
|
|
459
488
|
inferModulesFromPaths,
|
|
460
|
-
loadMemoriesFromDir as
|
|
489
|
+
loadMemoriesFromDir as loadMemoriesFromDir6,
|
|
461
490
|
loadUsageIndex as loadUsageIndex3,
|
|
462
491
|
memoryMatchesAnchorPaths,
|
|
463
492
|
trackReads as trackReads2
|
|
@@ -479,7 +508,7 @@ async function memForFiles(input, ctx) {
|
|
|
479
508
|
module_contexts: await loadModuleContexts(ctx, inferred, input.include_module_contexts)
|
|
480
509
|
};
|
|
481
510
|
}
|
|
482
|
-
const all = await
|
|
511
|
+
const all = await loadMemoriesFromDir6(ctx.paths.memoriesDir);
|
|
483
512
|
const usage = await loadUsageIndex3(ctx.paths);
|
|
484
513
|
const seen = /* @__PURE__ */ new Set();
|
|
485
514
|
const byAnchor = [];
|
|
@@ -558,7 +587,7 @@ import { existsSync as existsSync9 } from "fs";
|
|
|
558
587
|
import {
|
|
559
588
|
deriveConfidence as deriveConfidence3,
|
|
560
589
|
getUsage as getUsage3,
|
|
561
|
-
loadMemoriesFromDir as
|
|
590
|
+
loadMemoriesFromDir as loadMemoriesFromDir7,
|
|
562
591
|
loadUsageIndex as loadUsageIndex4
|
|
563
592
|
} from "@hiveai/core";
|
|
564
593
|
import { z as z9 } from "zod";
|
|
@@ -569,7 +598,7 @@ async function memGet(input, ctx) {
|
|
|
569
598
|
if (!existsSync9(ctx.paths.memoriesDir)) {
|
|
570
599
|
throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
|
|
571
600
|
}
|
|
572
|
-
const all = await
|
|
601
|
+
const all = await loadMemoriesFromDir7(ctx.paths.memoriesDir);
|
|
573
602
|
const found = all.find((m) => m.memory.frontmatter.id === input.id);
|
|
574
603
|
if (!found) throw new Error(`No memory with id "${input.id}".`);
|
|
575
604
|
const fm = found.memory.frontmatter;
|
|
@@ -601,7 +630,7 @@ async function memGet(input, ctx) {
|
|
|
601
630
|
import { existsSync as existsSync10 } from "fs";
|
|
602
631
|
import { unlink } from "fs/promises";
|
|
603
632
|
import {
|
|
604
|
-
loadMemoriesFromDir as
|
|
633
|
+
loadMemoriesFromDir as loadMemoriesFromDir8,
|
|
605
634
|
loadUsageIndex as loadUsageIndex5,
|
|
606
635
|
saveUsageIndex as saveUsageIndex2
|
|
607
636
|
} from "@hiveai/core";
|
|
@@ -614,7 +643,7 @@ async function memDelete(input, ctx) {
|
|
|
614
643
|
if (!existsSync10(ctx.paths.memoriesDir)) {
|
|
615
644
|
throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
|
|
616
645
|
}
|
|
617
|
-
const all = await
|
|
646
|
+
const all = await loadMemoriesFromDir8(ctx.paths.memoriesDir);
|
|
618
647
|
const found = all.find((m) => m.memory.frontmatter.id === input.id);
|
|
619
648
|
if (!found) throw new Error(`No memory with id "${input.id}".`);
|
|
620
649
|
await unlink(found.filePath);
|
|
@@ -633,7 +662,7 @@ async function memDelete(input, ctx) {
|
|
|
633
662
|
// src/tools/mem-update.ts
|
|
634
663
|
import { writeFile as writeFile5 } from "fs/promises";
|
|
635
664
|
import { existsSync as existsSync11 } from "fs";
|
|
636
|
-
import { loadMemoriesFromDir as
|
|
665
|
+
import { loadMemoriesFromDir as loadMemoriesFromDir9, serializeMemory as serializeMemory4 } from "@hiveai/core";
|
|
637
666
|
import { z as z11 } from "zod";
|
|
638
667
|
var MemUpdateInputSchema = {
|
|
639
668
|
id: z11.string().min(1).describe("Id of the memory to update"),
|
|
@@ -649,7 +678,7 @@ async function memUpdate(input, ctx) {
|
|
|
649
678
|
if (!existsSync11(ctx.paths.memoriesDir)) {
|
|
650
679
|
throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
|
|
651
680
|
}
|
|
652
|
-
const memories = await
|
|
681
|
+
const memories = await loadMemoriesFromDir9(ctx.paths.memoriesDir);
|
|
653
682
|
const loaded = memories.find((m) => m.memory.frontmatter.id === input.id);
|
|
654
683
|
if (!loaded) throw new Error(`No memory with id "${input.id}".`);
|
|
655
684
|
const { frontmatter, body } = loaded.memory;
|
|
@@ -694,7 +723,7 @@ async function memUpdate(input, ctx) {
|
|
|
694
723
|
import { existsSync as existsSync12 } from "fs";
|
|
695
724
|
import {
|
|
696
725
|
getUsage as getUsage4,
|
|
697
|
-
loadMemoriesFromDir as
|
|
726
|
+
loadMemoriesFromDir as loadMemoriesFromDir10,
|
|
698
727
|
loadUsageIndex as loadUsageIndex6
|
|
699
728
|
} from "@hiveai/core";
|
|
700
729
|
import { z as z12 } from "zod";
|
|
@@ -703,7 +732,7 @@ var MemPendingInputSchema = {
|
|
|
703
732
|
};
|
|
704
733
|
async function memPending(input, ctx) {
|
|
705
734
|
if (!existsSync12(ctx.paths.memoriesDir)) return { pending: [] };
|
|
706
|
-
const all = await
|
|
735
|
+
const all = await loadMemoriesFromDir10(ctx.paths.memoriesDir);
|
|
707
736
|
const usage = await loadUsageIndex6(ctx.paths);
|
|
708
737
|
const now = Date.now();
|
|
709
738
|
const proposed = all.filter(({ memory }) => {
|
|
@@ -737,7 +766,7 @@ async function memPending(input, ctx) {
|
|
|
737
766
|
import { writeFile as writeFile6 } from "fs/promises";
|
|
738
767
|
import { existsSync as existsSync13 } from "fs";
|
|
739
768
|
import {
|
|
740
|
-
loadMemoriesFromDir as
|
|
769
|
+
loadMemoriesFromDir as loadMemoriesFromDir11,
|
|
741
770
|
serializeMemory as serializeMemory5
|
|
742
771
|
} from "@hiveai/core";
|
|
743
772
|
import { z as z13 } from "zod";
|
|
@@ -748,7 +777,7 @@ async function memApprove(input, ctx) {
|
|
|
748
777
|
if (!existsSync13(ctx.paths.memoriesDir)) {
|
|
749
778
|
throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
|
|
750
779
|
}
|
|
751
|
-
const all = await
|
|
780
|
+
const all = await loadMemoriesFromDir11(ctx.paths.memoriesDir);
|
|
752
781
|
const found = all.find((m) => m.memory.frontmatter.id === input.id);
|
|
753
782
|
if (!found) throw new Error(`No memory with id "${input.id}".`);
|
|
754
783
|
const previous = found.memory.frontmatter.status;
|
|
@@ -765,10 +794,60 @@ async function memApprove(input, ctx) {
|
|
|
765
794
|
};
|
|
766
795
|
}
|
|
767
796
|
|
|
768
|
-
// src/tools/
|
|
769
|
-
import {
|
|
797
|
+
// src/tools/mem-tried.ts
|
|
798
|
+
import { mkdir as mkdir3, writeFile as writeFile7 } from "fs/promises";
|
|
770
799
|
import { existsSync as existsSync14 } from "fs";
|
|
771
800
|
import path5 from "path";
|
|
801
|
+
import {
|
|
802
|
+
buildFrontmatter as buildFrontmatter2,
|
|
803
|
+
memoryFilePath as memoryFilePath2,
|
|
804
|
+
serializeMemory as serializeMemory6
|
|
805
|
+
} from "@hiveai/core";
|
|
806
|
+
import { z as z14 } from "zod";
|
|
807
|
+
var MemTriedInputSchema = {
|
|
808
|
+
what: z14.string().min(1).describe("Brief description of the approach that was tried"),
|
|
809
|
+
why_failed: z14.string().min(1).describe("Why it failed or why it should NOT be used"),
|
|
810
|
+
instead: z14.string().optional().describe("What to use or do instead (recommended alternative)"),
|
|
811
|
+
scope: z14.enum(["personal", "team", "module"]).default("personal").describe("Visibility scope"),
|
|
812
|
+
module: z14.string().optional().describe("Module name (required when scope=module)"),
|
|
813
|
+
tags: z14.array(z14.string()).default([]).describe("Tags for filtering"),
|
|
814
|
+
paths: z14.array(z14.string()).default([]).describe("Anchor file paths this applies to"),
|
|
815
|
+
author: z14.string().optional().describe("Author handle or email")
|
|
816
|
+
};
|
|
817
|
+
async function memTried(input, ctx) {
|
|
818
|
+
if (!existsSync14(ctx.paths.haiveDir)) {
|
|
819
|
+
throw new Error(`No .ai/ directory at ${ctx.paths.root}. Run 'haive init' first.`);
|
|
820
|
+
}
|
|
821
|
+
const slug = input.what.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().split(/\s+/).slice(0, 5).join("-");
|
|
822
|
+
const baseFm = buildFrontmatter2({
|
|
823
|
+
type: "attempt",
|
|
824
|
+
slug,
|
|
825
|
+
scope: input.scope,
|
|
826
|
+
module: input.module,
|
|
827
|
+
tags: input.tags,
|
|
828
|
+
paths: input.paths,
|
|
829
|
+
author: input.author
|
|
830
|
+
});
|
|
831
|
+
const frontmatter = { ...baseFm, status: "validated" };
|
|
832
|
+
const lines = [`# ${input.what}`, ""];
|
|
833
|
+
lines.push(`**Why it failed / do NOT use:** ${input.why_failed}`);
|
|
834
|
+
if (input.instead) {
|
|
835
|
+
lines.push("", `**Instead, use:** ${input.instead}`);
|
|
836
|
+
}
|
|
837
|
+
const body = lines.join("\n") + "\n";
|
|
838
|
+
const file = memoryFilePath2(ctx.paths, frontmatter.scope, frontmatter.id, frontmatter.module);
|
|
839
|
+
await mkdir3(path5.dirname(file), { recursive: true });
|
|
840
|
+
if (existsSync14(file)) {
|
|
841
|
+
throw new Error(`Memory already exists at ${file}`);
|
|
842
|
+
}
|
|
843
|
+
await writeFile7(file, serializeMemory6({ frontmatter, body }), "utf8");
|
|
844
|
+
return { id: frontmatter.id, scope: frontmatter.scope, file_path: file };
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// src/tools/get-briefing.ts
|
|
848
|
+
import { readFile as readFile3, readdir as readdir3 } from "fs/promises";
|
|
849
|
+
import { existsSync as existsSync15 } from "fs";
|
|
850
|
+
import path6 from "path";
|
|
772
851
|
import {
|
|
773
852
|
allocateBudget,
|
|
774
853
|
deriveConfidence as deriveConfidence4,
|
|
@@ -776,36 +855,43 @@ import {
|
|
|
776
855
|
getUsage as getUsage5,
|
|
777
856
|
inferModulesFromPaths as inferModulesFromPaths2,
|
|
778
857
|
literalMatchesAllTokens as literalMatchesAllTokens2,
|
|
779
|
-
loadMemoriesFromDir as
|
|
858
|
+
loadMemoriesFromDir as loadMemoriesFromDir12,
|
|
780
859
|
loadUsageIndex as loadUsageIndex7,
|
|
781
860
|
memoryMatchesAnchorPaths as memoryMatchesAnchorPaths2,
|
|
782
861
|
tokenizeQuery as tokenizeQuery2,
|
|
783
862
|
trackReads as trackReads3,
|
|
784
863
|
truncateToTokens
|
|
785
864
|
} from "@hiveai/core";
|
|
786
|
-
import { z as
|
|
865
|
+
import { z as z15 } from "zod";
|
|
787
866
|
var GetBriefingInputSchema = {
|
|
788
|
-
task:
|
|
867
|
+
task: z15.string().optional().describe(
|
|
789
868
|
"What you are about to do, in 1\u20132 sentences. Used to rank relevant memories semantically."
|
|
790
869
|
),
|
|
791
|
-
files:
|
|
792
|
-
max_tokens:
|
|
870
|
+
files: z15.array(z15.string()).default([]).describe("Project-relative file paths the agent is currently looking at or about to edit"),
|
|
871
|
+
max_tokens: z15.number().int().positive().default(8e3).describe(
|
|
793
872
|
"Approximate token budget for the entire briefing. Each section is allocated a share and truncated to fit."
|
|
794
873
|
),
|
|
795
|
-
max_memories:
|
|
796
|
-
include_project_context:
|
|
797
|
-
include_module_contexts:
|
|
798
|
-
semantic:
|
|
874
|
+
max_memories: z15.number().int().positive().default(8).describe("Cap on memories surfaced regardless of token budget"),
|
|
875
|
+
include_project_context: z15.boolean().default(true),
|
|
876
|
+
include_module_contexts: z15.boolean().default(true),
|
|
877
|
+
semantic: z15.boolean().default(true).describe(
|
|
799
878
|
"Use semantic ranking when a task is provided (requires `haive embeddings index`)."
|
|
800
879
|
),
|
|
801
|
-
|
|
880
|
+
include_stale: z15.boolean().default(false).describe("Include stale memories (excluded by default \u2014 they may be outdated)"),
|
|
881
|
+
track: z15.boolean().default(true).describe("Increment read_count on returned memories")
|
|
802
882
|
};
|
|
803
883
|
async function getBriefing(input, ctx) {
|
|
804
884
|
const inferred = inferModulesFromPaths2(input.files);
|
|
805
885
|
const memories = [];
|
|
806
886
|
let searchMode = "literal";
|
|
807
|
-
if (
|
|
808
|
-
const
|
|
887
|
+
if (existsSync15(ctx.paths.memoriesDir)) {
|
|
888
|
+
const allLoaded = await loadMemoriesFromDir12(ctx.paths.memoriesDir);
|
|
889
|
+
const allMemories = allLoaded.filter(({ memory }) => {
|
|
890
|
+
const s = memory.frontmatter.status;
|
|
891
|
+
if (s === "rejected" || s === "deprecated") return false;
|
|
892
|
+
if (!input.include_stale && s === "stale") return false;
|
|
893
|
+
return true;
|
|
894
|
+
});
|
|
809
895
|
const usage = await loadUsageIndex7(ctx.paths);
|
|
810
896
|
const semanticHits = input.task && input.semantic ? await trySemanticHits(ctx, input.task, allMemories.length * 2) : null;
|
|
811
897
|
if (input.task && input.semantic) {
|
|
@@ -876,10 +962,13 @@ async function getBriefing(input, ctx) {
|
|
|
876
962
|
await trackReads3(ctx.paths, memories.map((m) => m.id));
|
|
877
963
|
}
|
|
878
964
|
}
|
|
879
|
-
const projectContext = input.include_project_context &&
|
|
965
|
+
const projectContext = input.include_project_context && existsSync15(ctx.paths.projectContext) ? await readFile3(ctx.paths.projectContext, "utf8") : "";
|
|
880
966
|
const moduleContents = input.include_module_contexts ? await loadModuleContexts2(ctx, inferred) : [];
|
|
881
|
-
const memoriesText = memories.map((m) =>
|
|
882
|
-
|
|
967
|
+
const memoriesText = memories.map((m) => {
|
|
968
|
+
const unverified = m.status === "proposed" ? " [UNVERIFIED \u2014 not yet validated]" : "";
|
|
969
|
+
return `### ${m.id} (${m.scope}/${m.type}, ${m.confidence})${unverified}
|
|
970
|
+
${m.body.trim()}`;
|
|
971
|
+
}).join("\n\n---\n\n");
|
|
883
972
|
const slices = allocateBudget(
|
|
884
973
|
[
|
|
885
974
|
{ key: "project", text: projectContext, weight: 3, mode: "head" },
|
|
@@ -947,15 +1036,15 @@ async function trySemanticHits(ctx, task, limit) {
|
|
|
947
1036
|
}
|
|
948
1037
|
async function loadModuleContexts2(ctx, modules) {
|
|
949
1038
|
if (modules.length === 0) return [];
|
|
950
|
-
if (!
|
|
1039
|
+
if (!existsSync15(ctx.paths.modulesContextDir)) return [];
|
|
951
1040
|
const available = new Set(
|
|
952
1041
|
(await readdir3(ctx.paths.modulesContextDir, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => d.name)
|
|
953
1042
|
);
|
|
954
1043
|
const out = [];
|
|
955
1044
|
for (const m of modules) {
|
|
956
1045
|
if (!available.has(m)) continue;
|
|
957
|
-
const file =
|
|
958
|
-
if (
|
|
1046
|
+
const file = path6.join(ctx.paths.modulesContextDir, m, "context.md");
|
|
1047
|
+
if (existsSync15(file)) {
|
|
959
1048
|
out.push({ name: m, content: await readFile3(file, "utf8") });
|
|
960
1049
|
}
|
|
961
1050
|
}
|
|
@@ -964,11 +1053,11 @@ async function loadModuleContexts2(ctx, modules) {
|
|
|
964
1053
|
|
|
965
1054
|
// src/tools/code-map.ts
|
|
966
1055
|
import { loadCodeMap, queryCodeMap } from "@hiveai/core";
|
|
967
|
-
import { z as
|
|
1056
|
+
import { z as z16 } from "zod";
|
|
968
1057
|
var CodeMapInputSchema = {
|
|
969
|
-
file:
|
|
970
|
-
symbol:
|
|
971
|
-
max_files:
|
|
1058
|
+
file: z16.string().optional().describe("Filter to files whose path contains this substring"),
|
|
1059
|
+
symbol: z16.string().optional().describe("Filter to files exporting a symbol whose name contains this substring"),
|
|
1060
|
+
max_files: z16.number().int().positive().default(40).describe("Cap on returned files")
|
|
972
1061
|
};
|
|
973
1062
|
async function codeMapTool(input, ctx) {
|
|
974
1063
|
const map = await loadCodeMap(ctx.paths);
|
|
@@ -994,12 +1083,12 @@ async function codeMapTool(input, ctx) {
|
|
|
994
1083
|
}
|
|
995
1084
|
|
|
996
1085
|
// src/prompts/bootstrap-project.ts
|
|
997
|
-
import { z as
|
|
1086
|
+
import { z as z17 } from "zod";
|
|
998
1087
|
var BootstrapProjectArgsSchema = {
|
|
999
|
-
module:
|
|
1088
|
+
module: z17.string().optional().describe(
|
|
1000
1089
|
"Optional module name to scope the analysis to (writes to .ai/modules/<module>/context.md)"
|
|
1001
1090
|
),
|
|
1002
|
-
focus:
|
|
1091
|
+
focus: z17.string().optional().describe("Optional area to emphasize (e.g. 'data layer', 'API surface')")
|
|
1003
1092
|
};
|
|
1004
1093
|
var ROOT_TEMPLATE = `# Project context
|
|
1005
1094
|
|
|
@@ -1082,7 +1171,7 @@ ${template}\`\`\`
|
|
|
1082
1171
|
|
|
1083
1172
|
// src/server.ts
|
|
1084
1173
|
var SERVER_NAME = "haive";
|
|
1085
|
-
var SERVER_VERSION = "0.2.
|
|
1174
|
+
var SERVER_VERSION = "0.2.6";
|
|
1086
1175
|
function jsonResult(data) {
|
|
1087
1176
|
return {
|
|
1088
1177
|
content: [
|
|
@@ -1189,6 +1278,12 @@ function createHaiveServer(options = {}) {
|
|
|
1189
1278
|
MemApproveInputSchema,
|
|
1190
1279
|
async (input) => jsonResult(await memApprove(input, context))
|
|
1191
1280
|
);
|
|
1281
|
+
server.tool(
|
|
1282
|
+
"mem_tried",
|
|
1283
|
+
"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.",
|
|
1284
|
+
MemTriedInputSchema,
|
|
1285
|
+
async (input) => jsonResult(await memTried(input, context))
|
|
1286
|
+
);
|
|
1192
1287
|
server.prompt(
|
|
1193
1288
|
"bootstrap_project",
|
|
1194
1289
|
"Instructions for the AI client to analyze the project and save the context.",
|