@hivelore/mcp 0.38.0 → 0.39.1

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.d.ts CHANGED
@@ -552,7 +552,7 @@ declare const MemTriedInputSchema: {
552
552
  what: z.ZodString;
553
553
  why_failed: z.ZodString;
554
554
  instead: z.ZodOptional<z.ZodString>;
555
- scope: z.ZodDefault<z.ZodEnum<["personal", "team", "module"]>>;
555
+ scope: z.ZodOptional<z.ZodEnum<["personal", "team", "module"]>>;
556
556
  module: z.ZodOptional<z.ZodString>;
557
557
  tags: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
558
558
  paths: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
@@ -619,16 +619,22 @@ interface MemTriedOutput {
619
619
  }
620
620
  declare function memTried(input: MemTriedInput, ctx: HaiveContext): Promise<MemTriedOutput>;
621
621
 
622
- /**
623
- * Detect the test framework + owning package dir (repo-relative) for an incident's anchor paths.
624
- * Walks up from each anchor path's directory to the repo root and uses the NEAREST enclosing manifest
625
- * (package.json / go.mod / a python signal); falls back to the repo root with a vitest default. This
626
- * is FS I/O, so it lives in the MCP layer (imported by the CLI too) rather than in pure core.
627
- */
628
622
  declare function detectTestFrameworkForPaths(root: string, anchorPaths: string[]): Promise<{
629
623
  framework: TestFramework;
630
624
  baseDir: string;
631
625
  }>;
626
+ interface AnchorFrameworkGroup {
627
+ framework: TestFramework;
628
+ baseDir: string;
629
+ /** The anchor paths owned by this package (subset of the lesson's anchors). */
630
+ anchors: string[];
631
+ }
632
+ /**
633
+ * Group a lesson's anchor paths by OWNING package: one entry per distinct enclosing manifest dir,
634
+ * in first-anchor order. A lesson that spans several packages gets one scaffold per package instead
635
+ * of "first anchor wins". Anchors with no enclosing manifest fall back to the repo root + vitest.
636
+ */
637
+ declare function detectTestFrameworksForAnchors(root: string, anchorPaths: string[]): Promise<AnchorFrameworkGroup[]>;
632
638
  declare const ScaffoldTestInputSchema: {
633
639
  memory_id: z.ZodString;
634
640
  framework: z.ZodOptional<z.ZodEnum<["vitest", "jest", "pytest", "gotest"]>>;
@@ -653,6 +659,19 @@ interface ScaffoldTestOutput {
653
659
  written?: boolean;
654
660
  already_exists?: boolean;
655
661
  notice?: string;
662
+ /**
663
+ * One entry per generated test. A lesson whose anchors span several packages scaffolds one test
664
+ * per OWNING package; they share a single propose_command (a memory carries one sensor) whose
665
+ * command chains every run command.
666
+ */
667
+ scaffolds?: Array<{
668
+ framework: TestFramework;
669
+ path: string;
670
+ run_command: string;
671
+ content: string;
672
+ written: boolean;
673
+ already_exists: boolean;
674
+ }>;
656
675
  }
657
676
  declare function scaffoldTest(input: ScaffoldTestInput, ctx: HaiveContext): Promise<ScaffoldTestOutput>;
658
677
 
@@ -761,4 +780,4 @@ declare function runHaiveMcpStdio(options: {
761
780
  root?: string;
762
781
  }): Promise<void>;
763
782
 
764
- export { type AntiPatternsCheckInput, type AntiPatternsCheckOutput, type BriefingOutput, type CodeMapInput, type CodeMapToolOutput, type CodeSearchInput, type CodeSearchOutput, ENFORCEMENT_PROFILE_TOOLS, EXPERIMENTAL_PROFILE_TOOLS, type GetBriefingInput, type GetRecapInput, type GetRecapOutput, MAINTENANCE_PROFILE_TOOLS, type MemConflictCandidatesInput, type MemDistillInput, type MemDistillOutput, type MemRelevantToInput, type MemRelevantToOutput, type MemResolveProjectInput, type MemSuggestTopicInput, type MemTimelineInput, type MemTriedOutput, type PreCommitCheckInput, type PreCommitCheckOutput, type ProposeSensorOutput, SERVER_NAME, SERVER_VERSION, type ScaffoldTestOutput, TOOL_PROFILES, type ToolProfile, antiPatternsCheck, codeMapTool, codeSearch, createHaiveServer, detectTestFrameworkForPaths, getAllowedToolsForProfile, getBriefing, getRecap, memConflictCandidates, memDistill, memRelevantTo, memResolveProject, memSuggestTopic, memTimeline, memTried, parseMcpCliArgs, preCommitCheck, printHaiveMcpVersion, proposeSensor, readPresumedCorrectTargets, runHaiveMcpStdio, scaffoldTest };
783
+ export { type AnchorFrameworkGroup, type AntiPatternsCheckInput, type AntiPatternsCheckOutput, type BriefingOutput, type CodeMapInput, type CodeMapToolOutput, type CodeSearchInput, type CodeSearchOutput, ENFORCEMENT_PROFILE_TOOLS, EXPERIMENTAL_PROFILE_TOOLS, type GetBriefingInput, type GetRecapInput, type GetRecapOutput, MAINTENANCE_PROFILE_TOOLS, type MemConflictCandidatesInput, type MemDistillInput, type MemDistillOutput, type MemRelevantToInput, type MemRelevantToOutput, type MemResolveProjectInput, type MemSuggestTopicInput, type MemTimelineInput, type MemTriedOutput, type PreCommitCheckInput, type PreCommitCheckOutput, type ProposeSensorOutput, SERVER_NAME, SERVER_VERSION, type ScaffoldTestOutput, TOOL_PROFILES, type ToolProfile, antiPatternsCheck, codeMapTool, codeSearch, createHaiveServer, detectTestFrameworkForPaths, detectTestFrameworksForAnchors, getAllowedToolsForProfile, getBriefing, getRecap, memConflictCandidates, memDistill, memRelevantTo, memResolveProject, memSuggestTopic, memTimeline, memTried, parseMcpCliArgs, preCommitCheck, printHaiveMcpVersion, proposeSensor, readPresumedCorrectTargets, runHaiveMcpStdio, scaffoldTest };
package/dist/server.js CHANGED
@@ -1138,6 +1138,8 @@ import { existsSync as existsSync15 } from "fs";
1138
1138
  import path5 from "path";
1139
1139
  import {
1140
1140
  extractSensorExamples,
1141
+ extractTestFilePathsFromCommand,
1142
+ hasPendingTestMarker,
1141
1143
  judgeProposedSensor,
1142
1144
  loadMemoriesFromDir as loadMemoriesFromDir13,
1143
1145
  serializeMemory as serializeMemory7
@@ -1259,7 +1261,26 @@ async function proposeSensor(input, ctx) {
1259
1261
  if (!found) {
1260
1262
  throw new Error(`No memory found with id ${input.memory_id}`);
1261
1263
  }
1264
+ 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}.` : "";
1262
1265
  if (kind !== "regex") {
1266
+ const referencedTests = extractTestFilePathsFromCommand(input.command.trim()).filter((rel) => existsSync15(path5.resolve(ctx.paths.root, rel)));
1267
+ const pendingTests = [];
1268
+ for (const rel of referencedTests) {
1269
+ try {
1270
+ if (hasPendingTestMarker(await readFile3(path5.resolve(ctx.paths.root, rel), "utf8"))) pendingTests.push(rel);
1271
+ } catch {
1272
+ }
1273
+ }
1274
+ if (pendingTests.length > 0 && input.severity === "block") {
1275
+ return {
1276
+ accepted: false,
1277
+ memory_id: input.memory_id,
1278
+ severity: input.severity,
1279
+ reason: "oracle-pending",
1280
+ guidance: `The routed test is still a PENDING stub (${pendingTests.join(", ")}) \u2014 it passes on anything, so the sensor would enforce nothing while reporting protection. Write the assertion (RED on the incident, GREEN once fixed), run it, then re-propose.`,
1281
+ self_check: { silent_on_current: false, fires_on_bad: null, fired_on: pendingTests }
1282
+ };
1283
+ }
1263
1284
  const verdictCmd = runCommandForValidation(input.command.trim(), ctx.paths.root, input.timeout_ms);
1264
1285
  const anchorPathsCmd = input.paths.length > 0 ? input.paths : found.memory.frontmatter.anchor.paths;
1265
1286
  if (verdictCmd.status !== "passed" && input.severity === "block") {
@@ -1293,7 +1314,7 @@ ${verdictCmd.detail}`,
1293
1314
  accepted: true,
1294
1315
  memory_id: input.memory_id,
1295
1316
  severity: input.severity,
1296
- 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}).`,
1317
+ 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}).`) + (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,
1297
1318
  self_check: { silent_on_current: verdictCmd.status === "passed", fires_on_bad: null, fired_on: [] }
1298
1319
  };
1299
1320
  }
@@ -1342,6 +1363,7 @@ ${verdictCmd.detail}`,
1342
1363
  accepted: true,
1343
1364
  memory_id: input.memory_id,
1344
1365
  severity: input.severity,
1366
+ ...personalScopeNudge ? { guidance: personalScopeNudge.trim() } : {},
1345
1367
  self_check,
1346
1368
  file_path: found.filePath
1347
1369
  };
@@ -1352,7 +1374,9 @@ var MemTriedInputSchema = {
1352
1374
  what: z16.string().min(1).describe("Brief description of the approach that was tried"),
1353
1375
  why_failed: z16.string().min(1).describe("Why it failed or why it should NOT be used"),
1354
1376
  instead: z16.string().optional().describe("What to use or do instead (recommended alternative)"),
1355
- scope: z16.enum(["personal", "team", "module"]).default("personal").describe("Visibility scope"),
1377
+ scope: z16.enum(["personal", "team", "module"]).optional().describe(
1378
+ "Visibility scope. Defaults to personal \u2014 EXCEPT when a one-shot `sensor` is attached: an enforced lesson is team truth (the sensor must travel to every machine and CI), so it defaults to team. Pass scope explicitly to override."
1379
+ ),
1356
1380
  module: z16.string().optional().describe("Module name (required when scope=module)"),
1357
1381
  tags: z16.array(z16.string()).default([]).describe("Tags for filtering"),
1358
1382
  paths: z16.array(z16.string()).default([]).describe("Anchor file paths this applies to"),
@@ -1375,11 +1399,15 @@ async function memTried(input, ctx) {
1375
1399
  if (!existsSync16(ctx.paths.haiveDir)) {
1376
1400
  throw new Error(`No .ai/ directory at ${ctx.paths.root}. Run 'hivelore init' first.`);
1377
1401
  }
1378
- const slug = input.what.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().split(/\s+/).slice(0, 5).join("-");
1402
+ const SLUG_STOPWORDS = /* @__PURE__ */ new Set(["and", "or", "the", "a", "an", "of", "to", "in", "for", "with", "on", "at", "by"]);
1403
+ const words = input.what.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().split(/\s+/).slice(0, 5);
1404
+ while (words.length > 2 && SLUG_STOPWORDS.has(words[words.length - 1])) words.pop();
1405
+ const slug = words.join("-");
1406
+ const scope = input.scope ?? (input.sensor ? "team" : "personal");
1379
1407
  const baseFm = buildFrontmatter2({
1380
1408
  type: "attempt",
1381
1409
  slug,
1382
- scope: input.scope,
1410
+ scope,
1383
1411
  module: input.module,
1384
1412
  tags: input.tags,
1385
1413
  paths: input.paths,
@@ -1427,7 +1455,7 @@ async function memTried(input, ctx) {
1427
1455
  ...verdict.reason ? { reason: verdict.reason } : {},
1428
1456
  ...verdict.guidance ? { guidance: verdict.guidance } : {}
1429
1457
  },
1430
- 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.`
1458
+ 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.`) + (input.scope === void 0 ? " Saved team-scoped (an enforced lesson must travel with the repo) \u2014 pass scope:'personal' to keep it private." : "")
1431
1459
  };
1432
1460
  }
1433
1461
  const seed = input.paths.length > 0 ? suggestSensorSeed2(body, input.paths) : null;
@@ -1454,6 +1482,7 @@ import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile10 } from
1454
1482
  import path7 from "path";
1455
1483
  import { z as z17 } from "zod";
1456
1484
  import {
1485
+ buildProposeCommand,
1457
1486
  loadMemoriesFromDir as loadMemoriesFromDir14,
1458
1487
  normalizeFramework,
1459
1488
  parseLessonFields,
@@ -1461,39 +1490,55 @@ import {
1461
1490
  scaffoldPostIncidentTest
1462
1491
  } from "@hivelore/core";
1463
1492
  var PY_SIGNALS = ["pyproject.toml", "setup.py", "pytest.ini", "requirements.txt", "tox.ini"];
1464
- async function detectTestFrameworkForPaths(root, anchorPaths) {
1465
- const starts = anchorPaths.length > 0 ? anchorPaths : ["."];
1466
- for (const rel of starts) {
1467
- let dir = path7.resolve(root, rel);
1468
- try {
1469
- if (!statSync(dir).isDirectory()) dir = path7.dirname(dir);
1470
- } catch {
1471
- if (path7.extname(dir)) dir = path7.dirname(dir);
1472
- }
1473
- while (dir.startsWith(root)) {
1474
- const pkgJson = path7.join(dir, "package.json");
1475
- const hasPkg = existsSync17(pkgJson);
1476
- const goMod = existsSync17(path7.join(dir, "go.mod"));
1477
- const pySignal = PY_SIGNALS.some((s) => existsSync17(path7.join(dir, s)));
1478
- if (hasPkg || goMod || pySignal) {
1479
- let pkg = null;
1480
- if (hasPkg) {
1481
- try {
1482
- pkg = JSON.parse(await readFile4(pkgJson, "utf8"));
1483
- } catch {
1484
- pkg = null;
1485
- }
1493
+ async function detectForAnchor(root, rel) {
1494
+ let dir = path7.resolve(root, rel);
1495
+ try {
1496
+ if (!statSync(dir).isDirectory()) dir = path7.dirname(dir);
1497
+ } catch {
1498
+ if (path7.extname(dir)) dir = path7.dirname(dir);
1499
+ }
1500
+ while (dir.startsWith(root)) {
1501
+ const pkgJson = path7.join(dir, "package.json");
1502
+ const hasPkg = existsSync17(pkgJson);
1503
+ const goMod = existsSync17(path7.join(dir, "go.mod"));
1504
+ const pySignal = PY_SIGNALS.some((s) => existsSync17(path7.join(dir, s)));
1505
+ if (hasPkg || goMod || pySignal) {
1506
+ let pkg = null;
1507
+ if (hasPkg) {
1508
+ try {
1509
+ pkg = JSON.parse(await readFile4(pkgJson, "utf8"));
1510
+ } catch {
1511
+ pkg = null;
1486
1512
  }
1487
- const baseDir = path7.relative(root, dir).split(path7.sep).join("/");
1488
- return { framework: pickTestFramework(pkg, { goMod, pySignal }), baseDir };
1489
1513
  }
1490
- const parent = path7.dirname(dir);
1491
- if (parent === dir || dir === root) break;
1492
- dir = parent;
1514
+ const baseDir = path7.relative(root, dir).split(path7.sep).join("/");
1515
+ return { framework: pickTestFramework(pkg, { goMod, pySignal }), baseDir };
1493
1516
  }
1517
+ const parent = path7.dirname(dir);
1518
+ if (parent === dir || dir === root) break;
1519
+ dir = parent;
1520
+ }
1521
+ return null;
1522
+ }
1523
+ async function detectTestFrameworkForPaths(root, anchorPaths) {
1524
+ const starts = anchorPaths.length > 0 ? anchorPaths : ["."];
1525
+ for (const rel of starts) {
1526
+ const found = await detectForAnchor(root, rel);
1527
+ if (found) return found;
1494
1528
  }
1495
1529
  return { framework: "vitest", baseDir: "" };
1496
1530
  }
1531
+ async function detectTestFrameworksForAnchors(root, anchorPaths) {
1532
+ const starts = anchorPaths.length > 0 ? anchorPaths : ["."];
1533
+ const groups = /* @__PURE__ */ new Map();
1534
+ for (const rel of starts) {
1535
+ const found = await detectForAnchor(root, rel) ?? { framework: "vitest", baseDir: "" };
1536
+ const existing = groups.get(found.baseDir);
1537
+ if (existing) existing.anchors.push(rel);
1538
+ else groups.set(found.baseDir, { ...found, anchors: [rel] });
1539
+ }
1540
+ return [...groups.values()];
1541
+ }
1497
1542
  var ScaffoldTestInputSchema = {
1498
1543
  memory_id: z17.string().min(1).describe("Id of the attempt/gotcha lesson to scaffold a post-incident test from."),
1499
1544
  framework: z17.enum(["vitest", "jest", "pytest", "gotest"]).optional().describe("Test framework. Auto-detected from the package that owns the lesson's anchor paths when omitted."),
@@ -1507,43 +1552,69 @@ async function scaffoldTest(input, ctx) {
1507
1552
  return { ok: false, error: `No memory found with id ${input.memory_id}`, memory_id: input.memory_id };
1508
1553
  }
1509
1554
  const anchorPaths = found.memory.frontmatter.anchor.paths ?? [];
1510
- const detected = await detectTestFrameworkForPaths(ctx.paths.root, anchorPaths);
1511
- const framework = input.framework ? normalizeFramework(input.framework) ?? detected.framework : detected.framework;
1555
+ const allGroups = await detectTestFrameworksForAnchors(ctx.paths.root, anchorPaths);
1556
+ const groups = input.out_path ? allGroups.slice(0, 1) : allGroups;
1557
+ const frameworkFor = (detected) => input.framework ? normalizeFramework(input.framework) ?? detected : detected;
1512
1558
  const fields = parseLessonFields(found.memory.body);
1513
- const scaffold = scaffoldPostIncidentTest(
1514
- {
1515
- memoryId: input.memory_id,
1516
- title: fields.title || input.memory_id,
1517
- whyFailed: fields.whyFailed,
1518
- instead: fields.instead,
1519
- incident: found.memory.frontmatter.sensor?.incident,
1520
- paths: anchorPaths
1521
- },
1522
- { framework, outPath: input.out_path, baseDir: detected.baseDir }
1559
+ const lesson = {
1560
+ memoryId: input.memory_id,
1561
+ title: fields.title || input.memory_id,
1562
+ whyFailed: fields.whyFailed,
1563
+ instead: fields.instead,
1564
+ incident: found.memory.frontmatter.sensor?.incident,
1565
+ paths: anchorPaths
1566
+ };
1567
+ let scaffolds = groups.map(
1568
+ (g) => scaffoldPostIncidentTest(lesson, { framework: frameworkFor(g.framework), outPath: input.out_path, baseDir: g.baseDir })
1523
1569
  );
1524
- const abs = path7.isAbsolute(scaffold.relPath) ? scaffold.relPath : path7.resolve(ctx.paths.root, scaffold.relPath);
1525
- let written = false;
1526
- let alreadyExists = false;
1527
- if (input.write) {
1528
- if (existsSync17(abs)) {
1529
- alreadyExists = true;
1530
- } else {
1531
- await mkdir4(path7.dirname(abs), { recursive: true });
1532
- await writeFile10(abs, scaffold.content, "utf8");
1533
- written = true;
1570
+ let proposeCommand = scaffolds[0].proposeCommand;
1571
+ if (scaffolds.length > 1) {
1572
+ proposeCommand = buildProposeCommand(lesson, scaffolds.map((s) => s.runCommand).join(" && "));
1573
+ scaffolds = groups.map(
1574
+ (g) => scaffoldPostIncidentTest(lesson, {
1575
+ framework: frameworkFor(g.framework),
1576
+ baseDir: g.baseDir,
1577
+ proposeCommandOverride: proposeCommand
1578
+ })
1579
+ );
1580
+ }
1581
+ const results = [];
1582
+ for (const scaffold of scaffolds) {
1583
+ const abs = path7.isAbsolute(scaffold.relPath) ? scaffold.relPath : path7.resolve(ctx.paths.root, scaffold.relPath);
1584
+ let written = false;
1585
+ let alreadyExists = false;
1586
+ if (input.write) {
1587
+ if (existsSync17(abs)) {
1588
+ alreadyExists = true;
1589
+ } else {
1590
+ await mkdir4(path7.dirname(abs), { recursive: true });
1591
+ await writeFile10(abs, scaffold.content, "utf8");
1592
+ written = true;
1593
+ }
1534
1594
  }
1595
+ results.push({
1596
+ framework: scaffold.framework,
1597
+ path: scaffold.relPath,
1598
+ run_command: scaffold.runCommand,
1599
+ content: scaffold.content,
1600
+ written,
1601
+ already_exists: alreadyExists
1602
+ });
1535
1603
  }
1604
+ const first = results[0];
1605
+ const anyExisting = results.some((r) => r.already_exists);
1536
1606
  return {
1537
1607
  ok: true,
1538
1608
  memory_id: input.memory_id,
1539
- framework,
1540
- path: scaffold.relPath,
1541
- run_command: scaffold.runCommand,
1542
- propose_command: scaffold.proposeCommand,
1543
- content: scaffold.content,
1544
- written,
1545
- already_exists: alreadyExists,
1546
- notice: alreadyExists ? "File already exists \u2014 not overwritten. Delete it or pass out_path to write elsewhere." : "PENDING test scaffolded. Fill in the assertion (RED on the incident, GREEN once fixed), run it, then arm it with propose_command \u2014 propose_sensor stays the sole validated writer."
1609
+ framework: first.framework,
1610
+ path: first.path,
1611
+ run_command: first.run_command,
1612
+ propose_command: proposeCommand,
1613
+ content: first.content,
1614
+ written: first.written,
1615
+ already_exists: first.already_exists,
1616
+ ...results.length > 1 ? { scaffolds: results } : {},
1617
+ notice: (results.length > 1 ? `Lesson spans ${results.length} packages \u2014 one pending test per owning package; ONE propose_command arms them all (chained oracle). ` : "") + (anyExisting ? "Some file(s) already exist \u2014 not overwritten. Delete them or pass out_path to write elsewhere." : "PENDING test scaffolded. Fill in the assertion (RED on the incident, GREEN once fixed), run it, then arm it with propose_command \u2014 propose_sensor stays the sole validated writer.")
1547
1618
  };
1548
1619
  }
1549
1620
 
@@ -2810,7 +2881,7 @@ function oneLine(value) {
2810
2881
  return value.replace(/\s+/g, " ").replace(/"/g, '\\"').trim().slice(0, 120);
2811
2882
  }
2812
2883
  function serverVersion() {
2813
- return true ? "0.38.0" : "dev";
2884
+ return true ? "0.39.1" : "dev";
2814
2885
  }
2815
2886
 
2816
2887
  // src/tools/code-map.ts
@@ -4238,7 +4309,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
4238
4309
  // src/server.ts
4239
4310
  import { hasRecentBriefingMarker, loadConfigSync } from "@hivelore/core";
4240
4311
  var SERVER_NAME = "hivelore";
4241
- var SERVER_VERSION = "0.38.0";
4312
+ var SERVER_VERSION = "0.39.1";
4242
4313
  function jsonResult(data) {
4243
4314
  return {
4244
4315
  content: [
@@ -5194,6 +5265,7 @@ export {
5194
5265
  codeSearch,
5195
5266
  createHaiveServer,
5196
5267
  detectTestFrameworkForPaths,
5268
+ detectTestFrameworksForAnchors,
5197
5269
  getAllowedToolsForProfile,
5198
5270
  getBriefing,
5199
5271
  getRecap,