@hiveai/mcp 0.2.6 → 0.2.7

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
@@ -903,7 +903,7 @@ async function getBriefing(input, ctx) {
903
903
  searchMode = semanticHits ? "semantic" : "literal_fallback";
904
904
  }
905
905
  const seen = /* @__PURE__ */ new Map();
906
- const addOrUpdate = (loaded, reason, score) => {
906
+ const addOrUpdate = (loaded, reason, score, matchQuality) => {
907
907
  const fm = loaded.memory.frontmatter;
908
908
  const existing = seen.get(fm.id);
909
909
  if (existing) {
@@ -911,6 +911,11 @@ async function getBriefing(input, ctx) {
911
911
  if (score !== void 0 && (existing.semantic_score ?? 0) < score) {
912
912
  existing.semantic_score = score;
913
913
  }
914
+ if (matchQuality === "exact" && existing.match_quality !== "exact") {
915
+ existing.match_quality = "exact";
916
+ } else if (matchQuality === "semantic" && existing.match_quality === "partial") {
917
+ existing.match_quality = "semantic";
918
+ }
914
919
  return;
915
920
  }
916
921
  const u = getUsage5(usage, fm.id);
@@ -924,6 +929,7 @@ async function getBriefing(input, ctx) {
924
929
  confidence: deriveConfidence4(fm, u),
925
930
  read_count: u.read_count,
926
931
  reasons: [reason],
932
+ match_quality: matchQuality ?? "partial",
927
933
  ...score !== void 0 ? { semantic_score: score } : {},
928
934
  body: loaded.memory.body,
929
935
  file_path: loaded.filePath
@@ -931,32 +937,33 @@ async function getBriefing(input, ctx) {
931
937
  };
932
938
  if (input.files.length > 0) {
933
939
  for (const loaded of allMemories) {
934
- if (memoryMatchesAnchorPaths2(loaded.memory, input.files)) addOrUpdate(loaded, "anchor");
940
+ if (memoryMatchesAnchorPaths2(loaded.memory, input.files)) addOrUpdate(loaded, "anchor", void 0, "exact");
935
941
  }
936
942
  for (const loaded of allMemories) {
937
943
  const fm = loaded.memory.frontmatter;
938
- if (fm.module && inferred.includes(fm.module)) addOrUpdate(loaded, "module");
939
- if (fm.domain && inferred.includes(fm.domain)) addOrUpdate(loaded, "domain");
940
- if (fm.tags.some((t) => inferred.includes(t))) addOrUpdate(loaded, "module");
944
+ if (fm.module && inferred.includes(fm.module)) addOrUpdate(loaded, "module", void 0, "partial");
945
+ if (fm.domain && inferred.includes(fm.domain)) addOrUpdate(loaded, "domain", void 0, "partial");
946
+ if (fm.tags.some((t) => inferred.includes(t))) addOrUpdate(loaded, "module", void 0, "partial");
941
947
  }
942
948
  }
943
949
  if (input.task) {
944
950
  const tokens = tokenizeQuery2(input.task);
945
951
  for (const loaded of allMemories) {
946
952
  if (literalMatchesAllTokens2(loaded.memory, tokens)) {
947
- addOrUpdate(loaded, "semantic");
953
+ addOrUpdate(loaded, "semantic", void 0, "exact");
948
954
  }
949
955
  }
950
956
  if (semanticHits) {
951
957
  const byId = new Map(allMemories.map((m) => [m.memory.frontmatter.id, m]));
952
958
  for (const hit of semanticHits) {
953
959
  const loaded = byId.get(hit.id);
954
- if (loaded) addOrUpdate(loaded, "semantic", hit.score);
960
+ if (loaded) addOrUpdate(loaded, "semantic", hit.score, "semantic");
955
961
  }
956
962
  }
957
963
  }
958
964
  const ranked = [...seen.values()].sort((a, b) => {
959
- const reasonScore = (m) => (m.reasons.includes("anchor") ? 4 : 0) + (m.reasons.includes("module") ? 2 : 0) + (m.reasons.includes("semantic") ? 2 : 0) + (m.reasons.includes("domain") ? 1 : 0);
965
+ const reasonScore = (m) => (m.type === "attempt" ? 3 : 0) + // attempt = negative knowledge, surface first to prevent repeating mistakes
966
+ (m.reasons.includes("anchor") ? 4 : 0) + (m.reasons.includes("module") ? 2 : 0) + (m.reasons.includes("semantic") ? 2 : 0) + (m.reasons.includes("domain") ? 1 : 0);
960
967
  const confidenceScore = (m) => m.confidence === "authoritative" ? 4 : m.confidence === "trusted" ? 3 : m.confidence === "low" ? 1 : m.confidence === "stale" ? -2 : 0;
961
968
  const sa = reasonScore(a) + confidenceScore(a) + (a.semantic_score ?? 0);
962
969
  const sb = reasonScore(b) + confidenceScore(b) + (b.semantic_score ?? 0);
@@ -1003,12 +1010,24 @@ ${m.content}`).join("\n\n---\n\n"),
1003
1010
  }
1004
1011
  }
1005
1012
  const trimmedMemoriesText = memoriesSlice.text;
1006
- const trimmedMemories = memories.map((m) => {
1007
- if (!memoriesSlice.truncated) return m;
1008
- const tokensPer = Math.floor(memoriesSlice.allocatedTokens / Math.max(1, memories.length));
1009
- const t = truncateToTokens(m.body, { maxTokens: tokensPer, mode: "head" });
1010
- return { ...m, body: t.text };
1011
- });
1013
+ const trimmedMemories = [];
1014
+ if (!memoriesSlice.truncated) {
1015
+ trimmedMemories.push(...memories);
1016
+ } else {
1017
+ let remaining = memoriesSlice.allocatedTokens;
1018
+ for (const m of memories) {
1019
+ const bodyTokens = estimateTokens(m.body);
1020
+ if (remaining <= 0) break;
1021
+ if (bodyTokens <= remaining) {
1022
+ trimmedMemories.push(m);
1023
+ remaining -= bodyTokens;
1024
+ } else if (remaining > 80) {
1025
+ const t = truncateToTokens(m.body, { maxTokens: remaining, mode: "head" });
1026
+ trimmedMemories.push({ ...m, body: t.text });
1027
+ remaining = 0;
1028
+ }
1029
+ }
1030
+ }
1012
1031
  const totalTokens = projectSlice.estimatedTokens + modulesSlice.estimatedTokens + memoriesSlice.estimatedTokens;
1013
1032
  return {
1014
1033
  ...input.task ? { task: input.task } : {},
@@ -1174,9 +1193,69 @@ ${template}\`\`\`
1174
1193
  };
1175
1194
  }
1176
1195
 
1196
+ // src/prompts/post-task.ts
1197
+ import { z as z18 } from "zod";
1198
+ var PostTaskArgsSchema = {
1199
+ task_summary: z18.string().optional().describe("One sentence describing what you just did"),
1200
+ files_touched: z18.array(z18.string()).optional().describe("Files you created or modified during the task")
1201
+ };
1202
+ function postTaskPrompt(args, ctx) {
1203
+ const taskLine = args.task_summary ? `
1204
+ Task just completed: **${args.task_summary}**` : "";
1205
+ const filesLine = args.files_touched && args.files_touched.length > 0 ? `
1206
+ Files touched: ${args.files_touched.map((f) => `\`${f}\``).join(", ")}` : "";
1207
+ const text = `You have just finished a task. Before closing this session, take 60 seconds to capture what you learned.
1208
+ ${taskLine}${filesLine}
1209
+
1210
+ Project root: \`${ctx.paths.root}\`
1211
+
1212
+ ## Checklist \u2014 answer each question honestly
1213
+
1214
+ Go through each item. If the answer is yes, call the corresponding tool immediately.
1215
+
1216
+ ### 1. Did you try an approach that failed?
1217
+ \u2192 If yes, call **\`mem_tried\`** with:
1218
+ - \`what\`: the approach you tried (e.g. "importing gray-matter with ESM dynamic import")
1219
+ - \`why_failed\`: why it didn't work
1220
+ - \`instead\`: what worked instead
1221
+ - \`scope\`: "team" if others will hit the same issue, "personal" if specific to your setup
1222
+ - \`paths\`: the files where the issue manifested
1223
+
1224
+ ### 2. Did you discover a convention that isn't documented?
1225
+ \u2192 If yes, call **\`mem_save\`** with \`type="convention"\` and \`scope="team"\`
1226
+
1227
+ ### 3. Did you make an architectural decision?
1228
+ \u2192 If yes, call **\`mem_save\`** with \`type="decision"\` and document the WHY (constraints, tradeoffs), not just the what
1229
+
1230
+ ### 4. Did you hit a non-obvious bug or surprising behavior?
1231
+ \u2192 If yes, call **\`mem_save\`** with \`type="gotcha"\` and anchor it to the relevant file paths
1232
+
1233
+ ### 5. Did you find that an existing memory is outdated or wrong?
1234
+ \u2192 If yes, call **\`mem_update\`** with the correct information, or **\`mem_reject\`** if it's completely wrong
1235
+
1236
+ ## Rules
1237
+
1238
+ - One memory per insight. Don't cram multiple lessons into one body.
1239
+ - Anchor memories to file paths when possible (the \`paths\` field) \u2014 this enables staleness detection.
1240
+ - Prefer \`scope="team"\` for anything a teammate or future agent would benefit from.
1241
+ - Skip sections where you genuinely have nothing to add. Don't fabricate memories.
1242
+
1243
+ When done, respond with a brief summary: "Saved N memories: [list of IDs]" or "Nothing new to save."
1244
+ `;
1245
+ return {
1246
+ description: "Post-task reflection: capture what you learned before closing the session",
1247
+ messages: [
1248
+ {
1249
+ role: "user",
1250
+ content: { type: "text", text }
1251
+ }
1252
+ ]
1253
+ };
1254
+ }
1255
+
1177
1256
  // src/server.ts
1178
1257
  var SERVER_NAME = "haive";
1179
- var SERVER_VERSION = "0.2.6";
1258
+ var SERVER_VERSION = "0.2.7";
1180
1259
  function jsonResult(data) {
1181
1260
  return {
1182
1261
  content: [
@@ -1195,7 +1274,7 @@ function createHaiveServer(options = {}) {
1195
1274
  );
1196
1275
  server.tool(
1197
1276
  "mem_save",
1198
- "Save a new memory (default scope=personal). Use scope=team for shared memories.",
1277
+ "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.",
1199
1278
  MemSaveInputSchema,
1200
1279
  async (input) => jsonResult(await memSave(input, context))
1201
1280
  );
@@ -1285,7 +1364,7 @@ function createHaiveServer(options = {}) {
1285
1364
  );
1286
1365
  server.tool(
1287
1366
  "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.",
1367
+ "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.",
1289
1368
  MemTriedInputSchema,
1290
1369
  async (input) => jsonResult(await memTried(input, context))
1291
1370
  );
@@ -1295,6 +1374,12 @@ function createHaiveServer(options = {}) {
1295
1374
  BootstrapProjectArgsSchema,
1296
1375
  (args) => bootstrapProjectPrompt(args, context)
1297
1376
  );
1377
+ server.prompt(
1378
+ "post_task",
1379
+ "Post-task checklist: run this after completing a task to capture failed approaches, new conventions, decisions, and gotchas before closing the session.",
1380
+ PostTaskArgsSchema,
1381
+ (args) => postTaskPrompt(args, context)
1382
+ );
1298
1383
  return { server, context };
1299
1384
  }
1300
1385