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