@hiveai/mcp 0.9.29 → 0.9.30

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
@@ -2427,6 +2427,58 @@ var AntiPatternsCheckInputSchema = {
2427
2427
  "When true, also use semantic search (requires @hiveai/embeddings + memory index) to find related anti-patterns."
2428
2428
  )
2429
2429
  };
2430
+ var CODE_STOPWORDS = /* @__PURE__ */ new Set([
2431
+ "import",
2432
+ "export",
2433
+ "function",
2434
+ "return",
2435
+ "const",
2436
+ "let",
2437
+ "var",
2438
+ "class",
2439
+ "public",
2440
+ "private",
2441
+ "protected",
2442
+ "static",
2443
+ "this",
2444
+ "true",
2445
+ "false",
2446
+ "null",
2447
+ "undefined",
2448
+ "void",
2449
+ "async",
2450
+ "await",
2451
+ "from",
2452
+ "type",
2453
+ "interface",
2454
+ "extends",
2455
+ "implements",
2456
+ "number",
2457
+ "string",
2458
+ "boolean",
2459
+ "value",
2460
+ "default",
2461
+ "case",
2462
+ "break",
2463
+ "continue",
2464
+ "throw",
2465
+ "catch",
2466
+ "finally",
2467
+ "else",
2468
+ "while",
2469
+ "for",
2470
+ "new",
2471
+ "super",
2472
+ "yield",
2473
+ "module",
2474
+ "require",
2475
+ "console"
2476
+ ]);
2477
+ function tokenizeDiffForLiteral(diff) {
2478
+ const wsTokens = tokenizeQuery3(diff);
2479
+ const wordTokens = diff.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 4 && !CODE_STOPWORDS.has(t));
2480
+ return [.../* @__PURE__ */ new Set([...wsTokens, ...wordTokens])];
2481
+ }
2430
2482
  async function antiPatternsCheck(input, ctx) {
2431
2483
  if (!input.diff && input.paths.length === 0) {
2432
2484
  return {
@@ -2480,7 +2532,7 @@ async function antiPatternsCheck(input, ctx) {
2480
2532
  }
2481
2533
  }
2482
2534
  if (input.diff) {
2483
- const tokens = tokenizeQuery3(input.diff);
2535
+ const tokens = tokenizeDiffForLiteral(input.diff);
2484
2536
  if (tokens.length > 0) {
2485
2537
  for (const { memory } of negative) {
2486
2538
  if (literalMatchesAnyToken3(memory, tokens)) {
@@ -2968,7 +3020,10 @@ var PreCommitCheckInputSchema = {
2968
3020
  block_on: z28.enum(["any", "high-confidence", "never"]).default("high-confidence").describe(
2969
3021
  "When to set should_block=true: 'any' = any warning blocks; 'high-confidence' = only warnings from authoritative/trusted memories block; 'never' = report only, never block."
2970
3022
  ),
2971
- semantic: z28.boolean().default(true).describe("Enable semantic search in anti_patterns_check (requires embeddings index).")
3023
+ semantic: z28.boolean().default(true).describe("Enable semantic search in anti_patterns_check (requires embeddings index)."),
3024
+ anchored_blocks: z28.boolean().default(false).describe(
3025
+ "When true, ALSO block a high-confidence anti-pattern (attempt/gotcha) that is anchored to a touched file AND corroborated by the diff (literal token overlap, or semantic >= 0.45) \u2014 not just very strong semantic matches. Powers the 'anchored' enforcement gate. Config/docs-only commits are still downgraded. Default false preserves the soft, semantic-only blocking behavior."
3026
+ )
2972
3027
  };
2973
3028
  async function preCommitCheck(input, ctx) {
2974
3029
  if (!input.diff && input.paths.length === 0) {
@@ -2993,7 +3048,7 @@ async function preCommitCheck(input, ctx) {
2993
3048
  const filesTouching = new Set(relevantMatches.map((m) => m.id));
2994
3049
  const staleHits = verifyResult.results.filter((r) => r.stale && filesTouching.has(r.id));
2995
3050
  const blockOn = input.block_on;
2996
- const classifiedWarnings = apResult.warnings.map((warning) => classifyWarning(warning, input.paths));
3051
+ const classifiedWarnings = apResult.warnings.map((warning) => classifyWarning(warning, input.paths, input.anchored_blocks));
2997
3052
  const blockingWarnings = classifiedWarnings.filter((w) => w.level === "blocking");
2998
3053
  const reviewWarnings = classifiedWarnings.filter((w) => w.level === "review");
2999
3054
  const infoWarnings = classifiedWarnings.filter((w) => w.level === "info");
@@ -3033,7 +3088,7 @@ async function preCommitCheck(input, ctx) {
3033
3088
  })
3034
3089
  };
3035
3090
  }
3036
- function classifyWarning(warning, paths) {
3091
+ function classifyWarning(warning, paths, anchoredBlocks = false) {
3037
3092
  const affectedFiles = paths.filter((p) => !p.startsWith(".ai/.usage/"));
3038
3093
  const repairCommand = repairCommandForWarning(warning, affectedFiles);
3039
3094
  const fileDowngrade = fileTypeDowngradeReason(warning, affectedFiles);
@@ -3058,6 +3113,15 @@ function classifyWarning(warning, paths) {
3058
3113
  const hasSemantic = warning.reasons.includes("semantic");
3059
3114
  const semanticScore = warning.semantic_score ?? 0;
3060
3115
  const highConfidence = warning.confidence === "authoritative" || warning.confidence === "trusted";
3116
+ if (anchoredBlocks && highConfidence && warning.reasons.includes("anchor") && (warning.reasons.includes("literal") || hasSemantic && semanticScore >= 0.45)) {
3117
+ return {
3118
+ ...warning,
3119
+ level: "blocking",
3120
+ rationale: "high-confidence anti-pattern anchored to a touched file and corroborated by the diff (anchored gate)",
3121
+ affected_files: affectedFiles,
3122
+ repair_command: repairCommand
3123
+ };
3124
+ }
3061
3125
  if (hasSemantic && semanticScore >= 0.45 || highConfidence && warning.reasons.includes("anchor") && warning.reasons.includes("literal")) {
3062
3126
  return {
3063
3127
  ...warning,
@@ -3763,7 +3827,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
3763
3827
  // src/server.ts
3764
3828
  import { loadConfigSync } from "@hiveai/core";
3765
3829
  var SERVER_NAME = "haive";
3766
- var SERVER_VERSION = "0.9.29";
3830
+ var SERVER_VERSION = "0.9.30";
3767
3831
  function jsonResult(data) {
3768
3832
  return {
3769
3833
  content: [