@vedtechsolutions/engram-mcp 1.0.4 → 1.0.6

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.
@@ -446,16 +446,16 @@ var PROACTIVE_RECALL = {
446
446
  var MEMORY_SURFACE = {
447
447
  /** Maximum memories surfaced per prompt check */
448
448
  MAX_SURFACE_ITEMS: 3,
449
- /** Candidate pool fetched from DB (filtered down to MAX_SURFACE_ITEMS) */
450
- CANDIDATE_POOL_SIZE: 8,
449
+ /** Candidate pool fetched from DB (wider pool = more rotation diversity) */
450
+ CANDIDATE_POOL_SIZE: 15,
451
451
  /** Minimum turns before re-surfacing the same memory */
452
- MIN_TURNS_BETWEEN_SAME: 8,
452
+ MIN_TURNS_BETWEEN_SAME: 12,
453
453
  /** Minimum domain string length to trigger surface injection */
454
454
  MIN_DOMAIN_LENGTH: 2,
455
455
  /** Minimum confidence for surface injection */
456
456
  MIN_SURFACE_CONFIDENCE: 0.5,
457
457
  /** Minimum reinforcement for surface injection (below default 1.0 to allow fresh memories) */
458
- MIN_SURFACE_REINFORCEMENT: 0.8
458
+ MIN_SURFACE_REINFORCEMENT: 0.5
459
459
  };
460
460
  var RETRIEVAL_FEEDBACK = {
461
461
  /** Maximum recalled memory IDs to track (ring buffer) */
@@ -491,6 +491,29 @@ var SCHEMA_SURFACING = {
491
491
  /** Maximum instances to sample when generating a description */
492
492
  INSTANCE_SAMPLE_COUNT: 5
493
493
  };
494
+ var PROCEDURAL_WORKFLOW = {
495
+ /** Minimum successful commands in sequence to form a workflow */
496
+ MIN_COMMANDS: 3,
497
+ /** Maximum commands to track in recent_commands buffer */
498
+ MAX_TRACKED_COMMANDS: 20,
499
+ /** Maximum procedural workflows to encode per session */
500
+ MAX_PER_SESSION: 5,
501
+ /** Minimum time gap (ms) between workflow encodings to avoid bursts */
502
+ MIN_ENCODE_GAP_MS: 12e4,
503
+ /** Workflow pattern keywords — commands matching these form workflow candidates */
504
+ WORKFLOW_PATTERNS: {
505
+ build: ["build", "compile", "tsup", "tsc", "webpack", "vite", "esbuild", "rollup", "make"],
506
+ test: ["test", "vitest", "jest", "pytest", "mocha", "cargo test"],
507
+ deploy: ["deploy", "publish", "release", "push", "npm publish", "yarn publish", "pnpm publish"],
508
+ install: ["install", "npm install", "pnpm install", "yarn", "pip install", "cargo add"],
509
+ lint: ["lint", "eslint", "prettier", "black", "ruff", "clippy"],
510
+ db: ["migrate", "migration", "seed", "prisma", "alembic", "knex"],
511
+ docker: ["docker", "compose", "podman"],
512
+ git: ["git commit", "git push", "git tag", "git merge", "git rebase"]
513
+ },
514
+ /** Minimum confidence for encoding */
515
+ MIN_CONFIDENCE: 0.65
516
+ };
494
517
  var CODE_CONTEXT_RECALL = {
495
518
  /** Maximum code identifiers to extract from content */
496
519
  MAX_CODE_KEYWORDS: 15,
@@ -9664,9 +9687,12 @@ function removeProficiency(model, domain) {
9664
9687
  function computeProficiency(prof, domain) {
9665
9688
  let avgConfidence = 0.5;
9666
9689
  try {
9667
- const domainMemories = getMemoriesByDomain(domain, 50);
9668
- if (domainMemories.length > 0) {
9669
- avgConfidence = domainMemories.reduce((sum, m) => sum + m.confidence, 0) / domainMemories.length;
9690
+ const domainMemories = getMemoriesByDomain(domain, 100);
9691
+ const qualityMemories = domainMemories.filter(
9692
+ (m) => m.type === "semantic" || m.type === "procedural" || m.type === "antipattern" || m.type === "episodic" && isEpisodicData(m.type_data) && m.type_data.lesson && m.type_data.lesson.length > 10
9693
+ );
9694
+ if (qualityMemories.length > 0) {
9695
+ avgConfidence = qualityMemories.reduce((sum, m) => sum + m.confidence, 0) / qualityMemories.length;
9670
9696
  }
9671
9697
  } catch {
9672
9698
  }
@@ -12376,6 +12402,7 @@ export {
12376
12402
  PROACTIVE_RECALL,
12377
12403
  MEMORY_SURFACE,
12378
12404
  RETRIEVAL_FEEDBACK,
12405
+ PROCEDURAL_WORKFLOW,
12379
12406
  CODE_CONTEXT_RECALL,
12380
12407
  DEDUP,
12381
12408
  SCHEMA_LIFECYCLE,
@@ -12627,4 +12654,4 @@ export {
12627
12654
  composeProjectUnderstanding,
12628
12655
  formatMentalModelInjection
12629
12656
  };
12630
- //# sourceMappingURL=chunk-QU7DOPA4.js.map
12657
+ //# sourceMappingURL=chunk-V5TTXT4V.js.map
package/dist/hook.js CHANGED
@@ -28,6 +28,7 @@ import {
28
28
  PREWRITE_BLOCKING,
29
29
  PRE_COMPACTION,
30
30
  PROACTIVE_RECALL,
31
+ PROCEDURAL_WORKFLOW,
31
32
  REASONING_CHAIN,
32
33
  REASONING_TRACE,
33
34
  RETRIEVAL_FEEDBACK,
@@ -173,7 +174,7 @@ import {
173
174
  updateReasoningChain,
174
175
  updateSelfModelFromSession,
175
176
  updateTask
176
- } from "./chunk-QU7DOPA4.js";
177
+ } from "./chunk-V5TTXT4V.js";
177
178
 
178
179
  // src/hook.ts
179
180
  import { readFileSync, writeFileSync, existsSync, renameSync, statSync, readdirSync, unlinkSync, appendFileSync, openSync, readSync, closeSync } from "fs";
@@ -1743,7 +1744,11 @@ function composeSessionNarrative(params) {
1743
1744
  if (params.total_turns < SESSION_NARRATIVE.MIN_TURNS_FOR_NARRATIVE) {
1744
1745
  return null;
1745
1746
  }
1746
- const goal = extractGoal(params);
1747
+ const goal = extractGoal({
1748
+ ...params,
1749
+ cognitive_state: params.cognitive_state,
1750
+ session_files: params.session_files
1751
+ });
1747
1752
  const approach = params.cognitive_state?.current_approach ?? extractApproach(params.conversation);
1748
1753
  const challenges = extractChallenges(params);
1749
1754
  const baseLessons = extractLessons(params);
@@ -1781,6 +1786,13 @@ function composeSessionNarrative(params) {
1781
1786
  }
1782
1787
  function extractGoal(params) {
1783
1788
  if (params.active_task) return params.active_task;
1789
+ if (params.cognitive_state?.current_approach) {
1790
+ return params.cognitive_state.current_approach;
1791
+ }
1792
+ if (params.cognitive_state?.recent_discovery && params.session_files && params.session_files.length > 0) {
1793
+ const topFiles = params.session_files.slice(-3).map((f) => f.split(/[/\\]/).pop() ?? f).join(", ");
1794
+ return `${params.cognitive_state.recent_discovery} (${topFiles})`;
1795
+ }
1784
1796
  if (params.conversation.topic_history.length > 0) {
1785
1797
  return params.conversation.topic_history[0].topic;
1786
1798
  }
@@ -3113,7 +3125,9 @@ function loadWatcherState() {
3113
3125
  recall_misses: raw.recall_misses ?? 0,
3114
3126
  last_status_turn: raw.last_status_turn ?? 0,
3115
3127
  offload_message_sent: raw.offload_message_sent ?? false,
3116
- summary_injection_mode: raw.summary_injection_mode ?? false
3128
+ summary_injection_mode: raw.summary_injection_mode ?? false,
3129
+ recent_commands: raw.recent_commands ?? [],
3130
+ procedural_encoded_count: raw.procedural_encoded_count ?? 0
3117
3131
  };
3118
3132
  }
3119
3133
  } catch {
@@ -3175,7 +3189,9 @@ function loadWatcherState() {
3175
3189
  recall_misses: 0,
3176
3190
  last_status_turn: 0,
3177
3191
  offload_message_sent: false,
3178
- summary_injection_mode: false
3192
+ summary_injection_mode: false,
3193
+ recent_commands: [],
3194
+ procedural_encoded_count: 0
3179
3195
  };
3180
3196
  }
3181
3197
  function saveWatcherState(state) {
@@ -4015,6 +4031,77 @@ Output: ${truncate(toolOutput, 500)}`,
4015
4031
  } catch {
4016
4032
  }
4017
4033
  }
4034
+ try {
4035
+ const cmdLower = cmd.toLowerCase();
4036
+ const exitCode = stdinJson?.tool_response_metadata;
4037
+ const cmdSuccess = !isError;
4038
+ state.recent_commands.push({ cmd: truncate(cmd, 200), success: cmdSuccess, time: (/* @__PURE__ */ new Date()).toISOString() });
4039
+ if (state.recent_commands.length > PROCEDURAL_WORKFLOW.MAX_TRACKED_COMMANDS) {
4040
+ state.recent_commands = state.recent_commands.slice(-PROCEDURAL_WORKFLOW.MAX_TRACKED_COMMANDS);
4041
+ }
4042
+ stateChanged = true;
4043
+ if (cmdSuccess && state.procedural_encoded_count < PROCEDURAL_WORKFLOW.MAX_PER_SESSION) {
4044
+ const successCmds = state.recent_commands.filter((c) => c.success);
4045
+ if (successCmds.length >= PROCEDURAL_WORKFLOW.MIN_COMMANDS) {
4046
+ for (const [workflowName, keywords] of Object.entries(PROCEDURAL_WORKFLOW.WORKFLOW_PATTERNS)) {
4047
+ const matching = successCmds.filter((c) => {
4048
+ const cl = c.cmd.toLowerCase();
4049
+ return keywords.some((kw) => cl.includes(kw));
4050
+ });
4051
+ if (matching.length >= PROCEDURAL_WORKFLOW.MIN_COMMANDS) {
4052
+ const steps = matching.slice(-6).map((c, i) => `${i + 1}. ${truncate(c.cmd, 120)}`).join("\n");
4053
+ const content = `${workflowName} workflow (${matching.length} steps):
4054
+ ${steps}`;
4055
+ const domains = state.active_domain ? [state.active_domain] : [];
4056
+ const existing = findDuplicate(content, "procedural", domains);
4057
+ if (!existing) {
4058
+ createMemory({
4059
+ type: "procedural",
4060
+ content,
4061
+ summary: `${workflowName} workflow: ${matching.slice(-3).map((c) => truncate(c.cmd, 40)).join(" \u2192 ")}`,
4062
+ encoding_strength: 0.7,
4063
+ reinforcement: 1.2,
4064
+ confidence: PROCEDURAL_WORKFLOW.MIN_CONFIDENCE,
4065
+ storage_tier: "short_term",
4066
+ pinned: false,
4067
+ tags: ["workflow", `workflow-${workflowName}`, "auto-encoded"],
4068
+ domains,
4069
+ version: state.active_version,
4070
+ encoding_context: {
4071
+ project: state.active_project,
4072
+ project_path: state.active_project_path,
4073
+ framework: state.active_domain,
4074
+ version: state.active_version,
4075
+ files: state.session_files.slice(-5),
4076
+ task_type: workflowName === "build" ? "building" : null,
4077
+ error_context: null,
4078
+ session_id: sessionId,
4079
+ significance_score: 0.7
4080
+ },
4081
+ type_data: {
4082
+ kind: "procedural",
4083
+ steps: matching.map((c) => c.cmd),
4084
+ preconditions: [],
4085
+ postconditions: [],
4086
+ practice_count: 1,
4087
+ automaticity: 0.3,
4088
+ variants: [],
4089
+ skill_metadata: null
4090
+ }
4091
+ });
4092
+ state.procedural_encoded_count++;
4093
+ stateChanged = true;
4094
+ log.info("Auto-encoded procedural workflow", { type: workflowName, steps: matching.length });
4095
+ const matchedTimes = new Set(matching.map((c) => c.time));
4096
+ state.recent_commands = state.recent_commands.filter((c) => !matchedTimes.has(c.time));
4097
+ }
4098
+ break;
4099
+ }
4100
+ }
4101
+ }
4102
+ }
4103
+ } catch {
4104
+ }
4018
4105
  if (stateChanged) {
4019
4106
  saveWatcherState(state);
4020
4107
  }
@@ -4851,7 +4938,9 @@ function handleSessionStart(stdinJson, argFallback) {
4851
4938
  recall_misses: isPostCompact ? prevState?.recall_misses ?? 0 : 0,
4852
4939
  last_status_turn: 0,
4853
4940
  offload_message_sent: false,
4854
- summary_injection_mode: false
4941
+ summary_injection_mode: false,
4942
+ recent_commands: isPostCompact ? prevState?.recent_commands ?? [] : [],
4943
+ procedural_encoded_count: isPostCompact ? prevState?.procedural_encoded_count ?? 0 : 0
4855
4944
  });
4856
4945
  const source = metadata.source;
4857
4946
  if (!source || source === "startup") {
@@ -6098,7 +6187,8 @@ ${distillLines}`
6098
6187
  }
6099
6188
  const rawCandidates = getTopDomainMemories(surfaceDomain, MEMORY_SURFACE.CANDIDATE_POOL_SIZE, excludeIds, state.active_project ?? void 0);
6100
6189
  const candidates = rawCandidates.filter(
6101
- (m) => m.confidence >= MEMORY_SURFACE.MIN_SURFACE_CONFIDENCE && m.reinforcement >= MEMORY_SURFACE.MIN_SURFACE_REINFORCEMENT && !isRecallNoise(m.content, m.type, m.tags)
6190
+ (m) => m.confidence >= MEMORY_SURFACE.MIN_SURFACE_CONFIDENCE && m.reinforcement >= MEMORY_SURFACE.MIN_SURFACE_REINFORCEMENT && !isRecallNoise(m.content, m.type, m.tags) && !m.tags.includes("session_narrative")
6191
+ // narratives are for model composition, not surfacing
6102
6192
  );
6103
6193
  const surfaced = selectDiverseSurface(candidates, MEMORY_SURFACE.MAX_SURFACE_ITEMS);
6104
6194
  if (surfaced.length > 0) {
@@ -6184,6 +6274,7 @@ ${distillLines}`
6184
6274
  if (somaticIds.has(m.memory.id)) continue;
6185
6275
  if (isRecallNoise(m.memory.content, m.memory.type, m.memory.tags)) continue;
6186
6276
  if (m.memory.tags.includes("pre-compact")) continue;
6277
+ if (m.memory.tags.includes("session_narrative")) continue;
6187
6278
  const isFailure = m.memory.type === "episodic" && isEpisodicData(m.memory.type_data) && m.memory.type_data.outcome === "negative";
6188
6279
  const prefix = m.somatic_marker ? "[ENGRAM GUT]" : isFailure ? "[ENGRAM CAUTION]" : "[ENGRAM CONTEXT]";
6189
6280
  const outcomeHint = m.memory.type === "episodic" && (m.somatic_marker || isFailure) ? getEpisodicOutcomeHint(m.memory) : "";
package/dist/index.js CHANGED
@@ -154,7 +154,7 @@ import {
154
154
  vaccinate,
155
155
  vacuumDatabase,
156
156
  validateMultiPerspective
157
- } from "./chunk-QU7DOPA4.js";
157
+ } from "./chunk-V5TTXT4V.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.4",
3
+ "version": "1.0.6",
4
4
  "description": "Cognitive memory system for AI — persistent, cross-session learning via MCP",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",