@timmeck/brain-core 1.1.0 → 1.5.0

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 (112) hide show
  1. package/README.md +66 -14
  2. package/brain.log +6 -0
  3. package/dist/config/__tests__/loader.test.d.ts +1 -0
  4. package/dist/config/__tests__/loader.test.js +85 -0
  5. package/dist/config/__tests__/loader.test.js.map +1 -0
  6. package/dist/config/loader.d.ts +15 -0
  7. package/dist/config/loader.js +39 -0
  8. package/dist/config/loader.js.map +1 -0
  9. package/dist/cross-brain/__tests__/client.test.d.ts +1 -0
  10. package/dist/cross-brain/__tests__/client.test.js +31 -0
  11. package/dist/cross-brain/__tests__/client.test.js.map +1 -0
  12. package/dist/cross-brain/__tests__/notifications.test.d.ts +1 -0
  13. package/dist/cross-brain/__tests__/notifications.test.js +52 -0
  14. package/dist/cross-brain/__tests__/notifications.test.js.map +1 -0
  15. package/dist/cross-brain/notifications.d.ts +25 -0
  16. package/dist/cross-brain/notifications.js +51 -0
  17. package/dist/cross-brain/notifications.js.map +1 -0
  18. package/dist/index.d.ts +16 -0
  19. package/dist/index.js +14 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/ipc/__tests__/protocol.test.d.ts +1 -0
  22. package/dist/ipc/__tests__/protocol.test.js +69 -0
  23. package/dist/ipc/__tests__/protocol.test.js.map +1 -0
  24. package/dist/learning/__tests__/base-engine.test.d.ts +1 -0
  25. package/dist/learning/__tests__/base-engine.test.js +49 -0
  26. package/dist/learning/__tests__/base-engine.test.js.map +1 -0
  27. package/dist/learning/base-engine.d.ts +16 -0
  28. package/dist/learning/base-engine.js +30 -0
  29. package/dist/learning/base-engine.js.map +1 -0
  30. package/dist/math/__tests__/time-decay.test.d.ts +1 -0
  31. package/dist/math/__tests__/time-decay.test.js +37 -0
  32. package/dist/math/__tests__/time-decay.test.js.map +1 -0
  33. package/dist/math/__tests__/wilson-score.test.d.ts +1 -0
  34. package/dist/math/__tests__/wilson-score.test.js +43 -0
  35. package/dist/math/__tests__/wilson-score.test.js.map +1 -0
  36. package/dist/math/time-decay.d.ts +10 -0
  37. package/dist/math/time-decay.js +16 -0
  38. package/dist/math/time-decay.js.map +1 -0
  39. package/dist/math/wilson-score.d.ts +10 -0
  40. package/dist/math/wilson-score.js +21 -0
  41. package/dist/math/wilson-score.js.map +1 -0
  42. package/dist/research/__tests__/base-engine.test.d.ts +1 -0
  43. package/dist/research/__tests__/base-engine.test.js +56 -0
  44. package/dist/research/__tests__/base-engine.test.js.map +1 -0
  45. package/dist/research/base-engine.d.ts +20 -0
  46. package/dist/research/base-engine.js +46 -0
  47. package/dist/research/base-engine.js.map +1 -0
  48. package/dist/synapses/__tests__/activation.test.d.ts +1 -0
  49. package/dist/synapses/__tests__/activation.test.js +87 -0
  50. package/dist/synapses/__tests__/activation.test.js.map +1 -0
  51. package/dist/synapses/__tests__/decay.test.d.ts +1 -0
  52. package/dist/synapses/__tests__/decay.test.js +73 -0
  53. package/dist/synapses/__tests__/decay.test.js.map +1 -0
  54. package/dist/synapses/__tests__/hebbian.test.d.ts +1 -0
  55. package/dist/synapses/__tests__/hebbian.test.js +95 -0
  56. package/dist/synapses/__tests__/hebbian.test.js.map +1 -0
  57. package/dist/synapses/__tests__/pathfinder.test.d.ts +1 -0
  58. package/dist/synapses/__tests__/pathfinder.test.js +74 -0
  59. package/dist/synapses/__tests__/pathfinder.test.js.map +1 -0
  60. package/dist/synapses/__tests__/synapse-manager.test.d.ts +1 -0
  61. package/dist/synapses/__tests__/synapse-manager.test.js +94 -0
  62. package/dist/synapses/__tests__/synapse-manager.test.js.map +1 -0
  63. package/dist/synapses/activation.d.ts +6 -0
  64. package/dist/synapses/activation.js +54 -0
  65. package/dist/synapses/activation.js.map +1 -0
  66. package/dist/synapses/decay.d.ts +9 -0
  67. package/dist/synapses/decay.js +26 -0
  68. package/dist/synapses/decay.js.map +1 -0
  69. package/dist/synapses/hebbian.d.ts +12 -0
  70. package/dist/synapses/hebbian.js +45 -0
  71. package/dist/synapses/hebbian.js.map +1 -0
  72. package/dist/synapses/pathfinder.d.ts +6 -0
  73. package/dist/synapses/pathfinder.js +54 -0
  74. package/dist/synapses/pathfinder.js.map +1 -0
  75. package/dist/synapses/synapse-manager.d.ts +35 -0
  76. package/dist/synapses/synapse-manager.js +72 -0
  77. package/dist/synapses/synapse-manager.js.map +1 -0
  78. package/dist/synapses/types.d.ts +85 -0
  79. package/dist/synapses/types.js +7 -0
  80. package/dist/synapses/types.js.map +1 -0
  81. package/dist/utils/__tests__/events.test.d.ts +1 -0
  82. package/dist/utils/__tests__/events.test.js +38 -0
  83. package/dist/utils/__tests__/events.test.js.map +1 -0
  84. package/dist/utils/__tests__/hash.test.d.ts +1 -0
  85. package/dist/utils/__tests__/hash.test.js +25 -0
  86. package/dist/utils/__tests__/hash.test.js.map +1 -0
  87. package/dist/utils/__tests__/logger.test.d.ts +1 -0
  88. package/dist/utils/__tests__/logger.test.js +29 -0
  89. package/dist/utils/__tests__/logger.test.js.map +1 -0
  90. package/dist/utils/__tests__/paths.test.d.ts +1 -0
  91. package/dist/utils/__tests__/paths.test.js +50 -0
  92. package/dist/utils/__tests__/paths.test.js.map +1 -0
  93. package/eslint.config.js +14 -0
  94. package/package.json +17 -2
  95. package/.github/FUNDING.yml +0 -1
  96. package/.github/workflows/ci.yml +0 -21
  97. package/src/api/server.ts +0 -210
  98. package/src/cli/colors.ts +0 -105
  99. package/src/cross-brain/client.ts +0 -94
  100. package/src/db/connection.ts +0 -22
  101. package/src/index.ts +0 -35
  102. package/src/ipc/client.ts +0 -117
  103. package/src/ipc/protocol.ts +0 -35
  104. package/src/ipc/server.ts +0 -170
  105. package/src/mcp/http-server.ts +0 -148
  106. package/src/mcp/server.ts +0 -84
  107. package/src/types/ipc.types.ts +0 -8
  108. package/src/utils/events.ts +0 -30
  109. package/src/utils/hash.ts +0 -5
  110. package/src/utils/logger.ts +0 -67
  111. package/src/utils/paths.ts +0 -24
  112. package/tsconfig.json +0 -18
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
6
  [![GitHub stars](https://img.shields.io/github/stars/timmeck/brain-core)](https://github.com/timmeck/brain-core)
7
7
 
8
- **Shared infrastructure for the Brain ecosystem — IPC, MCP, CLI, DB, and utilities.**
8
+ **Shared infrastructure for the Brain ecosystem — IPC, MCP, CLI, DB, math, synapses, and utilities.**
9
9
 
10
10
  Brain Core extracts the common infrastructure used across all Brain MCP servers ([Brain](https://github.com/timmeck/brain), [Trading Brain](https://github.com/timmeck/trading-brain), [Marketing Brain](https://github.com/timmeck/marketing-brain)) into a single, reusable package.
11
11
 
@@ -23,6 +23,15 @@ Brain Core extracts the common infrastructure used across all Brain MCP servers
23
23
  | **CLI Colors** | Shared color palette, formatting helpers (header, table, badges) |
24
24
  | **Logger** | Winston-based structured logging with file rotation |
25
25
  | **Event Bus** | Generic typed event emitter |
26
+ | **Cross-Brain Client** | Discover and query peer brains over IPC named pipes |
27
+ | **Cross-Brain Notifier** | Push event notifications to peer brains (new in v1.5) |
28
+ | **Math — Wilson Score** | Statistical confidence intervals for win rates / rule confidence |
29
+ | **Math — Time Decay** | Exponential half-life decay for synapse and rule freshness |
30
+ | **Config Loader** | `deepMerge()` + `loadConfigFile()` for layered config |
31
+ | **Synapse Algorithms** | Hebbian learning, decay, spreading activation, A* pathfinding |
32
+ | **BaseSynapseManager** | Abstract synapse manager with strengthen/weaken/activate/findPath/decay |
33
+ | **BaseLearningEngine** | Abstract timer-managed learning engine with error handling |
34
+ | **BaseResearchEngine** | Abstract timer-managed research engine with optional initial delay |
26
35
  | **Utils** | Path normalization, data dir resolution, SHA-256 hashing |
27
36
 
28
37
  ## Installation
@@ -120,24 +129,67 @@ class MyRouter implements IpcRouter {
120
129
 
121
130
  ```
122
131
  @timmeck/brain-core
123
- ├── Types ─── IpcMessage
124
- ├── Utils ─── hash, logger, paths, events
125
- ├── DB ────── SQLite connection (WAL mode)
126
- ├── IPC ───── protocol, server, client
127
- ├── MCP ───── stdio server, HTTP/SSE server
128
- ├── CLI ───── colors, formatting helpers
129
- └── API ───── BaseApiServer (CORS, auth, RPC, SSE)
132
+ ├── Types ──────── IpcMessage, SynapseRecord, NodeRef, NetworkStats
133
+ ├── Utils ──────── hash, logger, paths, events
134
+ ├── DB ─────────── SQLite connection (WAL mode)
135
+ ├── IPC ────────── protocol, server, client
136
+ ├── MCP ────────── stdio server, HTTP/SSE server
137
+ ├── CLI ────────── colors, formatting helpers
138
+ ├── API ────────── BaseApiServer (CORS, auth, RPC, SSE)
139
+ ├── Math ───────── Wilson Score, Time Decay
140
+ ├── Config ─────── deepMerge, loadConfigFile
141
+ ├── Synapses ───── Hebbian, Decay, Activation, Pathfinder, BaseSynapseManager
142
+ ├── Learning ───── BaseLearningEngine (abstract, timer-managed)
143
+ ├── Research ───── BaseResearchEngine (abstract, timer-managed)
144
+ └── Cross-Brain ── CrossBrainClient, CrossBrainNotifier
130
145
  ```
131
146
 
132
147
  ## Brain Ecosystem
133
148
 
134
- | Brain | Purpose | Ports |
135
- |-------|---------|-------|
136
- | [Brain](https://github.com/timmeck/brain) | Error memory & code intelligence | 7777/7778 |
137
- | [Trading Brain](https://github.com/timmeck/trading-brain) | Adaptive trading intelligence | 7779/7780 |
138
- | [Marketing Brain](https://github.com/timmeck/marketing-brain) | Content strategy & social media | 7781/7782 |
149
+ | Brain | Version | Purpose | Ports |
150
+ |-------|---------|---------|-------|
151
+ | [Brain](https://github.com/timmeck/brain) | v2.1.0 | Error memory & code intelligence | 7777/7778 |
152
+ | [Trading Brain](https://github.com/timmeck/trading-brain) | v1.2.0 | Adaptive trading intelligence | 7779/7780 |
153
+ | [Marketing Brain](https://github.com/timmeck/marketing-brain) | v0.4.0 | Content strategy & social media | 7781/7782/7783 |
154
+ | [Brain Core](https://github.com/timmeck/brain-core) | v1.6.0 | Shared infrastructure (this package) | — |
139
155
 
140
- All three brains are standalone — brain-core is an **optional** shared dependency that eliminates code duplication.
156
+ All three brains are standalone — brain-core is an **optional** shared dependency that eliminates ~600 lines of duplicated code across the ecosystem.
157
+
158
+ ## Cross-Brain Communication
159
+
160
+ `CrossBrainClient` lets brains discover and query each other over IPC named pipes. Each brain exposes a `status` IPC method returning its name, version, uptime, pid, and method count — enabling automatic peer discovery without central coordination.
161
+
162
+ ```typescript
163
+ import { CrossBrainClient, CrossBrainNotifier } from '@timmeck/brain-core';
164
+
165
+ // Query peers
166
+ const cross = new CrossBrainClient('brain');
167
+ const peers = await cross.getAvailablePeers();
168
+ // → [{ name: 'trading-brain', version: '1.2.0', uptime: 3600, pid: 12345, methods: 18 }, ...]
169
+
170
+ // Push event notifications to peers (v1.5+)
171
+ const notifier = new CrossBrainNotifier(cross, 'brain');
172
+ notifier.notify('error:reported', { errorId: 42, fingerprint: 'ENOENT' });
173
+ notifier.notifyPeer('trading-brain', 'insight:created', { insightId: 7 });
174
+ ```
175
+
176
+ ### Base Engines
177
+
178
+ Abstract base classes eliminate timer boilerplate from learning and research engines:
179
+
180
+ ```typescript
181
+ import { BaseLearningEngine, BaseResearchEngine } from '@timmeck/brain-core';
182
+
183
+ class MyLearningEngine extends BaseLearningEngine {
184
+ runCycle() { /* your learning logic */ }
185
+ }
186
+
187
+ class MyResearchEngine extends BaseResearchEngine {
188
+ runCycle() { /* your research logic */ }
189
+ }
190
+ ```
191
+
192
+ Visit the [Brain Hub](https://timmeck.github.io/brain-hub/) for the full ecosystem overview.
141
193
 
142
194
  ## License
143
195
 
package/brain.log ADDED
@@ -0,0 +1,6 @@
1
+ 2026-02-27T15:33:52.574Z [error] {"error":"Error: boom"} Learning cycle error
2
+ 2026-02-27T15:33:52.575Z [error] {"error":"Error: boom"} Research cycle error
3
+ 2026-02-27T15:36:06.467Z [error] {"error":"Error: boom"} Learning cycle error
4
+ 2026-02-27T15:36:06.471Z [error] {"error":"Error: boom"} Research cycle error
5
+ 2026-02-27T15:40:43.982Z [error] {"error":"Error: boom"} Research cycle error
6
+ 2026-02-27T15:40:43.982Z [error] {"error":"Error: boom"} Learning cycle error
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,85 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import { deepMerge, loadConfigFile } from '../loader.js';
4
+ describe('deepMerge', () => {
5
+ it('merges flat properties', () => {
6
+ const target = { a: 1, b: 2 };
7
+ deepMerge(target, { b: 3, c: 4 });
8
+ expect(target).toEqual({ a: 1, b: 3, c: 4 });
9
+ });
10
+ it('merges nested objects recursively', () => {
11
+ const target = { api: { port: 7777, enabled: true } };
12
+ deepMerge(target, { api: { port: 8080 } });
13
+ expect(target).toEqual({ api: { port: 8080, enabled: true } });
14
+ });
15
+ it('overwrites arrays (no merge)', () => {
16
+ const target = { tags: ['a', 'b'] };
17
+ deepMerge(target, { tags: ['c'] });
18
+ expect(target).toEqual({ tags: ['c'] });
19
+ });
20
+ it('ignores undefined values', () => {
21
+ const target = { a: 1 };
22
+ deepMerge(target, { a: undefined, b: 2 });
23
+ expect(target).toEqual({ a: 1, b: 2 });
24
+ });
25
+ it('handles deeply nested merge', () => {
26
+ const target = {
27
+ level1: {
28
+ level2: {
29
+ level3: { keep: true, replace: 'old' },
30
+ },
31
+ },
32
+ };
33
+ deepMerge(target, {
34
+ level1: { level2: { level3: { replace: 'new' } } },
35
+ });
36
+ expect(target.level1.level2.level3).toEqual({ keep: true, replace: 'new' });
37
+ });
38
+ });
39
+ describe('loadConfigFile', () => {
40
+ beforeEach(() => {
41
+ vi.spyOn(fs, 'existsSync');
42
+ vi.spyOn(fs, 'readFileSync');
43
+ });
44
+ afterEach(() => {
45
+ vi.restoreAllMocks();
46
+ });
47
+ it('returns defaults when no file exists', () => {
48
+ vi.mocked(fs.existsSync).mockReturnValue(false);
49
+ const defaults = { port: 8080, name: 'test' };
50
+ const result = loadConfigFile(defaults);
51
+ expect(result).toEqual(defaults);
52
+ });
53
+ it('merges config file into defaults', () => {
54
+ vi.mocked(fs.existsSync).mockReturnValue(true);
55
+ vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({ port: 9090 }));
56
+ const defaults = { port: 8080, name: 'test' };
57
+ const result = loadConfigFile(defaults, '/some/config.json');
58
+ expect(result).toEqual({ port: 9090, name: 'test' });
59
+ });
60
+ it('uses defaultConfigPath as fallback', () => {
61
+ vi.mocked(fs.existsSync).mockReturnValue(true);
62
+ vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({ name: 'custom' }));
63
+ const defaults = { port: 8080, name: 'test' };
64
+ const result = loadConfigFile(defaults, undefined, '/default/config.json');
65
+ expect(result).toEqual({ port: 8080, name: 'custom' });
66
+ expect(fs.existsSync).toHaveBeenCalledWith('/default/config.json');
67
+ });
68
+ it('does not mutate original defaults', () => {
69
+ vi.mocked(fs.existsSync).mockReturnValue(true);
70
+ vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({ port: 9090 }));
71
+ const defaults = { port: 8080, name: 'test' };
72
+ loadConfigFile(defaults, '/some/config.json');
73
+ expect(defaults.port).toBe(8080);
74
+ });
75
+ it('handles nested config merge', () => {
76
+ vi.mocked(fs.existsSync).mockReturnValue(true);
77
+ vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({
78
+ api: { port: 9999 },
79
+ }));
80
+ const defaults = { api: { port: 8080, enabled: true } };
81
+ const result = loadConfigFile(defaults, '/some/config.json');
82
+ expect(result).toEqual({ api: { port: 9999, enabled: true } });
83
+ });
84
+ });
85
+ //# sourceMappingURL=loader.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.test.js","sourceRoot":"","sources":["../../../src/config/__tests__/loader.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Deep-merge source into target. Recursively merges nested objects,
3
+ * overwrites primitives and arrays.
4
+ */
5
+ export declare function deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): void;
6
+ /**
7
+ * Load and parse a JSON config file, merging it into defaults.
8
+ * If the file doesn't exist, returns the defaults unchanged.
9
+ *
10
+ * @param defaults The default config object (will be cloned)
11
+ * @param configPath Explicit config file path, or undefined for auto-detect
12
+ * @param defaultConfigPath Fallback path when configPath is not provided
13
+ * @returns Merged config object
14
+ */
15
+ export declare function loadConfigFile<T>(defaults: T, configPath?: string, defaultConfigPath?: string): T;
@@ -0,0 +1,39 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ /**
4
+ * Deep-merge source into target. Recursively merges nested objects,
5
+ * overwrites primitives and arrays.
6
+ */
7
+ export function deepMerge(target, source) {
8
+ for (const key of Object.keys(source)) {
9
+ const val = source[key];
10
+ if (val && typeof val === 'object' && !Array.isArray(val) && target[key] && typeof target[key] === 'object') {
11
+ deepMerge(target[key], val);
12
+ }
13
+ else if (val !== undefined) {
14
+ target[key] = val;
15
+ }
16
+ }
17
+ }
18
+ /**
19
+ * Load and parse a JSON config file, merging it into defaults.
20
+ * If the file doesn't exist, returns the defaults unchanged.
21
+ *
22
+ * @param defaults The default config object (will be cloned)
23
+ * @param configPath Explicit config file path, or undefined for auto-detect
24
+ * @param defaultConfigPath Fallback path when configPath is not provided
25
+ * @returns Merged config object
26
+ */
27
+ export function loadConfigFile(defaults, configPath, defaultConfigPath) {
28
+ const config = structuredClone(defaults);
29
+ const filePath = configPath
30
+ ? path.resolve(configPath)
31
+ : defaultConfigPath;
32
+ if (filePath && fs.existsSync(filePath)) {
33
+ const raw = fs.readFileSync(filePath, 'utf-8');
34
+ const fileConfig = JSON.parse(raw);
35
+ deepMerge(config, fileConfig);
36
+ }
37
+ return config;
38
+ }
39
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,MAA+B,EAAE,MAA+B;IACxF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC5G,SAAS,CAAC,MAAM,CAAC,GAAG,CAA4B,EAAE,GAA8B,CAAC,CAAC;QACpF,CAAC;aAAM,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACpB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,QAAW,EACX,UAAmB,EACnB,iBAA0B;IAE1B,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAEzC,MAAM,QAAQ,GAAG,UAAU;QACzB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QAC1B,CAAC,CAAC,iBAAiB,CAAC;IAEtB,IAAI,QAAQ,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;QACjD,SAAS,CAAC,MAA4C,EAAE,UAAgD,CAAC,CAAC;IAC5G,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { CrossBrainClient } from '../client.js';
3
+ describe('CrossBrainClient', () => {
4
+ it('filters self from peers', () => {
5
+ const client = new CrossBrainClient('brain');
6
+ const names = client.getPeerNames();
7
+ expect(names).not.toContain('brain');
8
+ expect(names).toContain('trading-brain');
9
+ expect(names).toContain('marketing-brain');
10
+ });
11
+ it('returns empty for unavailable peers', async () => {
12
+ const client = new CrossBrainClient('brain');
13
+ const result = await client.query('nonexistent', 'status');
14
+ expect(result).toBeNull();
15
+ });
16
+ it('broadcast returns empty when no peers available', async () => {
17
+ const client = new CrossBrainClient('test', [
18
+ { name: 'fake', pipeName: '\\\\.\\pipe\\nonexistent-test-pipe' },
19
+ ]);
20
+ const results = await client.broadcast('status');
21
+ expect(results).toEqual([]);
22
+ });
23
+ it('getAvailablePeers returns empty when none running', async () => {
24
+ const client = new CrossBrainClient('test', [
25
+ { name: 'fake', pipeName: '\\\\.\\pipe\\nonexistent-test-pipe' },
26
+ ]);
27
+ const available = await client.getAvailablePeers();
28
+ expect(available).toEqual([]);
29
+ });
30
+ });
31
+ //# sourceMappingURL=client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../../src/cross-brain/__tests__/client.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QAC3D,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,EAAE;YAC1C,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,oCAAoC,EAAE;SACjE,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,EAAE;YAC1C,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,oCAAoC,EAAE;SACjE,CAAC,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,iBAAiB,EAAE,CAAC;QACnD,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,52 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ vi.mock('../../utils/logger.js', () => ({
3
+ getLogger: () => ({
4
+ debug: vi.fn(),
5
+ info: vi.fn(),
6
+ warn: vi.fn(),
7
+ error: vi.fn(),
8
+ }),
9
+ }));
10
+ import { CrossBrainNotifier } from '../notifications.js';
11
+ import { CrossBrainClient } from '../client.js';
12
+ describe('CrossBrainNotifier', () => {
13
+ let client;
14
+ let notifier;
15
+ beforeEach(() => {
16
+ client = new CrossBrainClient('brain');
17
+ vi.spyOn(client, 'broadcast').mockResolvedValue([]);
18
+ vi.spyOn(client, 'query').mockResolvedValue(null);
19
+ notifier = new CrossBrainNotifier(client, 'brain');
20
+ });
21
+ it('broadcasts notifications to all peers', async () => {
22
+ await notifier.notify('error:reported', { errorId: 1 });
23
+ expect(client.broadcast).toHaveBeenCalledWith('cross-brain.notify', expect.objectContaining({
24
+ source: 'brain',
25
+ event: 'error:reported',
26
+ data: { errorId: 1 },
27
+ }));
28
+ });
29
+ it('sends targeted notification to specific peer', async () => {
30
+ await notifier.notifyPeer('trading-brain', 'insight:created', { insightId: 5 });
31
+ expect(client.query).toHaveBeenCalledWith('trading-brain', 'cross-brain.notify', expect.objectContaining({
32
+ source: 'brain',
33
+ event: 'insight:created',
34
+ data: { insightId: 5 },
35
+ }));
36
+ });
37
+ it('includes timestamp in payload', async () => {
38
+ await notifier.notify('test', {});
39
+ const payload = client.broadcast.mock.calls[0][1];
40
+ expect(payload.timestamp).toBeDefined();
41
+ expect(new Date(payload.timestamp).getTime()).toBeGreaterThan(0);
42
+ });
43
+ it('does not throw when broadcast fails', async () => {
44
+ vi.spyOn(client, 'broadcast').mockRejectedValue(new Error('offline'));
45
+ await expect(notifier.notify('test', {})).resolves.toBeUndefined();
46
+ });
47
+ it('does not throw when peer query fails', async () => {
48
+ vi.spyOn(client, 'query').mockRejectedValue(new Error('offline'));
49
+ await expect(notifier.notifyPeer('trading-brain', 'test', {})).resolves.toBeUndefined();
50
+ });
51
+ });
52
+ //# sourceMappingURL=notifications.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.test.js","sourceRoot":"","sources":["../../../src/cross-brain/__tests__/notifications.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { CrossBrainClient } from './client.js';
2
+ export interface CrossBrainEvent {
3
+ source: string;
4
+ event: string;
5
+ data: unknown;
6
+ timestamp: string;
7
+ }
8
+ /**
9
+ * Cross-Brain Notifier — sends event notifications to peer brains.
10
+ * Built on top of CrossBrainClient's query/broadcast infrastructure.
11
+ */
12
+ export declare class CrossBrainNotifier {
13
+ private client;
14
+ private selfName;
15
+ private logger;
16
+ constructor(client: CrossBrainClient, selfName: string);
17
+ /**
18
+ * Notify all peers about an event.
19
+ */
20
+ notify(event: string, data: unknown): Promise<void>;
21
+ /**
22
+ * Notify a specific peer about an event.
23
+ */
24
+ notifyPeer(peerName: string, event: string, data: unknown): Promise<void>;
25
+ }
@@ -0,0 +1,51 @@
1
+ import { getLogger } from '../utils/logger.js';
2
+ /**
3
+ * Cross-Brain Notifier — sends event notifications to peer brains.
4
+ * Built on top of CrossBrainClient's query/broadcast infrastructure.
5
+ */
6
+ export class CrossBrainNotifier {
7
+ client;
8
+ selfName;
9
+ logger = getLogger();
10
+ constructor(client, selfName) {
11
+ this.client = client;
12
+ this.selfName = selfName;
13
+ }
14
+ /**
15
+ * Notify all peers about an event.
16
+ */
17
+ async notify(event, data) {
18
+ const payload = {
19
+ source: this.selfName,
20
+ event,
21
+ data,
22
+ timestamp: new Date().toISOString(),
23
+ };
24
+ try {
25
+ await this.client.broadcast('cross-brain.notify', payload);
26
+ this.logger.debug(`Cross-brain notification sent: ${event}`);
27
+ }
28
+ catch {
29
+ this.logger.debug(`Cross-brain notification failed (peers may be offline): ${event}`);
30
+ }
31
+ }
32
+ /**
33
+ * Notify a specific peer about an event.
34
+ */
35
+ async notifyPeer(peerName, event, data) {
36
+ const payload = {
37
+ source: this.selfName,
38
+ event,
39
+ data,
40
+ timestamp: new Date().toISOString(),
41
+ };
42
+ try {
43
+ await this.client.query(peerName, 'cross-brain.notify', payload);
44
+ this.logger.debug(`Cross-brain notification sent to ${peerName}: ${event}`);
45
+ }
46
+ catch {
47
+ this.logger.debug(`Cross-brain notification to ${peerName} failed: ${event}`);
48
+ }
49
+ }
50
+ }
51
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../src/cross-brain/notifications.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAS/C;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IAGT;IAAkC;IAF9C,MAAM,GAAG,SAAS,EAAE,CAAC;IAE7B,YAAoB,MAAwB,EAAU,QAAgB;QAAlD,WAAM,GAAN,MAAM,CAAkB;QAAU,aAAQ,GAAR,QAAQ,CAAQ;IAAG,CAAC;IAE1E;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,IAAa;QACvC,MAAM,OAAO,GAAoB;YAC/B,MAAM,EAAE,IAAI,CAAC,QAAQ;YACrB,KAAK;YACL,IAAI;YACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;YAC3D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,kCAAkC,KAAK,EAAE,CAAC,CAAC;QAC/D,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2DAA2D,KAAK,EAAE,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,QAAgB,EAAE,KAAa,EAAE,IAAa;QAC7D,MAAM,OAAO,GAAoB;YAC/B,MAAM,EAAE,IAAI,CAAC,QAAQ;YACrB,KAAK;YACL,IAAI;YACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,oBAAoB,EAAE,OAAO,CAAC,CAAC;YACjE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,QAAQ,KAAK,KAAK,EAAE,CAAC,CAAC;QAC9E,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,QAAQ,YAAY,KAAK,EAAE,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;CACF"}
package/dist/index.d.ts CHANGED
@@ -16,5 +16,21 @@ export type { McpHttpServerOptions } from './mcp/http-server.js';
16
16
  export { c, baseIcons, header, keyValue, statusBadge, progressBar, divider, table, stripAnsi } from './cli/colors.js';
17
17
  export { BaseApiServer } from './api/server.js';
18
18
  export type { ApiServerOptions, RouteDefinition } from './api/server.js';
19
+ export { wilsonScore } from './math/wilson-score.js';
20
+ export { timeDecayFactor } from './math/time-decay.js';
21
+ export { deepMerge, loadConfigFile } from './config/loader.js';
22
+ export type { NodeRef, SynapseRecord, ActivationResult, PathNode, SynapsePath, NetworkStats, HebbianConfig, DecayConfig, SynapseRepoInterface, } from './synapses/types.js';
23
+ export type { SynapseManagerConfig } from './synapses/synapse-manager.js';
24
+ export { strengthen, weaken } from './synapses/hebbian.js';
25
+ export { decayAll } from './synapses/decay.js';
26
+ export { spreadingActivation } from './synapses/activation.js';
27
+ export { findPath } from './synapses/pathfinder.js';
28
+ export { BaseSynapseManager } from './synapses/synapse-manager.js';
29
+ export { BaseLearningEngine } from './learning/base-engine.js';
30
+ export type { LearningEngineConfig } from './learning/base-engine.js';
31
+ export { BaseResearchEngine } from './research/base-engine.js';
32
+ export type { ResearchEngineConfig } from './research/base-engine.js';
19
33
  export { CrossBrainClient } from './cross-brain/client.js';
20
34
  export type { BrainPeer } from './cross-brain/client.js';
35
+ export { CrossBrainNotifier } from './cross-brain/notifications.js';
36
+ export type { CrossBrainEvent } from './cross-brain/notifications.js';
package/dist/index.js CHANGED
@@ -16,6 +16,20 @@ export { McpHttpServer } from './mcp/http-server.js';
16
16
  export { c, baseIcons, header, keyValue, statusBadge, progressBar, divider, table, stripAnsi } from './cli/colors.js';
17
17
  // ── API ────────────────────────────────────────────────────
18
18
  export { BaseApiServer } from './api/server.js';
19
+ // ── Math ───────────────────────────────────────────────────
20
+ export { wilsonScore } from './math/wilson-score.js';
21
+ export { timeDecayFactor } from './math/time-decay.js';
22
+ // ── Config ─────────────────────────────────────────────────
23
+ export { deepMerge, loadConfigFile } from './config/loader.js';
24
+ export { strengthen, weaken } from './synapses/hebbian.js';
25
+ export { decayAll } from './synapses/decay.js';
26
+ export { spreadingActivation } from './synapses/activation.js';
27
+ export { findPath } from './synapses/pathfinder.js';
28
+ export { BaseSynapseManager } from './synapses/synapse-manager.js';
29
+ // ── Engines ───────────────────────────────────────────────
30
+ export { BaseLearningEngine } from './learning/base-engine.js';
31
+ export { BaseResearchEngine } from './research/base-engine.js';
19
32
  // ── Cross-Brain ────────────────────────────────────────────
20
33
  export { CrossBrainClient } from './cross-brain/client.js';
34
+ export { CrossBrainNotifier } from './cross-brain/notifications.js';
21
35
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,8DAA8D;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,8DAA8D;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,8DAA8D;AAC9D,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,8DAA8D;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,8DAA8D;AAC9D,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEtH,8DAA8D;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,8DAA8D;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,8DAA8D;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,8DAA8D;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,8DAA8D;AAC9D,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,8DAA8D;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,8DAA8D;AAC9D,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEtH,8DAA8D;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,8DAA8D;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,8DAA8D;AAC9D,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAQ/D,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE,6DAA6D;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAG/D,8DAA8D;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,69 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { encodeMessage, MessageDecoder } from '../protocol.js';
3
+ describe('encodeMessage', () => {
4
+ it('encodes a request message', () => {
5
+ const msg = { id: 'test-1', type: 'request', method: 'status', params: {} };
6
+ const buffer = encodeMessage(msg);
7
+ expect(buffer).toBeInstanceOf(Buffer);
8
+ expect(buffer.length).toBeGreaterThan(4);
9
+ });
10
+ it('includes 4-byte length prefix', () => {
11
+ const msg = { id: 'test-1', type: 'request', method: 'test' };
12
+ const buffer = encodeMessage(msg);
13
+ const payloadLength = buffer.readUInt32BE(0);
14
+ expect(buffer.length).toBe(4 + payloadLength);
15
+ });
16
+ });
17
+ describe('MessageDecoder', () => {
18
+ it('decodes a single complete message', () => {
19
+ const msg = { id: 'x', type: 'response', result: { ok: true } };
20
+ const decoder = new MessageDecoder();
21
+ const messages = decoder.feed(encodeMessage(msg));
22
+ expect(messages).toHaveLength(1);
23
+ expect(messages[0].id).toBe('x');
24
+ expect(messages[0].result).toEqual({ ok: true });
25
+ });
26
+ it('handles multiple messages in one chunk', () => {
27
+ const msg1 = { id: '1', type: 'request', method: 'a' };
28
+ const msg2 = { id: '2', type: 'request', method: 'b' };
29
+ const decoder = new MessageDecoder();
30
+ const combined = Buffer.concat([encodeMessage(msg1), encodeMessage(msg2)]);
31
+ const messages = decoder.feed(combined);
32
+ expect(messages).toHaveLength(2);
33
+ });
34
+ it('handles partial messages across feeds', () => {
35
+ const msg = { id: 'partial', type: 'response', result: 'data' };
36
+ const buffer = encodeMessage(msg);
37
+ const decoder = new MessageDecoder();
38
+ const mid = Math.floor(buffer.length / 2);
39
+ const part1 = buffer.subarray(0, mid);
40
+ const part2 = buffer.subarray(mid);
41
+ expect(decoder.feed(part1)).toHaveLength(0);
42
+ const messages = decoder.feed(part2);
43
+ expect(messages).toHaveLength(1);
44
+ expect(messages[0].id).toBe('partial');
45
+ });
46
+ it('resets buffer state', () => {
47
+ const decoder = new MessageDecoder();
48
+ decoder.feed(Buffer.from([0, 0, 0, 10])); // incomplete
49
+ decoder.reset();
50
+ const msg = { id: 'after-reset', type: 'response', result: null };
51
+ const messages = decoder.feed(encodeMessage(msg));
52
+ expect(messages).toHaveLength(1);
53
+ expect(messages[0].id).toBe('after-reset');
54
+ });
55
+ it('handles byte-by-byte feeding', () => {
56
+ const msg = { id: 'byte', type: 'request', method: 'test' };
57
+ const buffer = encodeMessage(msg);
58
+ const decoder = new MessageDecoder();
59
+ let messages = [];
60
+ for (let i = 0; i < buffer.length; i++) {
61
+ messages = decoder.feed(buffer.subarray(i, i + 1));
62
+ if (messages.length > 0)
63
+ break;
64
+ }
65
+ expect(messages).toHaveLength(1);
66
+ expect(messages[0].id).toBe('byte');
67
+ });
68
+ });
69
+ //# sourceMappingURL=protocol.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.test.js","sourceRoot":"","sources":["../../../src/ipc/__tests__/protocol.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};