@hivelore/mcp 0.43.2 → 0.46.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/server.d.ts CHANGED
@@ -365,6 +365,7 @@ interface AntiPatternsCheckInput {
365
365
  limit: number;
366
366
  semantic: boolean;
367
367
  min_semantic_score?: number;
368
+ track?: boolean;
368
369
  }
369
370
  interface AntiPatternsWarning {
370
371
  id: string;
@@ -694,6 +695,7 @@ declare const ScaffoldTestInputSchema: {
694
695
  memory_id: z.ZodString;
695
696
  framework: z.ZodOptional<z.ZodEnum<["vitest", "jest", "pytest", "gotest"]>>;
696
697
  out_path: z.ZodOptional<z.ZodString>;
698
+ red_ref: z.ZodOptional<z.ZodString>;
697
699
  write: z.ZodDefault<z.ZodBoolean>;
698
700
  };
699
701
  type ScaffoldTestInput = {
@@ -834,5 +836,6 @@ declare function printHaiveMcpVersion(): void;
834
836
  declare function runHaiveMcpStdio(options: {
835
837
  root?: string;
836
838
  }): Promise<void>;
839
+ declare function writeMcpRuntimeMarker(context: HaiveContext): Promise<void>;
837
840
 
838
- export { type AnchorFrameworkGroup, type AntiPatternsCheckInput, type AntiPatternsCheckOutput, type AstMatch, type AstScanResult, 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, astEngineAvailable, astLangForPath, codeMapTool, codeSearch, createHaiveServer, detectTestFrameworkForPaths, detectTestFrameworksForAnchors, getAllowedToolsForProfile, getBriefing, getRecap, memConflictCandidates, memDistill, memRelevantTo, memResolveProject, memSuggestTopic, memTimeline, memTried, parseMcpCliArgs, preCommitCheck, printHaiveMcpVersion, proposeSensor, readPresumedCorrectTargets, runAstPattern, runAstSensorOnContent, runHaiveMcpStdio, scaffoldTest };
841
+ export { type AnchorFrameworkGroup, type AntiPatternsCheckInput, type AntiPatternsCheckOutput, type AstMatch, type AstScanResult, 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, astEngineAvailable, astLangForPath, codeMapTool, codeSearch, createHaiveServer, detectTestFrameworkForPaths, detectTestFrameworksForAnchors, getAllowedToolsForProfile, getBriefing, getRecap, memConflictCandidates, memDistill, memRelevantTo, memResolveProject, memSuggestTopic, memTimeline, memTried, parseMcpCliArgs, preCommitCheck, printHaiveMcpVersion, proposeSensor, readPresumedCorrectTargets, runAstPattern, runAstSensorOnContent, runHaiveMcpStdio, scaffoldTest, writeMcpRuntimeMarker };
package/dist/server.js CHANGED
@@ -1,6 +1,8 @@
1
1
  // src/server.ts
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { mkdir as mkdir8, writeFile as writeFile15 } from "fs/promises";
5
+ import path15 from "path";
4
6
 
5
7
  // src/context.ts
6
8
  import { findProjectRoot, resolveHaivePaths } from "@hivelore/core";
@@ -1791,15 +1793,24 @@ async function memTried(input, ctx) {
1791
1793
  import { existsSync as existsSync17, statSync } from "fs";
1792
1794
  import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile10 } from "fs/promises";
1793
1795
  import path8 from "path";
1796
+ import { execFile } from "child_process";
1797
+ import { promisify } from "util";
1794
1798
  import { z as z17 } from "zod";
1795
1799
  import {
1796
1800
  buildProposeCommand,
1801
+ incidentHintsFromDiff,
1797
1802
  loadMemoriesFromDir as loadMemoriesFromDir14,
1798
1803
  normalizeFramework,
1799
1804
  parseLessonFields,
1800
1805
  pickTestFramework,
1801
1806
  scaffoldPostIncidentTest
1802
1807
  } from "@hivelore/core";
1808
+ var execFileAsync = promisify(execFile);
1809
+ async function gitDiffText(root, redRef, paths) {
1810
+ const args = ["diff", redRef, "HEAD", "--", ...paths];
1811
+ const { stdout } = await execFileAsync("git", args, { cwd: root, maxBuffer: 64 * 1024 * 1024 });
1812
+ return stdout;
1813
+ }
1803
1814
  var PY_SIGNALS = ["pyproject.toml", "setup.py", "pytest.ini", "requirements.txt", "tox.ini"];
1804
1815
  async function detectForAnchor(root, rel) {
1805
1816
  let dir = path8.resolve(root, rel);
@@ -1854,6 +1865,9 @@ var ScaffoldTestInputSchema = {
1854
1865
  memory_id: z17.string().min(1).describe("Id of the attempt/gotcha lesson to scaffold a post-incident test from."),
1855
1866
  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."),
1856
1867
  out_path: z17.string().optional().describe("Override the generated test file path (repo-relative)."),
1868
+ red_ref: z17.string().optional().describe(
1869
+ "Pre-fix incident commit/ref. When set, the scaffold names the symbols the fix (<red_ref>..HEAD) touched within the lesson's anchor scope and pre-fills the example around them, so the assertion is a targeted edit rather than a blank page. A bad ref falls back to the generic template."
1870
+ ),
1857
1871
  write: z17.boolean().default(true).describe("Write the file to disk (default). false = return the content for preview without writing.")
1858
1872
  };
1859
1873
  async function scaffoldTest(input, ctx) {
@@ -1867,13 +1881,23 @@ async function scaffoldTest(input, ctx) {
1867
1881
  const groups = input.out_path ? allGroups.slice(0, 1) : allGroups;
1868
1882
  const frameworkFor = (detected) => input.framework ? normalizeFramework(input.framework) ?? detected : detected;
1869
1883
  const fields = parseLessonFields(found.memory.body);
1884
+ let incidentHints;
1885
+ if (input.red_ref) {
1886
+ try {
1887
+ const diff = await gitDiffText(ctx.paths.root, input.red_ref, anchorPaths);
1888
+ const hints = incidentHintsFromDiff(diff, { redRef: input.red_ref });
1889
+ if (hints.changedSymbols.length > 0 || hints.changedFiles.length > 0) incidentHints = hints;
1890
+ } catch {
1891
+ }
1892
+ }
1870
1893
  const lesson = {
1871
1894
  memoryId: input.memory_id,
1872
1895
  title: fields.title || input.memory_id,
1873
1896
  whyFailed: fields.whyFailed,
1874
1897
  instead: fields.instead,
1875
1898
  incident: found.memory.frontmatter.sensor?.incident,
1876
- paths: anchorPaths
1899
+ paths: anchorPaths,
1900
+ incidentHints
1877
1901
  };
1878
1902
  let scaffolds = groups.map(
1879
1903
  (g) => scaffoldPostIncidentTest(lesson, { framework: frameworkFor(g.framework), outPath: input.out_path, baseDir: g.baseDir })
@@ -3197,7 +3221,7 @@ function oneLine(value) {
3197
3221
  return value.replace(/\s+/g, " ").replace(/"/g, '\\"').trim().slice(0, 120);
3198
3222
  }
3199
3223
  function serverVersion() {
3200
- return true ? "0.43.2" : "dev";
3224
+ return true ? "0.46.0" : "dev";
3201
3225
  }
3202
3226
 
3203
3227
  // src/tools/code-map.ts
@@ -3483,7 +3507,8 @@ var AntiPatternsCheckInputSchema = {
3483
3507
  ),
3484
3508
  min_semantic_score: z26.number().min(0).max(1).default(0.45).describe(
3485
3509
  "Minimum cosine score for semantic-only anti-pattern hits. Anchor/literal matches still surface. Default 0.45 keeps broad, weakly-related memories out of review noise."
3486
- )
3510
+ ),
3511
+ track: z26.boolean().default(true).describe("Record real prevention outcomes. Set false for eval/selftest probes so synthetic cases never inflate ROI.")
3487
3512
  };
3488
3513
  function tokenizeDiffForLiteral(diff) {
3489
3514
  const lines = diff.split("\n");
@@ -3511,6 +3536,7 @@ function isHaiveOwnedPath(p) {
3511
3536
  if (/^\.github\/workflows\/haive-.*\.ya?ml$/.test(p)) return true;
3512
3537
  return false;
3513
3538
  }
3539
+ var MAX_FUZZY_SCAN_LINES = 2e4;
3514
3540
  var TEST_PATH_RE = /(?:^|\/)(?:tests?|__tests__|__mocks__|e2e|fixtures)\/|\.(?:test|spec)\.[cm]?[jt]sx?$/i;
3515
3541
  function isTestPath(p) {
3516
3542
  return TEST_PATH_RE.test(p);
@@ -3521,7 +3547,7 @@ function stripTestHunks(diff) {
3521
3547
  let block = [];
3522
3548
  let keep = true;
3523
3549
  const flush = () => {
3524
- if (keep) out.push(...block);
3550
+ if (keep) for (const l of block) out.push(l);
3525
3551
  block = [];
3526
3552
  keep = true;
3527
3553
  };
@@ -3542,7 +3568,7 @@ function stripAiDirHunks(diff) {
3542
3568
  let block = [];
3543
3569
  let keep = true;
3544
3570
  const flush = () => {
3545
- if (keep) out.push(...block);
3571
+ if (keep) for (const l of block) out.push(l);
3546
3572
  block = [];
3547
3573
  keep = true;
3548
3574
  };
@@ -3613,7 +3639,10 @@ async function antiPatternsCheck(input, ctx) {
3613
3639
  }
3614
3640
  }
3615
3641
  const scanDiff = input.diff ? stripTestHunks(stripAiDirHunks(input.diff)) : input.diff;
3616
- if (scanDiff) {
3642
+ const scanAddedLineCount = scanDiff ? addedLinesFromDiff(scanDiff).split("\n").length : 0;
3643
+ const fuzzyScanTooLarge = scanAddedLineCount > MAX_FUZZY_SCAN_LINES;
3644
+ const notice = fuzzyScanTooLarge ? `Diff is very large (${scanAddedLineCount.toLocaleString()} added lines) \u2014 literal/semantic corroboration skipped for performance; anchored lessons and deterministic sensors were still evaluated in full. If this staged node_modules or a build artifact, unstage it.` : void 0;
3645
+ if (scanDiff && !fuzzyScanTooLarge) {
3617
3646
  const tokens = tokenizeDiffForLiteral(scanDiff);
3618
3647
  const added = addedLinesFromDiff(scanDiff);
3619
3648
  const addedText = added.trim().length > 0 ? added : scanDiff;
@@ -3648,7 +3677,7 @@ async function antiPatternsCheck(input, ctx) {
3648
3677
  }
3649
3678
  }
3650
3679
  }
3651
- if (input.semantic && scanDiff) {
3680
+ if (input.semantic && scanDiff && !fuzzyScanTooLarge) {
3652
3681
  try {
3653
3682
  const mod = await import("@hivelore/embeddings");
3654
3683
  const added = addedLinesFromDiff(scanDiff);
@@ -3676,10 +3705,13 @@ async function antiPatternsCheck(input, ctx) {
3676
3705
  }).slice(0, input.limit);
3677
3706
  const isHardBlockCatch = (w) => w.reasons.includes("sensor");
3678
3707
  const strongCatches = warnings.filter(isHardBlockCatch);
3679
- await recordPreventionHits(ctx.paths, strongCatches.map((w) => w.id), "anti-pattern");
3708
+ if (input.track !== false) {
3709
+ await recordPreventionHits(ctx.paths, strongCatches.map((w) => w.id), "anti-pattern");
3710
+ }
3680
3711
  return {
3681
3712
  scanned: negative.length,
3682
- warnings
3713
+ warnings,
3714
+ ...notice ? { notice } : {}
3683
3715
  };
3684
3716
  }
3685
3717
 
@@ -3907,6 +3939,7 @@ async function preCommitCheck(input, ctx) {
3907
3939
  relevant_memories: relevant_memories.length,
3908
3940
  stale_anchors: staleHits.length
3909
3941
  },
3942
+ ...apResult.notice ? { notice: apResult.notice } : {},
3910
3943
  warnings: classifiedWarnings,
3911
3944
  relevant_memories,
3912
3945
  stale_anchors: staleHits.map((r) => {
@@ -4458,13 +4491,14 @@ Main code areas detected: ${areas}
4458
4491
  import { z as z35 } from "zod";
4459
4492
  var PostTaskArgsSchema = {
4460
4493
  task_summary: z35.string().optional().describe("One sentence describing what you just did"),
4461
- files_touched: z35.array(z35.string()).optional().describe("Files you created or modified during the task")
4494
+ files_touched: z35.string().optional().describe("Files you created or modified during the task, as CSV or a JSON array string")
4462
4495
  };
4463
4496
  function postTaskPrompt(args, ctx) {
4464
4497
  const taskLine = args.task_summary ? `
4465
4498
  Task just completed: **${args.task_summary}**` : "";
4466
- const filesLine = args.files_touched && args.files_touched.length > 0 ? `
4467
- Files touched: ${args.files_touched.map((f) => `\`${f}\``).join(", ")}` : "";
4499
+ const filesTouched = parsePromptFilesTouched(args.files_touched);
4500
+ const filesLine = filesTouched.length > 0 ? `
4501
+ Files touched: ${filesTouched.map((f) => `\`${f}\``).join(", ")}` : "";
4468
4502
  const text = `You have just finished a task. Before closing this session, take 60 seconds to capture what you learned.
4469
4503
  ${taskLine}${filesLine}
4470
4504
 
@@ -4553,6 +4587,20 @@ When done, respond with a brief summary: "Saved N memories: [list of IDs]. Sessi
4553
4587
  ]
4554
4588
  };
4555
4589
  }
4590
+ function parsePromptFilesTouched(input) {
4591
+ const raw = input?.trim();
4592
+ if (!raw) return [];
4593
+ if (raw.startsWith("[")) {
4594
+ try {
4595
+ const parsed = JSON.parse(raw);
4596
+ if (Array.isArray(parsed)) {
4597
+ return parsed.filter((value) => typeof value === "string").map((value) => value.trim()).filter(Boolean);
4598
+ }
4599
+ } catch {
4600
+ }
4601
+ }
4602
+ return raw.split(",").map((value) => value.trim()).filter(Boolean);
4603
+ }
4556
4604
 
4557
4605
  // src/prompts/import-docs.ts
4558
4606
  import { z as z36 } from "zod";
@@ -4626,7 +4674,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
4626
4674
  // src/server.ts
4627
4675
  import { hasRecentBriefingMarker, loadConfigSync } from "@hivelore/core";
4628
4676
  var SERVER_NAME = "hivelore";
4629
- var SERVER_VERSION = "0.43.2";
4677
+ var SERVER_VERSION = "0.46.0";
4630
4678
  function jsonResult(data) {
4631
4679
  return {
4632
4680
  content: [
@@ -5565,11 +5613,22 @@ function printHaiveMcpVersion() {
5565
5613
  }
5566
5614
  async function runHaiveMcpStdio(options) {
5567
5615
  const { server, context } = createHaiveServer({ root: options.root, env: process.env });
5616
+ await writeMcpRuntimeMarker(context).catch(() => {
5617
+ });
5568
5618
  console.error(
5569
5619
  `[haive-mcp] starting server v${SERVER_VERSION} (project root: ${context.paths.root})`
5570
5620
  );
5571
5621
  await server.connect(new StdioServerTransport());
5572
5622
  }
5623
+ async function writeMcpRuntimeMarker(context) {
5624
+ await mkdir8(context.paths.runtimeDir, { recursive: true });
5625
+ await writeFile15(path15.join(context.paths.runtimeDir, "mcp-server.json"), JSON.stringify({
5626
+ version: SERVER_VERSION,
5627
+ pid: process.pid,
5628
+ started_at: (/* @__PURE__ */ new Date()).toISOString(),
5629
+ command: "hivelore mcp --stdio"
5630
+ }, null, 2), "utf8");
5631
+ }
5573
5632
  export {
5574
5633
  ENFORCEMENT_PROFILE_TOOLS,
5575
5634
  EXPERIMENTAL_PROFILE_TOOLS,
@@ -5603,6 +5662,7 @@ export {
5603
5662
  runAstPattern,
5604
5663
  runAstSensorOnContent,
5605
5664
  runHaiveMcpStdio,
5606
- scaffoldTest
5665
+ scaffoldTest,
5666
+ writeMcpRuntimeMarker
5607
5667
  };
5608
5668
  //# sourceMappingURL=server.js.map