@hiveai/mcp 0.2.6 → 0.2.8
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 +268 -25
- package/dist/index.js.map +1 -1
- package/dist/server.js +268 -25
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -392,6 +392,7 @@ async function memVerify(input, ctx) {
|
|
|
392
392
|
file_path: filePath,
|
|
393
393
|
stale: result.stale,
|
|
394
394
|
reason: result.reason,
|
|
395
|
+
...result.possibleRenames.length > 0 ? { possible_renames: result.possibleRenames } : {},
|
|
395
396
|
status_after: statusAfter
|
|
396
397
|
});
|
|
397
398
|
}
|
|
@@ -854,6 +855,7 @@ import {
|
|
|
854
855
|
estimateTokens,
|
|
855
856
|
getUsage as getUsage5,
|
|
856
857
|
inferModulesFromPaths as inferModulesFromPaths2,
|
|
858
|
+
isDecaying,
|
|
857
859
|
literalMatchesAllTokens as literalMatchesAllTokens2,
|
|
858
860
|
loadMemoriesFromDir as loadMemoriesFromDir12,
|
|
859
861
|
loadUsageIndex as loadUsageIndex7,
|
|
@@ -878,12 +880,17 @@ var GetBriefingInputSchema = {
|
|
|
878
880
|
"Use semantic ranking when a task is provided (requires `haive embeddings index`)."
|
|
879
881
|
),
|
|
880
882
|
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")
|
|
883
|
+
track: z15.boolean().default(true).describe("Increment read_count on returned memories"),
|
|
884
|
+
format: z15.enum(["full", "compact"]).default("full").describe(
|
|
885
|
+
"Output format: 'full' returns complete memory bodies; 'compact' returns id + 1-line summary only (call mem_get for details)."
|
|
886
|
+
)
|
|
882
887
|
};
|
|
883
888
|
async function getBriefing(input, ctx) {
|
|
884
889
|
const inferred = inferModulesFromPaths2(input.files);
|
|
885
890
|
const memories = [];
|
|
886
891
|
let searchMode = "literal";
|
|
892
|
+
let usage = { version: 1, updated_at: "", by_id: {} };
|
|
893
|
+
let byId = /* @__PURE__ */ new Map();
|
|
887
894
|
if (existsSync15(ctx.paths.memoriesDir)) {
|
|
888
895
|
const allLoaded = await loadMemoriesFromDir12(ctx.paths.memoriesDir);
|
|
889
896
|
const allMemories = allLoaded.filter(({ memory }) => {
|
|
@@ -892,13 +899,13 @@ async function getBriefing(input, ctx) {
|
|
|
892
899
|
if (!input.include_stale && s === "stale") return false;
|
|
893
900
|
return true;
|
|
894
901
|
});
|
|
895
|
-
|
|
902
|
+
usage = await loadUsageIndex7(ctx.paths);
|
|
896
903
|
const semanticHits = input.task && input.semantic ? await trySemanticHits(ctx, input.task, allMemories.length * 2) : null;
|
|
897
904
|
if (input.task && input.semantic) {
|
|
898
905
|
searchMode = semanticHits ? "semantic" : "literal_fallback";
|
|
899
906
|
}
|
|
900
907
|
const seen = /* @__PURE__ */ new Map();
|
|
901
|
-
const addOrUpdate = (loaded, reason, score) => {
|
|
908
|
+
const addOrUpdate = (loaded, reason, score, matchQuality) => {
|
|
902
909
|
const fm = loaded.memory.frontmatter;
|
|
903
910
|
const existing = seen.get(fm.id);
|
|
904
911
|
if (existing) {
|
|
@@ -906,6 +913,11 @@ async function getBriefing(input, ctx) {
|
|
|
906
913
|
if (score !== void 0 && (existing.semantic_score ?? 0) < score) {
|
|
907
914
|
existing.semantic_score = score;
|
|
908
915
|
}
|
|
916
|
+
if (matchQuality === "exact" && existing.match_quality !== "exact") {
|
|
917
|
+
existing.match_quality = "exact";
|
|
918
|
+
} else if (matchQuality === "semantic" && existing.match_quality === "partial") {
|
|
919
|
+
existing.match_quality = "semantic";
|
|
920
|
+
}
|
|
909
921
|
return;
|
|
910
922
|
}
|
|
911
923
|
const u = getUsage5(usage, fm.id);
|
|
@@ -919,6 +931,7 @@ async function getBriefing(input, ctx) {
|
|
|
919
931
|
confidence: deriveConfidence4(fm, u),
|
|
920
932
|
read_count: u.read_count,
|
|
921
933
|
reasons: [reason],
|
|
934
|
+
match_quality: matchQuality ?? "partial",
|
|
922
935
|
...score !== void 0 ? { semantic_score: score } : {},
|
|
923
936
|
body: loaded.memory.body,
|
|
924
937
|
file_path: loaded.filePath
|
|
@@ -926,37 +939,48 @@ async function getBriefing(input, ctx) {
|
|
|
926
939
|
};
|
|
927
940
|
if (input.files.length > 0) {
|
|
928
941
|
for (const loaded of allMemories) {
|
|
929
|
-
if (memoryMatchesAnchorPaths2(loaded.memory, input.files)) addOrUpdate(loaded, "anchor");
|
|
942
|
+
if (memoryMatchesAnchorPaths2(loaded.memory, input.files)) addOrUpdate(loaded, "anchor", void 0, "exact");
|
|
930
943
|
}
|
|
931
944
|
for (const loaded of allMemories) {
|
|
932
945
|
const fm = loaded.memory.frontmatter;
|
|
933
|
-
if (fm.module && inferred.includes(fm.module)) addOrUpdate(loaded, "module");
|
|
934
|
-
if (fm.domain && inferred.includes(fm.domain)) addOrUpdate(loaded, "domain");
|
|
935
|
-
if (fm.tags.some((t) => inferred.includes(t))) addOrUpdate(loaded, "module");
|
|
946
|
+
if (fm.module && inferred.includes(fm.module)) addOrUpdate(loaded, "module", void 0, "partial");
|
|
947
|
+
if (fm.domain && inferred.includes(fm.domain)) addOrUpdate(loaded, "domain", void 0, "partial");
|
|
948
|
+
if (fm.tags.some((t) => inferred.includes(t))) addOrUpdate(loaded, "module", void 0, "partial");
|
|
936
949
|
}
|
|
937
950
|
}
|
|
938
951
|
if (input.task) {
|
|
939
952
|
const tokens = tokenizeQuery2(input.task);
|
|
940
953
|
for (const loaded of allMemories) {
|
|
941
954
|
if (literalMatchesAllTokens2(loaded.memory, tokens)) {
|
|
942
|
-
addOrUpdate(loaded, "semantic");
|
|
955
|
+
addOrUpdate(loaded, "semantic", void 0, "exact");
|
|
943
956
|
}
|
|
944
957
|
}
|
|
945
958
|
if (semanticHits) {
|
|
946
|
-
const byId = new Map(allMemories.map((m) => [m.memory.frontmatter.id, m]));
|
|
947
959
|
for (const hit of semanticHits) {
|
|
948
960
|
const loaded = byId.get(hit.id);
|
|
949
|
-
if (loaded) addOrUpdate(loaded, "semantic", hit.score);
|
|
961
|
+
if (loaded) addOrUpdate(loaded, "semantic", hit.score, "semantic");
|
|
950
962
|
}
|
|
951
963
|
}
|
|
952
964
|
}
|
|
953
965
|
const ranked = [...seen.values()].sort((a, b) => {
|
|
954
|
-
const reasonScore = (m) => (m.
|
|
966
|
+
const reasonScore = (m) => (m.type === "attempt" ? 3 : 0) + // attempt = negative knowledge, surface first to prevent repeating mistakes
|
|
967
|
+
(m.reasons.includes("anchor") ? 4 : 0) + (m.reasons.includes("module") ? 2 : 0) + (m.reasons.includes("semantic") ? 2 : 0) + (m.reasons.includes("domain") ? 1 : 0);
|
|
955
968
|
const confidenceScore = (m) => m.confidence === "authoritative" ? 4 : m.confidence === "trusted" ? 3 : m.confidence === "low" ? 1 : m.confidence === "stale" ? -2 : 0;
|
|
956
969
|
const sa = reasonScore(a) + confidenceScore(a) + (a.semantic_score ?? 0);
|
|
957
970
|
const sb = reasonScore(b) + confidenceScore(b) + (b.semantic_score ?? 0);
|
|
958
971
|
return sb - sa;
|
|
959
972
|
});
|
|
973
|
+
byId = new Map(allMemories.map((m) => [m.memory.frontmatter.id, m]));
|
|
974
|
+
for (const mem of ranked.slice(0, input.max_memories)) {
|
|
975
|
+
if (seen.size >= input.max_memories * 2) break;
|
|
976
|
+
const loaded = byId.get(mem.id);
|
|
977
|
+
if (!loaded) continue;
|
|
978
|
+
for (const relId of loaded.memory.frontmatter.related_ids ?? []) {
|
|
979
|
+
if (seen.has(relId)) continue;
|
|
980
|
+
const related = byId.get(relId);
|
|
981
|
+
if (related) addOrUpdate(related, "anchor", void 0, "partial");
|
|
982
|
+
}
|
|
983
|
+
}
|
|
960
984
|
memories.push(...ranked.slice(0, input.max_memories));
|
|
961
985
|
if (input.track && memories.length > 0) {
|
|
962
986
|
await trackReads3(ctx.paths, memories.map((m) => m.id));
|
|
@@ -997,21 +1021,41 @@ ${m.content}`).join("\n\n---\n\n"),
|
|
|
997
1021
|
trimmedModules.push({ name: m.name, content: sub.text, truncated: sub.truncated });
|
|
998
1022
|
}
|
|
999
1023
|
}
|
|
1000
|
-
const
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1024
|
+
const trimmedMemories = [];
|
|
1025
|
+
if (!memoriesSlice.truncated) {
|
|
1026
|
+
trimmedMemories.push(...memories);
|
|
1027
|
+
} else {
|
|
1028
|
+
let remaining = memoriesSlice.allocatedTokens;
|
|
1029
|
+
for (const m of memories) {
|
|
1030
|
+
const bodyTokens = estimateTokens(m.body);
|
|
1031
|
+
if (remaining <= 0) break;
|
|
1032
|
+
if (bodyTokens <= remaining) {
|
|
1033
|
+
trimmedMemories.push(m);
|
|
1034
|
+
remaining -= bodyTokens;
|
|
1035
|
+
} else if (remaining > 80) {
|
|
1036
|
+
const t = truncateToTokens(m.body, { maxTokens: remaining, mode: "head" });
|
|
1037
|
+
trimmedMemories.push({ ...m, body: t.text });
|
|
1038
|
+
remaining = 0;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1007
1042
|
const totalTokens = projectSlice.estimatedTokens + modulesSlice.estimatedTokens + memoriesSlice.estimatedTokens;
|
|
1043
|
+
const decayWarnings = [];
|
|
1044
|
+
for (const m of trimmedMemories) {
|
|
1045
|
+
const u = getUsage5(usage, m.id);
|
|
1046
|
+
const loaded = byId.get(m.id);
|
|
1047
|
+
const createdAt = loaded?.memory.frontmatter.created_at ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1048
|
+
if (isDecaying(u, createdAt)) decayWarnings.push(m.id);
|
|
1049
|
+
}
|
|
1050
|
+
const outputMemories = input.format === "compact" ? trimmedMemories.map((m) => ({ ...m, body: compactSummary(m.body) })) : trimmedMemories;
|
|
1008
1051
|
return {
|
|
1009
1052
|
...input.task ? { task: input.task } : {},
|
|
1010
1053
|
search_mode: searchMode,
|
|
1011
1054
|
inferred_modules: inferred,
|
|
1012
1055
|
project_context: projectContext ? { content: projectSlice.text, truncated: projectSlice.truncated } : null,
|
|
1013
1056
|
module_contexts: trimmedModules,
|
|
1014
|
-
memories:
|
|
1057
|
+
memories: outputMemories,
|
|
1058
|
+
decay_warnings: decayWarnings,
|
|
1015
1059
|
estimated_tokens: totalTokens,
|
|
1016
1060
|
budget: {
|
|
1017
1061
|
max_tokens: input.max_tokens,
|
|
@@ -1023,6 +1067,13 @@ ${m.content}`).join("\n\n---\n\n"),
|
|
|
1023
1067
|
}
|
|
1024
1068
|
};
|
|
1025
1069
|
}
|
|
1070
|
+
function compactSummary(body) {
|
|
1071
|
+
for (const line of body.split("\n")) {
|
|
1072
|
+
const trimmed = line.replace(/^#+\s*/, "").trim();
|
|
1073
|
+
if (trimmed.length > 0) return trimmed.slice(0, 120);
|
|
1074
|
+
}
|
|
1075
|
+
return body.slice(0, 120);
|
|
1076
|
+
}
|
|
1026
1077
|
async function trySemanticHits(ctx, task, limit) {
|
|
1027
1078
|
let mod;
|
|
1028
1079
|
try {
|
|
@@ -1082,13 +1133,58 @@ async function codeMapTool(input, ctx) {
|
|
|
1082
1133
|
};
|
|
1083
1134
|
}
|
|
1084
1135
|
|
|
1085
|
-
// src/
|
|
1136
|
+
// src/tools/mem-diff.ts
|
|
1137
|
+
import { existsSync as existsSync16 } from "fs";
|
|
1138
|
+
import { loadMemoriesFromDir as loadMemoriesFromDir13 } from "@hiveai/core";
|
|
1086
1139
|
import { z as z17 } from "zod";
|
|
1140
|
+
var MemDiffInputSchema = {
|
|
1141
|
+
id_a: z17.string().min(1).describe("First memory id"),
|
|
1142
|
+
id_b: z17.string().min(1).describe("Second memory id")
|
|
1143
|
+
};
|
|
1144
|
+
async function memDiff(input, ctx) {
|
|
1145
|
+
if (!existsSync16(ctx.paths.memoriesDir)) {
|
|
1146
|
+
throw new Error(`No .ai/memories at ${ctx.paths.root}.`);
|
|
1147
|
+
}
|
|
1148
|
+
const all = await loadMemoriesFromDir13(ctx.paths.memoriesDir);
|
|
1149
|
+
const foundA = all.find((m) => m.memory.frontmatter.id === input.id_a);
|
|
1150
|
+
const foundB = all.find((m) => m.memory.frontmatter.id === input.id_b);
|
|
1151
|
+
if (!foundA) throw new Error(`No memory with id "${input.id_a}".`);
|
|
1152
|
+
if (!foundB) throw new Error(`No memory with id "${input.id_b}".`);
|
|
1153
|
+
const fmA = foundA.memory.frontmatter;
|
|
1154
|
+
const fmB = foundB.memory.frontmatter;
|
|
1155
|
+
const frontmatterDiff = {};
|
|
1156
|
+
const allKeys = /* @__PURE__ */ new Set([...Object.keys(fmA), ...Object.keys(fmB)]);
|
|
1157
|
+
for (const key of allKeys) {
|
|
1158
|
+
const va = fmA[key];
|
|
1159
|
+
const vb = fmB[key];
|
|
1160
|
+
if (JSON.stringify(va) !== JSON.stringify(vb)) {
|
|
1161
|
+
frontmatterDiff[key] = { a: va, b: vb };
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
const linesA = new Set(foundA.memory.body.split("\n").map((l) => l.trim()).filter(Boolean));
|
|
1165
|
+
const linesB = new Set(foundB.memory.body.split("\n").map((l) => l.trim()).filter(Boolean));
|
|
1166
|
+
const onlyA = [...linesA].filter((l) => !linesB.has(l));
|
|
1167
|
+
const onlyB = [...linesB].filter((l) => !linesA.has(l));
|
|
1168
|
+
const common = [...linesA].filter((l) => linesB.has(l)).length;
|
|
1169
|
+
return {
|
|
1170
|
+
id_a: input.id_a,
|
|
1171
|
+
id_b: input.id_b,
|
|
1172
|
+
frontmatter_diff: frontmatterDiff,
|
|
1173
|
+
body_diff: {
|
|
1174
|
+
lines_only_in_a: onlyA,
|
|
1175
|
+
lines_only_in_b: onlyB,
|
|
1176
|
+
common_lines: common
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
// src/prompts/bootstrap-project.ts
|
|
1182
|
+
import { z as z18 } from "zod";
|
|
1087
1183
|
var BootstrapProjectArgsSchema = {
|
|
1088
|
-
module:
|
|
1184
|
+
module: z18.string().optional().describe(
|
|
1089
1185
|
"Optional module name to scope the analysis to (writes to .ai/modules/<module>/context.md)"
|
|
1090
1186
|
),
|
|
1091
|
-
focus:
|
|
1187
|
+
focus: z18.string().optional().describe("Optional area to emphasize (e.g. 'data layer', 'API surface')")
|
|
1092
1188
|
};
|
|
1093
1189
|
var ROOT_TEMPLATE = `# Project context
|
|
1094
1190
|
|
|
@@ -1169,9 +1265,138 @@ ${template}\`\`\`
|
|
|
1169
1265
|
};
|
|
1170
1266
|
}
|
|
1171
1267
|
|
|
1268
|
+
// src/prompts/post-task.ts
|
|
1269
|
+
import { z as z19 } from "zod";
|
|
1270
|
+
var PostTaskArgsSchema = {
|
|
1271
|
+
task_summary: z19.string().optional().describe("One sentence describing what you just did"),
|
|
1272
|
+
files_touched: z19.array(z19.string()).optional().describe("Files you created or modified during the task")
|
|
1273
|
+
};
|
|
1274
|
+
function postTaskPrompt(args, ctx) {
|
|
1275
|
+
const taskLine = args.task_summary ? `
|
|
1276
|
+
Task just completed: **${args.task_summary}**` : "";
|
|
1277
|
+
const filesLine = args.files_touched && args.files_touched.length > 0 ? `
|
|
1278
|
+
Files touched: ${args.files_touched.map((f) => `\`${f}\``).join(", ")}` : "";
|
|
1279
|
+
const text = `You have just finished a task. Before closing this session, take 60 seconds to capture what you learned.
|
|
1280
|
+
${taskLine}${filesLine}
|
|
1281
|
+
|
|
1282
|
+
Project root: \`${ctx.paths.root}\`
|
|
1283
|
+
|
|
1284
|
+
## Checklist \u2014 answer each question honestly
|
|
1285
|
+
|
|
1286
|
+
Go through each item. If the answer is yes, call the corresponding tool immediately.
|
|
1287
|
+
|
|
1288
|
+
### 1. Did you try an approach that failed?
|
|
1289
|
+
\u2192 If yes, call **\`mem_tried\`** with:
|
|
1290
|
+
- \`what\`: the approach you tried (e.g. "importing gray-matter with ESM dynamic import")
|
|
1291
|
+
- \`why_failed\`: why it didn't work
|
|
1292
|
+
- \`instead\`: what worked instead
|
|
1293
|
+
- \`scope\`: "team" if others will hit the same issue, "personal" if specific to your setup
|
|
1294
|
+
- \`paths\`: the files where the issue manifested
|
|
1295
|
+
|
|
1296
|
+
### 2. Did you discover a convention that isn't documented?
|
|
1297
|
+
\u2192 If yes, call **\`mem_save\`** with \`type="convention"\` and \`scope="team"\`
|
|
1298
|
+
|
|
1299
|
+
### 3. Did you make an architectural decision?
|
|
1300
|
+
\u2192 If yes, call **\`mem_save\`** with \`type="decision"\` and document the WHY (constraints, tradeoffs), not just the what
|
|
1301
|
+
|
|
1302
|
+
### 4. Did you hit a non-obvious bug or surprising behavior?
|
|
1303
|
+
\u2192 If yes, call **\`mem_save\`** with \`type="gotcha"\` and anchor it to the relevant file paths
|
|
1304
|
+
|
|
1305
|
+
### 5. Did you find that an existing memory is outdated or wrong?
|
|
1306
|
+
\u2192 If yes, call **\`mem_update\`** with the correct information, or **\`mem_reject\`** if it's completely wrong
|
|
1307
|
+
|
|
1308
|
+
## Rules
|
|
1309
|
+
|
|
1310
|
+
- One memory per insight. Don't cram multiple lessons into one body.
|
|
1311
|
+
- Anchor memories to file paths when possible (the \`paths\` field) \u2014 this enables staleness detection.
|
|
1312
|
+
- Prefer \`scope="team"\` for anything a teammate or future agent would benefit from.
|
|
1313
|
+
- Skip sections where you genuinely have nothing to add. Don't fabricate memories.
|
|
1314
|
+
|
|
1315
|
+
When done, respond with a brief summary: "Saved N memories: [list of IDs]" or "Nothing new to save."
|
|
1316
|
+
`;
|
|
1317
|
+
return {
|
|
1318
|
+
description: "Post-task reflection: capture what you learned before closing the session",
|
|
1319
|
+
messages: [
|
|
1320
|
+
{
|
|
1321
|
+
role: "user",
|
|
1322
|
+
content: { type: "text", text }
|
|
1323
|
+
}
|
|
1324
|
+
]
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// src/prompts/import-docs.ts
|
|
1329
|
+
import { z as z20 } from "zod";
|
|
1330
|
+
var ImportDocsArgsSchema = {
|
|
1331
|
+
content: z20.string().describe("The documentation content to analyze and import as memories (Markdown, README, ADR, etc.)"),
|
|
1332
|
+
source: z20.string().optional().describe("Origin of the content (file path, URL, or document title) \u2014 used to anchor memories"),
|
|
1333
|
+
scope: z20.enum(["personal", "team"]).default("team").describe("Scope to assign to created memories"),
|
|
1334
|
+
dry_run: z20.boolean().default(false).describe("If true, describe what would be saved without actually calling mem_save")
|
|
1335
|
+
};
|
|
1336
|
+
function importDocsPrompt(args, ctx) {
|
|
1337
|
+
const sourceLine = args.source ? `
|
|
1338
|
+
Source: **${args.source}**` : "";
|
|
1339
|
+
const dryRunNote = args.dry_run ? "\n> **DRY RUN** \u2014 describe what you would save but do not call any tools." : "";
|
|
1340
|
+
const text = `You are given documentation to analyze and import into the hAIve memory system.
|
|
1341
|
+
${sourceLine}
|
|
1342
|
+
Scope: **${args.scope}**
|
|
1343
|
+
Project root: \`${ctx.paths.root}\`
|
|
1344
|
+
${dryRunNote}
|
|
1345
|
+
|
|
1346
|
+
## Your task
|
|
1347
|
+
|
|
1348
|
+
Read the documentation below and extract actionable memories. For each distinct piece of knowledge:
|
|
1349
|
+
|
|
1350
|
+
1. **Identify the memory type** \u2014 which category fits best?
|
|
1351
|
+
- \`convention\` \u2014 how things are done here (naming, patterns, workflow)
|
|
1352
|
+
- \`decision\` \u2014 a choice that was made and why (tradeoffs, constraints)
|
|
1353
|
+
- \`gotcha\` \u2014 non-obvious behavior, traps, things that surprise newcomers
|
|
1354
|
+
- \`architecture\` \u2014 structural overview of a system or module
|
|
1355
|
+
- \`glossary\` \u2014 domain terms and their meaning in this project
|
|
1356
|
+
|
|
1357
|
+
2. **Determine the anchor** \u2014 which files or symbols does this knowledge apply to? List them in \`paths\`.
|
|
1358
|
+
|
|
1359
|
+
3. **Write a focused body** \u2014 one memory = one insight. Do not combine multiple unrelated facts.
|
|
1360
|
+
- Start with the key fact or rule
|
|
1361
|
+
- Add context: why it matters, when it applies
|
|
1362
|
+
- Add examples if helpful
|
|
1363
|
+
|
|
1364
|
+
4. **Call \`mem_save\`** for each memory (unless dry_run).
|
|
1365
|
+
- Set \`scope="${args.scope}"\`
|
|
1366
|
+
- Set \`slug\` to a short kebab-case identifier
|
|
1367
|
+
- Set \`paths\` to the relevant file paths (extracted from the doc if present)
|
|
1368
|
+
|
|
1369
|
+
## Rules
|
|
1370
|
+
|
|
1371
|
+
- Skip generic documentation that applies to any project (e.g., "install with npm install").
|
|
1372
|
+
- Prioritize gotchas, non-obvious decisions, and domain-specific conventions.
|
|
1373
|
+
- If the same knowledge is repeated in different sections, save it once.
|
|
1374
|
+
- Maximum 10 memories per import \u2014 select the most actionable ones.
|
|
1375
|
+
|
|
1376
|
+
## Documentation to import
|
|
1377
|
+
|
|
1378
|
+
---
|
|
1379
|
+
|
|
1380
|
+
${args.content}
|
|
1381
|
+
|
|
1382
|
+
---
|
|
1383
|
+
|
|
1384
|
+
When done, respond with: "Imported N memories: [list of IDs]" or "Nothing actionable found."
|
|
1385
|
+
`;
|
|
1386
|
+
return {
|
|
1387
|
+
description: "Import documentation as hAIve memories",
|
|
1388
|
+
messages: [
|
|
1389
|
+
{
|
|
1390
|
+
role: "user",
|
|
1391
|
+
content: { type: "text", text }
|
|
1392
|
+
}
|
|
1393
|
+
]
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1172
1397
|
// src/server.ts
|
|
1173
1398
|
var SERVER_NAME = "haive";
|
|
1174
|
-
var SERVER_VERSION = "0.2.
|
|
1399
|
+
var SERVER_VERSION = "0.2.8";
|
|
1175
1400
|
function jsonResult(data) {
|
|
1176
1401
|
return {
|
|
1177
1402
|
content: [
|
|
@@ -1190,7 +1415,7 @@ function createHaiveServer(options = {}) {
|
|
|
1190
1415
|
);
|
|
1191
1416
|
server.tool(
|
|
1192
1417
|
"mem_save",
|
|
1193
|
-
"Save a new memory (
|
|
1418
|
+
"Save a new memory (convention, decision, gotcha, architecture, glossary). For failed approaches use mem_tried instead \u2014 it enforces a structured format that is more useful to future agents. Use scope=team to share with the whole team.",
|
|
1194
1419
|
MemSaveInputSchema,
|
|
1195
1420
|
async (input) => jsonResult(await memSave(input, context))
|
|
1196
1421
|
);
|
|
@@ -1280,16 +1505,34 @@ function createHaiveServer(options = {}) {
|
|
|
1280
1505
|
);
|
|
1281
1506
|
server.tool(
|
|
1282
1507
|
"mem_tried",
|
|
1283
|
-
"
|
|
1508
|
+
"Preferred way to record a failed approach. Enforces a structured what/why_failed/instead format that is immediately actionable for future agents. Auto-validated (no approval cycle). Use whenever you tried an approach and it failed \u2014 prevents the same mistake from happening in the next session.",
|
|
1284
1509
|
MemTriedInputSchema,
|
|
1285
1510
|
async (input) => jsonResult(await memTried(input, context))
|
|
1286
1511
|
);
|
|
1512
|
+
server.tool(
|
|
1513
|
+
"mem_diff",
|
|
1514
|
+
"Compare two memories side-by-side: shows frontmatter fields that differ and lines unique to each body. Useful before merging or deduplicating memories.",
|
|
1515
|
+
MemDiffInputSchema,
|
|
1516
|
+
async (input) => jsonResult(await memDiff(input, context))
|
|
1517
|
+
);
|
|
1287
1518
|
server.prompt(
|
|
1288
1519
|
"bootstrap_project",
|
|
1289
1520
|
"Instructions for the AI client to analyze the project and save the context.",
|
|
1290
1521
|
BootstrapProjectArgsSchema,
|
|
1291
1522
|
(args) => bootstrapProjectPrompt(args, context)
|
|
1292
1523
|
);
|
|
1524
|
+
server.prompt(
|
|
1525
|
+
"post_task",
|
|
1526
|
+
"Post-task checklist: run this after completing a task to capture failed approaches, new conventions, decisions, and gotchas before closing the session.",
|
|
1527
|
+
PostTaskArgsSchema,
|
|
1528
|
+
(args) => postTaskPrompt(args, context)
|
|
1529
|
+
);
|
|
1530
|
+
server.prompt(
|
|
1531
|
+
"import_docs",
|
|
1532
|
+
"Analyze documentation (README, ADR, wiki page, etc.) and save the actionable knowledge as hAIve memories. Pass the content and an optional source/scope.",
|
|
1533
|
+
ImportDocsArgsSchema,
|
|
1534
|
+
(args) => importDocsPrompt(args, context)
|
|
1535
|
+
);
|
|
1293
1536
|
return { server, context };
|
|
1294
1537
|
}
|
|
1295
1538
|
export {
|