@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/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
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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: {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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/
|
|
774
|
-
import {
|
|
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
|
|
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
|
|
870
|
+
import { z as z15 } from "zod";
|
|
792
871
|
var GetBriefingInputSchema = {
|
|
793
|
-
task:
|
|
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:
|
|
797
|
-
max_tokens:
|
|
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:
|
|
801
|
-
include_project_context:
|
|
802
|
-
include_module_contexts:
|
|
803
|
-
semantic:
|
|
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
|
-
|
|
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 (
|
|
813
|
-
const
|
|
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 &&
|
|
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) =>
|
|
887
|
-
|
|
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 (!
|
|
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 =
|
|
963
|
-
if (
|
|
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
|
|
1061
|
+
import { z as z16 } from "zod";
|
|
973
1062
|
var CodeMapInputSchema = {
|
|
974
|
-
file:
|
|
975
|
-
symbol:
|
|
976
|
-
max_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
|
|
1091
|
+
import { z as z17 } from "zod";
|
|
1003
1092
|
var BootstrapProjectArgsSchema = {
|
|
1004
|
-
module:
|
|
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:
|
|
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.
|
|
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.",
|