@timmeck/brain-core 2.36.61 → 2.36.63

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 (254) hide show
  1. package/dist/guardrails/guardrail-engine.d.ts +2 -0
  2. package/dist/guardrails/guardrail-engine.js +29 -13
  3. package/dist/guardrails/guardrail-engine.js.map +1 -1
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.js +1 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/research/adapters/playwright-adapter.js +28 -2
  8. package/dist/research/adapters/playwright-adapter.js.map +1 -1
  9. package/dist/utils/memory-watchdog.d.ts +33 -0
  10. package/dist/utils/memory-watchdog.js +88 -0
  11. package/dist/utils/memory-watchdog.js.map +1 -0
  12. package/dist/watchdog/watchdog-service.js +11 -5
  13. package/dist/watchdog/watchdog-service.js.map +1 -1
  14. package/package.json +1 -1
  15. package/dist/action/__tests__/action-bridge.test.d.ts +0 -1
  16. package/dist/action/__tests__/action-bridge.test.js +0 -175
  17. package/dist/action/__tests__/action-bridge.test.js.map +0 -1
  18. package/dist/action/__tests__/adjust-parameter-handler.test.d.ts +0 -1
  19. package/dist/action/__tests__/adjust-parameter-handler.test.js +0 -138
  20. package/dist/action/__tests__/adjust-parameter-handler.test.js.map +0 -1
  21. package/dist/action/__tests__/content-handler.test.d.ts +0 -1
  22. package/dist/action/__tests__/content-handler.test.js +0 -100
  23. package/dist/action/__tests__/content-handler.test.js.map +0 -1
  24. package/dist/action/__tests__/creative-seed-handler.test.d.ts +0 -1
  25. package/dist/action/__tests__/creative-seed-handler.test.js +0 -96
  26. package/dist/action/__tests__/creative-seed-handler.test.js.map +0 -1
  27. package/dist/action/__tests__/trade-handler.test.d.ts +0 -1
  28. package/dist/action/__tests__/trade-handler.test.js +0 -165
  29. package/dist/action/__tests__/trade-handler.test.js.map +0 -1
  30. package/dist/active-learning/__tests__/active-learning.test.d.ts +0 -1
  31. package/dist/active-learning/__tests__/active-learning.test.js +0 -132
  32. package/dist/active-learning/__tests__/active-learning.test.js.map +0 -1
  33. package/dist/agent-training/__tests__/agent-trainer.test.d.ts +0 -1
  34. package/dist/agent-training/__tests__/agent-trainer.test.js +0 -158
  35. package/dist/agent-training/__tests__/agent-trainer.test.js.map +0 -1
  36. package/dist/agent-training/__tests__/sub-agent-factory.test.d.ts +0 -1
  37. package/dist/agent-training/__tests__/sub-agent-factory.test.js +0 -100
  38. package/dist/agent-training/__tests__/sub-agent-factory.test.js.map +0 -1
  39. package/dist/agent-training/__tests__/sub-agent.test.d.ts +0 -1
  40. package/dist/agent-training/__tests__/sub-agent.test.js +0 -102
  41. package/dist/agent-training/__tests__/sub-agent.test.js.map +0 -1
  42. package/dist/chat/__tests__/chat-engine.test.d.ts +0 -1
  43. package/dist/chat/__tests__/chat-engine.test.js +0 -209
  44. package/dist/chat/__tests__/chat-engine.test.js.map +0 -1
  45. package/dist/checkpoint/__tests__/checkpoint-manager.test.d.ts +0 -1
  46. package/dist/checkpoint/__tests__/checkpoint-manager.test.js +0 -160
  47. package/dist/checkpoint/__tests__/checkpoint-manager.test.js.map +0 -1
  48. package/dist/code-health/__tests__/code-health.test.d.ts +0 -1
  49. package/dist/code-health/__tests__/code-health.test.js +0 -123
  50. package/dist/code-health/__tests__/code-health.test.js.map +0 -1
  51. package/dist/codegen/__tests__/code-forge.test.d.ts +0 -1
  52. package/dist/codegen/__tests__/code-forge.test.js +0 -105
  53. package/dist/codegen/__tests__/code-forge.test.js.map +0 -1
  54. package/dist/config/__tests__/loader.test.d.ts +0 -1
  55. package/dist/config/__tests__/loader.test.js +0 -86
  56. package/dist/config/__tests__/loader.test.js.map +0 -1
  57. package/dist/consciousness/__tests__/thought-stream.test.d.ts +0 -1
  58. package/dist/consciousness/__tests__/thought-stream.test.js +0 -62
  59. package/dist/consciousness/__tests__/thought-stream.test.js.map +0 -1
  60. package/dist/consensus/__tests__/consensus.test.d.ts +0 -1
  61. package/dist/consensus/__tests__/consensus.test.js +0 -159
  62. package/dist/consensus/__tests__/consensus.test.js.map +0 -1
  63. package/dist/content/__tests__/auto-publisher.test.d.ts +0 -1
  64. package/dist/content/__tests__/auto-publisher.test.js +0 -125
  65. package/dist/content/__tests__/auto-publisher.test.js.map +0 -1
  66. package/dist/content/__tests__/content-forge.test.d.ts +0 -1
  67. package/dist/content/__tests__/content-forge.test.js +0 -117
  68. package/dist/content/__tests__/content-forge.test.js.map +0 -1
  69. package/dist/creative/__tests__/creative-engine.test.d.ts +0 -1
  70. package/dist/creative/__tests__/creative-engine.test.js +0 -229
  71. package/dist/creative/__tests__/creative-engine.test.js.map +0 -1
  72. package/dist/cross-brain/__tests__/borg-sync-engine.test.d.ts +0 -1
  73. package/dist/cross-brain/__tests__/borg-sync-engine.test.js +0 -240
  74. package/dist/cross-brain/__tests__/borg-sync-engine.test.js.map +0 -1
  75. package/dist/cross-brain/__tests__/client.test.d.ts +0 -1
  76. package/dist/cross-brain/__tests__/client.test.js +0 -31
  77. package/dist/cross-brain/__tests__/client.test.js.map +0 -1
  78. package/dist/cross-brain/__tests__/notifications.test.d.ts +0 -1
  79. package/dist/cross-brain/__tests__/notifications.test.js +0 -52
  80. package/dist/cross-brain/__tests__/notifications.test.js.map +0 -1
  81. package/dist/cross-brain/__tests__/signal-router.test.d.ts +0 -1
  82. package/dist/cross-brain/__tests__/signal-router.test.js +0 -218
  83. package/dist/cross-brain/__tests__/signal-router.test.js.map +0 -1
  84. package/dist/cross-brain/__tests__/subscription.test.d.ts +0 -1
  85. package/dist/cross-brain/__tests__/subscription.test.js +0 -75
  86. package/dist/cross-brain/__tests__/subscription.test.js.map +0 -1
  87. package/dist/dashboard/__tests__/command-center-server.test.d.ts +0 -1
  88. package/dist/dashboard/__tests__/command-center-server.test.js +0 -522
  89. package/dist/dashboard/__tests__/command-center-server.test.js.map +0 -1
  90. package/dist/dashboard/__tests__/server.test.d.ts +0 -1
  91. package/dist/dashboard/__tests__/server.test.js +0 -105
  92. package/dist/dashboard/__tests__/server.test.js.map +0 -1
  93. package/dist/db/__tests__/connection.test.d.ts +0 -1
  94. package/dist/db/__tests__/connection.test.js +0 -135
  95. package/dist/db/__tests__/connection.test.js.map +0 -1
  96. package/dist/dream/__tests__/dream-engine.test.d.ts +0 -1
  97. package/dist/dream/__tests__/dream-engine.test.js +0 -184
  98. package/dist/dream/__tests__/dream-engine.test.js.map +0 -1
  99. package/dist/embeddings/__tests__/engine.test.d.ts +0 -1
  100. package/dist/embeddings/__tests__/engine.test.js +0 -82
  101. package/dist/embeddings/__tests__/engine.test.js.map +0 -1
  102. package/dist/feedback/__tests__/feedback-engine.test.d.ts +0 -1
  103. package/dist/feedback/__tests__/feedback-engine.test.js +0 -156
  104. package/dist/feedback/__tests__/feedback-engine.test.js.map +0 -1
  105. package/dist/feedback/__tests__/feedback-router.test.d.ts +0 -1
  106. package/dist/feedback/__tests__/feedback-router.test.js +0 -173
  107. package/dist/feedback/__tests__/feedback-router.test.js.map +0 -1
  108. package/dist/goals/__tests__/goal-engine.test.d.ts +0 -1
  109. package/dist/goals/__tests__/goal-engine.test.js +0 -203
  110. package/dist/goals/__tests__/goal-engine.test.js.map +0 -1
  111. package/dist/guardrails/__tests__/guardrail-engine.test.d.ts +0 -1
  112. package/dist/guardrails/__tests__/guardrail-engine.test.js +0 -343
  113. package/dist/guardrails/__tests__/guardrail-engine.test.js.map +0 -1
  114. package/dist/ipc/__tests__/integration.test.d.ts +0 -1
  115. package/dist/ipc/__tests__/integration.test.js +0 -352
  116. package/dist/ipc/__tests__/integration.test.js.map +0 -1
  117. package/dist/ipc/__tests__/protocol.test.d.ts +0 -1
  118. package/dist/ipc/__tests__/protocol.test.js +0 -69
  119. package/dist/ipc/__tests__/protocol.test.js.map +0 -1
  120. package/dist/knowledge-graph/__tests__/contradiction-resolver.test.d.ts +0 -1
  121. package/dist/knowledge-graph/__tests__/contradiction-resolver.test.js +0 -114
  122. package/dist/knowledge-graph/__tests__/contradiction-resolver.test.js.map +0 -1
  123. package/dist/knowledge-graph/__tests__/knowledge-graph.test.d.ts +0 -1
  124. package/dist/knowledge-graph/__tests__/knowledge-graph.test.js +0 -215
  125. package/dist/knowledge-graph/__tests__/knowledge-graph.test.js.map +0 -1
  126. package/dist/learning/__tests__/base-engine.test.d.ts +0 -1
  127. package/dist/learning/__tests__/base-engine.test.js +0 -49
  128. package/dist/learning/__tests__/base-engine.test.js.map +0 -1
  129. package/dist/llm/__tests__/anthropic-provider.test.d.ts +0 -1
  130. package/dist/llm/__tests__/anthropic-provider.test.js +0 -121
  131. package/dist/llm/__tests__/anthropic-provider.test.js.map +0 -1
  132. package/dist/llm/__tests__/llm-service.test.d.ts +0 -1
  133. package/dist/llm/__tests__/llm-service.test.js +0 -507
  134. package/dist/llm/__tests__/llm-service.test.js.map +0 -1
  135. package/dist/llm/__tests__/ollama-embedding.test.d.ts +0 -1
  136. package/dist/llm/__tests__/ollama-embedding.test.js +0 -128
  137. package/dist/llm/__tests__/ollama-embedding.test.js.map +0 -1
  138. package/dist/llm/__tests__/ollama-provider.test.d.ts +0 -1
  139. package/dist/llm/__tests__/ollama-provider.test.js +0 -213
  140. package/dist/llm/__tests__/ollama-provider.test.js.map +0 -1
  141. package/dist/llm/__tests__/provider.test.d.ts +0 -1
  142. package/dist/llm/__tests__/provider.test.js +0 -126
  143. package/dist/llm/__tests__/provider.test.js.map +0 -1
  144. package/dist/math/__tests__/time-decay.test.d.ts +0 -1
  145. package/dist/math/__tests__/time-decay.test.js +0 -37
  146. package/dist/math/__tests__/time-decay.test.js.map +0 -1
  147. package/dist/math/__tests__/wilson-score.test.d.ts +0 -1
  148. package/dist/math/__tests__/wilson-score.test.js +0 -43
  149. package/dist/math/__tests__/wilson-score.test.js.map +0 -1
  150. package/dist/memory/__tests__/base-memory-engine.test.d.ts +0 -1
  151. package/dist/memory/__tests__/base-memory-engine.test.js +0 -233
  152. package/dist/memory/__tests__/base-memory-engine.test.js.map +0 -1
  153. package/dist/metacognition/__tests__/auto-experiment-engine.test.d.ts +0 -1
  154. package/dist/metacognition/__tests__/auto-experiment-engine.test.js +0 -218
  155. package/dist/metacognition/__tests__/auto-experiment-engine.test.js.map +0 -1
  156. package/dist/metacognition/__tests__/evolution-engine.test.d.ts +0 -1
  157. package/dist/metacognition/__tests__/evolution-engine.test.js +0 -473
  158. package/dist/metacognition/__tests__/evolution-engine.test.js.map +0 -1
  159. package/dist/metacognition/__tests__/parameter-registry.test.d.ts +0 -1
  160. package/dist/metacognition/__tests__/parameter-registry.test.js +0 -223
  161. package/dist/metacognition/__tests__/parameter-registry.test.js.map +0 -1
  162. package/dist/missions/__tests__/mission-engine.test.d.ts +0 -1
  163. package/dist/missions/__tests__/mission-engine.test.js +0 -67
  164. package/dist/missions/__tests__/mission-engine.test.js.map +0 -1
  165. package/dist/notifications/__tests__/notification-service.test.d.ts +0 -1
  166. package/dist/notifications/__tests__/notification-service.test.js +0 -176
  167. package/dist/notifications/__tests__/notification-service.test.js.map +0 -1
  168. package/dist/plugin/__tests__/plugin-registry.test.d.ts +0 -1
  169. package/dist/plugin/__tests__/plugin-registry.test.js +0 -166
  170. package/dist/plugin/__tests__/plugin-registry.test.js.map +0 -1
  171. package/dist/prediction/__tests__/prediction-engine.test.d.ts +0 -1
  172. package/dist/prediction/__tests__/prediction-engine.test.js +0 -252
  173. package/dist/prediction/__tests__/prediction-engine.test.js.map +0 -1
  174. package/dist/proactive/__tests__/proactive-engine.test.d.ts +0 -1
  175. package/dist/proactive/__tests__/proactive-engine.test.js +0 -183
  176. package/dist/proactive/__tests__/proactive-engine.test.js.map +0 -1
  177. package/dist/rag/__tests__/rag-engine.test.d.ts +0 -1
  178. package/dist/rag/__tests__/rag-engine.test.js +0 -235
  179. package/dist/rag/__tests__/rag-engine.test.js.map +0 -1
  180. package/dist/research/__tests__/autonomy-features.test.d.ts +0 -1
  181. package/dist/research/__tests__/autonomy-features.test.js +0 -155
  182. package/dist/research/__tests__/autonomy-features.test.js.map +0 -1
  183. package/dist/research/__tests__/base-engine.test.d.ts +0 -1
  184. package/dist/research/__tests__/base-engine.test.js +0 -56
  185. package/dist/research/__tests__/base-engine.test.js.map +0 -1
  186. package/dist/research/__tests__/semantic-compressor.test.d.ts +0 -1
  187. package/dist/research/__tests__/semantic-compressor.test.js +0 -153
  188. package/dist/research/__tests__/semantic-compressor.test.js.map +0 -1
  189. package/dist/research/adapters/__tests__/web-adapters.test.d.ts +0 -1
  190. package/dist/research/adapters/__tests__/web-adapters.test.js +0 -106
  191. package/dist/research/adapters/__tests__/web-adapters.test.js.map +0 -1
  192. package/dist/sandbox/__tests__/code-sandbox.test.d.ts +0 -1
  193. package/dist/sandbox/__tests__/code-sandbox.test.js +0 -182
  194. package/dist/sandbox/__tests__/code-sandbox.test.js.map +0 -1
  195. package/dist/scanner/__tests__/signal-scanner.test.d.ts +0 -1
  196. package/dist/scanner/__tests__/signal-scanner.test.js +0 -142
  197. package/dist/scanner/__tests__/signal-scanner.test.js.map +0 -1
  198. package/dist/self-modification/__tests__/self-modification-engine.test.d.ts +0 -1
  199. package/dist/self-modification/__tests__/self-modification-engine.test.js +0 -313
  200. package/dist/self-modification/__tests__/self-modification-engine.test.js.map +0 -1
  201. package/dist/strategy/__tests__/strategy-forge.test.d.ts +0 -1
  202. package/dist/strategy/__tests__/strategy-forge.test.js +0 -190
  203. package/dist/strategy/__tests__/strategy-forge.test.js.map +0 -1
  204. package/dist/strategy/__tests__/strategy-mutator.test.d.ts +0 -1
  205. package/dist/strategy/__tests__/strategy-mutator.test.js +0 -141
  206. package/dist/strategy/__tests__/strategy-mutator.test.js.map +0 -1
  207. package/dist/synapses/__tests__/activation.test.d.ts +0 -1
  208. package/dist/synapses/__tests__/activation.test.js +0 -87
  209. package/dist/synapses/__tests__/activation.test.js.map +0 -1
  210. package/dist/synapses/__tests__/decay.test.d.ts +0 -1
  211. package/dist/synapses/__tests__/decay.test.js +0 -73
  212. package/dist/synapses/__tests__/decay.test.js.map +0 -1
  213. package/dist/synapses/__tests__/hebbian.test.d.ts +0 -1
  214. package/dist/synapses/__tests__/hebbian.test.js +0 -95
  215. package/dist/synapses/__tests__/hebbian.test.js.map +0 -1
  216. package/dist/synapses/__tests__/pathfinder.test.d.ts +0 -1
  217. package/dist/synapses/__tests__/pathfinder.test.js +0 -74
  218. package/dist/synapses/__tests__/pathfinder.test.js.map +0 -1
  219. package/dist/synapses/__tests__/synapse-manager.test.d.ts +0 -1
  220. package/dist/synapses/__tests__/synapse-manager.test.js +0 -94
  221. package/dist/synapses/__tests__/synapse-manager.test.js.map +0 -1
  222. package/dist/teaching/__tests__/teaching.test.d.ts +0 -1
  223. package/dist/teaching/__tests__/teaching.test.js +0 -252
  224. package/dist/teaching/__tests__/teaching.test.js.map +0 -1
  225. package/dist/techradar/__tests__/techradar-engine.test.d.ts +0 -1
  226. package/dist/techradar/__tests__/techradar-engine.test.js +0 -246
  227. package/dist/techradar/__tests__/techradar-engine.test.js.map +0 -1
  228. package/dist/tool-learning/__tests__/tool-learning.test.d.ts +0 -1
  229. package/dist/tool-learning/__tests__/tool-learning.test.js +0 -187
  230. package/dist/tool-learning/__tests__/tool-learning.test.js.map +0 -1
  231. package/dist/user-model/__tests__/user-model.test.d.ts +0 -1
  232. package/dist/user-model/__tests__/user-model.test.js +0 -142
  233. package/dist/user-model/__tests__/user-model.test.js.map +0 -1
  234. package/dist/utils/__tests__/batch-queue.test.d.ts +0 -1
  235. package/dist/utils/__tests__/batch-queue.test.js +0 -85
  236. package/dist/utils/__tests__/batch-queue.test.js.map +0 -1
  237. package/dist/utils/__tests__/events.test.d.ts +0 -1
  238. package/dist/utils/__tests__/events.test.js +0 -38
  239. package/dist/utils/__tests__/events.test.js.map +0 -1
  240. package/dist/utils/__tests__/hash.test.d.ts +0 -1
  241. package/dist/utils/__tests__/hash.test.js +0 -25
  242. package/dist/utils/__tests__/hash.test.js.map +0 -1
  243. package/dist/utils/__tests__/logger.test.d.ts +0 -1
  244. package/dist/utils/__tests__/logger.test.js +0 -55
  245. package/dist/utils/__tests__/logger.test.js.map +0 -1
  246. package/dist/utils/__tests__/paths.test.d.ts +0 -1
  247. package/dist/utils/__tests__/paths.test.js +0 -50
  248. package/dist/utils/__tests__/paths.test.js.map +0 -1
  249. package/dist/utils/__tests__/retry.test.d.ts +0 -1
  250. package/dist/utils/__tests__/retry.test.js +0 -91
  251. package/dist/utils/__tests__/retry.test.js.map +0 -1
  252. package/dist/watchdog/__tests__/watchdog-service.test.d.ts +0 -1
  253. package/dist/watchdog/__tests__/watchdog-service.test.js +0 -113
  254. package/dist/watchdog/__tests__/watchdog-service.test.js.map +0 -1
@@ -1,166 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import os from 'node:os';
5
- import { PluginRegistry } from '../plugin-registry.js';
6
- function createMockContext(name) {
7
- return {
8
- dataDir: path.join(os.tmpdir(), 'brain-test-plugins', name),
9
- log: {
10
- info: vi.fn(),
11
- warn: vi.fn(),
12
- error: vi.fn(),
13
- debug: vi.fn(),
14
- },
15
- callBrain: vi.fn().mockResolvedValue({}),
16
- notify: vi.fn().mockResolvedValue(undefined),
17
- };
18
- }
19
- describe('PluginRegistry', () => {
20
- let tmpDir;
21
- let registry;
22
- beforeEach(() => {
23
- tmpDir = path.join(os.tmpdir(), `brain-plugin-test-${Date.now()}`);
24
- fs.mkdirSync(tmpDir, { recursive: true });
25
- registry = new PluginRegistry(tmpDir);
26
- });
27
- afterEach(() => {
28
- fs.rmSync(tmpDir, { recursive: true, force: true });
29
- });
30
- it('creates plugin directory if it does not exist', () => {
31
- const newDir = path.join(tmpDir, 'subdir');
32
- const reg = new PluginRegistry(newDir);
33
- expect(fs.existsSync(newDir)).toBe(true);
34
- });
35
- it('starts with no plugins', () => {
36
- expect(registry.size).toBe(0);
37
- expect(registry.list()).toEqual([]);
38
- expect(registry.getRoutes()).toEqual([]);
39
- expect(registry.getTools()).toEqual([]);
40
- });
41
- it('has() returns false for unknown plugin', () => {
42
- expect(registry.has('nonexistent')).toBe(false);
43
- });
44
- it('get() returns null for unknown plugin', () => {
45
- expect(registry.get('nonexistent')).toBeNull();
46
- });
47
- it('loadAll with empty directory loads nothing', async () => {
48
- await registry.loadAll((name) => createMockContext(name));
49
- expect(registry.size).toBe(0);
50
- });
51
- it('loadAll skips directories without package.json', async () => {
52
- fs.mkdirSync(path.join(tmpDir, 'empty-dir'));
53
- await registry.loadAll((name) => createMockContext(name));
54
- expect(registry.size).toBe(0);
55
- });
56
- it('loadAll skips packages without brainPlugin flag', async () => {
57
- const pluginDir = path.join(tmpDir, 'normal-pkg');
58
- fs.mkdirSync(pluginDir);
59
- fs.writeFileSync(path.join(pluginDir, 'package.json'), JSON.stringify({
60
- name: 'normal-pkg',
61
- version: '1.0.0',
62
- }));
63
- fs.writeFileSync(path.join(pluginDir, 'index.js'), 'module.exports = {}');
64
- await registry.loadAll((name) => createMockContext(name));
65
- expect(registry.size).toBe(0);
66
- });
67
- it('unloadPlugin returns false for unknown plugin', async () => {
68
- expect(await registry.unloadPlugin('nonexistent')).toBe(false);
69
- });
70
- it('runCycle does nothing with no plugins', async () => {
71
- await expect(registry.runCycle(1)).resolves.toBeUndefined();
72
- });
73
- it('list returns empty array when no plugins loaded', () => {
74
- expect(registry.list()).toEqual([]);
75
- });
76
- it('getRoutes returns plugin-prefixed routes', () => {
77
- // Manually inject a plugin for testing
78
- const plugin = {
79
- name: 'test-plugin',
80
- version: '1.0.0',
81
- routes: [
82
- { method: 'test.hello', handler: () => ({ hello: 'world' }) },
83
- ],
84
- };
85
- // Access internal map (testing only)
86
- registry.plugins.set('test-plugin', {
87
- plugin,
88
- path: '/fake',
89
- loadedAt: new Date().toISOString(),
90
- error: null,
91
- });
92
- const routes = registry.getRoutes();
93
- expect(routes).toHaveLength(1);
94
- expect(routes[0].plugin).toBe('test-plugin');
95
- expect(routes[0].method).toBe('test.hello');
96
- });
97
- it('getTools returns plugin-prefixed tools', () => {
98
- const plugin = {
99
- name: 'test-plugin',
100
- version: '1.0.0',
101
- tools: [
102
- { name: 'test_tool', description: 'A test', schema: {}, handler: () => 'ok' },
103
- ],
104
- };
105
- registry.plugins.set('test-plugin', {
106
- plugin,
107
- path: '/fake',
108
- loadedAt: new Date().toISOString(),
109
- error: null,
110
- });
111
- const tools = registry.getTools();
112
- expect(tools).toHaveLength(1);
113
- expect(tools[0].plugin).toBe('test-plugin');
114
- expect(tools[0].name).toBe('test_tool');
115
- });
116
- it('runCycle calls onCycle for loaded plugins', async () => {
117
- const onCycle = vi.fn();
118
- const plugin = {
119
- name: 'cycle-plugin',
120
- version: '1.0.0',
121
- onCycle,
122
- };
123
- registry.plugins.set('cycle-plugin', {
124
- plugin,
125
- path: '/fake',
126
- loadedAt: new Date().toISOString(),
127
- error: null,
128
- });
129
- await registry.runCycle(42);
130
- expect(onCycle).toHaveBeenCalledWith(42);
131
- });
132
- it('runCycle catches errors from plugins', async () => {
133
- const plugin = {
134
- name: 'bad-plugin',
135
- version: '1.0.0',
136
- onCycle: () => { throw new Error('boom'); },
137
- };
138
- registry.plugins.set('bad-plugin', {
139
- plugin,
140
- path: '/fake',
141
- loadedAt: new Date().toISOString(),
142
- error: null,
143
- });
144
- // Should not throw
145
- await expect(registry.runCycle(1)).resolves.toBeUndefined();
146
- });
147
- it('unloadPlugin calls onUnload and removes', async () => {
148
- const onUnload = vi.fn();
149
- const plugin = {
150
- name: 'unload-test',
151
- version: '1.0.0',
152
- onUnload,
153
- };
154
- registry.plugins.set('unload-test', {
155
- plugin,
156
- path: '/fake',
157
- loadedAt: new Date().toISOString(),
158
- error: null,
159
- });
160
- expect(registry.has('unload-test')).toBe(true);
161
- await registry.unloadPlugin('unload-test');
162
- expect(registry.has('unload-test')).toBe(false);
163
- expect(onUnload).toHaveBeenCalled();
164
- });
165
- });
166
- //# sourceMappingURL=plugin-registry.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin-registry.test.js","sourceRoot":"","sources":["../../../src/plugin/__tests__/plugin-registry.test.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,252 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import Database from 'better-sqlite3';
3
- vi.mock('../../utils/logger.js', () => ({
4
- getLogger: () => ({
5
- info: vi.fn(),
6
- warn: vi.fn(),
7
- error: vi.fn(),
8
- debug: vi.fn(),
9
- }),
10
- }));
11
- import { PredictionEngine, runPredictionMigration } from '../prediction-engine.js';
12
- // ── Helpers ───────────────────────────────────────────────
13
- /** Seed ascending metric data to produce a predictable upward trend. */
14
- function seedMetrics(db, metric, count, options) {
15
- const baseValue = options?.baseValue ?? 10;
16
- const step = options?.step ?? 1;
17
- const domain = options?.domain ?? 'metric';
18
- const baseTime = options?.baseTime ?? Date.now() - count * 60_000;
19
- for (let i = 0; i < count; i++) {
20
- db.prepare('INSERT INTO prediction_metrics (metric, value, domain, timestamp) VALUES (?, ?, ?, ?)').run(metric, baseValue + i * step, domain, baseTime + i * 60_000);
21
- }
22
- }
23
- // ── Tests ─────────────────────────────────────────────────
24
- describe('runPredictionMigration', () => {
25
- let db;
26
- beforeEach(() => { db = new Database(':memory:'); });
27
- afterEach(() => { db.close(); });
28
- it('creates predictions, prediction_metrics, and prediction_state tables', () => {
29
- runPredictionMigration(db);
30
- const tables = db
31
- .prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name")
32
- .all();
33
- const names = tables.map(t => t.name);
34
- expect(names).toContain('predictions');
35
- expect(names).toContain('prediction_metrics');
36
- expect(names).toContain('prediction_state');
37
- });
38
- it('initialises prediction_state with a single row', () => {
39
- runPredictionMigration(db);
40
- const row = db.prepare('SELECT * FROM prediction_state WHERE id = 1').get();
41
- expect(row).toBeDefined();
42
- expect(row.total_predictions).toBe(0);
43
- expect(row.total_resolved).toBe(0);
44
- expect(row.total_correct).toBe(0);
45
- expect(row.calibration_offset).toBe(0);
46
- });
47
- it('is idempotent (running twice does not throw)', () => {
48
- runPredictionMigration(db);
49
- expect(() => runPredictionMigration(db)).not.toThrow();
50
- });
51
- });
52
- describe('PredictionEngine', () => {
53
- let db;
54
- let engine;
55
- beforeEach(() => {
56
- db = new Database(':memory:');
57
- runPredictionMigration(db);
58
- engine = new PredictionEngine(db, { brainName: 'test-brain', minConfidence: 0.01, minDataPoints: 5 });
59
- });
60
- afterEach(() => {
61
- engine.stop();
62
- db.close();
63
- });
64
- // ── Creation & Config ───────────────────────────────────
65
- it('creates an engine with default config values', () => {
66
- const cfg = engine.getConfig();
67
- expect(cfg.brainName).toBe('test-brain');
68
- expect(cfg.defaultHorizonMs).toBe(600_000);
69
- expect(cfg.expirationMs).toBe(3_600_000);
70
- expect(cfg.ewmaAlpha).toBe(0.3);
71
- expect(cfg.trendBeta).toBe(0.1);
72
- expect(cfg.minDataPoints).toBe(5);
73
- expect(cfg.minConfidence).toBe(0.01);
74
- expect(cfg.maxPredictionsPerCycle).toBe(5);
75
- expect(cfg.resolveIntervalMs).toBe(60_000);
76
- });
77
- it('updateConfig merges partial updates', () => {
78
- engine.updateConfig({ ewmaAlpha: 0.5, trendBeta: 0.2 });
79
- const cfg = engine.getConfig();
80
- expect(cfg.ewmaAlpha).toBe(0.5);
81
- expect(cfg.trendBeta).toBe(0.2);
82
- // unchanged fields remain
83
- expect(cfg.minDataPoints).toBe(5);
84
- });
85
- // ── recordMetric ────────────────────────────────────────
86
- it('recordMetric inserts data points into prediction_metrics', () => {
87
- engine.recordMetric('cpu_load', 42.5, 'metric');
88
- engine.recordMetric('cpu_load', 45.0, 'metric');
89
- engine.recordMetric('cpu_load', 47.2, 'metric');
90
- const rows = db.prepare('SELECT * FROM prediction_metrics WHERE metric = ?').all('cpu_load');
91
- expect(rows).toHaveLength(3);
92
- });
93
- // ── predict ─────────────────────────────────────────────
94
- it('predict returns null when insufficient data (< 2 points)', () => {
95
- engine.recordMetric('sparse', 10);
96
- const result = engine.predict({ domain: 'metric', metric: 'sparse' });
97
- expect(result).toBeNull();
98
- });
99
- it('predict returns a Prediction with EWMA when 2-4 data points exist', () => {
100
- seedMetrics(db, 'short_series', 3, { baseValue: 10, step: 5 });
101
- const prediction = engine.predict({ domain: 'metric', metric: 'short_series' });
102
- expect(prediction).not.toBeNull();
103
- expect(prediction.method).toBe('ewma');
104
- expect(prediction.status).toBe('pending');
105
- expect(prediction.domain).toBe('metric');
106
- expect(prediction.metric).toBe('short_series');
107
- expect(prediction.prediction_id).toBeTruthy();
108
- expect(prediction.confidence).toBeGreaterThan(0);
109
- expect(prediction.horizon_ms).toBe(600_000);
110
- });
111
- it('predict returns a Prediction with holt_winters when >= minDataPoints', () => {
112
- seedMetrics(db, 'long_series', 10, { baseValue: 100, step: 2 });
113
- const prediction = engine.predict({ domain: 'trade', metric: 'long_series' });
114
- expect(prediction).not.toBeNull();
115
- expect(prediction.method).toBe('holt_winters');
116
- expect(prediction.predicted_direction).toBe('up');
117
- expect(prediction.evidence).toHaveProperty('dataPoints', 10);
118
- expect(prediction.evidence).toHaveProperty('trend');
119
- });
120
- it('predict increments total_predictions in prediction_state', () => {
121
- seedMetrics(db, 'counter_test', 3, { baseValue: 10, step: 1 });
122
- engine.predict({ domain: 'metric', metric: 'counter_test' });
123
- engine.predict({ domain: 'metric', metric: 'counter_test' });
124
- const state = db.prepare('SELECT total_predictions FROM prediction_state WHERE id = 1').get();
125
- expect(state.total_predictions).toBe(2);
126
- });
127
- // ── forecast ────────────────────────────────────────────
128
- it('forecast uses EWMA for small datasets and holt_winters for large', () => {
129
- const shortResult = engine.forecast([10, 20, 30], 60_000);
130
- expect(shortResult.method).toBe('ewma');
131
- expect(shortResult.dataPoints).toBe(3);
132
- const longResult = engine.forecast([10, 20, 30, 40, 50, 60, 70], 60_000);
133
- expect(longResult.method).toBe('holt_winters');
134
- expect(longResult.dataPoints).toBe(7);
135
- expect(longResult.direction).toBe('up');
136
- });
137
- // ── list ────────────────────────────────────────────────
138
- it('list returns stored predictions, optionally filtered by domain/status', () => {
139
- seedMetrics(db, 'm1', 3, { baseValue: 10, step: 1, domain: 'error' });
140
- seedMetrics(db, 'm2', 3, { baseValue: 50, step: 5, domain: 'trade' });
141
- engine.predict({ domain: 'error', metric: 'm1' });
142
- engine.predict({ domain: 'trade', metric: 'm2' });
143
- const all = engine.list();
144
- expect(all).toHaveLength(2);
145
- const errorOnly = engine.list('error');
146
- expect(errorOnly).toHaveLength(1);
147
- expect(errorOnly[0].domain).toBe('error');
148
- const pendingOnly = engine.list(undefined, 'pending');
149
- expect(pendingOnly).toHaveLength(2);
150
- });
151
- // ── getAccuracy ─────────────────────────────────────────
152
- it('getAccuracy returns per-domain accuracy stats after resolution', () => {
153
- // Insert a prediction directly, then resolve it via the tracker
154
- seedMetrics(db, 'acc_metric', 5, { baseValue: 100, step: 1 });
155
- const pred = engine.predict({ domain: 'error', metric: 'acc_metric' });
156
- expect(pred).not.toBeNull();
157
- // Manually resolve: set status to 'correct' in DB
158
- db.prepare("UPDATE predictions SET status = 'correct', actual_value = ?, error = 0.01 WHERE prediction_id = ?")
159
- .run(pred.predicted_value, pred.prediction_id);
160
- const accuracy = engine.getAccuracy('error');
161
- expect(accuracy).toHaveLength(1);
162
- expect(accuracy[0].domain).toBe('error');
163
- expect(accuracy[0].correct).toBe(1);
164
- expect(accuracy[0].accuracy_rate).toBe(1);
165
- });
166
- // ── getSummary ──────────────────────────────────────────
167
- it('getSummary returns a full summary with totals and recent predictions', () => {
168
- seedMetrics(db, 'sum_m', 4, { baseValue: 5, step: 2 });
169
- engine.predict({ domain: 'metric', metric: 'sum_m' });
170
- const summary = engine.getSummary();
171
- expect(summary.total_predictions).toBe(1);
172
- expect(summary.pending).toBe(1);
173
- expect(summary.resolved).toBe(0);
174
- expect(summary.accuracy_rate).toBe(0);
175
- expect(summary.calibration_offset).toBe(0);
176
- expect(summary.recent).toHaveLength(1);
177
- expect(summary.by_domain).toEqual([]);
178
- });
179
- // ── resolveExpired ──────────────────────────────────────
180
- it('resolveExpired marks predictions past expires_at as expired', () => {
181
- seedMetrics(db, 'exp_m', 3, { baseValue: 10, step: 1 });
182
- const pred = engine.predict({ domain: 'metric', metric: 'exp_m' });
183
- expect(pred).not.toBeNull();
184
- // Force the prediction to be expired by setting expires_at to the past
185
- const past = Date.now() - 10_000;
186
- db.prepare('UPDATE predictions SET expires_at = ? WHERE prediction_id = ?')
187
- .run(past, pred.prediction_id);
188
- const resolved = engine.resolveExpired();
189
- expect(resolved).toBeGreaterThanOrEqual(1);
190
- const updated = engine.list(undefined, 'expired');
191
- expect(updated).toHaveLength(1);
192
- expect(updated[0].prediction_id).toBe(pred.prediction_id);
193
- });
194
- it('resolveExpired resolves predictions past their horizon against actual data', () => {
195
- seedMetrics(db, 'res_m', 4, { baseValue: 50, step: 2 });
196
- const pred = engine.predict({ domain: 'metric', metric: 'res_m' });
197
- expect(pred).not.toBeNull();
198
- // Make the prediction resolvable: created_at + horizon_ms <= now AND expires_at >= now
199
- const now = Date.now();
200
- db.prepare('UPDATE predictions SET created_at = ?, expires_at = ? WHERE prediction_id = ?')
201
- .run(now - pred.horizon_ms - 1000, now + 100_000, pred.prediction_id);
202
- // Insert post-prediction metric values (timestamp > created_at)
203
- const predCreatedAt = now - pred.horizon_ms - 1000;
204
- for (let i = 0; i < 5; i++) {
205
- db.prepare('INSERT INTO prediction_metrics (metric, value, domain, timestamp) VALUES (?, ?, ?, ?)')
206
- .run('res_m', pred.predicted_value + i * 0.1, 'metric', predCreatedAt + 1000 + i * 1000);
207
- }
208
- const resolved = engine.resolveExpired();
209
- expect(resolved).toBeGreaterThanOrEqual(1);
210
- // The prediction should no longer be 'pending'
211
- const pending = engine.list(undefined, 'pending');
212
- const resolvedPred = pending.find(p => p.prediction_id === pred.prediction_id);
213
- expect(resolvedPred).toBeUndefined();
214
- });
215
- // ── getMetricHistory ────────────────────────────────────
216
- it('getMetricHistory returns data points in ascending timestamp order', () => {
217
- engine.recordMetric('hist_m', 10);
218
- engine.recordMetric('hist_m', 20);
219
- engine.recordMetric('hist_m', 30);
220
- const history = engine.getMetricHistory('hist_m', 10);
221
- expect(history).toHaveLength(3);
222
- expect(history[0].value).toBe(10);
223
- expect(history[2].value).toBe(30);
224
- expect(history[0].timestamp).toBeLessThanOrEqual(history[1].timestamp);
225
- expect(history[1].timestamp).toBeLessThanOrEqual(history[2].timestamp);
226
- });
227
- it('getMetricHistory respects the limit parameter', () => {
228
- for (let i = 0; i < 20; i++) {
229
- engine.recordMetric('limited_m', i);
230
- }
231
- const limited = engine.getMetricHistory('limited_m', 5);
232
- expect(limited).toHaveLength(5);
233
- });
234
- // ── start / stop ────────────────────────────────────────
235
- it('start and stop manage the resolution timer without error', () => {
236
- expect(() => engine.start()).not.toThrow();
237
- // calling start again is a no-op
238
- expect(() => engine.start()).not.toThrow();
239
- expect(() => engine.stop()).not.toThrow();
240
- // stopping again is safe
241
- expect(() => engine.stop()).not.toThrow();
242
- });
243
- // ── getCalibration ─────────────────────────────────────
244
- it('getCalibration returns offset and accuracy by domain', () => {
245
- const calibration = engine.getCalibration();
246
- expect(calibration).toHaveProperty('offset');
247
- expect(calibration).toHaveProperty('accuracyByDomain');
248
- expect(typeof calibration.offset).toBe('number');
249
- expect(Array.isArray(calibration.accuracyByDomain)).toBe(true);
250
- });
251
- });
252
- //# sourceMappingURL=prediction-engine.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prediction-engine.test.js","sourceRoot":"","sources":["../../../src/prediction/__tests__/prediction-engine.test.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,183 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import Database from 'better-sqlite3';
3
- vi.mock('../../utils/logger.js', () => ({
4
- getLogger: () => ({
5
- info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn(),
6
- }),
7
- }));
8
- import { ProactiveEngine, runProactiveMigration } from '../proactive-engine.js';
9
- function createDb() {
10
- return new Database(':memory:');
11
- }
12
- describe('ProactiveEngine', () => {
13
- let db;
14
- beforeEach(() => {
15
- db = createDb();
16
- });
17
- afterEach(() => {
18
- db.close();
19
- });
20
- it('creates a suggestion and retrieves it', () => {
21
- const engine = new ProactiveEngine(db, { brainName: 'test' });
22
- const ok = engine.createSuggestion('info', 'Test Suggestion', 'A description', 'Do something', 0.7);
23
- expect(ok).toBe(true);
24
- const suggestions = engine.getSuggestions();
25
- expect(suggestions).toHaveLength(1);
26
- expect(suggestions[0].title).toBe('Test Suggestion');
27
- expect(suggestions[0].priority).toBe(0.7);
28
- expect(suggestions[0].type).toBe('info');
29
- });
30
- it('returns suggestions sorted by priority descending', () => {
31
- const engine = new ProactiveEngine(db, { brainName: 'test' });
32
- engine.createSuggestion('low', 'Low Priority', undefined, undefined, 0.2);
33
- engine.createSuggestion('high', 'High Priority', undefined, undefined, 0.9);
34
- engine.createSuggestion('mid', 'Mid Priority', undefined, undefined, 0.5);
35
- const suggestions = engine.getSuggestions();
36
- expect(suggestions).toHaveLength(3);
37
- expect(suggestions[0].title).toBe('High Priority');
38
- expect(suggestions[1].title).toBe('Mid Priority');
39
- expect(suggestions[2].title).toBe('Low Priority');
40
- });
41
- it('dismisses a suggestion', () => {
42
- const engine = new ProactiveEngine(db, { brainName: 'test' });
43
- engine.createSuggestion('info', 'To Dismiss', 'desc');
44
- const before = engine.getSuggestions();
45
- expect(before).toHaveLength(1);
46
- engine.dismiss(before[0].id);
47
- const after = engine.getSuggestions();
48
- expect(after).toHaveLength(0);
49
- });
50
- it('respects rate limiting (max per hour)', () => {
51
- const engine = new ProactiveEngine(db, {
52
- brainName: 'test',
53
- maxSuggestionsPerHour: 2,
54
- });
55
- expect(engine.createSuggestion('a', 'First')).toBe(true);
56
- expect(engine.createSuggestion('b', 'Second')).toBe(true);
57
- expect(engine.createSuggestion('c', 'Third')).toBe(false); // Rate limited
58
- });
59
- it('checks recurring errors trigger', () => {
60
- const engine = new ProactiveEngine(db, {
61
- brainName: 'test',
62
- recurringThreshold: 3,
63
- });
64
- // Create error_memory table and populate
65
- db.exec(`
66
- CREATE TABLE error_memory (
67
- id INTEGER PRIMARY KEY,
68
- fingerprint TEXT NOT NULL,
69
- message TEXT NOT NULL
70
- )
71
- `);
72
- // Insert 3 errors with same fingerprint
73
- const insert = db.prepare('INSERT INTO error_memory (fingerprint, message) VALUES (?, ?)');
74
- insert.run('null-ref-001', 'Cannot read property of null');
75
- insert.run('null-ref-001', 'Cannot read property of null');
76
- insert.run('null-ref-001', 'Cannot read property of null');
77
- const created = engine.analyze({ db });
78
- expect(created).toBeGreaterThanOrEqual(1);
79
- const suggestions = engine.getSuggestions();
80
- const errorSuggestion = suggestions.find(s => s.type === 'recurring_error');
81
- expect(errorSuggestion).toBeDefined();
82
- expect(errorSuggestion.title).toContain('null-ref-001');
83
- });
84
- it('checks stale knowledge trigger', () => {
85
- const engine = new ProactiveEngine(db, {
86
- brainName: 'test',
87
- staleDays: 30,
88
- });
89
- // Create insights table with old high-confidence insight
90
- db.exec(`
91
- CREATE TABLE insights (
92
- id INTEGER PRIMARY KEY,
93
- topic TEXT NOT NULL,
94
- created_at TEXT NOT NULL,
95
- confidence REAL NOT NULL
96
- )
97
- `);
98
- db.prepare(`
99
- INSERT INTO insights (topic, created_at, confidence)
100
- VALUES (?, datetime('now', '-60 days'), 0.9)
101
- `).run('old-topic');
102
- const created = engine.analyze({ db });
103
- expect(created).toBeGreaterThanOrEqual(1);
104
- const suggestions = engine.getSuggestions();
105
- const staleSuggestion = suggestions.find(s => s.type === 'stale_knowledge');
106
- expect(staleSuggestion).toBeDefined();
107
- expect(staleSuggestion.title).toContain('old-topic');
108
- });
109
- it('getStatus returns correct counts', () => {
110
- const engine = new ProactiveEngine(db, { brainName: 'test' });
111
- engine.createSuggestion('a', 'Active 1');
112
- engine.createSuggestion('b', 'Active 2');
113
- const suggestions = engine.getSuggestions();
114
- engine.dismiss(suggestions[0].id);
115
- const status = engine.getStatus();
116
- expect(status.totalSuggestions).toBe(2);
117
- expect(status.activeSuggestions).toBe(1);
118
- expect(status.dismissedCount).toBe(1);
119
- expect(status.lastAnalysis).toBeNull(); // No analyze() called
120
- });
121
- it('migration is idempotent', () => {
122
- const engine1 = new ProactiveEngine(db, { brainName: 'test' });
123
- engine1.createSuggestion('test', 'Survives Migration');
124
- // Run migration again
125
- runProactiveMigration(db);
126
- const engine2 = new ProactiveEngine(db, { brainName: 'test' });
127
- const suggestions = engine2.getSuggestions();
128
- expect(suggestions).toHaveLength(1);
129
- expect(suggestions[0].title).toBe('Survives Migration');
130
- });
131
- it('returns zero suggestions from empty analysis', () => {
132
- const engine = new ProactiveEngine(db, { brainName: 'test' });
133
- // No error_memory, insights, or tool_usage tables exist
134
- const created = engine.analyze({ db });
135
- expect(created).toBe(0);
136
- });
137
- it('dismissed suggestions not returned by default', () => {
138
- const engine = new ProactiveEngine(db, { brainName: 'test' });
139
- engine.createSuggestion('a', 'Visible');
140
- engine.createSuggestion('b', 'Hidden');
141
- const all = engine.getSuggestions();
142
- engine.dismiss(all.find(s => s.title === 'Hidden').id);
143
- const active = engine.getSuggestions();
144
- expect(active).toHaveLength(1);
145
- expect(active[0].title).toBe('Visible');
146
- const withDismissed = engine.getSuggestions(20, true);
147
- expect(withDismissed).toHaveLength(2);
148
- });
149
- it('deduplicates suggestions with same title', () => {
150
- const engine = new ProactiveEngine(db, { brainName: 'test' });
151
- expect(engine.createSuggestion('a', 'Same Title')).toBe(true);
152
- expect(engine.createSuggestion('b', 'Same Title')).toBe(false); // Duplicate
153
- const suggestions = engine.getSuggestions();
154
- expect(suggestions).toHaveLength(1);
155
- });
156
- it('checks quick wins trigger (tool_usage table)', () => {
157
- const engine = new ProactiveEngine(db, { brainName: 'test' });
158
- // Create tool_usage table
159
- db.exec(`
160
- CREATE TABLE IF NOT EXISTS tool_usage (
161
- id INTEGER PRIMARY KEY,
162
- tool_name TEXT NOT NULL,
163
- context TEXT,
164
- duration_ms INTEGER,
165
- outcome TEXT DEFAULT 'success',
166
- metadata TEXT,
167
- created_at TEXT DEFAULT (datetime('now'))
168
- )
169
- `);
170
- // Insert a tool with high success rate but low usage
171
- const insert = db.prepare('INSERT INTO tool_usage (tool_name, outcome) VALUES (?, ?)');
172
- insert.run('rare-but-good', 'success');
173
- insert.run('rare-but-good', 'success');
174
- insert.run('rare-but-good', 'success');
175
- const created = engine.analyze({ db });
176
- expect(created).toBeGreaterThanOrEqual(1);
177
- const suggestions = engine.getSuggestions();
178
- const quickWin = suggestions.find(s => s.type === 'quick_win');
179
- expect(quickWin).toBeDefined();
180
- expect(quickWin.title).toContain('rare-but-good');
181
- });
182
- });
183
- //# sourceMappingURL=proactive-engine.test.js.map