@vedtechsolutions/engram-mcp 1.0.2 → 1.0.4

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.
@@ -1710,7 +1710,11 @@ var CONTEXTUAL = {
1710
1710
  /** Penalty multiplier for project mismatch on episodic memories (0.3 = 70% reduction) */
1711
1711
  PROJECT_MISMATCH_PENALTY: 0.3,
1712
1712
  /** Boost for failure experiences with lessons (surfaces "I tried this and it didn't work") */
1713
- FAILURE_EXPERIENCE_BOOST: 0.2
1713
+ FAILURE_EXPERIENCE_BOOST: 0.2,
1714
+ /** Boost when memory files share the same module directory as current file */
1715
+ MODULE_PROXIMITY_BOOST: 0.2,
1716
+ /** Penalty multiplier when memory files are all from a different module (0.3 = 70% reduction) */
1717
+ MODULE_MISMATCH_PENALTY: 0.3
1714
1718
  };
1715
1719
  var REWARD = {
1716
1720
  /** Seed activation boost for positively-reinforced memories */
@@ -8758,6 +8762,19 @@ function extractCodeContext(code, filePath) {
8758
8762
  identifiers: uniqueTerms
8759
8763
  };
8760
8764
  }
8765
+ function extractModuleFromPath(filePath) {
8766
+ const parts = filePath.split(/[/\\]/).filter(Boolean);
8767
+ const markers = ["addons", "custom-addons", "extra-addons", "packages", "apps"];
8768
+ for (let i = 0; i < parts.length - 1; i++) {
8769
+ if (markers.includes(parts[i]) && i + 1 < parts.length) {
8770
+ return parts[i + 1];
8771
+ }
8772
+ }
8773
+ if (parts.length >= 3) {
8774
+ return parts[parts.length - 3];
8775
+ }
8776
+ return null;
8777
+ }
8761
8778
  function detectLanguage(code, filePath) {
8762
8779
  if (filePath) {
8763
8780
  const ext = filePath.split(".").pop()?.toLowerCase();
@@ -9033,6 +9050,18 @@ function contextualBoost(memory, context) {
9033
9050
  if (context.current_files.length > 0 && enc.files.length > 0) {
9034
9051
  const overlap = context.current_files.filter((f) => enc.files.includes(f)).length;
9035
9052
  boost += Math.min(overlap * CONTEXTUAL.FILE_BOOST_PER_MATCH, CONTEXTUAL.FILE_BOOST_CAP);
9053
+ if (overlap === 0) {
9054
+ const currentModules = context.current_files.map(extractModuleFromPath).filter(Boolean);
9055
+ const memModules = enc.files.map(extractModuleFromPath).filter(Boolean);
9056
+ if (currentModules.length > 0 && memModules.length > 0) {
9057
+ const moduleOverlap = currentModules.some((m) => memModules.includes(m));
9058
+ if (moduleOverlap) {
9059
+ boost += CONTEXTUAL.MODULE_PROXIMITY_BOOST;
9060
+ } else {
9061
+ return (1 + boost) * CONTEXTUAL.MODULE_MISMATCH_PENALTY;
9062
+ }
9063
+ }
9064
+ }
9036
9065
  }
9037
9066
  if (context.current_error && enc.error_context) {
9038
9067
  const errorKeywords = context.current_error.toLowerCase().split(/\s+/).slice(0, 10);
@@ -12541,6 +12570,7 @@ export {
12541
12570
  computeActivationProfile,
12542
12571
  contextualRecall,
12543
12572
  codeContextRecall,
12573
+ extractModuleFromPath,
12544
12574
  findSimilarDecisions,
12545
12575
  formatDecisionInjection,
12546
12576
  findSimilarChains,
@@ -12597,4 +12627,4 @@ export {
12597
12627
  composeProjectUnderstanding,
12598
12628
  formatMentalModelInjection
12599
12629
  };
12600
- //# sourceMappingURL=chunk-AC6AZCP4.js.map
12630
+ //# sourceMappingURL=chunk-QU7DOPA4.js.map
package/dist/hook.js CHANGED
@@ -79,6 +79,7 @@ import {
79
79
  estimateTokens,
80
80
  extractErrorFingerprint,
81
81
  extractKeywords,
82
+ extractModuleFromPath,
82
83
  findDuplicate,
83
84
  findErrorByFingerprint,
84
85
  findResolutionForError,
@@ -172,7 +173,7 @@ import {
172
173
  updateReasoningChain,
173
174
  updateSelfModelFromSession,
174
175
  updateTask
175
- } from "./chunk-AC6AZCP4.js";
176
+ } from "./chunk-QU7DOPA4.js";
176
177
 
177
178
  // src/hook.ts
178
179
  import { readFileSync, writeFileSync, existsSync, renameSync, statSync, readdirSync, unlinkSync, appendFileSync, openSync, readSync, closeSync } from "fs";
@@ -3527,9 +3528,7 @@ function handlePreWrite(toolInput, argFallback) {
3527
3528
  if (filePath) {
3528
3529
  const fileCount = (watcherState.prewrite_file_counts[filePath] ?? 0) + 1;
3529
3530
  watcherState.prewrite_file_counts[filePath] = fileCount;
3530
- if (fileCount <= CODE_CONTEXT_RECALL.PREWRITE_COOLDOWN_PER_FILE) {
3531
- skipCodeRecall = fileCount > 1;
3532
- }
3531
+ skipCodeRecall = fileCount % CODE_CONTEXT_RECALL.PREWRITE_COOLDOWN_PER_FILE !== 1;
3533
3532
  saveWatcherState(watcherState);
3534
3533
  }
3535
3534
  if (!skipCodeRecall && content.length >= CODE_CONTEXT_RECALL.MIN_CONTENT_LENGTH) {
@@ -3540,18 +3539,30 @@ function handlePreWrite(toolInput, argFallback) {
3540
3539
  project: watcherState.active_project
3541
3540
  }, config.retrieval);
3542
3541
  const activeDomain = watcherState.active_domain;
3542
+ const currentModule = filePath ? extractModuleFromPath(filePath) : null;
3543
+ const isModuleMismatch = (mem) => {
3544
+ if (!currentModule) return false;
3545
+ const memFiles = mem.memory.encoding_context?.files;
3546
+ if (!memFiles || memFiles.length === 0) return false;
3547
+ const memModules = memFiles.map(extractModuleFromPath).filter(Boolean);
3548
+ if (memModules.length === 0) return false;
3549
+ return !memModules.includes(currentModule);
3550
+ };
3543
3551
  for (const p of codeResult.patterns) {
3544
3552
  if (p.activation < CODE_CONTEXT_RECALL.MIN_PREWRITE_ACTIVATION) continue;
3545
3553
  if (p.memory.type === "episodic") continue;
3546
3554
  if (activeDomain && p.memory.encoding_context?.framework && p.memory.encoding_context.framework !== activeDomain) continue;
3555
+ if (isModuleMismatch(p)) continue;
3547
3556
  contextLines.push(`[ENGRAM PATTERN] ${truncate(p.memory.content, 200)}`);
3548
3557
  }
3549
3558
  for (const c of codeResult.conventions) {
3550
3559
  if (c.activation < CODE_CONTEXT_RECALL.MIN_PREWRITE_ACTIVATION) continue;
3551
3560
  if (activeDomain && c.memory.encoding_context?.framework && c.memory.encoding_context.framework !== activeDomain) continue;
3561
+ if (isModuleMismatch(c)) continue;
3552
3562
  contextLines.push(`[ENGRAM CONVENTION] ${truncate(c.memory.content, 200)}`);
3553
3563
  }
3554
3564
  for (const p of codeResult.procedural) {
3565
+ if (isModuleMismatch(p)) continue;
3555
3566
  contextLines.push(`[ENGRAM HOW-TO] ${truncate(p.memory.content, 200)}`);
3556
3567
  }
3557
3568
  } catch (e) {
@@ -6817,6 +6828,39 @@ function handlePostCompact(stdinJson) {
6817
6828
  if (!recovery) return;
6818
6829
  const budget = new OutputBudget(OUTPUT_BUDGET.POST_COMPACT_MAX_BYTES);
6819
6830
  const lines = [];
6831
+ const cog = state.cognitive_state;
6832
+ const cogCtx = recovery.working_state?.cognitive_context;
6833
+ const hasAnyCognitive = cog?.current_approach || cog?.active_hypothesis || cog?.recent_discovery || cogCtx?.planned_next_step || recovery.continuation_hint;
6834
+ if (hasAnyCognitive) {
6835
+ const mindLines = ["[Engram] Before compaction, you were:"];
6836
+ if (state.active_task) mindLines.push(` Task: ${truncate(state.active_task, 200)}`);
6837
+ if (cog?.session_phase) mindLines.push(` Phase: ${cog.session_phase}`);
6838
+ if (cog?.current_approach) mindLines.push(` Approach: ${truncate(cog.current_approach, 300)}`);
6839
+ if (cog?.active_hypothesis) mindLines.push(` Hypothesis: ${truncate(cog.active_hypothesis, 300)}`);
6840
+ if (cog?.recent_discovery) mindLines.push(` Discovery: ${truncate(cog.recent_discovery, 300)}`);
6841
+ if (cogCtx?.planned_next_step) mindLines.push(` Next step: ${truncate(cogCtx.planned_next_step, 200)}`);
6842
+ if (cog?.search_intent) mindLines.push(` Investigating: ${truncate(cog.search_intent, 200)}`);
6843
+ const ruledOut = (state.session_outcomes ?? []).filter((o) => o.includes("\u2192 fail") || o.includes("\u2192 dead end") || o.includes("\u2192 blocked"));
6844
+ if (ruledOut.length > 0) {
6845
+ mindLines.push(` Already tried (didn't work):`);
6846
+ for (const o of ruledOut.slice(-3)) mindLines.push(` - ${truncate(o, 150)}`);
6847
+ }
6848
+ const blockers = recovery.working_state?.active_blockers ?? [];
6849
+ if (blockers.length > 0) {
6850
+ mindLines.push(` Blockers: ${blockers.slice(0, 3).map((b) => truncate(b, 100)).join("; ")}`);
6851
+ }
6852
+ if (state.recent_errors.length > 0) {
6853
+ mindLines.push(` Recent errors: ${state.recent_errors.slice(-2).map((e) => truncate(e, 100)).join("; ")}`);
6854
+ }
6855
+ if (state.session_files.length > 0) {
6856
+ const files = state.session_files.slice(-8).map((f) => f.split(/[/\\]/).pop() ?? f);
6857
+ mindLines.push(` Files: ${files.join(", ")}`);
6858
+ }
6859
+ if (recovery.continuation_hint) {
6860
+ mindLines.push(` Continue: ${truncate(recovery.continuation_hint, 300)}`);
6861
+ }
6862
+ lines.push(mindLines.join("\n"));
6863
+ }
6820
6864
  try {
6821
6865
  const transcriptPath = stdinJson?.transcript_path ?? null;
6822
6866
  if (transcriptPath) {
package/dist/index.js CHANGED
@@ -154,7 +154,7 @@ import {
154
154
  vaccinate,
155
155
  vacuumDatabase,
156
156
  validateMultiPerspective
157
- } from "./chunk-AC6AZCP4.js";
157
+ } from "./chunk-QU7DOPA4.js";
158
158
 
159
159
  // src/index.ts
160
160
  import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vedtechsolutions/engram-mcp",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Cognitive memory system for AI — persistent, cross-session learning via MCP",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",