@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 +127 -79
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +60 -1
- package/dist/server.js +128 -79
- package/dist/server.js.map +1 -1
- package/package.json +3 -3
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
|
|
1126
|
-
import { existsSync as
|
|
1127
|
-
import
|
|
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
|
|
1131
|
+
serializeMemory as serializeMemory8,
|
|
1132
1132
|
suggestSensorSeed as suggestSensorSeed2
|
|
1133
1133
|
} from "@hivelore/core";
|
|
1134
|
-
import { z as
|
|
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
|
|
1193
|
-
import { existsSync as
|
|
1194
|
-
import
|
|
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
|
|
1145
|
+
serializeMemory as serializeMemory7
|
|
1200
1146
|
} from "@hivelore/core";
|
|
1201
|
-
import { z as
|
|
1147
|
+
import { z as z15 } from "zod";
|
|
1202
1148
|
var ProposeSensorInputSchema = {
|
|
1203
|
-
memory_id:
|
|
1204
|
-
pattern:
|
|
1205
|
-
absent:
|
|
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:
|
|
1209
|
-
severity:
|
|
1210
|
-
message:
|
|
1211
|
-
flags:
|
|
1212
|
-
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 =
|
|
1238
|
-
if (!
|
|
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 (!
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
4756
|
+
var SERVER_VERSION = "0.31.0";
|
|
4709
4757
|
function jsonResult(data) {
|
|
4710
4758
|
return {
|
|
4711
4759
|
content: [
|