@timmeck/brain 1.0.0 → 1.1.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.
Files changed (202) hide show
  1. package/BRAIN_PLAN.md +3324 -3324
  2. package/LICENSE +21 -21
  3. package/README.md +194 -188
  4. package/dist/brain.js +2 -0
  5. package/dist/brain.js.map +1 -1
  6. package/dist/cli/colors.d.ts +50 -0
  7. package/dist/cli/colors.js +106 -0
  8. package/dist/cli/colors.js.map +1 -0
  9. package/dist/cli/commands/config.d.ts +2 -0
  10. package/dist/cli/commands/config.js +165 -0
  11. package/dist/cli/commands/config.js.map +1 -0
  12. package/dist/cli/commands/dashboard.js +222 -8
  13. package/dist/cli/commands/dashboard.js.map +1 -1
  14. package/dist/cli/commands/export.js +3 -0
  15. package/dist/cli/commands/export.js.map +1 -1
  16. package/dist/cli/commands/import.js +24 -15
  17. package/dist/cli/commands/import.js.map +1 -1
  18. package/dist/cli/commands/insights.js +33 -6
  19. package/dist/cli/commands/insights.js.map +1 -1
  20. package/dist/cli/commands/learn.d.ts +2 -0
  21. package/dist/cli/commands/learn.js +22 -0
  22. package/dist/cli/commands/learn.js.map +1 -0
  23. package/dist/cli/commands/modules.js +25 -6
  24. package/dist/cli/commands/modules.js.map +1 -1
  25. package/dist/cli/commands/network.js +15 -9
  26. package/dist/cli/commands/network.js.map +1 -1
  27. package/dist/cli/commands/query.js +92 -25
  28. package/dist/cli/commands/query.js.map +1 -1
  29. package/dist/cli/commands/start.js +8 -5
  30. package/dist/cli/commands/start.js.map +1 -1
  31. package/dist/cli/commands/status.js +21 -16
  32. package/dist/cli/commands/status.js.map +1 -1
  33. package/dist/cli/commands/stop.js +5 -4
  34. package/dist/cli/commands/stop.js.map +1 -1
  35. package/dist/cli/ipc-helper.js +4 -3
  36. package/dist/cli/ipc-helper.js.map +1 -1
  37. package/dist/cli/update-check.d.ts +2 -0
  38. package/dist/cli/update-check.js +58 -0
  39. package/dist/cli/update-check.js.map +1 -0
  40. package/dist/db/migrations/001_core_schema.js +115 -115
  41. package/dist/db/migrations/002_learning_schema.js +33 -33
  42. package/dist/db/migrations/003_code_schema.js +48 -48
  43. package/dist/db/migrations/004_synapses_schema.js +52 -52
  44. package/dist/db/migrations/005_fts_indexes.js +73 -73
  45. package/dist/db/migrations/index.js +6 -6
  46. package/dist/db/repositories/antipattern.repository.js +3 -3
  47. package/dist/db/repositories/code-module.repository.d.ts +1 -0
  48. package/dist/db/repositories/code-module.repository.js +8 -0
  49. package/dist/db/repositories/code-module.repository.js.map +1 -1
  50. package/dist/db/repositories/error.repository.js +46 -46
  51. package/dist/db/repositories/insight.repository.js +3 -3
  52. package/dist/db/repositories/notification.repository.js +3 -3
  53. package/dist/db/repositories/project.repository.js +21 -21
  54. package/dist/db/repositories/rule.repository.js +24 -24
  55. package/dist/db/repositories/solution.repository.js +50 -50
  56. package/dist/db/repositories/synapse.repository.js +18 -18
  57. package/dist/db/repositories/terminal.repository.js +24 -24
  58. package/dist/index.js +4 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/ipc/router.d.ts +2 -0
  61. package/dist/ipc/router.js +7 -1
  62. package/dist/ipc/router.js.map +1 -1
  63. package/dist/services/code.service.d.ts +1 -1
  64. package/dist/services/code.service.js +5 -2
  65. package/dist/services/code.service.js.map +1 -1
  66. package/package.json +5 -4
  67. package/src/brain.ts +3 -0
  68. package/src/cli/colors.ts +116 -0
  69. package/src/cli/commands/config.ts +169 -0
  70. package/src/cli/commands/dashboard.ts +231 -8
  71. package/src/cli/commands/export.ts +4 -0
  72. package/src/cli/commands/import.ts +24 -15
  73. package/src/cli/commands/insights.ts +37 -5
  74. package/src/cli/commands/learn.ts +24 -0
  75. package/src/cli/commands/modules.ts +28 -5
  76. package/src/cli/commands/network.ts +15 -9
  77. package/src/cli/commands/query.ts +103 -26
  78. package/src/cli/commands/start.ts +8 -5
  79. package/src/cli/commands/status.ts +22 -16
  80. package/src/cli/commands/stop.ts +5 -4
  81. package/src/cli/ipc-helper.ts +4 -3
  82. package/src/cli/update-check.ts +63 -0
  83. package/src/code/analyzer.ts +77 -77
  84. package/src/code/fingerprint.ts +87 -87
  85. package/src/code/matcher.ts +64 -64
  86. package/src/code/parsers/generic.ts +29 -29
  87. package/src/code/parsers/python.ts +54 -54
  88. package/src/code/parsers/typescript.ts +65 -65
  89. package/src/code/registry.ts +60 -60
  90. package/src/code/scorer.ts +108 -108
  91. package/src/config.ts +111 -111
  92. package/src/db/connection.ts +22 -22
  93. package/src/db/migrations/001_core_schema.ts +120 -120
  94. package/src/db/migrations/002_learning_schema.ts +38 -38
  95. package/src/db/migrations/003_code_schema.ts +53 -53
  96. package/src/db/migrations/004_synapses_schema.ts +57 -57
  97. package/src/db/migrations/005_fts_indexes.ts +78 -78
  98. package/src/db/migrations/006_synapses_phase3.ts +17 -17
  99. package/src/db/migrations/index.ts +64 -64
  100. package/src/db/repositories/antipattern.repository.ts +66 -66
  101. package/src/db/repositories/code-module.repository.ts +9 -0
  102. package/src/db/repositories/error.repository.ts +149 -149
  103. package/src/db/repositories/insight.repository.ts +78 -78
  104. package/src/db/repositories/notification.repository.ts +66 -66
  105. package/src/db/repositories/project.repository.ts +93 -93
  106. package/src/db/repositories/rule.repository.ts +108 -108
  107. package/src/db/repositories/solution.repository.ts +154 -154
  108. package/src/db/repositories/synapse.repository.ts +153 -153
  109. package/src/db/repositories/terminal.repository.ts +101 -101
  110. package/src/hooks/post-tool-use.ts +90 -90
  111. package/src/hooks/post-write.ts +117 -117
  112. package/src/index.ts +4 -0
  113. package/src/ipc/client.ts +118 -118
  114. package/src/ipc/protocol.ts +35 -35
  115. package/src/ipc/router.ts +9 -1
  116. package/src/ipc/server.ts +110 -110
  117. package/src/learning/confidence-scorer.ts +47 -47
  118. package/src/learning/decay.ts +46 -46
  119. package/src/learning/learning-engine.ts +162 -162
  120. package/src/learning/pattern-extractor.ts +90 -90
  121. package/src/learning/rule-generator.ts +74 -74
  122. package/src/matching/error-matcher.ts +115 -115
  123. package/src/matching/fingerprint.ts +29 -29
  124. package/src/matching/similarity.ts +61 -61
  125. package/src/matching/tfidf.ts +74 -74
  126. package/src/matching/tokenizer.ts +41 -41
  127. package/src/mcp/auto-detect.ts +93 -93
  128. package/src/mcp/server.ts +73 -73
  129. package/src/mcp/tools.ts +290 -290
  130. package/src/parsing/error-parser.ts +28 -28
  131. package/src/parsing/parsers/compiler.ts +93 -93
  132. package/src/parsing/parsers/generic.ts +28 -28
  133. package/src/parsing/parsers/go.ts +97 -97
  134. package/src/parsing/parsers/node.ts +69 -69
  135. package/src/parsing/parsers/python.ts +62 -62
  136. package/src/parsing/parsers/rust.ts +50 -50
  137. package/src/parsing/parsers/shell.ts +42 -42
  138. package/src/parsing/types.ts +47 -47
  139. package/src/research/gap-analyzer.ts +135 -135
  140. package/src/research/insight-generator.ts +123 -123
  141. package/src/research/research-engine.ts +116 -116
  142. package/src/research/synergy-detector.ts +126 -126
  143. package/src/research/template-extractor.ts +130 -130
  144. package/src/research/trend-analyzer.ts +127 -127
  145. package/src/services/analytics.service.ts +87 -87
  146. package/src/services/code.service.ts +5 -2
  147. package/src/services/error.service.ts +164 -164
  148. package/src/services/notification.service.ts +41 -41
  149. package/src/services/prevention.service.ts +119 -119
  150. package/src/services/research.service.ts +93 -93
  151. package/src/services/solution.service.ts +116 -116
  152. package/src/services/synapse.service.ts +59 -59
  153. package/src/services/terminal.service.ts +81 -81
  154. package/src/synapses/activation.ts +80 -80
  155. package/src/synapses/decay.ts +38 -38
  156. package/src/synapses/hebbian.ts +69 -69
  157. package/src/synapses/pathfinder.ts +81 -81
  158. package/src/synapses/synapse-manager.ts +109 -109
  159. package/src/types/code.types.ts +52 -52
  160. package/src/types/config.types.ts +79 -79
  161. package/src/types/error.types.ts +67 -67
  162. package/src/types/ipc.types.ts +8 -8
  163. package/src/types/mcp.types.ts +53 -53
  164. package/src/types/research.types.ts +28 -28
  165. package/src/types/solution.types.ts +30 -30
  166. package/src/types/synapse.types.ts +49 -49
  167. package/src/utils/events.ts +45 -45
  168. package/src/utils/hash.ts +5 -5
  169. package/src/utils/logger.ts +48 -48
  170. package/src/utils/paths.ts +19 -19
  171. package/tests/fixtures/code-modules/modules.ts +83 -83
  172. package/tests/fixtures/errors/go.ts +9 -9
  173. package/tests/fixtures/errors/node.ts +24 -24
  174. package/tests/fixtures/errors/python.ts +21 -21
  175. package/tests/fixtures/errors/rust.ts +25 -25
  176. package/tests/fixtures/errors/shell.ts +15 -15
  177. package/tests/fixtures/solutions/solutions.ts +27 -27
  178. package/tests/helpers/setup-db.ts +52 -52
  179. package/tests/integration/code-flow.test.ts +86 -86
  180. package/tests/integration/error-flow.test.ts +83 -83
  181. package/tests/integration/ipc-flow.test.ts +166 -166
  182. package/tests/integration/learning-cycle.test.ts +82 -82
  183. package/tests/integration/synapse-flow.test.ts +117 -117
  184. package/tests/unit/code/analyzer.test.ts +58 -58
  185. package/tests/unit/code/fingerprint.test.ts +51 -51
  186. package/tests/unit/code/scorer.test.ts +55 -55
  187. package/tests/unit/learning/confidence-scorer.test.ts +60 -60
  188. package/tests/unit/learning/decay.test.ts +45 -45
  189. package/tests/unit/learning/pattern-extractor.test.ts +50 -50
  190. package/tests/unit/matching/error-matcher.test.ts +69 -69
  191. package/tests/unit/matching/fingerprint.test.ts +47 -47
  192. package/tests/unit/matching/similarity.test.ts +65 -65
  193. package/tests/unit/matching/tfidf.test.ts +71 -71
  194. package/tests/unit/matching/tokenizer.test.ts +83 -83
  195. package/tests/unit/parsing/parsers.test.ts +113 -113
  196. package/tests/unit/research/gap-analyzer.test.ts +45 -45
  197. package/tests/unit/research/trend-analyzer.test.ts +45 -45
  198. package/tests/unit/synapses/activation.test.ts +80 -80
  199. package/tests/unit/synapses/decay.test.ts +27 -27
  200. package/tests/unit/synapses/hebbian.test.ts +96 -96
  201. package/tests/unit/synapses/pathfinder.test.ts +72 -72
  202. package/tsconfig.json +18 -18
@@ -1,113 +1,113 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { parseError } from '../../../src/parsing/error-parser.js';
3
- import { nodeTypeError, nodeModuleNotFound, nodeReferenceError, nodeSyntaxError } from '../../fixtures/errors/node.js';
4
- import { pythonTraceback, pythonImportError, pythonTypeError } from '../../fixtures/errors/python.js';
5
- import { rustCompilerError, rustBorrowError } from '../../fixtures/errors/rust.js';
6
- import { goCompileError, goPanicError } from '../../fixtures/errors/go.js';
7
- import { shellCommandNotFound, shellPermissionDenied, npmError } from '../../fixtures/errors/shell.js';
8
-
9
- describe('Node.js Parser', () => {
10
- it('parses TypeError with stack trace', () => {
11
- const result = parseError(nodeTypeError);
12
- expect(result.errorType).toBe('TypeError');
13
- expect(result.message).toContain('Cannot read properties');
14
- expect(result.frames.length).toBeGreaterThan(0);
15
- expect(result.language).toBe('javascript');
16
- });
17
-
18
- it('parses module not found error', () => {
19
- const result = parseError(nodeModuleNotFound);
20
- expect(result.errorType).toContain('Error');
21
- expect(result.message).toContain('Cannot find module');
22
- });
23
-
24
- it('parses ReferenceError', () => {
25
- const result = parseError(nodeReferenceError);
26
- expect(result.errorType).toBe('ReferenceError');
27
- expect(result.message).toContain('process is not defined');
28
- });
29
-
30
- it('parses SyntaxError', () => {
31
- const result = parseError(nodeSyntaxError);
32
- expect(result.errorType).toBe('SyntaxError');
33
- });
34
- });
35
-
36
- describe('Python Parser', () => {
37
- it('parses Python traceback with KeyError', () => {
38
- const result = parseError(pythonTraceback);
39
- expect(result.errorType).toBe('KeyError');
40
- expect(result.frames.length).toBeGreaterThan(0);
41
- expect(result.language).toBe('python');
42
- });
43
-
44
- it('parses ModuleNotFoundError', () => {
45
- const result = parseError(pythonImportError);
46
- expect(result.errorType).toBe('ModuleNotFoundError');
47
- expect(result.message).toContain('flask');
48
- });
49
-
50
- it('parses TypeError', () => {
51
- const result = parseError(pythonTypeError);
52
- expect(result.errorType).toBe('TypeError');
53
- });
54
- });
55
-
56
- describe('Rust Parser', () => {
57
- it('parses compiler error with code', () => {
58
- const result = parseError(rustCompilerError);
59
- expect(result.errorType).toContain('E0308');
60
- expect(result.message).toContain('mismatched types');
61
- expect(result.language).toBe('rust');
62
- });
63
-
64
- it('parses borrow checker error', () => {
65
- const result = parseError(rustBorrowError);
66
- expect(result.errorType).toContain('E0502');
67
- expect(result.message).toContain('borrow');
68
- });
69
- });
70
-
71
- describe('Go Parser', () => {
72
- it('parses compile error', () => {
73
- const result = parseError(goCompileError);
74
- expect(result.errorType).toBeTruthy();
75
- expect(result.language).toBe('go');
76
- });
77
-
78
- it('parses panic', () => {
79
- const result = parseError(goPanicError);
80
- expect(result.message).toContain('index out of range');
81
- });
82
- });
83
-
84
- describe('Shell Parser', () => {
85
- it('parses command not found', () => {
86
- const result = parseError(shellCommandNotFound);
87
- expect(result.message).toContain('command not found');
88
- expect(result.language).toBe('shell');
89
- });
90
-
91
- it('parses permission denied', () => {
92
- const result = parseError(shellPermissionDenied);
93
- expect(result.message).toContain('Permission denied');
94
- });
95
-
96
- it('parses npm error', () => {
97
- const result = parseError(npmError);
98
- expect(result.message).toBeTruthy();
99
- });
100
- });
101
-
102
- describe('Generic fallback', () => {
103
- it('handles unknown error format gracefully', () => {
104
- const result = parseError('Something went wrong: unexpected token');
105
- expect(result.errorType).toBeTruthy();
106
- expect(result.message).toBeTruthy();
107
- });
108
-
109
- it('handles empty string', () => {
110
- const result = parseError('');
111
- expect(result).toBeTruthy();
112
- });
113
- });
1
+ import { describe, it, expect } from 'vitest';
2
+ import { parseError } from '../../../src/parsing/error-parser.js';
3
+ import { nodeTypeError, nodeModuleNotFound, nodeReferenceError, nodeSyntaxError } from '../../fixtures/errors/node.js';
4
+ import { pythonTraceback, pythonImportError, pythonTypeError } from '../../fixtures/errors/python.js';
5
+ import { rustCompilerError, rustBorrowError } from '../../fixtures/errors/rust.js';
6
+ import { goCompileError, goPanicError } from '../../fixtures/errors/go.js';
7
+ import { shellCommandNotFound, shellPermissionDenied, npmError } from '../../fixtures/errors/shell.js';
8
+
9
+ describe('Node.js Parser', () => {
10
+ it('parses TypeError with stack trace', () => {
11
+ const result = parseError(nodeTypeError);
12
+ expect(result.errorType).toBe('TypeError');
13
+ expect(result.message).toContain('Cannot read properties');
14
+ expect(result.frames.length).toBeGreaterThan(0);
15
+ expect(result.language).toBe('javascript');
16
+ });
17
+
18
+ it('parses module not found error', () => {
19
+ const result = parseError(nodeModuleNotFound);
20
+ expect(result.errorType).toContain('Error');
21
+ expect(result.message).toContain('Cannot find module');
22
+ });
23
+
24
+ it('parses ReferenceError', () => {
25
+ const result = parseError(nodeReferenceError);
26
+ expect(result.errorType).toBe('ReferenceError');
27
+ expect(result.message).toContain('process is not defined');
28
+ });
29
+
30
+ it('parses SyntaxError', () => {
31
+ const result = parseError(nodeSyntaxError);
32
+ expect(result.errorType).toBe('SyntaxError');
33
+ });
34
+ });
35
+
36
+ describe('Python Parser', () => {
37
+ it('parses Python traceback with KeyError', () => {
38
+ const result = parseError(pythonTraceback);
39
+ expect(result.errorType).toBe('KeyError');
40
+ expect(result.frames.length).toBeGreaterThan(0);
41
+ expect(result.language).toBe('python');
42
+ });
43
+
44
+ it('parses ModuleNotFoundError', () => {
45
+ const result = parseError(pythonImportError);
46
+ expect(result.errorType).toBe('ModuleNotFoundError');
47
+ expect(result.message).toContain('flask');
48
+ });
49
+
50
+ it('parses TypeError', () => {
51
+ const result = parseError(pythonTypeError);
52
+ expect(result.errorType).toBe('TypeError');
53
+ });
54
+ });
55
+
56
+ describe('Rust Parser', () => {
57
+ it('parses compiler error with code', () => {
58
+ const result = parseError(rustCompilerError);
59
+ expect(result.errorType).toContain('E0308');
60
+ expect(result.message).toContain('mismatched types');
61
+ expect(result.language).toBe('rust');
62
+ });
63
+
64
+ it('parses borrow checker error', () => {
65
+ const result = parseError(rustBorrowError);
66
+ expect(result.errorType).toContain('E0502');
67
+ expect(result.message).toContain('borrow');
68
+ });
69
+ });
70
+
71
+ describe('Go Parser', () => {
72
+ it('parses compile error', () => {
73
+ const result = parseError(goCompileError);
74
+ expect(result.errorType).toBeTruthy();
75
+ expect(result.language).toBe('go');
76
+ });
77
+
78
+ it('parses panic', () => {
79
+ const result = parseError(goPanicError);
80
+ expect(result.message).toContain('index out of range');
81
+ });
82
+ });
83
+
84
+ describe('Shell Parser', () => {
85
+ it('parses command not found', () => {
86
+ const result = parseError(shellCommandNotFound);
87
+ expect(result.message).toContain('command not found');
88
+ expect(result.language).toBe('shell');
89
+ });
90
+
91
+ it('parses permission denied', () => {
92
+ const result = parseError(shellPermissionDenied);
93
+ expect(result.message).toContain('Permission denied');
94
+ });
95
+
96
+ it('parses npm error', () => {
97
+ const result = parseError(npmError);
98
+ expect(result.message).toBeTruthy();
99
+ });
100
+ });
101
+
102
+ describe('Generic fallback', () => {
103
+ it('handles unknown error format gracefully', () => {
104
+ const result = parseError('Something went wrong: unexpected token');
105
+ expect(result.errorType).toBeTruthy();
106
+ expect(result.message).toBeTruthy();
107
+ });
108
+
109
+ it('handles empty string', () => {
110
+ const result = parseError('');
111
+ expect(result).toBeTruthy();
112
+ });
113
+ });
@@ -1,45 +1,45 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import { GapAnalyzer } from '../../../src/research/gap-analyzer.js';
3
- import { createTestDb, type TestDb } from '../../helpers/setup-db.js';
4
-
5
- describe('GapAnalyzer', () => {
6
- let testDb: TestDb;
7
-
8
- beforeEach(() => {
9
- testDb = createTestDb();
10
- testDb.repos.project.create({ name: 'test-project', path: '/test' } as any);
11
-
12
- for (let i = 0; i < 8; i++) {
13
- testDb.repos.error.create({
14
- project_id: 1, terminal_id: null, fingerprint: 'same_fp', type: 'ModuleNotFoundError',
15
- message: "No module named 'missing_lib'",
16
- raw_output: `ModuleNotFoundError: No module named 'missing_lib'`,
17
- context: null, file_path: null, line_number: null, column_number: null,
18
- } as any);
19
- }
20
- });
21
-
22
- const researchConfig = {
23
- intervalMs: 3600000, initialDelayMs: 300000, minDataPoints: 3,
24
- trendWindowDays: 7, gapMinOccurrences: 5, synergyMinWeight: 0.5,
25
- templateMinAdaptations: 3, insightExpiryDays: 30,
26
- };
27
-
28
- it('creates without error', () => {
29
- const analyzer = new GapAnalyzer(
30
- testDb.repos.error, testDb.repos.solution, testDb.repos.synapse,
31
- testDb.repos.project, testDb.repos.insight, researchConfig,
32
- );
33
- expect(analyzer).toBeTruthy();
34
- });
35
-
36
- it('runs analyze without crashing', () => {
37
- const analyzer = new GapAnalyzer(
38
- testDb.repos.error, testDb.repos.solution, testDb.repos.synapse,
39
- testDb.repos.project, testDb.repos.insight, researchConfig,
40
- );
41
- const count = analyzer.analyze();
42
- expect(typeof count).toBe('number');
43
- expect(count).toBeGreaterThanOrEqual(0);
44
- });
45
- });
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { GapAnalyzer } from '../../../src/research/gap-analyzer.js';
3
+ import { createTestDb, type TestDb } from '../../helpers/setup-db.js';
4
+
5
+ describe('GapAnalyzer', () => {
6
+ let testDb: TestDb;
7
+
8
+ beforeEach(() => {
9
+ testDb = createTestDb();
10
+ testDb.repos.project.create({ name: 'test-project', path: '/test' } as any);
11
+
12
+ for (let i = 0; i < 8; i++) {
13
+ testDb.repos.error.create({
14
+ project_id: 1, terminal_id: null, fingerprint: 'same_fp', type: 'ModuleNotFoundError',
15
+ message: "No module named 'missing_lib'",
16
+ raw_output: `ModuleNotFoundError: No module named 'missing_lib'`,
17
+ context: null, file_path: null, line_number: null, column_number: null,
18
+ } as any);
19
+ }
20
+ });
21
+
22
+ const researchConfig = {
23
+ intervalMs: 3600000, initialDelayMs: 300000, minDataPoints: 3,
24
+ trendWindowDays: 7, gapMinOccurrences: 5, synergyMinWeight: 0.5,
25
+ templateMinAdaptations: 3, insightExpiryDays: 30,
26
+ };
27
+
28
+ it('creates without error', () => {
29
+ const analyzer = new GapAnalyzer(
30
+ testDb.repos.error, testDb.repos.solution, testDb.repos.synapse,
31
+ testDb.repos.project, testDb.repos.insight, researchConfig,
32
+ );
33
+ expect(analyzer).toBeTruthy();
34
+ });
35
+
36
+ it('runs analyze without crashing', () => {
37
+ const analyzer = new GapAnalyzer(
38
+ testDb.repos.error, testDb.repos.solution, testDb.repos.synapse,
39
+ testDb.repos.project, testDb.repos.insight, researchConfig,
40
+ );
41
+ const count = analyzer.analyze();
42
+ expect(typeof count).toBe('number');
43
+ expect(count).toBeGreaterThanOrEqual(0);
44
+ });
45
+ });
@@ -1,45 +1,45 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import { TrendAnalyzer } from '../../../src/research/trend-analyzer.js';
3
- import { createTestDb, type TestDb } from '../../helpers/setup-db.js';
4
-
5
- describe('TrendAnalyzer', () => {
6
- let testDb: TestDb;
7
-
8
- beforeEach(() => {
9
- testDb = createTestDb();
10
- testDb.repos.project.create({ name: 'test-project', path: '/test' } as any);
11
-
12
- for (let i = 0; i < 10; i++) {
13
- testDb.repos.error.create({
14
- project_id: 1, terminal_id: null, fingerprint: `fp${i}`, type: 'TypeError',
15
- message: `Cannot read property of undefined ${i}`,
16
- raw_output: `TypeError: test ${i}`, context: null,
17
- file_path: null, line_number: null, column_number: null,
18
- } as any);
19
- }
20
- });
21
-
22
- const researchConfig = {
23
- intervalMs: 3600000, initialDelayMs: 300000, minDataPoints: 3,
24
- trendWindowDays: 7, gapMinOccurrences: 5, synergyMinWeight: 0.5,
25
- templateMinAdaptations: 3, insightExpiryDays: 30,
26
- };
27
-
28
- it('creates without error', () => {
29
- const analyzer = new TrendAnalyzer(
30
- testDb.repos.error, testDb.repos.solution, testDb.repos.project,
31
- testDb.repos.insight, researchConfig,
32
- );
33
- expect(analyzer).toBeTruthy();
34
- });
35
-
36
- it('runs analyze without crashing', () => {
37
- const analyzer = new TrendAnalyzer(
38
- testDb.repos.error, testDb.repos.solution, testDb.repos.project,
39
- testDb.repos.insight, researchConfig,
40
- );
41
- const count = analyzer.analyze();
42
- expect(typeof count).toBe('number');
43
- expect(count).toBeGreaterThanOrEqual(0);
44
- });
45
- });
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { TrendAnalyzer } from '../../../src/research/trend-analyzer.js';
3
+ import { createTestDb, type TestDb } from '../../helpers/setup-db.js';
4
+
5
+ describe('TrendAnalyzer', () => {
6
+ let testDb: TestDb;
7
+
8
+ beforeEach(() => {
9
+ testDb = createTestDb();
10
+ testDb.repos.project.create({ name: 'test-project', path: '/test' } as any);
11
+
12
+ for (let i = 0; i < 10; i++) {
13
+ testDb.repos.error.create({
14
+ project_id: 1, terminal_id: null, fingerprint: `fp${i}`, type: 'TypeError',
15
+ message: `Cannot read property of undefined ${i}`,
16
+ raw_output: `TypeError: test ${i}`, context: null,
17
+ file_path: null, line_number: null, column_number: null,
18
+ } as any);
19
+ }
20
+ });
21
+
22
+ const researchConfig = {
23
+ intervalMs: 3600000, initialDelayMs: 300000, minDataPoints: 3,
24
+ trendWindowDays: 7, gapMinOccurrences: 5, synergyMinWeight: 0.5,
25
+ templateMinAdaptations: 3, insightExpiryDays: 30,
26
+ };
27
+
28
+ it('creates without error', () => {
29
+ const analyzer = new TrendAnalyzer(
30
+ testDb.repos.error, testDb.repos.solution, testDb.repos.project,
31
+ testDb.repos.insight, researchConfig,
32
+ );
33
+ expect(analyzer).toBeTruthy();
34
+ });
35
+
36
+ it('runs analyze without crashing', () => {
37
+ const analyzer = new TrendAnalyzer(
38
+ testDb.repos.error, testDb.repos.solution, testDb.repos.project,
39
+ testDb.repos.insight, researchConfig,
40
+ );
41
+ const count = analyzer.analyze();
42
+ expect(typeof count).toBe('number');
43
+ expect(count).toBeGreaterThanOrEqual(0);
44
+ });
45
+ });
@@ -1,80 +1,80 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
- import { spreadingActivation } from '../../../src/synapses/activation.js';
3
- import { createTestDb, type TestDb } from '../../helpers/setup-db.js';
4
-
5
- describe('spreadingActivation', () => {
6
- let testDb: TestDb;
7
-
8
- beforeEach(() => {
9
- testDb = createTestDb();
10
- testDb.repos.project.create({ name: 'test', path: '/test' } as any);
11
- for (let i = 0; i < 3; i++) {
12
- testDb.repos.error.create({
13
- project_id: 1, terminal_id: null, fingerprint: `fp${i}`, type: 'TypeError',
14
- message: `error ${i}`, raw_output: `TypeError: ${i}`,
15
- context: null, file_path: null, line_number: null, column_number: null,
16
- } as any);
17
- }
18
-
19
- // Create synapses directly via DB: error1 → error2, error2 → error3
20
- testDb.repos.synapse.create({
21
- source_type: 'error', source_id: 1,
22
- target_type: 'error', target_id: 2,
23
- synapse_type: 'similar_to', weight: 0.8, metadata: null,
24
- } as any);
25
- testDb.repos.synapse.create({
26
- source_type: 'error', source_id: 2,
27
- target_type: 'error', target_id: 3,
28
- synapse_type: 'similar_to', weight: 0.7, metadata: null,
29
- } as any);
30
- });
31
-
32
- it('finds directly connected nodes', () => {
33
- const results = spreadingActivation(
34
- testDb.repos.synapse,
35
- { type: 'error', id: 1 },
36
- 1,
37
- );
38
- expect(results.length).toBeGreaterThan(0);
39
- });
40
-
41
- it('finds multi-hop connections', () => {
42
- const results = spreadingActivation(
43
- testDb.repos.synapse,
44
- { type: 'error', id: 1 },
45
- 2,
46
- );
47
- // Should reach error3 through error2
48
- const nodeIds = results.map(r => r.node.id);
49
- expect(nodeIds).toContain(3);
50
- });
51
-
52
- it('returns empty for isolated node', () => {
53
- // error3 has no outgoing connections (only incoming)
54
- // Add an isolated error
55
- testDb.repos.error.create({
56
- project_id: 1, terminal_id: null, fingerprint: 'fp_isolated', type: 'TypeError',
57
- message: 'isolated', raw_output: 'TypeError: isolated',
58
- context: null, file_path: null, line_number: null, column_number: null,
59
- } as any);
60
- const results = spreadingActivation(
61
- testDb.repos.synapse,
62
- { type: 'error', id: 4 },
63
- 3,
64
- );
65
- expect(results).toEqual([]);
66
- });
67
-
68
- it('activation decays with depth', () => {
69
- const results = spreadingActivation(
70
- testDb.repos.synapse,
71
- { type: 'error', id: 1 },
72
- 2,
73
- );
74
- const direct = results.find(r => r.node.id === 2);
75
- const twoHop = results.find(r => r.node.id === 3);
76
- if (direct && twoHop) {
77
- expect(direct.activation).toBeGreaterThan(twoHop.activation);
78
- }
79
- });
80
- });
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { spreadingActivation } from '../../../src/synapses/activation.js';
3
+ import { createTestDb, type TestDb } from '../../helpers/setup-db.js';
4
+
5
+ describe('spreadingActivation', () => {
6
+ let testDb: TestDb;
7
+
8
+ beforeEach(() => {
9
+ testDb = createTestDb();
10
+ testDb.repos.project.create({ name: 'test', path: '/test' } as any);
11
+ for (let i = 0; i < 3; i++) {
12
+ testDb.repos.error.create({
13
+ project_id: 1, terminal_id: null, fingerprint: `fp${i}`, type: 'TypeError',
14
+ message: `error ${i}`, raw_output: `TypeError: ${i}`,
15
+ context: null, file_path: null, line_number: null, column_number: null,
16
+ } as any);
17
+ }
18
+
19
+ // Create synapses directly via DB: error1 → error2, error2 → error3
20
+ testDb.repos.synapse.create({
21
+ source_type: 'error', source_id: 1,
22
+ target_type: 'error', target_id: 2,
23
+ synapse_type: 'similar_to', weight: 0.8, metadata: null,
24
+ } as any);
25
+ testDb.repos.synapse.create({
26
+ source_type: 'error', source_id: 2,
27
+ target_type: 'error', target_id: 3,
28
+ synapse_type: 'similar_to', weight: 0.7, metadata: null,
29
+ } as any);
30
+ });
31
+
32
+ it('finds directly connected nodes', () => {
33
+ const results = spreadingActivation(
34
+ testDb.repos.synapse,
35
+ { type: 'error', id: 1 },
36
+ 1,
37
+ );
38
+ expect(results.length).toBeGreaterThan(0);
39
+ });
40
+
41
+ it('finds multi-hop connections', () => {
42
+ const results = spreadingActivation(
43
+ testDb.repos.synapse,
44
+ { type: 'error', id: 1 },
45
+ 2,
46
+ );
47
+ // Should reach error3 through error2
48
+ const nodeIds = results.map(r => r.node.id);
49
+ expect(nodeIds).toContain(3);
50
+ });
51
+
52
+ it('returns empty for isolated node', () => {
53
+ // error3 has no outgoing connections (only incoming)
54
+ // Add an isolated error
55
+ testDb.repos.error.create({
56
+ project_id: 1, terminal_id: null, fingerprint: 'fp_isolated', type: 'TypeError',
57
+ message: 'isolated', raw_output: 'TypeError: isolated',
58
+ context: null, file_path: null, line_number: null, column_number: null,
59
+ } as any);
60
+ const results = spreadingActivation(
61
+ testDb.repos.synapse,
62
+ { type: 'error', id: 4 },
63
+ 3,
64
+ );
65
+ expect(results).toEqual([]);
66
+ });
67
+
68
+ it('activation decays with depth', () => {
69
+ const results = spreadingActivation(
70
+ testDb.repos.synapse,
71
+ { type: 'error', id: 1 },
72
+ 2,
73
+ );
74
+ const direct = results.find(r => r.node.id === 2);
75
+ const twoHop = results.find(r => r.node.id === 3);
76
+ if (direct && twoHop) {
77
+ expect(direct.activation).toBeGreaterThan(twoHop.activation);
78
+ }
79
+ });
80
+ });
@@ -1,27 +1,27 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { timeDecayFactor } from '../../../src/synapses/decay.js';
3
-
4
- describe('timeDecayFactor', () => {
5
- it('returns ~1.0 for recent activation', () => {
6
- const now = new Date().toISOString();
7
- expect(timeDecayFactor(now, 45)).toBeCloseTo(1.0, 1);
8
- });
9
-
10
- it('returns ~0.5 after one half-life', () => {
11
- const halfLifeDays = 45;
12
- const past = new Date(Date.now() - halfLifeDays * 86400000).toISOString();
13
- expect(timeDecayFactor(past, halfLifeDays)).toBeCloseTo(0.5, 1);
14
- });
15
-
16
- it('returns near 0 for very old activation', () => {
17
- const veryOld = new Date(Date.now() - 500 * 86400000).toISOString();
18
- expect(timeDecayFactor(veryOld, 45)).toBeLessThan(0.01);
19
- });
20
-
21
- it('always returns between 0 and 1', () => {
22
- const past = new Date(Date.now() - 15 * 86400000).toISOString();
23
- const val = timeDecayFactor(past, 45);
24
- expect(val).toBeGreaterThanOrEqual(0);
25
- expect(val).toBeLessThanOrEqual(1);
26
- });
27
- });
1
+ import { describe, it, expect } from 'vitest';
2
+ import { timeDecayFactor } from '../../../src/synapses/decay.js';
3
+
4
+ describe('timeDecayFactor', () => {
5
+ it('returns ~1.0 for recent activation', () => {
6
+ const now = new Date().toISOString();
7
+ expect(timeDecayFactor(now, 45)).toBeCloseTo(1.0, 1);
8
+ });
9
+
10
+ it('returns ~0.5 after one half-life', () => {
11
+ const halfLifeDays = 45;
12
+ const past = new Date(Date.now() - halfLifeDays * 86400000).toISOString();
13
+ expect(timeDecayFactor(past, halfLifeDays)).toBeCloseTo(0.5, 1);
14
+ });
15
+
16
+ it('returns near 0 for very old activation', () => {
17
+ const veryOld = new Date(Date.now() - 500 * 86400000).toISOString();
18
+ expect(timeDecayFactor(veryOld, 45)).toBeLessThan(0.01);
19
+ });
20
+
21
+ it('always returns between 0 and 1', () => {
22
+ const past = new Date(Date.now() - 15 * 86400000).toISOString();
23
+ const val = timeDecayFactor(past, 45);
24
+ expect(val).toBeGreaterThanOrEqual(0);
25
+ expect(val).toBeLessThanOrEqual(1);
26
+ });
27
+ });