@hivelore/mcp 0.42.1 → 0.43.2
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 +96 -37
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +23 -6
- package/dist/server.js +96 -37
- package/dist/server.js.map +1 -1
- package/package.json +8 -4
package/dist/index.js
CHANGED
|
@@ -1134,7 +1134,7 @@ import {
|
|
|
1134
1134
|
import { z as z16 } from "zod";
|
|
1135
1135
|
|
|
1136
1136
|
// src/tools/propose-sensor.ts
|
|
1137
|
-
import {
|
|
1137
|
+
import { execFileSync } from "child_process";
|
|
1138
1138
|
import { readFile as readFile3, writeFile as writeFile8 } from "fs/promises";
|
|
1139
1139
|
import { existsSync as existsSync15, rmSync, symlinkSync } from "fs";
|
|
1140
1140
|
import os from "os";
|
|
@@ -1154,10 +1154,32 @@ import { z as z15 } from "zod";
|
|
|
1154
1154
|
// src/ast-sensors.ts
|
|
1155
1155
|
import path5 from "path";
|
|
1156
1156
|
var cachedEngine;
|
|
1157
|
+
var registeredDynamicLanguages = /* @__PURE__ */ new Set();
|
|
1158
|
+
async function loadDynamicLanguages(engine) {
|
|
1159
|
+
const registrations = {};
|
|
1160
|
+
const candidates = [
|
|
1161
|
+
["python", () => import("@ast-grep/lang-python")],
|
|
1162
|
+
["go", () => import("@ast-grep/lang-go")],
|
|
1163
|
+
["rust", () => import("@ast-grep/lang-rust")],
|
|
1164
|
+
["java", () => import("@ast-grep/lang-java")]
|
|
1165
|
+
];
|
|
1166
|
+
for (const [name, load] of candidates) {
|
|
1167
|
+
try {
|
|
1168
|
+
const mod = await load();
|
|
1169
|
+
registrations[name] = mod.default;
|
|
1170
|
+
registeredDynamicLanguages.add(name);
|
|
1171
|
+
} catch {
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
if (Object.keys(registrations).length > 0) {
|
|
1175
|
+
engine.registerDynamicLanguage(registrations);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1157
1178
|
async function loadAstEngine() {
|
|
1158
1179
|
if (cachedEngine !== void 0) return cachedEngine;
|
|
1159
1180
|
try {
|
|
1160
1181
|
cachedEngine = await import("@ast-grep/napi");
|
|
1182
|
+
await loadDynamicLanguages(cachedEngine);
|
|
1161
1183
|
} catch {
|
|
1162
1184
|
cachedEngine = null;
|
|
1163
1185
|
}
|
|
@@ -1166,11 +1188,22 @@ async function loadAstEngine() {
|
|
|
1166
1188
|
async function astEngineAvailable() {
|
|
1167
1189
|
return await loadAstEngine() !== null;
|
|
1168
1190
|
}
|
|
1169
|
-
function astLangForPath(filePath) {
|
|
1191
|
+
function astLangForPath(filePath, explicitLanguage) {
|
|
1192
|
+
if (explicitLanguage) {
|
|
1193
|
+
const normalized = explicitLanguage.toLowerCase();
|
|
1194
|
+
if (["typescript", "tsx", "javascript", "html", "css"].includes(normalized)) {
|
|
1195
|
+
return normalized === "typescript" ? "TypeScript" : normalized === "tsx" ? "Tsx" : normalized === "javascript" ? "JavaScript" : normalized[0].toUpperCase() + normalized.slice(1);
|
|
1196
|
+
}
|
|
1197
|
+
return registeredDynamicLanguages.has(normalized) ? normalized : null;
|
|
1198
|
+
}
|
|
1170
1199
|
const ext = path5.extname(filePath).toLowerCase();
|
|
1171
1200
|
if (ext === ".ts" || ext === ".mts" || ext === ".cts") return "TypeScript";
|
|
1172
1201
|
if (ext === ".tsx") return "Tsx";
|
|
1173
1202
|
if (ext === ".js" || ext === ".jsx" || ext === ".mjs" || ext === ".cjs") return "JavaScript";
|
|
1203
|
+
if (ext === ".py" && registeredDynamicLanguages.has("python")) return "python";
|
|
1204
|
+
if (ext === ".go" && registeredDynamicLanguages.has("go")) return "go";
|
|
1205
|
+
if (ext === ".rs" && registeredDynamicLanguages.has("rust")) return "rust";
|
|
1206
|
+
if (ext === ".java" && registeredDynamicLanguages.has("java")) return "java";
|
|
1174
1207
|
return null;
|
|
1175
1208
|
}
|
|
1176
1209
|
function absentPresentInNode(node, absent) {
|
|
@@ -1185,12 +1218,12 @@ function absentPresentInNode(node, absent) {
|
|
|
1185
1218
|
return text.includes(absent);
|
|
1186
1219
|
}
|
|
1187
1220
|
}
|
|
1188
|
-
async function runAstPattern(content, filePath, pattern, absent) {
|
|
1221
|
+
async function runAstPattern(content, filePath, pattern, absent, rule, language) {
|
|
1189
1222
|
const engine = await loadAstEngine();
|
|
1190
1223
|
if (!engine) return { status: "engine-missing", matches: [] };
|
|
1191
|
-
const langName = astLangForPath(filePath);
|
|
1224
|
+
const langName = astLangForPath(filePath, language);
|
|
1192
1225
|
if (!langName) return { status: "unsupported-language", matches: [] };
|
|
1193
|
-
const lang = engine.Lang[langName];
|
|
1226
|
+
const lang = langName in engine.Lang ? engine.Lang[langName] : langName;
|
|
1194
1227
|
let root;
|
|
1195
1228
|
try {
|
|
1196
1229
|
root = engine.parse(lang, content).root();
|
|
@@ -1199,7 +1232,9 @@ async function runAstPattern(content, filePath, pattern, absent) {
|
|
|
1199
1232
|
}
|
|
1200
1233
|
let nodes;
|
|
1201
1234
|
try {
|
|
1202
|
-
|
|
1235
|
+
const matcher = rule ? { rule: pattern ? { all: [{ pattern }, rule] } : rule } : pattern;
|
|
1236
|
+
if (!matcher) return { status: "invalid-pattern", matches: [], detail: "missing pattern/rule" };
|
|
1237
|
+
nodes = root.findAll(matcher);
|
|
1203
1238
|
} catch (err) {
|
|
1204
1239
|
return { status: "invalid-pattern", matches: [], detail: String(err).slice(0, 200) };
|
|
1205
1240
|
}
|
|
@@ -1216,7 +1251,7 @@ async function runAstPattern(content, filePath, pattern, absent) {
|
|
|
1216
1251
|
return { status: "ok", matches };
|
|
1217
1252
|
}
|
|
1218
1253
|
async function runAstSensorOnContent(input) {
|
|
1219
|
-
const scan = await runAstPattern(input.content, input.filePath, input.pattern, input.absent);
|
|
1254
|
+
const scan = await runAstPattern(input.content, input.filePath, input.pattern, input.absent, input.rule, input.language);
|
|
1220
1255
|
if (scan.status !== "ok" || !input.addedLines || input.addedLines.size === 0) return scan;
|
|
1221
1256
|
const added = input.addedLines;
|
|
1222
1257
|
return {
|
|
@@ -1236,7 +1271,9 @@ var ProposeSensorInputSchema = {
|
|
|
1236
1271
|
kind: z15.enum(["regex", "ast", "shell", "test"]).default("regex").describe(
|
|
1237
1272
|
"regex = pattern matched on added diff lines (default). ast = an ast-grep STRUCTURAL pattern (e.g. 'stripe.paymentIntents.create($$$)') matched on the AST of changed files \u2014 comments and strings can never false-positive; `absent` is a sub-pattern that must be missing INSIDE the match (requires the optional @ast-grep/napi engine). shell|test = a COMMAND the gate runs when the diff touches the sensor's paths \u2014 routes the team's own oracle (an existing test, an invariant script) to this lesson. Command sensors only execute where enforcement.runCommandSensors=true."
|
|
1238
1273
|
),
|
|
1239
|
-
pattern: z15.string().optional().describe("kind=regex: regex matching the
|
|
1274
|
+
pattern: z15.string().optional().describe("kind=regex: regex matching the faulty usage; kind=ast: optional structural pattern (may be combined with `rule`)."),
|
|
1275
|
+
rule: z15.record(z15.unknown()).optional().describe("kind=ast: full ast-grep Rule object (kind/inside/has/not/all/any/etc.). May be used alone or combined with pattern."),
|
|
1276
|
+
language: z15.string().optional().describe("kind=ast: explicit built-in/dynamic language name for non-standard file extensions."),
|
|
1240
1277
|
command: z15.string().optional().describe("kind=shell|test: command to execute (e.g. 'npx vitest run tests/payments/refund.spec.ts'). Non-zero exit = the lesson fires."),
|
|
1241
1278
|
timeout_ms: z15.number().int().positive().optional().describe("kind=shell|test: max runtime before the executor kills the command (default 120000)."),
|
|
1242
1279
|
absent: z15.string().optional().describe(
|
|
@@ -1267,7 +1304,7 @@ async function readPresumedCorrectTargets(root, relPaths) {
|
|
|
1267
1304
|
const targets = [];
|
|
1268
1305
|
for (const rel of relPaths) {
|
|
1269
1306
|
try {
|
|
1270
|
-
const content =
|
|
1307
|
+
const content = execFileSync("git", ["show", `HEAD:./${rel}`], {
|
|
1271
1308
|
cwd: root,
|
|
1272
1309
|
encoding: "utf8",
|
|
1273
1310
|
maxBuffer: 10 * 1024 * 1024,
|
|
@@ -1288,7 +1325,7 @@ async function readPresumedCorrectTargets(root, relPaths) {
|
|
|
1288
1325
|
}
|
|
1289
1326
|
function runCommandForValidation(command, root, timeoutMs = 12e4) {
|
|
1290
1327
|
try {
|
|
1291
|
-
|
|
1328
|
+
execFileSync("bash", ["-c", command], {
|
|
1292
1329
|
cwd: root,
|
|
1293
1330
|
timeout: timeoutMs,
|
|
1294
1331
|
maxBuffer: 8 * 1024 * 1024,
|
|
@@ -1313,7 +1350,7 @@ function proveRedOnIncident(command, root, redRef, timeoutMs) {
|
|
|
1313
1350
|
let added = false;
|
|
1314
1351
|
try {
|
|
1315
1352
|
try {
|
|
1316
|
-
|
|
1353
|
+
execFileSync("git", ["worktree", "add", "--detach", worktree, redRef], {
|
|
1317
1354
|
cwd: root,
|
|
1318
1355
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1319
1356
|
timeout: 6e4
|
|
@@ -1340,7 +1377,7 @@ function proveRedOnIncident(command, root, redRef, timeoutMs) {
|
|
|
1340
1377
|
} finally {
|
|
1341
1378
|
if (added) {
|
|
1342
1379
|
try {
|
|
1343
|
-
|
|
1380
|
+
execFileSync("git", ["worktree", "remove", "--force", worktree], { cwd: root, stdio: "ignore", timeout: 6e4 });
|
|
1344
1381
|
} catch {
|
|
1345
1382
|
try {
|
|
1346
1383
|
rmSync(worktree, { recursive: true, force: true });
|
|
@@ -1380,13 +1417,13 @@ async function proposeSensor(input, ctx) {
|
|
|
1380
1417
|
};
|
|
1381
1418
|
}
|
|
1382
1419
|
} else if (kind === "ast") {
|
|
1383
|
-
if (!input.pattern?.trim()) {
|
|
1420
|
+
if (!input.pattern?.trim() && !input.rule) {
|
|
1384
1421
|
return {
|
|
1385
1422
|
accepted: false,
|
|
1386
1423
|
memory_id: input.memory_id,
|
|
1387
1424
|
severity: input.severity,
|
|
1388
1425
|
reason: "invalid-pattern",
|
|
1389
|
-
guidance: "kind=ast requires a `pattern`
|
|
1426
|
+
guidance: "kind=ast requires a structural `pattern` or a full ast-grep `rule` object.",
|
|
1390
1427
|
self_check: { silent_on_current: false, fires_on_bad: null, fired_on: [] }
|
|
1391
1428
|
};
|
|
1392
1429
|
}
|
|
@@ -1407,7 +1444,7 @@ async function proposeSensor(input, ctx) {
|
|
|
1407
1444
|
}
|
|
1408
1445
|
const personalScopeNudge = found.memory.frontmatter.scope === "personal" ? ` Note: this lesson is personal-scoped, so the sensor guards only YOUR machine (personal memories are gitignored). Promote it so the gate travels with the repo: hivelore memory promote ${input.memory_id}.` : "";
|
|
1409
1446
|
if (kind === "ast") {
|
|
1410
|
-
const pattern = input.pattern
|
|
1447
|
+
const pattern = input.pattern?.trim();
|
|
1411
1448
|
if (!await astEngineAvailable() && input.severity === "block") {
|
|
1412
1449
|
return {
|
|
1413
1450
|
accepted: false,
|
|
@@ -1418,7 +1455,7 @@ async function proposeSensor(input, ctx) {
|
|
|
1418
1455
|
self_check: { silent_on_current: false, fires_on_bad: null, fired_on: [] }
|
|
1419
1456
|
};
|
|
1420
1457
|
}
|
|
1421
|
-
const brittleAst = sensorPatternBrittleness(pattern);
|
|
1458
|
+
const brittleAst = pattern ? sensorPatternBrittleness(pattern) : null;
|
|
1422
1459
|
if (brittleAst && input.severity === "block") {
|
|
1423
1460
|
return {
|
|
1424
1461
|
accepted: false,
|
|
@@ -1433,7 +1470,7 @@ async function proposeSensor(input, ctx) {
|
|
|
1433
1470
|
const currentTargetsAst = await readPresumedCorrectTargets(ctx.paths.root, anchorPathsAst);
|
|
1434
1471
|
const firedOnAst = [];
|
|
1435
1472
|
for (const target of currentTargetsAst) {
|
|
1436
|
-
const scan = await runAstSensorOnContent({ pattern, absent: input.absent, content: target.content, filePath: target.path });
|
|
1473
|
+
const scan = await runAstSensorOnContent({ pattern, rule: input.rule, language: input.language, absent: input.absent, content: target.content, filePath: target.path });
|
|
1437
1474
|
if (scan.status === "invalid-pattern") {
|
|
1438
1475
|
return {
|
|
1439
1476
|
accepted: false,
|
|
@@ -1462,10 +1499,10 @@ async function proposeSensor(input, ctx) {
|
|
|
1462
1499
|
];
|
|
1463
1500
|
let firesOnBadAst = null;
|
|
1464
1501
|
if (badExamplesAst.length > 0 && await astEngineAvailable()) {
|
|
1465
|
-
const exampleLang = anchorPathsAst.find((p) => astLangForPath(p) !== null) ?? "example.tsx";
|
|
1502
|
+
const exampleLang = anchorPathsAst.find((p) => astLangForPath(p, input.language) !== null) ?? "example.tsx";
|
|
1466
1503
|
firesOnBadAst = false;
|
|
1467
1504
|
for (const example of badExamplesAst) {
|
|
1468
|
-
const scan = await runAstSensorOnContent({ pattern, absent: input.absent, content: example, filePath: exampleLang });
|
|
1505
|
+
const scan = await runAstSensorOnContent({ pattern, rule: input.rule, language: input.language, absent: input.absent, content: example, filePath: exampleLang });
|
|
1469
1506
|
if (scan.status === "ok" && scan.matches.length > 0) {
|
|
1470
1507
|
firesOnBadAst = true;
|
|
1471
1508
|
break;
|
|
@@ -1484,10 +1521,12 @@ async function proposeSensor(input, ctx) {
|
|
|
1484
1521
|
}
|
|
1485
1522
|
const sensorAst = {
|
|
1486
1523
|
kind: "ast",
|
|
1487
|
-
pattern,
|
|
1524
|
+
...pattern ? { pattern } : {},
|
|
1525
|
+
...input.rule ? { rule: input.rule } : {},
|
|
1526
|
+
...input.language ? { language: input.language } : {},
|
|
1488
1527
|
...input.absent ? { absent: input.absent } : {},
|
|
1489
1528
|
paths: anchorPathsAst,
|
|
1490
|
-
message: input.message?.trim() || deriveMessage(found.memory.body, pattern, input.absent),
|
|
1529
|
+
message: input.message?.trim() || deriveMessage(found.memory.body, pattern ?? "AST rule", input.absent),
|
|
1491
1530
|
...input.incident?.trim() ? { incident: input.incident.trim() } : {},
|
|
1492
1531
|
severity: input.severity,
|
|
1493
1532
|
autogen: false,
|
|
@@ -1550,6 +1589,16 @@ ${verdictCmd.detail}`,
|
|
|
1550
1589
|
self_check: { silent_on_current: false, fires_on_bad: null, fired_on: anchorPathsCmd }
|
|
1551
1590
|
};
|
|
1552
1591
|
}
|
|
1592
|
+
if (input.severity === "block" && !input.red_ref?.trim()) {
|
|
1593
|
+
return {
|
|
1594
|
+
accepted: false,
|
|
1595
|
+
memory_id: input.memory_id,
|
|
1596
|
+
severity: input.severity,
|
|
1597
|
+
reason: "red-required",
|
|
1598
|
+
guidance: "A blocking shell/test sensor requires `red_ref`: the oracle must PASS on the current tree and FAIL on the pre-fix incident state. Pass the incident commit/ref, or propose the sensor at warn severity until RED can be proven.",
|
|
1599
|
+
self_check: { silent_on_current: true, fires_on_bad: null, fired_on: [] }
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1553
1602
|
const sensorCmd = {
|
|
1554
1603
|
kind,
|
|
1555
1604
|
command: input.command.trim(),
|
|
@@ -1571,7 +1620,7 @@ ${verdictCmd.detail}`,
|
|
|
1571
1620
|
accepted: true,
|
|
1572
1621
|
memory_id: input.memory_id,
|
|
1573
1622
|
severity: input.severity,
|
|
1574
|
-
guidance: (verdictCmd.status === "passed" ? "Command oracle passes on the current tree; the gate now runs it when the diff touches the sensor's paths (requires enforcement.runCommandSensors=true)." : `Accepted at warn severity, but note: ${verdictCmd.status} on the current tree (${verdictCmd.detail}).`) + (redProven ? " RED proven: the oracle demonstrably FAILS on the incident state (red_ref) \u2014 recorded as red_proven." : "
|
|
1623
|
+
guidance: (verdictCmd.status === "passed" ? "Command oracle passes on the current tree; the gate now runs it when the diff touches the sensor's paths (requires enforcement.runCommandSensors=true)." : `Accepted at warn severity, but note: ${verdictCmd.status} on the current tree (${verdictCmd.detail}).`) + (redProven ? " RED proven: the oracle demonstrably FAILS on the incident state (red_ref) \u2014 recorded as red_proven." : " This warn-only oracle is not RED-proven; pass red_ref before promoting it to block.") + (pendingTests.length > 0 ? ` Note: the routed test is still a PENDING stub (${pendingTests.join(", ")}) \u2014 it passes on anything; write the assertion to make this oracle real.` : "") + personalScopeNudge,
|
|
1575
1624
|
self_check: { silent_on_current: verdictCmd.status === "passed", fires_on_bad: redProven ? true : null, fired_on: [] },
|
|
1576
1625
|
file_path: found.filePath
|
|
1577
1626
|
};
|
|
@@ -1640,8 +1689,10 @@ var MemTriedInputSchema = {
|
|
|
1640
1689
|
paths: z16.array(z16.string()).default([]).describe("Anchor file paths this applies to"),
|
|
1641
1690
|
author: z16.string().optional().describe("Author handle or email"),
|
|
1642
1691
|
sensor: z16.object({
|
|
1643
|
-
kind: z16.enum(["regex", "shell", "test"]).default("regex").describe("regex pattern, or a shell/test
|
|
1644
|
-
pattern: z16.string().optional().describe("kind=regex:
|
|
1692
|
+
kind: z16.enum(["regex", "ast", "shell", "test"]).default("regex").describe("regex/AST pattern, or a shell/test command"),
|
|
1693
|
+
pattern: z16.string().optional().describe("kind=regex|ast: pattern matching the faulty usage"),
|
|
1694
|
+
rule: z16.record(z16.unknown()).optional().describe("kind=ast: full ast-grep Rule object"),
|
|
1695
|
+
language: z16.string().optional().describe("kind=ast: explicit built-in/dynamic language"),
|
|
1645
1696
|
command: z16.string().optional().describe("kind=shell|test: command the gate runs when the diff touches the sensor's paths (non-zero exit = lesson fires)"),
|
|
1646
1697
|
timeout_ms: z16.number().int().positive().optional().describe("kind=shell|test: max runtime (default 120000)"),
|
|
1647
1698
|
absent: z16.string().optional().describe("kind=regex: regex marking CORRECT usage nearby \u2014 excludes it from firing"),
|
|
@@ -1691,6 +1742,8 @@ async function memTried(input, ctx) {
|
|
|
1691
1742
|
memory_id: frontmatter.id,
|
|
1692
1743
|
kind: input.sensor.kind ?? "regex",
|
|
1693
1744
|
pattern: input.sensor.pattern,
|
|
1745
|
+
rule: input.sensor.rule,
|
|
1746
|
+
language: input.sensor.language,
|
|
1694
1747
|
command: input.sensor.command,
|
|
1695
1748
|
timeout_ms: input.sensor.timeout_ms,
|
|
1696
1749
|
absent: input.sensor.absent,
|
|
@@ -1985,7 +2038,7 @@ import {
|
|
|
1985
2038
|
import { mkdir as mkdir6, writeFile as writeFile12, rm } from "fs/promises";
|
|
1986
2039
|
import { existsSync as existsSync19 } from "fs";
|
|
1987
2040
|
import path10 from "path";
|
|
1988
|
-
import { execSync
|
|
2041
|
+
import { execSync } from "child_process";
|
|
1989
2042
|
function pendingDistillPath(ctx) {
|
|
1990
2043
|
return path10.join(ctx.paths.haiveDir, ".cache", "pending-distill.json");
|
|
1991
2044
|
}
|
|
@@ -2028,7 +2081,7 @@ var SessionTracker = class {
|
|
|
2028
2081
|
}
|
|
2029
2082
|
let gitDiff;
|
|
2030
2083
|
try {
|
|
2031
|
-
const raw =
|
|
2084
|
+
const raw = execSync("git diff HEAD", {
|
|
2032
2085
|
cwd: this.ctx.paths.root,
|
|
2033
2086
|
timeout: 5e3,
|
|
2034
2087
|
encoding: "utf8",
|
|
@@ -2060,7 +2113,7 @@ var SessionTracker = class {
|
|
|
2060
2113
|
const triedThreads = this.events.filter((e) => e.tool === "mem_tried").map((e) => e.summary ?? "").filter(Boolean);
|
|
2061
2114
|
let diffStat;
|
|
2062
2115
|
try {
|
|
2063
|
-
diffStat =
|
|
2116
|
+
diffStat = execSync("git diff --stat HEAD", {
|
|
2064
2117
|
cwd: this.ctx.paths.root,
|
|
2065
2118
|
timeout: 5e3,
|
|
2066
2119
|
encoding: "utf8",
|
|
@@ -2472,6 +2525,8 @@ var GetBriefingInputSchema = {
|
|
|
2472
2525
|
),
|
|
2473
2526
|
include_stale: z20.boolean().default(false).describe("Include stale memories (excluded by default \u2014 they may be outdated)"),
|
|
2474
2527
|
track: z20.boolean().default(true).describe("Increment read_count on returned memories"),
|
|
2528
|
+
memory_scopes: z20.array(z20.enum(["personal", "team", "module", "shared"])).optional().describe("Restrict the candidate corpus to selected scopes. Omit to include every scope."),
|
|
2529
|
+
deterministic: z20.boolean().optional().describe("Ignore machine-local usage/impact signals so repeated evaluations rank the shared corpus reproducibly."),
|
|
2475
2530
|
format: z20.enum(["full", "compact", "actions"]).default("full").describe(
|
|
2476
2531
|
"Output format: 'full' returns memory bodies (honors token budget via truncation); 'compact' returns a 1-line summary per memory (call mem_get for detail); 'actions' squeezes bodies to actionable bullet lines \u2014 fewer tokens vs full."
|
|
2477
2532
|
),
|
|
@@ -2500,9 +2555,11 @@ async function getBriefing(input, ctx) {
|
|
|
2500
2555
|
let searchMode = "literal";
|
|
2501
2556
|
let usage = { version: 1, updated_at: "", by_id: {} };
|
|
2502
2557
|
let byId = /* @__PURE__ */ new Map();
|
|
2558
|
+
const allowedScopes = input.memory_scopes ? new Set(input.memory_scopes) : null;
|
|
2559
|
+
const scopeAllowed = (loaded) => allowedScopes === null || allowedScopes.has(loaded.memory.frontmatter.scope);
|
|
2503
2560
|
let lastSession;
|
|
2504
2561
|
if (existsSync22(ctx.paths.memoriesDir)) {
|
|
2505
|
-
const allLoaded = await loadMemoriesFromDir17(ctx.paths.memoriesDir);
|
|
2562
|
+
const allLoaded = (await loadMemoriesFromDir17(ctx.paths.memoriesDir)).filter(scopeAllowed);
|
|
2506
2563
|
const recaps = allLoaded.filter(({ memory }) => memory.frontmatter.type === "session_recap").sort(
|
|
2507
2564
|
(a, b) => new Date(b.memory.frontmatter.created_at).getTime() - new Date(a.memory.frontmatter.created_at).getTime()
|
|
2508
2565
|
);
|
|
@@ -2535,10 +2592,11 @@ async function getBriefing(input, ctx) {
|
|
|
2535
2592
|
if (memoryHasExcludedTag(memory.frontmatter, excludeTags)) return false;
|
|
2536
2593
|
return true;
|
|
2537
2594
|
});
|
|
2538
|
-
usage = await loadUsageIndex8(ctx.paths);
|
|
2595
|
+
usage = input.deterministic ? { version: 1, updated_at: "", by_id: {} } : await loadUsageIndex8(ctx.paths);
|
|
2539
2596
|
byId = new Map(allMemories.map((m) => [m.memory.frontmatter.id, m]));
|
|
2540
|
-
const
|
|
2541
|
-
|
|
2597
|
+
const semanticEnabled = input.semantic && input.deterministic !== true;
|
|
2598
|
+
const semanticHits = input.task && semanticEnabled ? await trySemanticHits(ctx, input.task, allMemories.length * 2) : null;
|
|
2599
|
+
if (input.task && semanticEnabled) {
|
|
2542
2600
|
searchMode = semanticHits ? "semantic" : "literal_fallback";
|
|
2543
2601
|
}
|
|
2544
2602
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -2874,7 +2932,7 @@ ${m.content}`).join("\n\n---\n\n"),
|
|
|
2874
2932
|
}
|
|
2875
2933
|
}
|
|
2876
2934
|
if (existsSync22(ctx.paths.memoriesDir)) {
|
|
2877
|
-
const allMems = await loadMemoriesFromDir17(ctx.paths.memoriesDir);
|
|
2935
|
+
const allMems = (await loadMemoriesFromDir17(ctx.paths.memoriesDir)).filter(scopeAllowed);
|
|
2878
2936
|
for (const { memory } of allMems) {
|
|
2879
2937
|
const fm = memory.frontmatter;
|
|
2880
2938
|
if (!fm.requires_human_approval) continue;
|
|
@@ -2931,7 +2989,7 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
2931
2989
|
pcRaw = await readFile7(ctx.paths.projectContext, "utf8");
|
|
2932
2990
|
} catch {
|
|
2933
2991
|
}
|
|
2934
|
-
const allForBootstrap = existsSync22(ctx.paths.memoriesDir) ? await loadMemoriesFromDir17(ctx.paths.memoriesDir) : [];
|
|
2992
|
+
const allForBootstrap = existsSync22(ctx.paths.memoriesDir) ? (await loadMemoriesFromDir17(ctx.paths.memoriesDir)).filter(scopeAllowed) : [];
|
|
2935
2993
|
const cmForBootstrap = await loadCodeMap(ctx.paths);
|
|
2936
2994
|
let existingModules = [];
|
|
2937
2995
|
try {
|
|
@@ -2942,7 +3000,7 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
2942
3000
|
const bootstrap = assessBootstrapState({
|
|
2943
3001
|
projectContextRaw: pcRaw,
|
|
2944
3002
|
memories: allForBootstrap,
|
|
2945
|
-
codeFiles: cmForBootstrap ? Object.keys(cmForBootstrap.files) : [],
|
|
3003
|
+
codeFiles: cmForBootstrap ? Object.keys(cmForBootstrap.files).filter((file) => existsSync22(path13.join(ctx.paths.root, file))) : [],
|
|
2946
3004
|
existingModules
|
|
2947
3005
|
});
|
|
2948
3006
|
if (bootstrap.state !== "ready" && bootstrap.metrics.mainAreas > 0) {
|
|
@@ -3133,7 +3191,7 @@ function oneLine(value) {
|
|
|
3133
3191
|
return value.replace(/\s+/g, " ").replace(/"/g, '\\"').trim().slice(0, 120);
|
|
3134
3192
|
}
|
|
3135
3193
|
function serverVersion() {
|
|
3136
|
-
return true ? "0.
|
|
3194
|
+
return true ? "0.43.2" : "dev";
|
|
3137
3195
|
}
|
|
3138
3196
|
|
|
3139
3197
|
// src/tools/code-map.ts
|
|
@@ -4306,6 +4364,7 @@ ${template}\`\`\`
|
|
|
4306
4364
|
// src/prompts/bootstrap-repo.ts
|
|
4307
4365
|
import { readFile as readFile8, readdir as readdir5 } from "fs/promises";
|
|
4308
4366
|
import { existsSync as existsSync29 } from "fs";
|
|
4367
|
+
import path14 from "path";
|
|
4309
4368
|
import {
|
|
4310
4369
|
assessBootstrapState as assessBootstrapState2,
|
|
4311
4370
|
loadCodeMap as loadCodeMap4,
|
|
@@ -4333,7 +4392,7 @@ async function currentAssessment(ctx) {
|
|
|
4333
4392
|
return assessBootstrapState2({
|
|
4334
4393
|
projectContextRaw,
|
|
4335
4394
|
memories,
|
|
4336
|
-
codeFiles: codeMap ? Object.keys(codeMap.files) : [],
|
|
4395
|
+
codeFiles: codeMap ? Object.keys(codeMap.files).filter((file) => existsSync29(path14.join(ctx.paths.root, file))) : [],
|
|
4337
4396
|
existingModules
|
|
4338
4397
|
});
|
|
4339
4398
|
}
|
|
@@ -4561,7 +4620,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
4561
4620
|
// src/server.ts
|
|
4562
4621
|
import { hasRecentBriefingMarker, loadConfigSync } from "@hivelore/core";
|
|
4563
4622
|
var SERVER_NAME = "hivelore";
|
|
4564
|
-
var SERVER_VERSION = "0.
|
|
4623
|
+
var SERVER_VERSION = "0.43.2";
|
|
4565
4624
|
function jsonResult(data) {
|
|
4566
4625
|
return {
|
|
4567
4626
|
content: [
|