@vedtechsolutions/engram-mcp 1.0.20 → 1.0.21

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 +74 -10
  2. package/package.json +1 -1
package/dist/hook.js CHANGED
@@ -3250,13 +3250,29 @@ function sanitizeCognitiveState(state) {
3250
3250
  const cog = state.cognitive_state;
3251
3251
  if (!cog) return;
3252
3252
  const placeholders = ["X", "X.", "Y", "Y.", "Z", "Z."];
3253
- if (cog.current_approach && placeholders.includes(cog.current_approach)) {
3253
+ const templatePatterns = [
3254
+ /^X[\.\s]/,
3255
+ // Starts with X. or X<space>
3256
+ /^Approach:\s*X/i,
3257
+ // "Approach: X..."
3258
+ /Hypothesis:\s*[XYZ][\.\s]/,
3259
+ // Contains "Hypothesis: X."
3260
+ /Discovery:\s*[XYZ][\.\s]/,
3261
+ // Contains "Discovery: Z."
3262
+ /^[XYZ]\.\s+(?:Hypothesis|Discovery|Approach):/i
3263
+ // "X. Hypothesis: Y..."
3264
+ ];
3265
+ const isPlaceholderValue = (val) => {
3266
+ if (placeholders.includes(val)) return true;
3267
+ return templatePatterns.some((p) => p.test(val));
3268
+ };
3269
+ if (cog.current_approach && isPlaceholderValue(cog.current_approach)) {
3254
3270
  cog.current_approach = null;
3255
3271
  }
3256
- if (cog.active_hypothesis && placeholders.includes(cog.active_hypothesis)) {
3272
+ if (cog.active_hypothesis && isPlaceholderValue(cog.active_hypothesis)) {
3257
3273
  cog.active_hypothesis = null;
3258
3274
  }
3259
- if (cog.recent_discovery && placeholders.includes(cog.recent_discovery)) {
3275
+ if (cog.recent_discovery && isPlaceholderValue(cog.recent_discovery)) {
3260
3276
  cog.recent_discovery = null;
3261
3277
  }
3262
3278
  if (cog.active_hypothesis && cog.active_hypothesis.startsWith("/")) {
@@ -3285,11 +3301,35 @@ function sanitizeCognitiveState(state) {
3285
3301
  }
3286
3302
  }
3287
3303
  }
3304
+ if (cog.recent_discovery && cog.recent_discovery.length < 15 && !cog.recent_discovery.includes(" ")) {
3305
+ cog.recent_discovery = null;
3306
+ }
3307
+ if (cog.recent_discovery && /^that\s/i.test(cog.recent_discovery) && cog.recent_discovery.length < 40) {
3308
+ cog.recent_discovery = null;
3309
+ }
3288
3310
  if (state.active_task && state.active_task.startsWith("<")) {
3289
3311
  state.active_task = null;
3290
3312
  }
3313
+ if (state.active_task) {
3314
+ const conversationalPatterns = [
3315
+ /^i have another/i,
3316
+ /^just letting you/i,
3317
+ /^just a quick/i,
3318
+ /^now tell me/i,
3319
+ /^do another final/i,
3320
+ /^reviewing$/i
3321
+ // Generic tool-inferred task, not specific
3322
+ ];
3323
+ if (conversationalPatterns.some((p) => p.test(state.active_task))) {
3324
+ state.active_task = null;
3325
+ }
3326
+ }
3291
3327
  if (!state.active_task || state.active_task === "unknown task") {
3292
- const editedFiles = state.recent_actions.filter((a) => a.tool === "Edit" || a.tool === "Write").map((a) => a.target.split(/[/\\]/).pop() ?? a.target);
3328
+ const editedFiles = state.recent_actions.filter((a) => a.tool === "Edit" || a.tool === "Write").map((a) => {
3329
+ const arrowIdx = a.target.indexOf(" \u2192");
3330
+ const path = arrowIdx > 0 ? a.target.slice(0, arrowIdx) : a.target;
3331
+ return path.split(/[/\\]/).pop() ?? path;
3332
+ });
3293
3333
  const uniqueFiles = [...new Set(editedFiles)].slice(-5);
3294
3334
  if (uniqueFiles.length > 0) {
3295
3335
  if (cog.current_approach && cog.current_approach.length >= 10) {
@@ -3299,6 +3339,16 @@ function sanitizeCognitiveState(state) {
3299
3339
  }
3300
3340
  }
3301
3341
  }
3342
+ if (state.session_files.length > 0) {
3343
+ state.session_files = state.session_files.filter((f) => {
3344
+ if (f.length < 3 || f.length > 500) return false;
3345
+ if (!f.includes("/") && !f.includes("\\")) return false;
3346
+ if (f.includes("/../") || f.startsWith("../")) return false;
3347
+ if (/^\/?\d+\.\d+/.test(f)) return false;
3348
+ if (f === "/root/.ssh" || f.includes("/etc/cron")) return false;
3349
+ return true;
3350
+ });
3351
+ }
3302
3352
  }
3303
3353
  function deleteSessionState() {
3304
3354
  const watcherPath = getWatcherPath(activeSessionId);
@@ -5449,6 +5499,9 @@ function handleSubagentStop(stdinJson) {
5449
5499
  const fileMatches = lastMessage.match(/(?:\/[\w./+-]+\.\w+|[\w./+-]+\.(?:ts|js|py|xml|json|css|scss|md))/g);
5450
5500
  if (fileMatches) {
5451
5501
  for (const f of fileMatches) {
5502
+ if (!f.includes("/")) continue;
5503
+ if (f.includes("/../") || f.startsWith("../") || /^\/?\d+\.\d+/.test(f)) continue;
5504
+ if (f === "/root/.ssh" || f.includes("/etc/cron")) continue;
5452
5505
  if (!state.session_files.includes(f)) {
5453
5506
  state.session_files.push(f);
5454
5507
  }
@@ -5457,7 +5510,7 @@ function handleSubagentStop(stdinJson) {
5457
5510
  state.session_files = state.session_files.slice(-50);
5458
5511
  }
5459
5512
  }
5460
- const isMetaAnalysis = lastMessage.startsWith("<analysis>") || lastMessage.startsWith("<summary>") || /^#+\s/.test(lastMessage) || lastMessage.startsWith("Based on ");
5513
+ const isMetaAnalysis = lastMessage.startsWith("<analysis>") || lastMessage.startsWith("<summary>") || /^#+\s/.test(lastMessage) || lastMessage.startsWith("Based on ") || /^(I now have|Perfect!|I have (sufficient|enough|comprehensive))/i.test(lastMessage) || /^(Here('s| is) (the|my|a) (comprehensive|complete|detailed|full))/i.test(lastMessage) || lastMessage.includes("## ") && lastMessage.length > 500;
5461
5514
  const hasError = !isMetaAnalysis && containsError(lastMessage);
5462
5515
  if (hasError) {
5463
5516
  state.recent_errors.push(truncate(lastMessage, 200));
@@ -5696,13 +5749,20 @@ function buildContinuationBrief(state) {
5696
5749
  for (const id of state.decision_memory_ids.slice(-5)) {
5697
5750
  try {
5698
5751
  const mem = getMemory(id);
5699
- if (mem) decisions.push(truncate(mem.content, 150));
5752
+ if (mem) {
5753
+ const content = mem.content;
5754
+ if (/^Delegated:|^Decision:\s*Delegated/i.test(content)) continue;
5755
+ decisions.push(truncate(content, 150));
5756
+ }
5700
5757
  } catch {
5701
5758
  }
5702
5759
  }
5703
5760
  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));
5704
5761
  const editActions = state.recent_actions.filter((a) => a.tool === "Edit" || a.tool === "Write");
5705
- const keyFiles = [...new Set(editActions.map((a) => a.target))].slice(-10);
5762
+ const keyFiles = [...new Set(editActions.map((a) => {
5763
+ const arrowIdx = a.target.indexOf(" \u2192");
5764
+ return arrowIdx > 0 ? a.target.slice(0, arrowIdx) : a.target;
5765
+ }))].slice(-10);
5706
5766
  const recentBash = state.recent_commands?.slice(-5) ?? [];
5707
5767
  if (recentBash.length > 0) {
5708
5768
  const bashSummary = recentBash.map((c) => truncate(c.cmd, 80));
@@ -7131,10 +7191,14 @@ function handlePostCompact(stdinJson) {
7131
7191
  if (!recovery) return;
7132
7192
  const budget = new OutputBudget(OUTPUT_BUDGET.POST_COMPACT_MAX_BYTES);
7133
7193
  const lines = [];
7134
- const brief = state.continuation_brief;
7135
- if (brief) {
7194
+ sanitizeCognitiveState(state);
7195
+ const brief = buildContinuationBrief(state);
7196
+ const briefUsable = brief.task !== "unknown task" || brief.last_actions.length > 0;
7197
+ if (briefUsable) {
7136
7198
  const mindLines = ["[Engram] Continue from where you left off:"];
7137
- mindLines.push(` Task: ${brief.task}`);
7199
+ if (brief.task !== "unknown task") {
7200
+ mindLines.push(` Task: ${brief.task}`);
7201
+ }
7138
7202
  mindLines.push(` Phase: ${brief.phase}`);
7139
7203
  if (brief.last_actions.length > 0) {
7140
7204
  mindLines.push(` Last actions:`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vedtechsolutions/engram-mcp",
3
- "version": "1.0.20",
3
+ "version": "1.0.21",
4
4
  "description": "Cognitive memory system for AI — persistent, cross-session learning via MCP",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",