@hivelore/mcp 0.30.0 → 0.31.0

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
@@ -1122,94 +1122,40 @@ async function memApprove(input, ctx) {
1122
1122
  }
1123
1123
 
1124
1124
  // src/tools/mem-tried.ts
1125
- import { mkdir as mkdir3, writeFile as writeFile8 } from "fs/promises";
1126
- import { existsSync as existsSync15 } from "fs";
1127
- import path5 from "path";
1125
+ import { mkdir as mkdir3, writeFile as writeFile9 } from "fs/promises";
1126
+ import { existsSync as existsSync16 } from "fs";
1127
+ import path6 from "path";
1128
1128
  import {
1129
1129
  buildFrontmatter as buildFrontmatter2,
1130
1130
  memoryFilePath as memoryFilePath2,
1131
- serializeMemory as serializeMemory7,
1131
+ serializeMemory as serializeMemory8,
1132
1132
  suggestSensorSeed as suggestSensorSeed2
1133
1133
  } from "@hivelore/core";
1134
- import { z as z15 } from "zod";
1135
- var MemTriedInputSchema = {
1136
- what: z15.string().min(1).describe("Brief description of the approach that was tried"),
1137
- why_failed: z15.string().min(1).describe("Why it failed or why it should NOT be used"),
1138
- instead: z15.string().optional().describe("What to use or do instead (recommended alternative)"),
1139
- scope: z15.enum(["personal", "team", "module"]).default("personal").describe("Visibility scope"),
1140
- module: z15.string().optional().describe("Module name (required when scope=module)"),
1141
- tags: z15.array(z15.string()).default([]).describe("Tags for filtering"),
1142
- paths: z15.array(z15.string()).default([]).describe("Anchor file paths this applies to"),
1143
- author: z15.string().optional().describe("Author handle or email")
1144
- };
1145
- async function memTried(input, ctx) {
1146
- if (!existsSync15(ctx.paths.haiveDir)) {
1147
- throw new Error(`No .ai/ directory at ${ctx.paths.root}. Run 'hivelore init' first.`);
1148
- }
1149
- const slug = input.what.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().split(/\s+/).slice(0, 5).join("-");
1150
- const baseFm = buildFrontmatter2({
1151
- type: "attempt",
1152
- slug,
1153
- scope: input.scope,
1154
- module: input.module,
1155
- tags: input.tags,
1156
- paths: input.paths,
1157
- author: input.author
1158
- });
1159
- const frontmatter = { ...baseFm, status: "validated" };
1160
- const lines = [`# ${input.what}`, ""];
1161
- lines.push(`**Why it failed / do NOT use:** ${input.why_failed}`);
1162
- if (input.instead) {
1163
- lines.push("", `**Instead, use:** ${input.instead}`);
1164
- }
1165
- const body = lines.join("\n") + "\n";
1166
- const file = memoryFilePath2(ctx.paths, frontmatter.scope, frontmatter.id, frontmatter.module);
1167
- await mkdir3(path5.dirname(file), { recursive: true });
1168
- if (existsSync15(file)) {
1169
- throw new Error(`Memory already exists at ${file}`);
1170
- }
1171
- await writeFile8(file, serializeMemory7({ frontmatter, body }), "utf8");
1172
- const seed = input.paths.length > 0 ? suggestSensorSeed2(body, input.paths) : null;
1173
- const hint = input.paths.length === 0 ? "No `paths` given, so this attempt is feedforward-only \u2014 it will be briefed but the gate cannot block the repeat. Re-run with `paths` set to the file(s) where the mistake lives, then call propose_sensor to close the loop." : seed ? "This attempt is NOT yet enforced. Call propose_sensor to turn it into a reliable block \u2014 a candidate is pre-filled in proposed_sensor_seed (refine it: pattern = the faulty usage, absent = the correct-usage marker). Hivelore validates the proposal (silent on current code, fires on the bad example) before trusting it to block." : "This attempt is NOT yet enforced and no candidate pattern could be derived from the wording. Call propose_sensor with a discriminating pattern (pattern = faulty usage, absent = correct-usage marker) to close the loop.";
1174
- return {
1175
- id: frontmatter.id,
1176
- scope: frontmatter.scope,
1177
- file_path: file,
1178
- loop_open: true,
1179
- ...seed ? {
1180
- proposed_sensor_seed: {
1181
- pattern: seed.pattern,
1182
- ...seed.absent ? { absent: seed.absent } : {},
1183
- message: seed.message
1184
- }
1185
- } : {},
1186
- hint
1187
- };
1188
- }
1134
+ import { z as z16 } from "zod";
1189
1135
 
1190
1136
  // src/tools/propose-sensor.ts
1191
1137
  import { execSync } from "child_process";
1192
- import { readFile as readFile3, writeFile as writeFile9 } from "fs/promises";
1193
- import { existsSync as existsSync16 } from "fs";
1194
- import path6 from "path";
1138
+ import { readFile as readFile3, writeFile as writeFile8 } from "fs/promises";
1139
+ import { existsSync as existsSync15 } from "fs";
1140
+ import path5 from "path";
1195
1141
  import {
1196
1142
  extractSensorExamples,
1197
1143
  judgeProposedSensor,
1198
1144
  loadMemoriesFromDir as loadMemoriesFromDir13,
1199
- serializeMemory as serializeMemory8
1145
+ serializeMemory as serializeMemory7
1200
1146
  } from "@hivelore/core";
1201
- import { z as z16 } from "zod";
1147
+ import { z as z15 } from "zod";
1202
1148
  var ProposeSensorInputSchema = {
1203
- memory_id: z16.string().min(1).describe("Id of the gotcha/attempt memory this sensor protects."),
1204
- pattern: z16.string().min(1).describe("Regex matching the FAULTY usage (the risky call/token), e.g. 'stripe\\.paymentIntents\\.create'."),
1205
- absent: z16.string().optional().describe(
1149
+ memory_id: z15.string().min(1).describe("Id of the gotcha/attempt memory this sensor protects."),
1150
+ pattern: z15.string().min(1).describe("Regex matching the FAULTY usage (the risky call/token), e.g. 'stripe\\.paymentIntents\\.create'."),
1151
+ absent: z15.string().optional().describe(
1206
1152
  "Regex for the CORRECT-usage marker (e.g. 'idempotencyKey'). When it appears in the window around a match, the catch is suppressed \u2014 this is what makes the sensor discriminate the faulty call from the correct one. STRONGLY recommended for 'X without Y' lessons."
1207
1153
  ),
1208
- bad_example: z16.string().optional().describe("A code snippet that SHOULD match \u2014 proves the sensor catches the mistake. If omitted, examples are read from the lesson body."),
1209
- severity: z16.enum(["warn", "block"]).default("block").describe("block = hard-fail the gate (accepted ONLY if it passes self-validation). warn = advisory."),
1210
- message: z16.string().optional().describe("LLM-facing fix message shown when it fires. Defaults to one derived from the lesson."),
1211
- flags: z16.string().optional().describe("Optional regex flags (e.g. 'i' for case-insensitive)."),
1212
- paths: z16.array(z16.string()).default([]).describe("Override scope paths. Defaults to the memory's anchor paths.")
1154
+ bad_example: z15.string().optional().describe("A code snippet that SHOULD match \u2014 proves the sensor catches the mistake. If omitted, examples are read from the lesson body."),
1155
+ severity: z15.enum(["warn", "block"]).default("block").describe("block = hard-fail the gate (accepted ONLY if it passes self-validation). warn = advisory."),
1156
+ message: z15.string().optional().describe("LLM-facing fix message shown when it fires. Defaults to one derived from the lesson."),
1157
+ flags: z15.string().optional().describe("Optional regex flags (e.g. 'i' for case-insensitive)."),
1158
+ paths: z15.array(z15.string()).default([]).describe("Override scope paths. Defaults to the memory's anchor paths.")
1213
1159
  };
1214
1160
  function deriveMessage(body, pattern, absent) {
1215
1161
  const instead = body.match(/\*\*Instead,\s*use:\*\*\s*([^\n]+)/i)?.[1]?.trim();
@@ -1234,8 +1180,8 @@ async function readPresumedCorrectTargets(root, relPaths) {
1234
1180
  continue;
1235
1181
  } catch {
1236
1182
  }
1237
- const abs = path6.resolve(root, rel);
1238
- if (!existsSync16(abs)) continue;
1183
+ const abs = path5.resolve(root, rel);
1184
+ if (!existsSync15(abs)) continue;
1239
1185
  try {
1240
1186
  targets.push({ path: rel, content: await readFile3(abs, "utf8") });
1241
1187
  } catch {
@@ -1244,7 +1190,7 @@ async function readPresumedCorrectTargets(root, relPaths) {
1244
1190
  return targets;
1245
1191
  }
1246
1192
  async function proposeSensor(input, ctx) {
1247
- if (!existsSync16(ctx.paths.memoriesDir)) {
1193
+ if (!existsSync15(ctx.paths.memoriesDir)) {
1248
1194
  throw new Error(`No .ai/memories at ${ctx.paths.root}. Run 'hivelore init' first.`);
1249
1195
  }
1250
1196
  try {
@@ -1304,7 +1250,7 @@ async function proposeSensor(input, ctx) {
1304
1250
  frontmatter: { ...found.memory.frontmatter, sensor },
1305
1251
  body: found.memory.body
1306
1252
  };
1307
- await writeFile9(found.filePath, serializeMemory8(next), "utf8");
1253
+ await writeFile8(found.filePath, serializeMemory7(next), "utf8");
1308
1254
  return {
1309
1255
  accepted: true,
1310
1256
  memory_id: input.memory_id,
@@ -1314,6 +1260,99 @@ async function proposeSensor(input, ctx) {
1314
1260
  };
1315
1261
  }
1316
1262
 
1263
+ // src/tools/mem-tried.ts
1264
+ var MemTriedInputSchema = {
1265
+ what: z16.string().min(1).describe("Brief description of the approach that was tried"),
1266
+ why_failed: z16.string().min(1).describe("Why it failed or why it should NOT be used"),
1267
+ instead: z16.string().optional().describe("What to use or do instead (recommended alternative)"),
1268
+ scope: z16.enum(["personal", "team", "module"]).default("personal").describe("Visibility scope"),
1269
+ module: z16.string().optional().describe("Module name (required when scope=module)"),
1270
+ tags: z16.array(z16.string()).default([]).describe("Tags for filtering"),
1271
+ paths: z16.array(z16.string()).default([]).describe("Anchor file paths this applies to"),
1272
+ author: z16.string().optional().describe("Author handle or email"),
1273
+ sensor: z16.object({
1274
+ pattern: z16.string().min(1).describe("Regex matching the FAULTY usage (added diff lines)"),
1275
+ absent: z16.string().optional().describe("Regex marking CORRECT usage nearby \u2014 excludes it from firing"),
1276
+ severity: z16.enum(["warn", "block"]).default("block").describe("block = deterministic gate refusal"),
1277
+ message: z16.string().optional().describe("Self-correction message shown when the sensor fires"),
1278
+ bad_example: z16.string().optional().describe("Code snippet the sensor MUST fire on (validation)")
1279
+ }).optional().describe(
1280
+ "ONE-SHOT loop close: validate and attach a sensor in the same call (equivalent to a follow-up propose_sensor). Validated against HEAD \u2014 silent on current code, fires on the bad example. If rejected, the attempt is still saved and the verdict tells you how to revise."
1281
+ )
1282
+ };
1283
+ async function memTried(input, ctx) {
1284
+ if (!existsSync16(ctx.paths.haiveDir)) {
1285
+ throw new Error(`No .ai/ directory at ${ctx.paths.root}. Run 'hivelore init' first.`);
1286
+ }
1287
+ const slug = input.what.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().split(/\s+/).slice(0, 5).join("-");
1288
+ const baseFm = buildFrontmatter2({
1289
+ type: "attempt",
1290
+ slug,
1291
+ scope: input.scope,
1292
+ module: input.module,
1293
+ tags: input.tags,
1294
+ paths: input.paths,
1295
+ author: input.author
1296
+ });
1297
+ const frontmatter = { ...baseFm, status: "validated" };
1298
+ const lines = [`# ${input.what}`, ""];
1299
+ lines.push(`**Why it failed / do NOT use:** ${input.why_failed}`);
1300
+ if (input.instead) {
1301
+ lines.push("", `**Instead, use:** ${input.instead}`);
1302
+ }
1303
+ const body = lines.join("\n") + "\n";
1304
+ const file = memoryFilePath2(ctx.paths, frontmatter.scope, frontmatter.id, frontmatter.module);
1305
+ await mkdir3(path6.dirname(file), { recursive: true });
1306
+ if (existsSync16(file)) {
1307
+ throw new Error(`Memory already exists at ${file}`);
1308
+ }
1309
+ await writeFile9(file, serializeMemory8({ frontmatter, body }), "utf8");
1310
+ if (input.sensor) {
1311
+ const verdict = await proposeSensor(
1312
+ {
1313
+ memory_id: frontmatter.id,
1314
+ pattern: input.sensor.pattern,
1315
+ absent: input.sensor.absent,
1316
+ severity: input.sensor.severity ?? "block",
1317
+ message: input.sensor.message,
1318
+ bad_example: input.sensor.bad_example,
1319
+ flags: void 0,
1320
+ paths: []
1321
+ },
1322
+ ctx
1323
+ );
1324
+ return {
1325
+ id: frontmatter.id,
1326
+ scope: frontmatter.scope,
1327
+ file_path: file,
1328
+ loop_open: !verdict.accepted,
1329
+ sensor_result: {
1330
+ accepted: verdict.accepted,
1331
+ severity: input.sensor.severity ?? "block",
1332
+ ...verdict.reason ? { reason: verdict.reason } : {},
1333
+ ...verdict.guidance ? { guidance: verdict.guidance } : {}
1334
+ },
1335
+ hint: verdict.accepted ? "Loop closed: the attempt is saved AND enforced \u2014 the gate now refuses a repeat deterministically." : `Attempt saved, but the sensor was rejected (${verdict.reason}). Revise per the guidance and re-propose with propose_sensor.`
1336
+ };
1337
+ }
1338
+ const seed = input.paths.length > 0 ? suggestSensorSeed2(body, input.paths) : null;
1339
+ const hint = input.paths.length === 0 ? "No `paths` given, so this attempt is feedforward-only \u2014 it will be briefed but the gate cannot block the repeat. Re-run with `paths` set to the file(s) where the mistake lives, then call propose_sensor to close the loop." : seed ? "This attempt is NOT yet enforced. Call propose_sensor (or re-run mem_tried with the one-shot `sensor` parameter) to turn it into a reliable block \u2014 a candidate is pre-filled in proposed_sensor_seed (refine it: pattern = the faulty usage, absent = the correct-usage marker). Hivelore validates the proposal (silent on current code, fires on the bad example) before trusting it to block." : "This attempt is NOT yet enforced and no candidate pattern could be derived from the wording. Call propose_sensor with a discriminating pattern (pattern = faulty usage, absent = correct-usage marker) to close the loop.";
1340
+ return {
1341
+ id: frontmatter.id,
1342
+ scope: frontmatter.scope,
1343
+ file_path: file,
1344
+ loop_open: true,
1345
+ ...seed ? {
1346
+ proposed_sensor_seed: {
1347
+ pattern: seed.pattern,
1348
+ ...seed.absent ? { absent: seed.absent } : {},
1349
+ message: seed.message
1350
+ }
1351
+ } : {},
1352
+ hint
1353
+ };
1354
+ }
1355
+
1317
1356
  // src/tools/ingest-findings.ts
1318
1357
  import { existsSync as existsSync17 } from "fs";
1319
1358
  import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile10 } from "fs/promises";
@@ -2315,11 +2354,20 @@ ${m.content}`).join("\n\n---\n\n"),
2315
2354
  if (isDecaying(u, createdAt)) decayWarnings.push(m.id);
2316
2355
  }
2317
2356
  const formattedMemories = input.format === "compact" ? trimmedMemories.map((m) => ({ ...m, body: compactSummary(m.body) })) : input.format === "actions" ? trimmedMemories.map((m) => ({ ...m, body: extractActionsBriefBody(m.body) })) : trimmedMemories;
2318
- const outputMemories = formattedMemories.map((m) => ({
2357
+ let outputMemories = formattedMemories.map((m) => ({
2319
2358
  ...m,
2320
2359
  priority: classifyMemoryPriority(m, byId.get(m.id), input.files, input.symbols),
2321
2360
  why: explainWhySurfaced(m, byId.get(m.id), input.files, inferred)
2322
2361
  }));
2362
+ if (input.format === "full") {
2363
+ const hasDirectHits = outputMemories.some((m) => m.priority === "must_read" || m.priority === "useful");
2364
+ if (hasDirectHits) {
2365
+ outputMemories = outputMemories.map(
2366
+ (m) => m.priority === "background" ? { ...m, body: `${compactSummary(m.body)}
2367
+ (background \u2014 full body: mem_get("${m.id}"))` } : m
2368
+ );
2369
+ }
2370
+ }
2323
2371
  const briefingQuality = classifyBriefingQuality(outputMemories, {
2324
2372
  isTemplateContext,
2325
2373
  autoContextGenerated,
@@ -2634,7 +2682,7 @@ function oneLine(value) {
2634
2682
  return value.replace(/\s+/g, " ").replace(/"/g, '\\"').trim().slice(0, 120);
2635
2683
  }
2636
2684
  function serverVersion() {
2637
- return true ? "0.30.0" : "dev";
2685
+ return true ? "0.31.0" : "dev";
2638
2686
  }
2639
2687
 
2640
2688
  // src/tools/code-map.ts
@@ -4705,7 +4753,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
4705
4753
  // src/server.ts
4706
4754
  import { hasRecentBriefingMarker, loadConfigSync } from "@hivelore/core";
4707
4755
  var SERVER_NAME = "hivelore";
4708
- var SERVER_VERSION = "0.30.0";
4756
+ var SERVER_VERSION = "0.31.0";
4709
4757
  function jsonResult(data) {
4710
4758
  return {
4711
4759
  content: [