@cogmem/engram 0.3.0 → 0.3.1

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.
@@ -1,7 +1,8 @@
1
1
  import { defineCommand } from "citty";
2
+
2
3
  import { EngramEngine } from "../../core/engine.ts";
3
- import { focusUtilization } from "../../core/working-memory.ts";
4
4
  import { refreshActivations } from "../../core/forgetting.ts";
5
+ import { focusUtilization } from "../../core/working-memory.ts";
5
6
  import { bold, dim, green, yellow, red, isInteractive } from "../format.ts";
6
7
 
7
8
  export const healthCommand = defineCommand({
@@ -13,7 +14,10 @@ export const healthCommand = defineCommand({
13
14
  const engine = EngramEngine.create();
14
15
  try {
15
16
  const { atRisk } = refreshActivations(engine.storage, engine.config);
16
- const { used, capacity } = focusUtilization(engine.storage, engine.config);
17
+ const { used, capacity } = focusUtilization(
18
+ engine.storage,
19
+ engine.config
20
+ );
17
21
  const lastConsolidation = engine.storage.getLastConsolidation();
18
22
  const totalMemories = engine.storage.getMemoryCount();
19
23
  const associationCount = engine.storage.getAssociationCount();
@@ -29,7 +33,7 @@ export const healthCommand = defineCommand({
29
33
  totalMemories,
30
34
  associations: associationCount,
31
35
  lastConsolidationHoursAgo: hoursAgo ? Math.round(hoursAgo) : null,
32
- }),
36
+ })
33
37
  );
34
38
  return;
35
39
  }
@@ -37,42 +41,72 @@ export const healthCommand = defineCommand({
37
41
  console.log(bold(" engram — health check\n"));
38
42
 
39
43
  if (atRisk > 0) {
40
- console.log(yellow(` ! ${atRisk} memories at risk of being forgotten`));
44
+ console.log(
45
+ yellow(` ! ${atRisk} memories at risk of being forgotten`)
46
+ );
41
47
  } else {
42
48
  console.log(green(" + All memories above retrieval threshold"));
43
49
  }
44
50
 
45
51
  if (used <= capacity) {
46
- console.log(green(` + Working memory within capacity (${used}/${capacity})`));
52
+ console.log(
53
+ green(` + Working memory within capacity (${used}/${capacity})`)
54
+ );
47
55
  } else {
48
- console.log(red(` ! Working memory over capacity (${used}/${capacity})`));
56
+ console.log(
57
+ red(` ! Working memory over capacity (${used}/${capacity})`)
58
+ );
49
59
  }
50
60
 
51
61
  if (lastConsolidation) {
52
62
  const hoursAgo = (Date.now() - lastConsolidation.ranAt) / 3600000;
53
63
  if (hoursAgo > 18) {
54
- console.log(red(` ! Consolidation overdue (last: ${Math.round(hoursAgo)}h ago)`));
64
+ console.log(
65
+ red(
66
+ ` ! Consolidation overdue (last: ${Math.round(hoursAgo)}h ago)`
67
+ )
68
+ );
55
69
  } else if (hoursAgo > 8) {
56
70
  console.log(
57
- yellow(` ~ Consolidation recommended soon (last: ${Math.round(hoursAgo)}h ago)`),
71
+ yellow(
72
+ ` ~ Consolidation recommended soon (last: ${Math.round(
73
+ hoursAgo
74
+ )}h ago)`
75
+ )
58
76
  );
59
77
  } else {
60
- console.log(green(` + Consolidation recent (last: ${Math.round(hoursAgo)}h ago)`));
78
+ console.log(
79
+ green(
80
+ ` + Consolidation recent (last: ${Math.round(hoursAgo)}h ago)`
81
+ )
82
+ );
61
83
  }
62
84
  } else if (totalMemories > 0) {
63
- console.log(yellow(" ! No consolidation has ever run — run `engram sleep`"));
85
+ console.log(
86
+ yellow(" ! No consolidation has ever run — run `engram sleep`")
87
+ );
64
88
  } else {
65
89
  console.log(dim(" ~ No memories encoded yet"));
66
90
  }
67
91
 
68
92
  if (totalMemories > 5 && associationCount === 0) {
69
- console.log(yellow(" ! No associations formed — run `engram sleep` to discover links"));
93
+ console.log(
94
+ yellow(
95
+ " ! No associations formed — run `engram sleep` to discover links"
96
+ )
97
+ );
70
98
  } else if (associationCount > 0) {
71
99
  const ratio = associationCount / Math.max(1, totalMemories);
72
100
  if (ratio > 1) {
73
- console.log(green(` + Association network is rich (${associationCount} links)`));
101
+ console.log(
102
+ green(` + Association network is rich (${associationCount} links)`)
103
+ );
74
104
  } else {
75
- console.log(green(` + Association network is healthy (${associationCount} links)`));
105
+ console.log(
106
+ green(
107
+ ` + Association network is healthy (${associationCount} links)`
108
+ )
109
+ );
76
110
  }
77
111
  }
78
112
  } finally {
@@ -1,4 +1,5 @@
1
1
  import { defineCommand } from "citty";
2
+
2
3
  import { EngramEngine } from "../../core/engine.ts";
3
4
  import { formatMemoryInspection, dim } from "../format.ts";
4
5
 
@@ -18,7 +19,9 @@ export const inspectCommand = defineCommand({
18
19
  const engine = EngramEngine.create();
19
20
  try {
20
21
  const allMemories = engine.storage.getAllMemories();
21
- const match = allMemories.find((m) => m.id === args.id || m.id.startsWith(args.id));
22
+ const match = allMemories.find(
23
+ (m) => m.id === args.id || m.id.startsWith(args.id)
24
+ );
22
25
 
23
26
  if (!match) {
24
27
  console.log(dim(` No memory found matching "${args.id}"`));
@@ -28,7 +31,9 @@ export const inspectCommand = defineCommand({
28
31
  const accessLog = engine.storage.getAccessLog(match.id);
29
32
  const associations = engine.storage.getAssociations(match.id);
30
33
 
31
- console.log(formatMemoryInspection(match, accessLog.length, associations.length));
34
+ console.log(
35
+ formatMemoryInspection(match, accessLog.length, associations.length)
36
+ );
32
37
  } finally {
33
38
  engine.close();
34
39
  }
@@ -1,10 +1,12 @@
1
- import { defineCommand } from "citty";
2
1
  import { readFileSync } from "node:fs";
3
2
  import { join, dirname } from "node:path";
4
3
  import { fileURLToPath } from "node:url";
4
+
5
+ import { defineCommand } from "citty";
5
6
  import { consola } from "consola";
6
- import { getProvider, availableProviders } from "../providers/index.ts";
7
+
7
8
  import { green, dim, yellow, bold } from "../format.ts";
9
+ import { getProvider, availableProviders } from "../providers/index.ts";
8
10
 
9
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
12
  const SKILL_PATH = join(__dirname, "..", "..", "..", "SKILL.md");
@@ -96,16 +98,23 @@ export const installCommand = defineCommand({
96
98
  if (result.status === "already_installed") {
97
99
  console.log(dim(" already installed — nothing to do"));
98
100
  console.log(dim(` skill: ${result.skillPath}`));
99
- if (result.mcpConfigPath) console.log(dim(` mcp: ${result.mcpConfigPath}`));
101
+ if (result.mcpConfigPath)
102
+ console.log(dim(` mcp: ${result.mcpConfigPath}`));
100
103
  return;
101
104
  }
102
105
 
103
106
  const prefix = dryRun ? "would install" : "installed";
104
107
  const check = dryRun ? yellow("~") : green("\u2713");
105
108
 
106
- console.log(` ${check} Skill ${prefix} ${dim("\u2192")} ${bold(result.skillPath)}`);
109
+ console.log(
110
+ ` ${check} Skill ${prefix} ${dim("\u2192")} ${bold(result.skillPath)}`
111
+ );
107
112
  if (result.mcpConfigured && result.mcpConfigPath) {
108
- console.log(` ${check} MCP ${prefix} ${dim("\u2192")} ${bold(result.mcpConfigPath)}`);
113
+ console.log(
114
+ ` ${check} MCP ${prefix} ${dim("\u2192")} ${bold(
115
+ result.mcpConfigPath
116
+ )}`
117
+ );
109
118
  } else if (result.mcpConfigPath) {
110
119
  console.log(dim(` - MCP already configured → ${result.mcpConfigPath}`));
111
120
  }
@@ -1,4 +1,5 @@
1
1
  import { defineCommand } from "citty";
2
+
2
3
  import { EngramEngine } from "../../core/engine.ts";
3
4
  import { isValidMemoryType } from "../../core/memory.ts";
4
5
  import { formatMemoryList } from "../format.ts";
@@ -32,7 +33,8 @@ export const listCommand = defineCommand({
32
33
  run({ args }) {
33
34
  const engine = EngramEngine.create();
34
35
  try {
35
- const type = args.type && isValidMemoryType(args.type) ? args.type : undefined;
36
+ const type =
37
+ args.type && isValidMemoryType(args.type) ? args.type : undefined;
36
38
  const limit = Number(args.limit);
37
39
 
38
40
  let memories;
@@ -1,8 +1,9 @@
1
1
  import { defineCommand } from "citty";
2
+
2
3
  import { EngramEngine } from "../../core/engine.ts";
4
+ import { isValidMemoryType } from "../../core/memory.ts";
3
5
  import { recall } from "../../core/recall.ts";
4
6
  import { formatRecallResults } from "../format.ts";
5
- import { isValidMemoryType } from "../../core/memory.ts";
6
7
 
7
8
  export const recallCommand = defineCommand({
8
9
  meta: {
@@ -38,7 +39,8 @@ export const recallCommand = defineCommand({
38
39
  run({ args }) {
39
40
  const engine = EngramEngine.create();
40
41
  try {
41
- const typeFilter = args.type && isValidMemoryType(args.type) ? args.type : undefined;
42
+ const typeFilter =
43
+ args.type && isValidMemoryType(args.type) ? args.type : undefined;
42
44
 
43
45
  const results = recall(engine.storage, args.cue, engine.config, {
44
46
  type: typeFilter,
@@ -1,13 +1,15 @@
1
1
  import { defineCommand } from "citty";
2
- import { EngramEngine } from "../../core/engine.ts";
3
- import { consolidate } from "../../core/consolidation.ts";
2
+
4
3
  import { discoverChunks } from "../../core/chunking.ts";
4
+ import { consolidate } from "../../core/consolidation.ts";
5
+ import { EngramEngine } from "../../core/engine.ts";
5
6
  import { bold, dim, green, cyan, isInteractive } from "../format.ts";
6
7
 
7
8
  export const sleepCommand = defineCommand({
8
9
  meta: {
9
10
  name: "sleep",
10
- description: "Run consolidation cycle (replay, strengthen, prune, extract, link)",
11
+ description:
12
+ "Run consolidation cycle (replay, strengthen, prune, extract, link)",
11
13
  },
12
14
  args: {
13
15
  report: {
@@ -41,7 +43,7 @@ export const sleepCommand = defineCommand({
41
43
  })),
42
44
  }
43
45
  : {}),
44
- }),
46
+ })
45
47
  );
46
48
  return;
47
49
  }
@@ -49,17 +51,29 @@ export const sleepCommand = defineCommand({
49
51
  console.log(dim(" Running consolidation cycle...\n"));
50
52
  console.log(green(" Consolidation complete:\n"));
51
53
  console.log(
52
- ` ${cyan("Strengthened")} ${result.memoriesStrengthened} frequently-accessed memories`,
54
+ ` ${cyan("Strengthened")} ${
55
+ result.memoriesStrengthened
56
+ } frequently-accessed memories`
53
57
  );
54
58
  console.log(
55
- ` ${cyan("Pruned")} ${result.memoriesPruned} memories below activation threshold`,
59
+ ` ${cyan("Pruned")} ${
60
+ result.memoriesPruned
61
+ } memories below activation threshold`
56
62
  );
57
63
  console.log(
58
- ` ${cyan("Extracted")} ${result.factsExtracted} semantic facts from episodic patterns`,
64
+ ` ${cyan("Extracted")} ${
65
+ result.factsExtracted
66
+ } semantic facts from episodic patterns`
67
+ );
68
+ console.log(
69
+ ` ${cyan("Discovered")} ${
70
+ result.associationsDiscovered
71
+ } new associations`
59
72
  );
60
- console.log(` ${cyan("Discovered")} ${result.associationsDiscovered} new associations`);
61
73
  if (chunks.length > 0) {
62
- console.log(` ${cyan("Chunked")} ${chunks.length} new memory groups`);
74
+ console.log(
75
+ ` ${cyan("Chunked")} ${chunks.length} new memory groups`
76
+ );
63
77
  }
64
78
 
65
79
  if (args.report) {
@@ -84,14 +98,20 @@ export const sleepCommand = defineCommand({
84
98
  if (chunks.length > 0) {
85
99
  console.log(bold(" New Chunks:"));
86
100
  for (const chunk of chunks) {
87
- console.log(` ${dim(">")} ${chunk.label} (${chunk.memberIds.length} memories)`);
101
+ console.log(
102
+ ` ${dim(">")} ${chunk.label} (${
103
+ chunk.memberIds.length
104
+ } memories)`
105
+ );
88
106
  }
89
107
  console.log("");
90
108
  }
91
109
 
92
110
  if (result.discoveredAssociationPairs.length > 0) {
93
111
  console.log(
94
- bold(` Associations Discovered: ${result.discoveredAssociationPairs.length}`),
112
+ bold(
113
+ ` Associations Discovered: ${result.discoveredAssociationPairs.length}`
114
+ )
95
115
  );
96
116
  }
97
117
  }
@@ -1,8 +1,9 @@
1
1
  import { defineCommand } from "citty";
2
+
2
3
  import { EngramEngine } from "../../core/engine.ts";
4
+ import { refreshActivations } from "../../core/forgetting.ts";
3
5
  import { focusUtilization } from "../../core/working-memory.ts";
4
6
  import { bold, dim, green, yellow, red, isInteractive } from "../format.ts";
5
- import { refreshActivations } from "../../core/forgetting.ts";
6
7
 
7
8
  export const statsCommand = defineCommand({
8
9
  meta: {
@@ -18,16 +19,28 @@ export const statsCommand = defineCommand({
18
19
  const semanticCount = engine.storage.getMemoryCount("semantic");
19
20
  const proceduralCount = engine.storage.getMemoryCount("procedural");
20
21
  const associationCount = engine.storage.getAssociationCount();
21
- const { used, capacity } = focusUtilization(engine.storage, engine.config);
22
+ const { used, capacity } = focusUtilization(
23
+ engine.storage,
24
+ engine.config
25
+ );
22
26
 
23
27
  const lastConsolidation = engine.storage.getLastConsolidation();
24
28
 
25
29
  const projectContext = engine.projectContext;
26
30
  const projectCounts = projectContext
27
31
  ? {
28
- episodic: engine.storage.getMemoryCountByContext(projectContext, "episodic"),
29
- semantic: engine.storage.getMemoryCountByContext(projectContext, "semantic"),
30
- procedural: engine.storage.getMemoryCountByContext(projectContext, "procedural"),
32
+ episodic: engine.storage.getMemoryCountByContext(
33
+ projectContext,
34
+ "episodic"
35
+ ),
36
+ semantic: engine.storage.getMemoryCountByContext(
37
+ projectContext,
38
+ "semantic"
39
+ ),
40
+ procedural: engine.storage.getMemoryCountByContext(
41
+ projectContext,
42
+ "procedural"
43
+ ),
31
44
  total: engine.storage.getMemoryCountByContext(projectContext),
32
45
  }
33
46
  : null;
@@ -41,9 +54,13 @@ export const statsCommand = defineCommand({
41
54
  procedural: proceduralCount,
42
55
  associations: associationCount,
43
56
  atRisk,
44
- lastConsolidation: lastConsolidation ? { ranAt: lastConsolidation.ranAt } : null,
45
- ...(projectCounts ? { project: { context: projectContext, ...projectCounts } } : {}),
46
- }),
57
+ lastConsolidation: lastConsolidation
58
+ ? { ranAt: lastConsolidation.ranAt }
59
+ : null,
60
+ ...(projectCounts
61
+ ? { project: { context: projectContext, ...projectCounts } }
62
+ : {}),
63
+ })
47
64
  );
48
65
  return;
49
66
  }
@@ -54,27 +71,33 @@ export const statsCommand = defineCommand({
54
71
  used >= capacity
55
72
  ? red(`${used}/${capacity} slots used (FULL)`)
56
73
  : used > capacity * 0.7
57
- ? yellow(`${used}/${capacity} slots used`)
58
- : green(`${used}/${capacity} slots used`);
74
+ ? yellow(`${used}/${capacity} slots used`)
75
+ : green(`${used}/${capacity} slots used`);
59
76
  console.log(` Working Memory: ${wmStatus}`);
60
77
 
61
78
  console.log(
62
79
  ` Episodic: ${episodicCount} memories` +
63
- (atRisk > 0 ? ` ${yellow(`(${atRisk} at risk of forgetting)`)}` : ""),
80
+ (atRisk > 0 ? ` ${yellow(`(${atRisk} at risk of forgetting)`)}` : "")
64
81
  );
65
82
  console.log(` Semantic: ${semanticCount} facts`);
66
- console.log(` Procedural: ${proceduralCount} skills ${dim("(immune to decay)")}`);
83
+ console.log(
84
+ ` Procedural: ${proceduralCount} skills ${dim(
85
+ "(immune to decay)"
86
+ )}`
87
+ );
67
88
 
68
89
  console.log(` Associations: ${associationCount} links`);
69
90
 
70
91
  if (lastConsolidation) {
71
- const hoursAgo = Math.round((Date.now() - lastConsolidation.ranAt) / 3600000);
92
+ const hoursAgo = Math.round(
93
+ (Date.now() - lastConsolidation.ranAt) / 3600000
94
+ );
72
95
  const consolidationStatus =
73
96
  hoursAgo > 12
74
97
  ? red(`${hoursAgo}h ago (overdue)`)
75
98
  : hoursAgo > 6
76
- ? yellow(`${hoursAgo}h ago`)
77
- : green(`${hoursAgo}h ago`);
99
+ ? yellow(`${hoursAgo}h ago`)
100
+ : green(`${hoursAgo}h ago`);
78
101
  console.log(` Last sleep: ${consolidationStatus}`);
79
102
  } else {
80
103
  console.log(` Last sleep: ${dim("never")}`);
package/src/cli/format.ts CHANGED
@@ -1,8 +1,9 @@
1
- import type { Memory, RecallResult } from "../core/memory.ts";
2
- import kleur from "kleur";
3
1
  import Table from "cli-table3";
4
2
  import dayjs from "dayjs";
5
3
  import relativeTime from "dayjs/plugin/relativeTime.js";
4
+ import kleur from "kleur";
5
+
6
+ import type { Memory, RecallResult } from "../core/memory.ts";
6
7
 
7
8
  dayjs.extend(relativeTime);
8
9
 
package/src/cli/index.ts CHANGED
@@ -1,15 +1,16 @@
1
1
  #!/usr/bin/env bun
2
2
  import { defineCommand, runMain } from "citty";
3
+
3
4
  import pkg from "../../package.json";
4
5
  import { encodeCommand } from "./commands/encode.ts";
5
- import { recallCommand } from "./commands/recall.ts";
6
6
  import { focusCommand } from "./commands/focus.ts";
7
+ import { healthCommand } from "./commands/health.ts";
7
8
  import { inspectCommand } from "./commands/inspect.ts";
8
- import { statsCommand } from "./commands/stats.ts";
9
+ import { installCommand } from "./commands/install.ts";
9
10
  import { listCommand } from "./commands/list.ts";
11
+ import { recallCommand } from "./commands/recall.ts";
10
12
  import { sleepCommand } from "./commands/sleep.ts";
11
- import { healthCommand } from "./commands/health.ts";
12
- import { installCommand } from "./commands/install.ts";
13
+ import { statsCommand } from "./commands/stats.ts";
13
14
 
14
15
  const main = defineCommand({
15
16
  meta: {
@@ -1,6 +1,7 @@
1
1
  import { mkdirSync, readFileSync, writeFileSync, existsSync } from "node:fs";
2
- import { join } from "node:path";
3
2
  import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+
4
5
  import type { ProviderInstaller } from "./types.ts";
5
6
 
6
7
  const MCP_SERVER_CONFIG = {
@@ -55,12 +56,17 @@ export const claudeProvider: ProviderInstaller = {
55
56
  async installGlobal(skillContent, dryRun) {
56
57
  const home = homedir();
57
58
  const skillDir = join(home, ".claude", "skills", "engram");
58
- const configPath = join(home, ".claude", "settings.json");
59
+ const configPath = join(home, ".claude.json");
59
60
 
60
61
  const skillInstalled = installSkill(skillDir, skillContent, dryRun);
61
62
  const mcpInstalled = configureMcp(configPath, dryRun);
62
63
 
63
- const status = !skillInstalled && !mcpInstalled ? "already_installed" : skillInstalled && mcpInstalled ? "installed" : "updated";
64
+ const status =
65
+ !skillInstalled && !mcpInstalled
66
+ ? "already_installed"
67
+ : skillInstalled && mcpInstalled
68
+ ? "installed"
69
+ : "updated";
64
70
 
65
71
  return {
66
72
  status,
@@ -72,12 +78,17 @@ export const claudeProvider: ProviderInstaller = {
72
78
 
73
79
  async installProject(skillContent, projectDir, dryRun) {
74
80
  const skillDir = join(projectDir, ".claude", "skills", "engram");
75
- const configPath = join(projectDir, ".claude", "settings.local.json");
81
+ const configPath = join(projectDir, ".mcp.json");
76
82
 
77
83
  const skillInstalled = installSkill(skillDir, skillContent, dryRun);
78
84
  const mcpInstalled = configureMcp(configPath, dryRun);
79
85
 
80
- const status = !skillInstalled && !mcpInstalled ? "already_installed" : skillInstalled && mcpInstalled ? "installed" : "updated";
86
+ const status =
87
+ !skillInstalled && !mcpInstalled
88
+ ? "already_installed"
89
+ : skillInstalled && mcpInstalled
90
+ ? "installed"
91
+ : "updated";
81
92
 
82
93
  return {
83
94
  status,
@@ -12,5 +12,9 @@ export interface ProviderInstaller {
12
12
  displayName: string;
13
13
  available: boolean;
14
14
  installGlobal(skillContent: string, dryRun: boolean): Promise<InstallResult>;
15
- installProject(skillContent: string, projectDir: string, dryRun: boolean): Promise<InstallResult>;
15
+ installProject(
16
+ skillContent: string,
17
+ projectDir: string,
18
+ dryRun: boolean
19
+ ): Promise<InstallResult>;
16
20
  }
@@ -50,11 +50,14 @@ export function resolveDbPath(dbPath: string): string {
50
50
  return dbPath;
51
51
  }
52
52
 
53
- export function loadConfig(overrides?: Partial<CognitiveConfig>): CognitiveConfig {
53
+ export function loadConfig(
54
+ overrides?: Partial<CognitiveConfig>
55
+ ): CognitiveConfig {
54
56
  const config = { ...DEFAULT_CONFIG, ...overrides };
55
57
 
56
58
  if (process.env.ENGRAM_DB_PATH) config.dbPath = process.env.ENGRAM_DB_PATH;
57
- if (process.env.ENGRAM_DECAY_RATE) config.decayRate = Number(process.env.ENGRAM_DECAY_RATE);
59
+ if (process.env.ENGRAM_DECAY_RATE)
60
+ config.decayRate = Number(process.env.ENGRAM_DECAY_RATE);
58
61
  if (process.env.ENGRAM_WM_CAPACITY)
59
62
  config.workingMemoryCapacity = Number(process.env.ENGRAM_WM_CAPACITY);
60
63
  if (process.env.ENGRAM_RETRIEVAL_THRESHOLD)
@@ -4,7 +4,7 @@ import type { CognitiveConfig } from "../config/defaults.ts";
4
4
  export function baseLevelActivation(
5
5
  accessTimestamps: number[],
6
6
  now: number,
7
- decayRate: number,
7
+ decayRate: number
8
8
  ): number {
9
9
  if (accessTimestamps.length === 0) return -Infinity;
10
10
 
@@ -18,13 +18,20 @@ export function baseLevelActivation(
18
18
  }
19
19
 
20
20
  // S_ji = S - ln(fan_j)
21
- export function spreadingActivationStrength(maxStrength: number, fanCount: number): number {
21
+ export function spreadingActivationStrength(
22
+ maxStrength: number,
23
+ fanCount: number
24
+ ): number {
22
25
  if (fanCount <= 0) return 0;
23
26
  return Math.max(0, maxStrength - Math.log(fanCount));
24
27
  }
25
28
 
26
29
  // A_i = B_i + Σ(W_j · S_ji) + ε
27
- export function totalActivation(baseLevel: number, spreadingSum: number, noise: number): number {
30
+ export function totalActivation(
31
+ baseLevel: number,
32
+ spreadingSum: number,
33
+ noise: number
34
+ ): number {
28
35
  return baseLevel + spreadingSum + noise;
29
36
  }
30
37
 
@@ -44,7 +51,7 @@ export function canRetrieve(activation: number, threshold: number): boolean {
44
51
  export function retrievalLatency(
45
52
  activation: number,
46
53
  latencyFactor: number,
47
- latencyExponent: number,
54
+ latencyExponent: number
48
55
  ): number {
49
56
  return latencyFactor * Math.exp(-latencyExponent * activation);
50
57
  }
@@ -57,19 +64,44 @@ export function computeActivation(
57
64
  spreadingSum?: number;
58
65
  noiseOverride?: number;
59
66
  emotionWeight?: number;
60
- },
61
- ): { activation: number; baseLevel: number; spreading: number; noise: number; latency: number } {
62
- const baseLevel = baseLevelActivation(accessTimestamps, now, config.decayRate);
67
+ }
68
+ ): {
69
+ activation: number;
70
+ baseLevel: number;
71
+ spreading: number;
72
+ noise: number;
73
+ latency: number;
74
+ } {
75
+ const baseLevel = baseLevelActivation(
76
+ accessTimestamps,
77
+ now,
78
+ config.decayRate
79
+ );
63
80
 
64
81
  const emotionBoost = options?.emotionWeight
65
82
  ? Math.log(1 + options.emotionWeight * config.emotionalBoostFactor)
66
83
  : 0;
67
84
 
68
85
  const spreading = options?.spreadingSum ?? 0;
69
- const noise = options?.noiseOverride ?? activationNoise(config.activationNoise);
86
+ const noise =
87
+ options?.noiseOverride ?? activationNoise(config.activationNoise);
70
88
 
71
- const activation = totalActivation(baseLevel + emotionBoost, spreading, noise);
72
- const latency = retrievalLatency(activation, config.latencyFactor, config.latencyExponent);
89
+ const activation = totalActivation(
90
+ baseLevel + emotionBoost,
91
+ spreading,
92
+ noise
93
+ );
94
+ const latency = retrievalLatency(
95
+ activation,
96
+ config.latencyFactor,
97
+ config.latencyExponent
98
+ );
73
99
 
74
- return { activation, baseLevel: baseLevel + emotionBoost, spreading, noise, latency };
100
+ return {
101
+ activation,
102
+ baseLevel: baseLevel + emotionBoost,
103
+ spreading,
104
+ noise,
105
+ latency,
106
+ };
75
107
  }
@@ -122,10 +122,7 @@ export function formSemanticAssociations(
122
122
  const candidates = preloadedMemories ?? storage.getAllMemories();
123
123
  const existing = storage.getAssociations(memory.id);
124
124
  const linkedSet = new Set(
125
- existing.flatMap((a) => [
126
- `${a.sourceId}:${a.targetId}`,
127
- `${a.targetId}:${a.sourceId}`,
128
- ]),
125
+ existing.flatMap((a) => [`${a.sourceId}:${a.targetId}`, `${a.targetId}:${a.sourceId}`]),
129
126
  );
130
127
  const formed: Association[] = [];
131
128
 
@@ -62,7 +62,10 @@ class UnionFind {
62
62
  }
63
63
  }
64
64
 
65
- export function discoverChunks(storage: EngramStorage, config: CognitiveConfig): Chunk[] {
65
+ export function discoverChunks(
66
+ storage: EngramStorage,
67
+ config: CognitiveConfig
68
+ ): Chunk[] {
66
69
  const allMemories = storage.getAllMemories();
67
70
  const memoryMap = new Map<string, Memory>();
68
71
  const uf = new UnionFind();
@@ -77,7 +80,8 @@ export function discoverChunks(storage: EngramStorage, config: CognitiveConfig):
77
80
  const associations = storage.getAssociations(memory.id);
78
81
  for (const assoc of associations) {
79
82
  if (assoc.strength < config.chunkingSimilarityThreshold) continue;
80
- const otherId = assoc.sourceId === memory.id ? assoc.targetId : assoc.sourceId;
83
+ const otherId =
84
+ assoc.sourceId === memory.id ? assoc.targetId : assoc.sourceId;
81
85
  if (!memoryMap.has(otherId)) continue;
82
86
  uf.union(memory.id, otherId);
83
87
  }
@@ -89,7 +93,10 @@ export function discoverChunks(storage: EngramStorage, config: CognitiveConfig):
89
93
 
90
94
  const members = memberIds.map((id) => memoryMap.get(id)!);
91
95
  const chunkId = generateId();
92
- const keywords = extractKeywords(members.map((m) => m.content).join(" "), 3);
96
+ const keywords = extractKeywords(
97
+ members.map((m) => m.content).join(" "),
98
+ 3
99
+ );
93
100
  const label = keywords.join(" + ") || "chunk";
94
101
 
95
102
  for (const member of members) {
@@ -103,6 +110,9 @@ export function discoverChunks(storage: EngramStorage, config: CognitiveConfig):
103
110
  return chunks;
104
111
  }
105
112
 
106
- export function getChunkMembers(storage: EngramStorage, chunkId: string): Memory[] {
113
+ export function getChunkMembers(
114
+ storage: EngramStorage,
115
+ chunkId: string
116
+ ): Memory[] {
107
117
  return storage.getAllMemories().filter((m) => m.chunkId === chunkId);
108
118
  }