@hiveai/mcp 0.9.31 → 0.10.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/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({
@@ -1414,6 +1428,8 @@ import {
1414
1428
  queryCodeMap,
1415
1429
  resolveBriefingBudget,
1416
1430
  serializeMemory as serializeMemory9,
1431
+ specificityScore,
1432
+ GUESSABLE_THRESHOLD,
1417
1433
  tokenizeQuery as tokenizeQuery2,
1418
1434
  trackReads as trackReads3,
1419
1435
  truncateToTokens,
@@ -1839,6 +1855,14 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
1839
1855
  const memoriesEmpty = outputMemories.length === 0;
1840
1856
  const hasMemoriesDir = existsSync18(ctx.paths.memoriesDir);
1841
1857
  const isColdStart = isTemplateContext && memoriesEmpty && !lastSession && !autoContextGenerated;
1858
+ const hasUnguessableSignal = outputMemories.some(
1859
+ (m) => (m.priority === "must_read" || m.priority === "useful") && specificityScore(m.body) >= GUESSABLE_THRESHOLD
1860
+ );
1861
+ const briefingValueLow = !hasUnguessableSignal;
1862
+ const adaptiveConfig = await loadConfig3(ctx.paths);
1863
+ const bootstrapUnfilled = /Auto-generated by `haive init/i.test(projectContextRaw) && (projectContextRaw.match(/TODO —/g)?.length ?? 0) >= 2;
1864
+ const contextIsInferable = isTemplateContext || autoContextGenerated || bootstrapUnfilled;
1865
+ const adaptiveTrim = adaptiveConfig.adaptiveBriefing !== false && briefingValueLow && contextIsInferable;
1842
1866
  const hints = [];
1843
1867
  if (isColdStart) {
1844
1868
  hints.push(
@@ -1871,6 +1895,11 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
1871
1895
  );
1872
1896
  }
1873
1897
  }
1898
+ if (adaptiveTrim) {
1899
+ hints.push(
1900
+ "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."
1901
+ );
1902
+ }
1874
1903
  if (existsSync18(ctx.paths.haiveDir)) {
1875
1904
  await writeBriefingMarker(ctx.paths, {
1876
1905
  sessionId: process.env.HAIVE_SESSION_ID,
@@ -1886,7 +1915,12 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
1886
1915
  search_mode: searchMode,
1887
1916
  inferred_modules: inferred,
1888
1917
  ...lastSession ? { last_session: lastSession } : {},
1889
- project_context: projectContextRaw || autoContextGenerated ? {
1918
+ project_context: adaptiveTrim ? {
1919
+ content: "(adaptive briefing: auto-generated context omitted \u2014 no team-specific policy matched, so a capable model needs nothing extra here)",
1920
+ truncated: false,
1921
+ ...isTemplateContext && !autoContextGenerated ? { is_template: true } : {},
1922
+ ...autoContextGenerated ? { auto_generated: true } : {}
1923
+ } : projectContextRaw || autoContextGenerated ? {
1890
1924
  content: projectSlice.text,
1891
1925
  truncated: projectSlice.truncated,
1892
1926
  ...isTemplateContext && !autoContextGenerated ? { is_template: true } : {},
@@ -1900,6 +1934,7 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
1900
1934
  decay_warnings: decayWarnings,
1901
1935
  setup_warnings: setupWarnings,
1902
1936
  ...isColdStart ? { low_value: true } : {},
1937
+ briefing_value: briefingValueLow ? "low" : "high",
1903
1938
  ...hints.length > 0 ? { hints } : {},
1904
1939
  estimated_tokens: totalTokens,
1905
1940
  budget: {
@@ -2475,8 +2510,12 @@ var CODE_STOPWORDS = /* @__PURE__ */ new Set([
2475
2510
  "console"
2476
2511
  ]);
2477
2512
  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));
2513
+ const lines = diff.split("\n");
2514
+ const looksLikeDiff = lines.some((l) => /^[+-]/.test(l));
2515
+ const addedOnly = looksLikeDiff ? lines.filter((l) => l.startsWith("+") && !l.startsWith("+++")).join("\n") : diff;
2516
+ const source = addedOnly.trim().length > 0 ? addedOnly : diff;
2517
+ const wsTokens = tokenizeQuery3(source);
2518
+ const wordTokens = source.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 4 && !CODE_STOPWORDS.has(t));
2480
2519
  return [.../* @__PURE__ */ new Set([...wsTokens, ...wordTokens])];
2481
2520
  }
2482
2521
  async function antiPatternsCheck(input, ctx) {
@@ -3827,7 +3866,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
3827
3866
  // src/server.ts
3828
3867
  import { loadConfigSync } from "@hiveai/core";
3829
3868
  var SERVER_NAME = "haive";
3830
- var SERVER_VERSION = "0.9.31";
3869
+ var SERVER_VERSION = "0.10.0";
3831
3870
  function jsonResult(data) {
3832
3871
  return {
3833
3872
  content: [