@hiveai/mcp 0.9.31 → 0.10.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/index.js CHANGED
@@ -1076,6 +1076,7 @@ import { existsSync as existsSync15 } from "fs";
1076
1076
  import path6 from "path";
1077
1077
  import {
1078
1078
  buildFrontmatter as buildFrontmatter3,
1079
+ isLikelyGuessable,
1079
1080
  memoryFilePath as memoryFilePath3,
1080
1081
  serializeMemory as serializeMemory7
1081
1082
  } from "@hiveai/core";
@@ -1088,12 +1089,25 @@ var MemObserveInputSchema = {
1088
1089
  scope: z15.enum(["personal", "team", "module"]).default("team").describe("Visibility scope \u2014 defaults to team since discoveries benefit everyone"),
1089
1090
  module: z15.string().optional().describe("Module name (required when scope=module)"),
1090
1091
  tags: z15.array(z15.string()).default([]).describe("Tags for filtering"),
1091
- author: z15.string().optional().describe("Author handle or email")
1092
+ author: z15.string().optional().describe("Author handle or email"),
1093
+ force: z15.boolean().default(false).describe(
1094
+ "Save even if the observation looks like generic, guessable knowledge. By default, low-specificity observations (things a capable model already knows) are SKIPPED to keep the corpus high-signal \u2014 only unguessable, team-specific discoveries are worth storing."
1095
+ )
1092
1096
  };
1093
1097
  async function memObserve(input, ctx) {
1094
1098
  if (!existsSync15(ctx.paths.haiveDir)) {
1095
1099
  throw new Error(`No .ai/ directory at ${ctx.paths.root}. Run 'haive init' first.`);
1096
1100
  }
1101
+ const signalText = [input.what, input.impact, input.fix ?? ""].join(" ");
1102
+ if (!input.force && isLikelyGuessable(signalText)) {
1103
+ return {
1104
+ id: "",
1105
+ scope: input.scope,
1106
+ file_path: "",
1107
+ skipped: true,
1108
+ reason: "Observation looks like generic, guessable knowledge (low specificity) \u2014 not saved. Capture only arbitrary, team-specific facts (exact names, values, formats). Pass force=true to override."
1109
+ };
1110
+ }
1097
1111
  const slug = input.what.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().split(/\s+/).slice(0, 6).join("-");
1098
1112
  const anchorPaths = input.where.split(/[,\n]/).map((s) => s.trim()).filter(Boolean);
1099
1113
  const baseFm = buildFrontmatter3({
@@ -1400,6 +1414,7 @@ import {
1400
1414
  getUsage as getUsage5,
1401
1415
  inferModulesFromPaths as inferModulesFromPaths2,
1402
1416
  isGlobPath,
1417
+ isRetiredMemory,
1403
1418
  isAutoPromoteEligible,
1404
1419
  isDecaying,
1405
1420
  isStackPackSeed,
@@ -1414,6 +1429,8 @@ import {
1414
1429
  queryCodeMap,
1415
1430
  resolveBriefingBudget,
1416
1431
  serializeMemory as serializeMemory9,
1432
+ specificityScore,
1433
+ GUESSABLE_THRESHOLD,
1417
1434
  tokenizeQuery as tokenizeQuery2,
1418
1435
  trackReads as trackReads3,
1419
1436
  truncateToTokens,
@@ -1484,6 +1501,7 @@ async function getBriefing(input, ctx) {
1484
1501
  const s = memory.frontmatter.status;
1485
1502
  if (s === "rejected" || s === "deprecated") return false;
1486
1503
  if (!input.include_stale && s === "stale") return false;
1504
+ if (!input.include_stale && isRetiredMemory(memory.frontmatter, memory.body)) return false;
1487
1505
  if (memory.frontmatter.type === "session_recap") return false;
1488
1506
  return true;
1489
1507
  });
@@ -1839,6 +1857,14 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
1839
1857
  const memoriesEmpty = outputMemories.length === 0;
1840
1858
  const hasMemoriesDir = existsSync18(ctx.paths.memoriesDir);
1841
1859
  const isColdStart = isTemplateContext && memoriesEmpty && !lastSession && !autoContextGenerated;
1860
+ const hasUnguessableSignal = outputMemories.some(
1861
+ (m) => (m.priority === "must_read" || m.priority === "useful") && specificityScore(m.body) >= GUESSABLE_THRESHOLD
1862
+ );
1863
+ const briefingValueLow = !hasUnguessableSignal;
1864
+ const adaptiveConfig = await loadConfig3(ctx.paths);
1865
+ const bootstrapUnfilled = /Auto-generated by `haive init/i.test(projectContextRaw) && (projectContextRaw.match(/TODO —/g)?.length ?? 0) >= 2;
1866
+ const contextIsInferable = isTemplateContext || autoContextGenerated || bootstrapUnfilled;
1867
+ const adaptiveTrim = adaptiveConfig.adaptiveBriefing !== false && briefingValueLow && contextIsInferable;
1842
1868
  const hints = [];
1843
1869
  if (isColdStart) {
1844
1870
  hints.push(
@@ -1871,6 +1897,11 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
1871
1897
  );
1872
1898
  }
1873
1899
  }
1900
+ if (adaptiveTrim) {
1901
+ hints.push(
1902
+ "No team-specific policy matched these files/task \u2014 nothing here a capable model can't infer. The auto-generated project context was trimmed to keep this briefing near-zero-cost; proceed with normal Read/Grep."
1903
+ );
1904
+ }
1874
1905
  if (existsSync18(ctx.paths.haiveDir)) {
1875
1906
  await writeBriefingMarker(ctx.paths, {
1876
1907
  sessionId: process.env.HAIVE_SESSION_ID,
@@ -1886,7 +1917,12 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
1886
1917
  search_mode: searchMode,
1887
1918
  inferred_modules: inferred,
1888
1919
  ...lastSession ? { last_session: lastSession } : {},
1889
- project_context: projectContextRaw || autoContextGenerated ? {
1920
+ project_context: adaptiveTrim ? {
1921
+ content: "(adaptive briefing: auto-generated context omitted \u2014 no team-specific policy matched, so a capable model needs nothing extra here)",
1922
+ truncated: false,
1923
+ ...isTemplateContext && !autoContextGenerated ? { is_template: true } : {},
1924
+ ...autoContextGenerated ? { auto_generated: true } : {}
1925
+ } : projectContextRaw || autoContextGenerated ? {
1890
1926
  content: projectSlice.text,
1891
1927
  truncated: projectSlice.truncated,
1892
1928
  ...isTemplateContext && !autoContextGenerated ? { is_template: true } : {},
@@ -1900,6 +1936,7 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
1900
1936
  decay_warnings: decayWarnings,
1901
1937
  setup_warnings: setupWarnings,
1902
1938
  ...isColdStart ? { low_value: true } : {},
1939
+ briefing_value: briefingValueLow ? "low" : "high",
1903
1940
  ...hints.length > 0 ? { hints } : {},
1904
1941
  estimated_tokens: totalTokens,
1905
1942
  budget: {
@@ -2408,6 +2445,7 @@ import { existsSync as existsSync22 } from "fs";
2408
2445
  import {
2409
2446
  deriveConfidence as deriveConfidence6,
2410
2447
  getUsage as getUsage7,
2448
+ isRetiredMemory as isRetiredMemory2,
2411
2449
  loadMemoriesFromDir as loadMemoriesFromDir17,
2412
2450
  loadUsageIndex as loadUsageIndex9,
2413
2451
  literalMatchesAnyToken as literalMatchesAnyToken3,
@@ -2425,6 +2463,9 @@ var AntiPatternsCheckInputSchema = {
2425
2463
  limit: z24.number().int().positive().max(20).default(8).describe("Cap on returned warnings."),
2426
2464
  semantic: z24.boolean().default(true).describe(
2427
2465
  "When true, also use semantic search (requires @hiveai/embeddings + memory index) to find related anti-patterns."
2466
+ ),
2467
+ min_semantic_score: z24.number().min(0).max(1).default(0.45).describe(
2468
+ "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."
2428
2469
  )
2429
2470
  };
2430
2471
  var CODE_STOPWORDS = /* @__PURE__ */ new Set([
@@ -2475,8 +2516,12 @@ var CODE_STOPWORDS = /* @__PURE__ */ new Set([
2475
2516
  "console"
2476
2517
  ]);
2477
2518
  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));
2519
+ const lines = diff.split("\n");
2520
+ const looksLikeDiff = lines.some((l) => /^[+-]/.test(l));
2521
+ const addedOnly = looksLikeDiff ? lines.filter((l) => l.startsWith("+") && !l.startsWith("+++")).join("\n") : diff;
2522
+ const source = addedOnly.trim().length > 0 ? addedOnly : diff;
2523
+ const wsTokens = tokenizeQuery3(source);
2524
+ const wordTokens = source.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 4 && !CODE_STOPWORDS.has(t));
2480
2525
  return [.../* @__PURE__ */ new Set([...wsTokens, ...wordTokens])];
2481
2526
  }
2482
2527
  async function antiPatternsCheck(input, ctx) {
@@ -2491,11 +2536,12 @@ async function antiPatternsCheck(input, ctx) {
2491
2536
  return { scanned: 0, warnings: [], notice: "No .ai/memories directory \u2014 nothing to check against." };
2492
2537
  }
2493
2538
  const all = await loadMemoriesFromDir17(ctx.paths.memoriesDir);
2539
+ const minSemanticScore = input.min_semantic_score ?? 0.45;
2494
2540
  const negative = all.filter(({ memory }) => {
2495
2541
  const t = memory.frontmatter.type;
2496
2542
  if (t !== "attempt" && t !== "gotcha") return false;
2497
2543
  const s = memory.frontmatter.status;
2498
- return s !== "rejected" && s !== "deprecated" && s !== "stale";
2544
+ return s !== "rejected" && s !== "deprecated" && s !== "stale" && !isRetiredMemory2(memory.frontmatter, memory.body);
2499
2545
  });
2500
2546
  if (negative.length === 0) {
2501
2547
  return { scanned: 0, warnings: [], notice: "No attempt/gotcha memories found yet." };
@@ -2549,6 +2595,7 @@ async function antiPatternsCheck(input, ctx) {
2549
2595
  const negativeIds = new Set(negative.map(({ memory }) => memory.frontmatter.id));
2550
2596
  for (const hit of result.hits) {
2551
2597
  if (!negativeIds.has(hit.id)) continue;
2598
+ if (hit.score < minSemanticScore && !seen.has(hit.id)) continue;
2552
2599
  const found = negative.find(({ memory }) => memory.frontmatter.id === hit.id);
2553
2600
  if (found) upsert(found.memory.frontmatter, found.memory.body, "semantic", hit.score);
2554
2601
  }
@@ -3827,7 +3874,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
3827
3874
  // src/server.ts
3828
3875
  import { loadConfigSync } from "@hiveai/core";
3829
3876
  var SERVER_NAME = "haive";
3830
- var SERVER_VERSION = "0.9.31";
3877
+ var SERVER_VERSION = "0.10.1";
3831
3878
  function jsonResult(data) {
3832
3879
  return {
3833
3880
  content: [
@@ -3866,7 +3913,6 @@ var MAINTENANCE_PROFILE_TOOLS = [
3866
3913
  "mem_delete",
3867
3914
  "mem_diff",
3868
3915
  "get_recap",
3869
- "code_search",
3870
3916
  "anti_patterns_check",
3871
3917
  "mem_distill",
3872
3918
  "mem_timeline",