@vedtechsolutions/engram-mcp 1.0.10 → 1.0.12

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.
Files changed (2) hide show
  1. package/dist/hook.js +120 -40
  2. package/package.json +1 -1
package/dist/hook.js CHANGED
@@ -3141,7 +3141,8 @@ function loadWatcherState() {
3141
3141
  recent_commands: raw.recent_commands ?? [],
3142
3142
  procedural_encoded_count: raw.procedural_encoded_count ?? 0,
3143
3143
  recent_actions: raw.recent_actions ?? [],
3144
- continuation_brief: raw.continuation_brief ?? null
3144
+ continuation_brief: raw.continuation_brief ?? null,
3145
+ recent_prompts: raw.recent_prompts ?? []
3145
3146
  };
3146
3147
  }
3147
3148
  } catch {
@@ -3207,10 +3208,12 @@ function loadWatcherState() {
3207
3208
  recent_commands: [],
3208
3209
  procedural_encoded_count: 0,
3209
3210
  recent_actions: [],
3210
- continuation_brief: null
3211
+ continuation_brief: null,
3212
+ recent_prompts: []
3211
3213
  };
3212
3214
  }
3213
3215
  function saveWatcherState(state) {
3216
+ sanitizeCognitiveState(state);
3214
3217
  const watcherPath = getWatcherPath(activeSessionId);
3215
3218
  try {
3216
3219
  const tmpPath = watcherPath + ".tmp";
@@ -3219,6 +3222,46 @@ function saveWatcherState(state) {
3219
3222
  } catch {
3220
3223
  }
3221
3224
  }
3225
+ function sanitizeCognitiveState(state) {
3226
+ const cog = state.cognitive_state;
3227
+ if (!cog) return;
3228
+ const placeholders = ["X", "X.", "Y", "Y.", "Z", "Z."];
3229
+ if (cog.current_approach && placeholders.includes(cog.current_approach)) {
3230
+ cog.current_approach = null;
3231
+ }
3232
+ if (cog.active_hypothesis && placeholders.includes(cog.active_hypothesis)) {
3233
+ cog.active_hypothesis = null;
3234
+ }
3235
+ if (cog.recent_discovery && placeholders.includes(cog.recent_discovery)) {
3236
+ cog.recent_discovery = null;
3237
+ }
3238
+ if (cog.active_hypothesis && cog.active_hypothesis.startsWith("/")) {
3239
+ cog.active_hypothesis = null;
3240
+ }
3241
+ if (cog.search_intent && cog.search_intent.startsWith("/")) {
3242
+ cog.search_intent = null;
3243
+ }
3244
+ if (cog.current_approach && cog.current_approach.length < 5) {
3245
+ cog.current_approach = null;
3246
+ }
3247
+ if (cog.current_approach && cog.current_approach.startsWith("Pre-compaction")) {
3248
+ cog.current_approach = null;
3249
+ }
3250
+ if (cog.recent_discovery && cog.recent_discovery.startsWith("Pre-compaction")) {
3251
+ cog.recent_discovery = null;
3252
+ }
3253
+ if (!state.active_task || state.active_task === "unknown task") {
3254
+ const editedFiles = state.recent_actions.filter((a) => a.tool === "Edit" || a.tool === "Write").map((a) => a.target.split(/[/\\]/).pop() ?? a.target);
3255
+ const uniqueFiles = [...new Set(editedFiles)].slice(-5);
3256
+ if (uniqueFiles.length > 0) {
3257
+ if (cog.current_approach && cog.current_approach.length >= 10) {
3258
+ state.active_task = cog.current_approach.slice(0, 150);
3259
+ } else {
3260
+ state.active_task = `Working on ${uniqueFiles.join(", ")}`;
3261
+ }
3262
+ }
3263
+ }
3264
+ }
3222
3265
  function deleteSessionState() {
3223
3266
  const watcherPath = getWatcherPath(activeSessionId);
3224
3267
  try {
@@ -4135,13 +4178,18 @@ function handlePostWrite(toolInput, argFallback) {
4135
4178
  const filePath = input?.file_path ?? input?.path ?? "";
4136
4179
  if (!filePath) return;
4137
4180
  const state = loadWatcherState();
4138
- state.recent_actions.push({
4139
- tool: "Edit",
4140
- target: filePath,
4141
- time: (/* @__PURE__ */ new Date()).toISOString()
4142
- });
4143
- if (state.recent_actions.length > 15) {
4144
- state.recent_actions = state.recent_actions.slice(-15);
4181
+ {
4182
+ const newStr = input?.new_string ?? "";
4183
+ const firstNewLine = newStr.split("\n").find((l) => l.trim().length > 0) ?? "";
4184
+ const actionTarget = firstNewLine ? `${filePath} \u2192 ${firstNewLine}`.slice(0, 250) : filePath;
4185
+ state.recent_actions.push({
4186
+ tool: "Edit",
4187
+ target: actionTarget,
4188
+ time: (/* @__PURE__ */ new Date()).toISOString()
4189
+ });
4190
+ if (state.recent_actions.length > 15) {
4191
+ state.recent_actions = state.recent_actions.slice(-15);
4192
+ }
4145
4193
  }
4146
4194
  if (typeof filePath === "string" && !state.session_files.includes(filePath)) {
4147
4195
  state.session_files.push(filePath);
@@ -4665,6 +4713,14 @@ function summarizeToolInput(tool, input) {
4665
4713
  `pattern=${input.pattern ?? ""} path=${input.path ?? ""}`,
4666
4714
  200
4667
4715
  );
4716
+ case "Edit": {
4717
+ const filePath = input.file_path ?? "";
4718
+ const newStr = input.new_string ?? "";
4719
+ const firstNewLine = newStr.split("\n").find((l) => l.trim().length > 0) ?? "";
4720
+ return truncate(`${filePath} \u2192 ${firstNewLine}`, 250);
4721
+ }
4722
+ case "Write":
4723
+ return truncate(input.file_path ?? "", 200);
4668
4724
  case "Agent":
4669
4725
  return truncate(input.prompt ?? "", 300);
4670
4726
  case "WebSearch":
@@ -4984,7 +5040,8 @@ function handleSessionStart(stdinJson, argFallback) {
4984
5040
  recent_commands: isPostCompact ? prevState?.recent_commands ?? [] : [],
4985
5041
  procedural_encoded_count: isPostCompact ? prevState?.procedural_encoded_count ?? 0 : 0,
4986
5042
  recent_actions: isPostCompact ? prevState?.recent_actions ?? [] : [],
4987
- continuation_brief: isPostCompact ? prevState?.continuation_brief ?? null : null
5043
+ continuation_brief: isPostCompact ? prevState?.continuation_brief ?? null : null,
5044
+ recent_prompts: isPostCompact ? prevState?.recent_prompts ?? [] : []
4988
5045
  });
4989
5046
  const source = metadata.source;
4990
5047
  if (!source || source === "startup") {
@@ -5588,24 +5645,39 @@ function buildContinuationBrief(state) {
5588
5645
  const cog = state.cognitive_state;
5589
5646
  const task = state.active_task ?? cog.current_approach ?? (state.session_files.length > 0 ? `Working on ${state.session_files.slice(-3).map((f) => f.split(/[/\\]/).pop() ?? f).join(", ")}` : "unknown task");
5590
5647
  const lastActions = state.recent_actions.slice(-8).map((a) => {
5648
+ if (a.tool === "Edit" || a.tool === "Write") {
5649
+ const shortPath = a.target.length > 60 ? "..." + a.target.slice(-57) : a.target;
5650
+ return `${a.tool}: ${shortPath}`;
5651
+ }
5652
+ if (a.tool === "Bash") {
5653
+ return `Bash: ${truncate(a.target, 100)}`;
5654
+ }
5591
5655
  const fileName = a.target.includes("/") ? a.target.split(/[/\\]/).pop() ?? a.target : a.target;
5592
5656
  return `${a.tool}: ${truncate(fileName, 80)}`;
5593
5657
  });
5594
5658
  const nextSteps = [];
5659
+ if (cog.recent_discovery && cog.recent_discovery.length > 10) {
5660
+ nextSteps.push(`Act on finding: ${truncate(cog.recent_discovery, 120)}`);
5661
+ }
5595
5662
  if (cog.search_intent && !nextSteps.some((s) => s.includes(cog.search_intent))) {
5596
5663
  nextSteps.push(`Investigate: ${cog.search_intent}`);
5597
5664
  }
5598
5665
  const lastAction = state.recent_actions[state.recent_actions.length - 1];
5599
5666
  if (lastAction && nextSteps.length === 0) {
5600
5667
  if (lastAction.tool === "Edit" || lastAction.tool === "Write") {
5601
- nextSteps.push("Run tests to verify changes");
5668
+ nextSteps.push(`Continue editing ${lastAction.target.split(/[/\\]/).pop() ?? lastAction.target}, then run tests`);
5602
5669
  } else if (lastAction.tool === "Bash" && lastAction.target.includes("test")) {
5603
5670
  nextSteps.push("Review test results and commit if passing");
5671
+ } else if (lastAction.tool === "Bash" && lastAction.target.includes("push")) {
5672
+ nextSteps.push("Verify push succeeded, publish if needed");
5604
5673
  }
5605
5674
  }
5606
5675
  if (state.recent_errors.length > 0 && nextSteps.length < 3) {
5607
5676
  nextSteps.push(`Fix: ${truncate(state.recent_errors[state.recent_errors.length - 1], 120)}`);
5608
5677
  }
5678
+ if (cog.active_hypothesis && cog.active_hypothesis.length > 5) {
5679
+ nextSteps.push(`Testing hypothesis: ${truncate(cog.active_hypothesis, 120)}`);
5680
+ }
5609
5681
  const decisions = [];
5610
5682
  for (const id of state.decision_memory_ids.slice(-5)) {
5611
5683
  try {
@@ -5617,6 +5689,15 @@ function buildContinuationBrief(state) {
5617
5689
  const triedFailed = (state.session_outcomes ?? []).filter((o) => o.includes("\u2192 fail") || o.includes("\u2192 dead end") || o.includes("\u2192 blocked")).slice(-5).map((o) => truncate(o, 120));
5618
5690
  const editActions = state.recent_actions.filter((a) => a.tool === "Edit" || a.tool === "Write");
5619
5691
  const keyFiles = [...new Set(editActions.map((a) => a.target))].slice(-10);
5692
+ const recentBash = state.recent_commands?.slice(-5) ?? [];
5693
+ if (recentBash.length > 0) {
5694
+ const bashSummary = recentBash.map((c) => truncate(c.cmd, 80));
5695
+ for (const cmd of bashSummary) {
5696
+ if (lastActions.length < 12) {
5697
+ lastActions.push(`Ran: ${cmd}`);
5698
+ }
5699
+ }
5700
+ }
5620
5701
  return {
5621
5702
  task: truncate(task, 300),
5622
5703
  phase: cog.session_phase ?? "unknown",
@@ -5625,7 +5706,8 @@ function buildContinuationBrief(state) {
5625
5706
  decisions,
5626
5707
  tried_failed: triedFailed,
5627
5708
  key_files: keyFiles.length > 0 ? keyFiles : state.session_files.slice(-10),
5628
- blockers: state.recent_errors.slice(-3).map((e) => truncate(e, 150))
5709
+ blockers: state.recent_errors.slice(-3).map((e) => truncate(e, 150)),
5710
+ user_requests: state.recent_prompts.slice(-5).map((p) => truncate(p, 200))
5629
5711
  };
5630
5712
  }
5631
5713
  function handlePreCompact() {
@@ -6215,32 +6297,13 @@ ${distillLines}`
6215
6297
  }
6216
6298
  }
6217
6299
  }
6218
- if (!state.active_task || state.active_task === "write a comprehensive report") {
6219
- const editedFiles = state.recent_actions.filter((a) => a.tool === "Edit" || a.tool === "Write").map((a) => a.target.split(/[/\\]/).pop() ?? a.target);
6220
- const uniqueFiles = [...new Set(editedFiles)].slice(-5);
6221
- if (uniqueFiles.length > 0) {
6222
- const cog = state.cognitive_state;
6223
- if (cog.current_approach && cog.current_approach.length > 5 && cog.current_approach !== "X") {
6224
- state.active_task = truncate(cog.current_approach, 150);
6225
- } else {
6226
- state.active_task = `Working on ${uniqueFiles.join(", ")}`;
6227
- }
6300
+ if (content.length >= 10) {
6301
+ state.recent_prompts.push(truncate(content, 300));
6302
+ if (state.recent_prompts.length > 8) {
6303
+ state.recent_prompts = state.recent_prompts.slice(-8);
6228
6304
  }
6229
6305
  }
6230
6306
  try {
6231
- const cog = state.cognitive_state;
6232
- if (cog.current_approach === "X" || cog.current_approach === "X.") {
6233
- state.cognitive_state.current_approach = null;
6234
- }
6235
- if (cog.active_hypothesis === "Y" || cog.active_hypothesis === "Y.") {
6236
- state.cognitive_state.active_hypothesis = null;
6237
- }
6238
- if (cog.recent_discovery === "Z" || cog.recent_discovery === "Z.") {
6239
- state.cognitive_state.recent_discovery = null;
6240
- }
6241
- if (cog.active_hypothesis && cog.active_hypothesis.startsWith("/")) {
6242
- state.cognitive_state.active_hypothesis = null;
6243
- }
6244
6307
  if (content.length >= 20 && !state.cognitive_state.current_approach) {
6245
6308
  const approach = extractApproachFromPrompt(content);
6246
6309
  if (approach) {
@@ -6395,6 +6458,7 @@ ${distillLines}`
6395
6458
  if (isRecallNoise(m.memory.content, m.memory.type, m.memory.tags)) continue;
6396
6459
  if (m.memory.tags.includes("pre-compact")) continue;
6397
6460
  if (m.memory.tags.includes("session-narrative")) continue;
6461
+ if (m.memory.tags.includes("milestone") || m.memory.content.startsWith("Session milestone")) continue;
6398
6462
  const isFailure = m.memory.type === "episodic" && isEpisodicData(m.memory.type_data) && m.memory.type_data.outcome === "negative";
6399
6463
  const prefix = m.somatic_marker ? "[ENGRAM GUT]" : isFailure ? "[ENGRAM CAUTION]" : "[ENGRAM CONTEXT]";
6400
6464
  const outcomeHint = m.memory.type === "episodic" && (m.somatic_marker || isFailure) ? getEpisodicOutcomeHint(m.memory) : "";
@@ -6540,6 +6604,8 @@ ${distillLines}`
6540
6604
  if (contextOutputIds.has(mem.id)) continue;
6541
6605
  if (isRecallNoise(mem.content, mem.type, mem.tags)) continue;
6542
6606
  if (mem.tags.includes("pre-compact")) continue;
6607
+ if (mem.tags.includes("session-narrative")) continue;
6608
+ if (mem.tags.includes("milestone") || mem.content.startsWith("Session milestone")) continue;
6543
6609
  if (state.active_project && mem.encoding_context?.project && mem.encoding_context.project !== state.active_project && (mem.type === "episodic" || mem.type === "semantic" && mem.domains.length > 0)) continue;
6544
6610
  const lastTurn = state.proactive_injection_turns[mem.id];
6545
6611
  if (lastTurn !== void 0 && state.total_turns - lastTurn < PROACTIVE_RECALL.MIN_TURNS_BETWEEN_SAME) continue;
@@ -7067,6 +7133,10 @@ function handlePostCompact(stdinJson) {
7067
7133
  const files = brief.key_files.map((f) => f.split(/[/\\]/).pop() ?? f);
7068
7134
  mindLines.push(` Files: ${files.join(", ")}`);
7069
7135
  }
7136
+ if (brief.user_requests && brief.user_requests.length > 0) {
7137
+ mindLines.push(` User asked:`);
7138
+ for (const req of brief.user_requests.slice(-3)) mindLines.push(` - ${req}`);
7139
+ }
7070
7140
  lines.push(mindLines.join("\n"));
7071
7141
  } else {
7072
7142
  const cog = state.cognitive_state;
@@ -7129,11 +7199,21 @@ function handlePostCompact(stdinJson) {
7129
7199
  }
7130
7200
  const cogCtx2 = recovery.working_state?.cognitive_context;
7131
7201
  const queryParts = [];
7132
- if (state.active_task) queryParts.push(state.active_task.split(/[.;!\n]/)[0] ?? "");
7133
- if (cogCtx2?.current_approach) queryParts.push(cogCtx2.current_approach);
7134
- if (cogCtx2?.active_hypothesis) queryParts.push(cogCtx2.active_hypothesis);
7135
- if (cogCtx2?.recent_discovery) queryParts.push(cogCtx2.recent_discovery);
7136
- if (queryParts.length < 2) {
7202
+ if (brief?.task && brief.task !== "unknown task") {
7203
+ queryParts.push(brief.task.split(/[.;!\n]/)[0] ?? "");
7204
+ } else if (state.active_task) {
7205
+ queryParts.push(state.active_task.split(/[.;!\n]/)[0] ?? "");
7206
+ }
7207
+ if (cogCtx2?.current_approach && !queryParts.some((q) => q.includes(cogCtx2.current_approach.slice(0, 20)))) {
7208
+ queryParts.push(cogCtx2.current_approach);
7209
+ }
7210
+ if (brief?.key_files && brief.key_files.length > 0) {
7211
+ const fileNames = brief.key_files.slice(-3).map((f) => f.split(/[/\\]/).pop() ?? f).filter((f) => f.length > 2);
7212
+ if (fileNames.length > 0) {
7213
+ queryParts.push(fileNames.join(" "));
7214
+ }
7215
+ }
7216
+ if (queryParts.length < 1) {
7137
7217
  queryParts.push(...recovery.high_value_topics.slice(0, 6));
7138
7218
  }
7139
7219
  const query = queryParts.join(" ");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vedtechsolutions/engram-mcp",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Cognitive memory system for AI — persistent, cross-session learning via MCP",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",