@hiveai/mcp 0.21.0 → 0.23.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
@@ -670,6 +670,13 @@ declare function memTimeline(input: MemTimelineInput, ctx: HaiveContext): Promis
670
670
  notice: string | undefined;
671
671
  }>;
672
672
 
673
+ interface SuggestedResolution {
674
+ keep_id: string;
675
+ supersede_id: string;
676
+ reason: string;
677
+ /** Copy-paste command that APPLIES the guided supersede (promotes winner, deprecates loser). */
678
+ command: string;
679
+ }
673
680
  declare const MemConflictCandidatesInputSchema: {
674
681
  since_days: z.ZodDefault<z.ZodNumber>;
675
682
  types: z.ZodDefault<z.ZodArray<z.ZodEnum<["decision", "architecture", "convention", "gotcha"]>, "many">>;
@@ -682,8 +689,20 @@ type MemConflictCandidatesInput = {
682
689
  [K in keyof typeof MemConflictCandidatesInputSchema]: z.infer<(typeof MemConflictCandidatesInputSchema)[K]>;
683
690
  };
684
691
  declare function memConflictCandidates(input: MemConflictCandidatesInput, ctx: HaiveContext): Promise<{
685
- pairs: _hiveai_core.ConflictCandidatePair[];
686
- topic_status_pairs: _hiveai_core.TopicStatusPair[];
692
+ pairs: {
693
+ suggested_resolution: SuggestedResolution | null;
694
+ id_a: string;
695
+ id_b: string;
696
+ jaccard: number;
697
+ }[];
698
+ topic_status_pairs: {
699
+ suggested_resolution: SuggestedResolution | null;
700
+ id_a: string;
701
+ id_b: string;
702
+ topic: string;
703
+ status_a: string;
704
+ status_b: string;
705
+ }[];
687
706
  scanned: number;
688
707
  truncated: boolean;
689
708
  notice: string | undefined;
package/dist/server.js CHANGED
@@ -1149,7 +1149,15 @@ async function memTried(input, ctx) {
1149
1149
  throw new Error(`Memory already exists at ${file}`);
1150
1150
  }
1151
1151
  await writeFile8(file, serializeMemory7({ frontmatter, body }), "utf8");
1152
- return { id: frontmatter.id, scope: frontmatter.scope, file_path: file };
1152
+ const sensorGenerated = Boolean(sensor);
1153
+ const hint = sensorGenerated ? void 0 : input.paths.length === 0 ? "No sensor was generated (no `paths` given), so this lesson is feedforward-only \u2014 it will be briefed but the gate cannot block the repeat. Re-run with `paths` set to the file(s) where the mistake lives to close the loop." : "No sensor could be derived from the wording (no distinctive code token). The lesson is briefed but not enforced; add a concrete forbidden token/value, or attach a sensor manually, to make the gate block the repeat.";
1154
+ return {
1155
+ id: frontmatter.id,
1156
+ scope: frontmatter.scope,
1157
+ file_path: file,
1158
+ sensor_generated: sensorGenerated,
1159
+ ...hint ? { hint } : {}
1160
+ };
1153
1161
  }
1154
1162
 
1155
1163
  // src/tools/ingest-findings.ts
@@ -2665,7 +2673,6 @@ function runCommand(cmd, args, cwd) {
2665
2673
  import { existsSync as existsSync25 } from "fs";
2666
2674
  import {
2667
2675
  addedLinesFromDiff,
2668
- appendPreventionEvent,
2669
2676
  BRIDGE_TARGET_PATH,
2670
2677
  buildDocFrequency,
2671
2678
  CODE_STOPWORDS,
@@ -2677,9 +2684,8 @@ import {
2677
2684
  loadUsageIndex as loadUsageIndex10,
2678
2685
  literalMatchesAnyToken as literalMatchesAnyToken3,
2679
2686
  memoryMatchesAnchorPaths as memoryMatchesAnchorPaths4,
2680
- recordPrevention,
2687
+ recordPreventionHits,
2681
2688
  runSensors,
2682
- saveUsageIndex as saveUsageIndex4,
2683
2689
  sensorTargetsFromDiff,
2684
2690
  tokenizeQuery as tokenizeQuery3
2685
2691
  } from "@hiveai/core";
@@ -2864,19 +2870,7 @@ async function antiPatternsCheck(input, ctx) {
2864
2870
  const strongCatches = warnings.filter(
2865
2871
  (w) => w.reasons.includes("sensor") || w.reasons.includes("anchor") && w.reasons.includes("literal")
2866
2872
  );
2867
- if (strongCatches.length > 0) {
2868
- const recordedIds = [];
2869
- for (const w of strongCatches) if (recordPrevention(usage, w.id)) recordedIds.push(w.id);
2870
- if (recordedIds.length > 0) {
2871
- await saveUsageIndex4(ctx.paths, usage).catch(() => {
2872
- });
2873
- const at = (/* @__PURE__ */ new Date()).toISOString();
2874
- for (const id of recordedIds) {
2875
- await appendPreventionEvent(ctx.paths, { at, id, source: "anti-pattern" }).catch(() => {
2876
- });
2877
- }
2878
- }
2879
- }
2873
+ await recordPreventionHits(ctx.paths, strongCatches.map((w) => w.id), "anti-pattern");
2880
2874
  return {
2881
2875
  scanned: negative.length,
2882
2876
  warnings
@@ -3848,9 +3842,22 @@ import { existsSync as existsSync30 } from "fs";
3848
3842
  import {
3849
3843
  findLexicalConflictPairs,
3850
3844
  findTopicStatusConflictPairs,
3851
- loadMemoriesFromDir as loadMemoriesFromDir23
3845
+ loadMemoriesFromDir as loadMemoriesFromDir23,
3846
+ planConflictResolution
3852
3847
  } from "@hiveai/core";
3853
3848
  import { z as z32 } from "zod";
3849
+ function suggestResolution(byId, idA, idB) {
3850
+ const a = byId.get(idA);
3851
+ const b = byId.get(idB);
3852
+ if (!a || !b) return null;
3853
+ const plan = planConflictResolution(a, b);
3854
+ return {
3855
+ keep_id: plan.keep_id,
3856
+ supersede_id: plan.supersede_id,
3857
+ reason: plan.reason,
3858
+ command: `haive memory resolve-conflict ${plan.keep_id} ${plan.supersede_id} --yes`
3859
+ };
3860
+ }
3854
3861
  var MemConflictCandidatesInputSchema = {
3855
3862
  since_days: z32.number().int().positive().max(3650).default(365).describe("Only memories created since N days ago"),
3856
3863
  types: z32.array(z32.enum(["decision", "architecture", "convention", "gotcha"])).default(["decision", "architecture"]).describe("Memory types scanned for pairwise lexical overlap"),
@@ -3872,6 +3879,7 @@ async function memConflictCandidates(input, ctx) {
3872
3879
  };
3873
3880
  }
3874
3881
  const all = await loadMemoriesFromDir23(ctx.paths.memoriesDir);
3882
+ const byId = new Map(all.map((m) => [m.memory.frontmatter.id, m]));
3875
3883
  const { pairs, scanned, truncated } = findLexicalConflictPairs(all, {
3876
3884
  sinceDays: input.since_days,
3877
3885
  types: input.types,
@@ -3880,8 +3888,22 @@ async function memConflictCandidates(input, ctx) {
3880
3888
  maxScan: input.max_scan
3881
3889
  });
3882
3890
  const topicStatusPairs = findTopicStatusConflictPairs(all, input.max_topic_pairs);
3891
+ const enrichedPairs = pairs.map((p) => ({
3892
+ ...p,
3893
+ suggested_resolution: suggestResolution(byId, p.id_a, p.id_b)
3894
+ }));
3895
+ const enrichedTopicStatusPairs = topicStatusPairs.map((p) => ({
3896
+ ...p,
3897
+ suggested_resolution: suggestResolution(byId, p.id_a, p.id_b)
3898
+ }));
3883
3899
  const notice = pairs.length === 0 && topicStatusPairs.length === 0 ? "No lexical or topic-status candidates \u2014 widen since_days/types or lower min_jaccard." : void 0;
3884
- return { pairs, topic_status_pairs: topicStatusPairs, scanned, truncated, notice };
3900
+ return {
3901
+ pairs: enrichedPairs,
3902
+ topic_status_pairs: enrichedTopicStatusPairs,
3903
+ scanned,
3904
+ truncated,
3905
+ notice
3906
+ };
3885
3907
  }
3886
3908
 
3887
3909
  // src/tools/mem-resolve-project.ts
@@ -4228,7 +4250,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
4228
4250
  // src/server.ts
4229
4251
  import { hasRecentBriefingMarker, loadConfigSync } from "@hiveai/core";
4230
4252
  var SERVER_NAME = "haive";
4231
- var SERVER_VERSION = "0.21.0";
4253
+ var SERVER_VERSION = "0.23.0";
4232
4254
  function jsonResult(data) {
4233
4255
  return {
4234
4256
  content: [