@timmeck/brain 1.9.0 → 2.1.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 (253) hide show
  1. package/README.md +33 -0
  2. package/brain.log +3876 -0
  3. package/{src/cli/commands/dashboard.ts → dashboard.html} +694 -807
  4. package/dist/api/server.d.ts +4 -18
  5. package/dist/api/server.js +4 -173
  6. package/dist/api/server.js.map +1 -1
  7. package/dist/brain.d.ts +2 -0
  8. package/dist/brain.js +15 -4
  9. package/dist/brain.js.map +1 -1
  10. package/dist/cli/colors.d.ts +4 -25
  11. package/dist/cli/colors.js +3 -89
  12. package/dist/cli/colors.js.map +1 -1
  13. package/dist/cli/commands/dashboard.js +21 -2
  14. package/dist/cli/commands/dashboard.js.map +1 -1
  15. package/dist/cli/commands/peers.d.ts +2 -0
  16. package/dist/cli/commands/peers.js +38 -0
  17. package/dist/cli/commands/peers.js.map +1 -0
  18. package/dist/cli/commands/status.js +0 -1
  19. package/dist/cli/commands/status.js.map +1 -1
  20. package/dist/config.js +2 -29
  21. package/dist/config.js.map +1 -1
  22. package/dist/db/connection.d.ts +1 -2
  23. package/dist/db/connection.js +1 -18
  24. package/dist/db/connection.js.map +1 -1
  25. package/dist/index.js +3 -1
  26. package/dist/index.js.map +1 -1
  27. package/dist/ipc/__tests__/protocol.test.d.ts +1 -0
  28. package/dist/ipc/__tests__/protocol.test.js +117 -0
  29. package/dist/ipc/__tests__/protocol.test.js.map +1 -0
  30. package/dist/ipc/client.d.ts +1 -16
  31. package/dist/ipc/client.js +1 -100
  32. package/dist/ipc/client.js.map +1 -1
  33. package/dist/ipc/protocol.d.ts +1 -8
  34. package/dist/ipc/protocol.js +1 -28
  35. package/dist/ipc/protocol.js.map +1 -1
  36. package/dist/ipc/router.d.ts +2 -0
  37. package/dist/ipc/router.js +30 -0
  38. package/dist/ipc/router.js.map +1 -1
  39. package/dist/ipc/server.d.ts +1 -22
  40. package/dist/ipc/server.js +1 -163
  41. package/dist/ipc/server.js.map +1 -1
  42. package/dist/learning/confidence-scorer.d.ts +2 -5
  43. package/dist/learning/confidence-scorer.js +4 -19
  44. package/dist/learning/confidence-scorer.js.map +1 -1
  45. package/dist/learning/decay.js +2 -3
  46. package/dist/learning/decay.js.map +1 -1
  47. package/dist/learning/learning-engine.d.ts +2 -5
  48. package/dist/learning/learning-engine.js +3 -15
  49. package/dist/learning/learning-engine.js.map +1 -1
  50. package/dist/mcp/http-server.d.ts +1 -7
  51. package/dist/mcp/http-server.js +6 -117
  52. package/dist/mcp/http-server.js.map +1 -1
  53. package/dist/mcp/server.js +5 -61
  54. package/dist/mcp/server.js.map +1 -1
  55. package/dist/mcp/tools.js +36 -0
  56. package/dist/mcp/tools.js.map +1 -1
  57. package/dist/parsing/parsers/compiler.js +1 -1
  58. package/dist/parsing/parsers/compiler.js.map +1 -1
  59. package/dist/research/research-engine.d.ts +2 -6
  60. package/dist/research/research-engine.js +3 -23
  61. package/dist/research/research-engine.js.map +1 -1
  62. package/dist/services/synapse.service.d.ts +3 -3
  63. package/dist/signals/__tests__/fingerprint.test.d.ts +1 -0
  64. package/dist/signals/__tests__/fingerprint.test.js +118 -0
  65. package/dist/signals/__tests__/fingerprint.test.js.map +1 -0
  66. package/dist/synapses/activation.d.ts +3 -13
  67. package/dist/synapses/activation.js +2 -49
  68. package/dist/synapses/activation.js.map +1 -1
  69. package/dist/synapses/decay.d.ts +2 -11
  70. package/dist/synapses/decay.js +2 -26
  71. package/dist/synapses/decay.js.map +1 -1
  72. package/dist/synapses/hebbian.d.ts +2 -13
  73. package/dist/synapses/hebbian.js +2 -35
  74. package/dist/synapses/hebbian.js.map +1 -1
  75. package/dist/synapses/pathfinder.d.ts +2 -14
  76. package/dist/synapses/pathfinder.js +2 -49
  77. package/dist/synapses/pathfinder.js.map +1 -1
  78. package/dist/synapses/synapse-manager.d.ts +7 -23
  79. package/dist/synapses/synapse-manager.js +6 -63
  80. package/dist/synapses/synapse-manager.js.map +1 -1
  81. package/dist/types/ipc.types.d.ts +1 -11
  82. package/dist/utils/__tests__/hash.test.d.ts +1 -0
  83. package/dist/utils/__tests__/hash.test.js +32 -0
  84. package/dist/utils/__tests__/hash.test.js.map +1 -0
  85. package/dist/utils/__tests__/paths.test.d.ts +1 -0
  86. package/dist/utils/__tests__/paths.test.js +75 -0
  87. package/dist/utils/__tests__/paths.test.js.map +1 -0
  88. package/dist/utils/events.d.ts +4 -8
  89. package/dist/utils/events.js +2 -14
  90. package/dist/utils/events.js.map +1 -1
  91. package/dist/utils/hash.d.ts +1 -1
  92. package/dist/utils/hash.js +1 -4
  93. package/dist/utils/hash.js.map +1 -1
  94. package/dist/utils/logger.d.ts +3 -2
  95. package/dist/utils/logger.js +8 -35
  96. package/dist/utils/logger.js.map +1 -1
  97. package/dist/utils/paths.d.ts +2 -1
  98. package/dist/utils/paths.js +4 -13
  99. package/dist/utils/paths.js.map +1 -1
  100. package/eslint.config.js +14 -0
  101. package/package.json +56 -49
  102. package/BRAIN_PLAN.md +0 -3324
  103. package/reddit_post.md +0 -45
  104. package/src/api/server.ts +0 -395
  105. package/src/brain.ts +0 -313
  106. package/src/cli/colors.ts +0 -116
  107. package/src/cli/commands/config.ts +0 -169
  108. package/src/cli/commands/doctor.ts +0 -124
  109. package/src/cli/commands/explain.ts +0 -83
  110. package/src/cli/commands/export.ts +0 -31
  111. package/src/cli/commands/import.ts +0 -199
  112. package/src/cli/commands/insights.ts +0 -65
  113. package/src/cli/commands/learn.ts +0 -24
  114. package/src/cli/commands/modules.ts +0 -53
  115. package/src/cli/commands/network.ts +0 -67
  116. package/src/cli/commands/projects.ts +0 -42
  117. package/src/cli/commands/query.ts +0 -120
  118. package/src/cli/commands/start.ts +0 -105
  119. package/src/cli/commands/status.ts +0 -75
  120. package/src/cli/commands/stop.ts +0 -34
  121. package/src/cli/ipc-helper.ts +0 -22
  122. package/src/cli/update-check.ts +0 -63
  123. package/src/code/analyzer.ts +0 -117
  124. package/src/code/fingerprint.ts +0 -87
  125. package/src/code/matcher.ts +0 -129
  126. package/src/code/parsers/generic.ts +0 -29
  127. package/src/code/parsers/python.ts +0 -54
  128. package/src/code/parsers/typescript.ts +0 -65
  129. package/src/code/registry.ts +0 -60
  130. package/src/code/scorer.ts +0 -120
  131. package/src/config.ts +0 -135
  132. package/src/dashboard/server.ts +0 -142
  133. package/src/db/connection.ts +0 -22
  134. package/src/db/migrations/001_core_schema.ts +0 -120
  135. package/src/db/migrations/002_learning_schema.ts +0 -38
  136. package/src/db/migrations/003_code_schema.ts +0 -53
  137. package/src/db/migrations/004_synapses_schema.ts +0 -57
  138. package/src/db/migrations/005_fts_indexes.ts +0 -78
  139. package/src/db/migrations/006_synapses_phase3.ts +0 -17
  140. package/src/db/migrations/007_feedback.ts +0 -13
  141. package/src/db/migrations/008_git_integration.ts +0 -38
  142. package/src/db/migrations/009_embeddings.ts +0 -8
  143. package/src/db/migrations/index.ts +0 -70
  144. package/src/db/repositories/antipattern.repository.ts +0 -66
  145. package/src/db/repositories/code-module.repository.ts +0 -142
  146. package/src/db/repositories/error.repository.ts +0 -189
  147. package/src/db/repositories/insight.repository.ts +0 -99
  148. package/src/db/repositories/notification.repository.ts +0 -66
  149. package/src/db/repositories/project.repository.ts +0 -93
  150. package/src/db/repositories/rule.repository.ts +0 -108
  151. package/src/db/repositories/solution.repository.ts +0 -154
  152. package/src/db/repositories/synapse.repository.ts +0 -163
  153. package/src/db/repositories/terminal.repository.ts +0 -101
  154. package/src/embeddings/engine.ts +0 -238
  155. package/src/hooks/post-tool-use.ts +0 -92
  156. package/src/hooks/post-write.ts +0 -129
  157. package/src/index.ts +0 -63
  158. package/src/ipc/client.ts +0 -118
  159. package/src/ipc/protocol.ts +0 -35
  160. package/src/ipc/router.ts +0 -133
  161. package/src/ipc/server.ts +0 -176
  162. package/src/learning/confidence-scorer.ts +0 -80
  163. package/src/learning/decay.ts +0 -46
  164. package/src/learning/learning-engine.ts +0 -170
  165. package/src/learning/pattern-extractor.ts +0 -90
  166. package/src/learning/rule-generator.ts +0 -74
  167. package/src/main.rs:10:5 +0 -0
  168. package/src/matching/error-matcher.ts +0 -166
  169. package/src/matching/fingerprint.ts +0 -34
  170. package/src/matching/similarity.ts +0 -61
  171. package/src/matching/tfidf.ts +0 -74
  172. package/src/matching/tokenizer.ts +0 -41
  173. package/src/mcp/auto-detect.ts +0 -93
  174. package/src/mcp/http-server.ts +0 -140
  175. package/src/mcp/server.ts +0 -73
  176. package/src/mcp/tools.ts +0 -328
  177. package/src/parsing/error-parser.ts +0 -28
  178. package/src/parsing/parsers/compiler.ts +0 -93
  179. package/src/parsing/parsers/generic.ts +0 -28
  180. package/src/parsing/parsers/go.ts +0 -97
  181. package/src/parsing/parsers/node.ts +0 -69
  182. package/src/parsing/parsers/python.ts +0 -62
  183. package/src/parsing/parsers/rust.ts +0 -50
  184. package/src/parsing/parsers/shell.ts +0 -42
  185. package/src/parsing/types.ts +0 -47
  186. package/src/research/gap-analyzer.ts +0 -135
  187. package/src/research/insight-generator.ts +0 -123
  188. package/src/research/research-engine.ts +0 -116
  189. package/src/research/synergy-detector.ts +0 -126
  190. package/src/research/template-extractor.ts +0 -130
  191. package/src/research/trend-analyzer.ts +0 -127
  192. package/src/services/analytics.service.ts +0 -226
  193. package/src/services/code.service.ts +0 -271
  194. package/src/services/error.service.ts +0 -266
  195. package/src/services/git.service.ts +0 -132
  196. package/src/services/notification.service.ts +0 -41
  197. package/src/services/prevention.service.ts +0 -159
  198. package/src/services/research.service.ts +0 -98
  199. package/src/services/solution.service.ts +0 -174
  200. package/src/services/synapse.service.ts +0 -59
  201. package/src/services/terminal.service.ts +0 -81
  202. package/src/synapses/activation.ts +0 -80
  203. package/src/synapses/decay.ts +0 -38
  204. package/src/synapses/hebbian.ts +0 -69
  205. package/src/synapses/pathfinder.ts +0 -81
  206. package/src/synapses/synapse-manager.ts +0 -113
  207. package/src/types/code.types.ts +0 -52
  208. package/src/types/config.types.ts +0 -103
  209. package/src/types/error.types.ts +0 -67
  210. package/src/types/ipc.types.ts +0 -8
  211. package/src/types/mcp.types.ts +0 -53
  212. package/src/types/research.types.ts +0 -28
  213. package/src/types/solution.types.ts +0 -30
  214. package/src/types/synapse.types.ts +0 -50
  215. package/src/utils/events.ts +0 -45
  216. package/src/utils/hash.ts +0 -5
  217. package/src/utils/logger.ts +0 -48
  218. package/src/utils/paths.ts +0 -19
  219. package/tests/e2e/test_code_intelligence.py +0 -1015
  220. package/tests/e2e/test_error_memory.py +0 -451
  221. package/tests/e2e/test_full_integration.py +0 -534
  222. package/tests/fixtures/code-modules/modules.ts +0 -83
  223. package/tests/fixtures/errors/go.ts +0 -9
  224. package/tests/fixtures/errors/node.ts +0 -24
  225. package/tests/fixtures/errors/python.ts +0 -21
  226. package/tests/fixtures/errors/rust.ts +0 -25
  227. package/tests/fixtures/errors/shell.ts +0 -15
  228. package/tests/fixtures/solutions/solutions.ts +0 -27
  229. package/tests/helpers/setup-db.ts +0 -52
  230. package/tests/integration/code-flow.test.ts +0 -86
  231. package/tests/integration/error-flow.test.ts +0 -83
  232. package/tests/integration/ipc-flow.test.ts +0 -166
  233. package/tests/integration/learning-cycle.test.ts +0 -82
  234. package/tests/integration/synapse-flow.test.ts +0 -117
  235. package/tests/unit/code/analyzer.test.ts +0 -58
  236. package/tests/unit/code/fingerprint.test.ts +0 -51
  237. package/tests/unit/code/scorer.test.ts +0 -55
  238. package/tests/unit/learning/confidence-scorer.test.ts +0 -60
  239. package/tests/unit/learning/decay.test.ts +0 -45
  240. package/tests/unit/learning/pattern-extractor.test.ts +0 -50
  241. package/tests/unit/matching/error-matcher.test.ts +0 -69
  242. package/tests/unit/matching/fingerprint.test.ts +0 -47
  243. package/tests/unit/matching/similarity.test.ts +0 -65
  244. package/tests/unit/matching/tfidf.test.ts +0 -71
  245. package/tests/unit/matching/tokenizer.test.ts +0 -83
  246. package/tests/unit/parsing/parsers.test.ts +0 -113
  247. package/tests/unit/research/gap-analyzer.test.ts +0 -45
  248. package/tests/unit/research/trend-analyzer.test.ts +0 -45
  249. package/tests/unit/synapses/activation.test.ts +0 -80
  250. package/tests/unit/synapses/decay.test.ts +0 -27
  251. package/tests/unit/synapses/hebbian.test.ts +0 -96
  252. package/tests/unit/synapses/pathfinder.test.ts +0 -72
  253. package/tsconfig.json +0 -18
@@ -1,69 +0,0 @@
1
- import type { ErrorParser, ParsedError, StackFrame } from '../types.js';
2
- import path from 'node:path';
3
-
4
- const V8_STACK_RE = /at (?:(.+?) )?\((.+?):(\d+):(\d+)\)/;
5
- const V8_STACK_BARE_RE = /at (.+?):(\d+):(\d+)/;
6
- const ERROR_TYPE_RE = /^(\w+(?:Error|Exception|Warning)?): (.+)$/m;
7
-
8
- function parseFrames(input: string): StackFrame[] {
9
- const frames: StackFrame[] = [];
10
- for (const line of input.split('\n')) {
11
- const trimmed = line.trim();
12
- let match = V8_STACK_RE.exec(trimmed);
13
- if (match) {
14
- frames.push({
15
- function_name: match[1] || null,
16
- file_path: match[2]!,
17
- line_number: parseInt(match[3]!, 10),
18
- column_number: parseInt(match[4]!, 10),
19
- normalized: `${match[1] || '<anon>'}@${path.basename(match[2]!)}`,
20
- });
21
- continue;
22
- }
23
- match = V8_STACK_BARE_RE.exec(trimmed);
24
- if (match) {
25
- frames.push({
26
- function_name: null,
27
- file_path: match[1]!,
28
- line_number: parseInt(match[2]!, 10),
29
- column_number: parseInt(match[3]!, 10),
30
- normalized: `<anon>@${path.basename(match[1]!)}`,
31
- });
32
- }
33
- }
34
- return frames;
35
- }
36
-
37
- export const nodeParser: ErrorParser = {
38
- name: 'node',
39
- priority: 10,
40
-
41
- canParse(input: string): boolean {
42
- return (
43
- /at .+ \(.+:\d+:\d+\)/.test(input) ||
44
- /at .+:\d+:\d+/.test(input) ||
45
- /^\w*Error:/.test(input) ||
46
- /^\w*TypeError:/.test(input)
47
- );
48
- },
49
-
50
- parse(input: string): ParsedError | null {
51
- const typeMatch = ERROR_TYPE_RE.exec(input);
52
- if (!typeMatch) return null;
53
-
54
- const errorType = typeMatch[1]!;
55
- const message = typeMatch[2]!;
56
- const frames = parseFrames(input);
57
- const topFrame = frames[0];
58
-
59
- return {
60
- errorType,
61
- message,
62
- stackTrace: input,
63
- frames,
64
- sourceFile: topFrame?.file_path ?? null,
65
- sourceLine: topFrame?.line_number ?? null,
66
- language: 'javascript',
67
- };
68
- },
69
- };
@@ -1,62 +0,0 @@
1
- import type { ErrorParser, ParsedError, StackFrame } from '../types.js';
2
- import path from 'node:path';
3
-
4
- const FRAME_RE = /File "(.+?)", line (\d+)(?:, in (.+))?/g;
5
- const ERROR_LINE_RE = /^(\w+(?:Error|Exception|Warning)?): (.+)$/m;
6
-
7
- export const pythonParser: ErrorParser = {
8
- name: 'python',
9
- priority: 10,
10
-
11
- canParse(input: string): boolean {
12
- return (
13
- /Traceback \(most recent call last\)/.test(input) ||
14
- /File ".+", line \d+/.test(input)
15
- );
16
- },
17
-
18
- parse(input: string): ParsedError | null {
19
- const frames: StackFrame[] = [];
20
- let match: RegExpExecArray | null;
21
- const frameRe = new RegExp(FRAME_RE.source, 'g');
22
-
23
- while ((match = frameRe.exec(input)) !== null) {
24
- frames.push({
25
- function_name: match[3] || null,
26
- file_path: match[1]!,
27
- line_number: parseInt(match[2]!, 10),
28
- column_number: null,
29
- normalized: `${match[3] || '<module>'}@${path.basename(match[1]!)}`,
30
- });
31
- }
32
-
33
- const lines = input.trim().split('\n');
34
- let errorType = 'PythonError';
35
- let message = '';
36
-
37
- for (let i = lines.length - 1; i >= 0; i--) {
38
- const errMatch = ERROR_LINE_RE.exec(lines[i]!);
39
- if (errMatch) {
40
- errorType = errMatch[1]!;
41
- message = errMatch[2]!;
42
- break;
43
- }
44
- }
45
-
46
- if (!message && lines.length > 0) {
47
- message = lines[lines.length - 1]!;
48
- }
49
-
50
- const topFrame = frames[frames.length - 1];
51
-
52
- return {
53
- errorType,
54
- message,
55
- stackTrace: input,
56
- frames,
57
- sourceFile: topFrame?.file_path ?? null,
58
- sourceLine: topFrame?.line_number ?? null,
59
- language: 'python',
60
- };
61
- },
62
- };
@@ -1,50 +0,0 @@
1
- import type { ErrorParser, ParsedError, StackFrame } from '../types.js';
2
- import path from 'node:path';
3
-
4
- const RUST_ERROR_RE = /error(?:\[E(\d+)\])?: (.+)/;
5
- const RUST_LOCATION_RE = /^\s*--> (.+):(\d+):(\d+)/m;
6
- const RUST_NOTE_RE = /^\s*= note: (.+)/gm;
7
-
8
- export const rustParser: ErrorParser = {
9
- name: 'rust',
10
- priority: 10,
11
-
12
- canParse(input: string): boolean {
13
- return /error\[E\d+\]:/.test(input) || /^error:/.test(input);
14
- },
15
-
16
- parse(input: string): ParsedError | null {
17
- const errMatch = RUST_ERROR_RE.exec(input);
18
- if (!errMatch) return null;
19
-
20
- const message = errMatch[2]!.trim();
21
- const errorType = errMatch[1] ? `E${errMatch[1]}` : 'CompilerError';
22
-
23
- const frames: StackFrame[] = [];
24
- let sourceFile: string | null = null;
25
- let sourceLine: number | null = null;
26
-
27
- const locMatch = RUST_LOCATION_RE.exec(input);
28
- if (locMatch) {
29
- sourceFile = locMatch[1]!;
30
- sourceLine = parseInt(locMatch[2]!, 10);
31
- frames.push({
32
- function_name: null,
33
- file_path: locMatch[1]!,
34
- line_number: parseInt(locMatch[2]!, 10),
35
- column_number: parseInt(locMatch[3]!, 10),
36
- normalized: `<compiler>@${path.basename(locMatch[1]!)}`,
37
- });
38
- }
39
-
40
- return {
41
- errorType,
42
- message,
43
- stackTrace: input,
44
- frames,
45
- sourceFile,
46
- sourceLine,
47
- language: 'rust',
48
- };
49
- },
50
- };
@@ -1,42 +0,0 @@
1
- import type { ErrorParser, ParsedError } from '../types.js';
2
-
3
- const ERROR_MAP: Array<{ pattern: RegExp; type: string }> = [
4
- { pattern: /command not found/i, type: 'CommandNotFound' },
5
- { pattern: /Permission denied|EACCES/i, type: 'PermissionError' },
6
- { pattern: /No such file or directory|ENOENT/i, type: 'FileNotFound' },
7
- { pattern: /ECONNREFUSED/i, type: 'ConnectionRefused' },
8
- { pattern: /EADDRINUSE/i, type: 'AddressInUse' },
9
- { pattern: /ETIMEDOUT|ESOCKETTIMEDOUT/i, type: 'Timeout' },
10
- { pattern: /ENOMEM/i, type: 'OutOfMemory' },
11
- ];
12
-
13
- export const shellParser: ErrorParser = {
14
- name: 'shell',
15
- priority: 5,
16
-
17
- canParse(input: string): boolean {
18
- return ERROR_MAP.some(e => e.pattern.test(input));
19
- },
20
-
21
- parse(input: string): ParsedError | null {
22
- let errorType = 'ShellError';
23
- for (const entry of ERROR_MAP) {
24
- if (entry.pattern.test(input)) {
25
- errorType = entry.type;
26
- break;
27
- }
28
- }
29
-
30
- const firstLine = input.trim().split('\n')[0] ?? input;
31
-
32
- return {
33
- errorType,
34
- message: firstLine,
35
- stackTrace: null,
36
- frames: [],
37
- sourceFile: null,
38
- sourceLine: null,
39
- language: 'shell',
40
- };
41
- },
42
- };
@@ -1,47 +0,0 @@
1
- export interface StackFrame {
2
- function_name: string | null;
3
- file_path: string | null;
4
- line_number: number | null;
5
- column_number: number | null;
6
- normalized: string | null;
7
- }
8
-
9
- export interface ParsedError {
10
- errorType: string;
11
- message: string;
12
- stackTrace: string | null;
13
- frames: StackFrame[];
14
- sourceFile: string | null;
15
- sourceLine: number | null;
16
- language: string | null;
17
- }
18
-
19
- export interface ErrorParser {
20
- name: string;
21
- priority: number;
22
- canParse(input: string): boolean;
23
- parse(input: string): ParsedError | null;
24
- }
25
-
26
- export class ErrorParserRegistry {
27
- private parsers: ErrorParser[] = [];
28
-
29
- register(parser: ErrorParser): void {
30
- this.parsers.push(parser);
31
- this.parsers.sort((a, b) => b.priority - a.priority);
32
- }
33
-
34
- parse(input: string): ParsedError | null {
35
- for (const parser of this.parsers) {
36
- if (parser.canParse(input)) {
37
- const result = parser.parse(input);
38
- if (result) return result;
39
- }
40
- }
41
- return null;
42
- }
43
-
44
- getRegistered(): string[] {
45
- return this.parsers.map(p => p.name);
46
- }
47
- }
@@ -1,135 +0,0 @@
1
- import type { ResearchConfig } from '../types/config.types.js';
2
- import type { ErrorRepository } from '../db/repositories/error.repository.js';
3
- import type { SolutionRepository } from '../db/repositories/solution.repository.js';
4
- import type { SynapseRepository } from '../db/repositories/synapse.repository.js';
5
- import type { ProjectRepository } from '../db/repositories/project.repository.js';
6
- import type { InsightRepository } from '../db/repositories/insight.repository.js';
7
- import { getLogger } from '../utils/logger.js';
8
-
9
- /**
10
- * Identifies gaps: unresolved recurring errors, missing solutions, isolated synapse nodes.
11
- */
12
- export class GapAnalyzer {
13
- private logger = getLogger();
14
-
15
- constructor(
16
- private errorRepo: ErrorRepository,
17
- private solutionRepo: SolutionRepository,
18
- private synapseRepo: SynapseRepository,
19
- private projectRepo: ProjectRepository,
20
- private insightRepo: InsightRepository,
21
- private config: ResearchConfig,
22
- ) {}
23
-
24
- analyze(): number {
25
- let insightsCreated = 0;
26
-
27
- insightsCreated += this.findUnresolvedRecurring();
28
- insightsCreated += this.findFailedSolutions();
29
- insightsCreated += this.findIsolatedNodes();
30
-
31
- this.logger.info(`Gap analysis complete: ${insightsCreated} insights`);
32
- return insightsCreated;
33
- }
34
-
35
- private findUnresolvedRecurring(): number {
36
- const unresolved = this.errorRepo.findUnresolved();
37
- const recurring = unresolved.filter(e => e.occurrence_count >= this.config.gapMinOccurrences);
38
- let count = 0;
39
- const expiresAt = new Date(Date.now() + this.config.insightExpiryDays * 86400000).toISOString();
40
-
41
- for (const error of recurring) {
42
- const solutions = this.solutionRepo.findForError(error.id);
43
- if (solutions.length === 0) {
44
- this.insightRepo.create({
45
- type: 'warning',
46
- title: `Unresolved recurring error: ${error.type}`,
47
- description: `"${error.message.substring(0, 80)}..." has occurred ${error.occurrence_count} times with no solution.`,
48
- evidence: JSON.stringify({ errorId: error.id, occurrences: error.occurrence_count, type: error.type }),
49
- priority: Math.min(95, 40 + error.occurrence_count * 5),
50
- project_id: error.project_id,
51
- active: 1,
52
- expires_at: expiresAt,
53
- });
54
- count++;
55
- }
56
- }
57
-
58
- return count;
59
- }
60
-
61
- private findFailedSolutions(): number {
62
- const projects = this.projectRepo.getAll();
63
- let count = 0;
64
- const expiresAt = new Date(Date.now() + this.config.insightExpiryDays * 86400000).toISOString();
65
-
66
- for (const project of projects) {
67
- const errors = this.errorRepo.findUnresolved(project.id);
68
- for (const error of errors) {
69
- if (error.occurrence_count < this.config.gapMinOccurrences) continue;
70
-
71
- const solutions = this.solutionRepo.findForError(error.id);
72
- if (solutions.length < 2) continue;
73
-
74
- const allFailed = solutions.every(s => {
75
- const rate = this.solutionRepo.successRate(s.id);
76
- return rate < 0.3;
77
- });
78
-
79
- if (allFailed) {
80
- this.insightRepo.create({
81
- type: 'warning',
82
- title: `All solutions failing for: ${error.type}`,
83
- description: `${solutions.length} solutions tried for "${error.message.substring(0, 60)}..." but all have <30% success rate.`,
84
- evidence: JSON.stringify({
85
- errorId: error.id,
86
- solutionCount: solutions.length,
87
- solutionIds: solutions.map(s => s.id),
88
- }),
89
- priority: Math.min(90, 50 + solutions.length * 10),
90
- project_id: project.id,
91
- active: 1,
92
- expires_at: expiresAt,
93
- });
94
- count++;
95
- }
96
- }
97
- }
98
-
99
- return count;
100
- }
101
-
102
- private findIsolatedNodes(): number {
103
- const projects = this.projectRepo.getAll();
104
- let count = 0;
105
- const expiresAt = new Date(Date.now() + this.config.insightExpiryDays * 86400000).toISOString();
106
-
107
- for (const project of projects) {
108
- const errors = this.errorRepo.findByProject(project.id);
109
- let projectIsolated = 0;
110
-
111
- for (const error of errors) {
112
- const connections = this.synapseRepo.findConnected('error', error.id);
113
- if (connections.length === 0) {
114
- projectIsolated++;
115
- }
116
- }
117
-
118
- if (projectIsolated > 5) {
119
- this.insightRepo.create({
120
- type: 'optimization',
121
- title: `${projectIsolated} errors without connections in ${project.name}`,
122
- description: `These errors have no synapses to solutions, modules, or other errors. Brain cannot contextualize them.`,
123
- evidence: JSON.stringify({ projectId: project.id, isolatedCount: projectIsolated }),
124
- priority: 25,
125
- project_id: project.id,
126
- active: 1,
127
- expires_at: expiresAt,
128
- });
129
- count++;
130
- }
131
- }
132
-
133
- return count;
134
- }
135
- }
@@ -1,123 +0,0 @@
1
- import type { ResearchConfig } from '../types/config.types.js';
2
- import type { ProjectRepository } from '../db/repositories/project.repository.js';
3
- import type { ErrorRepository } from '../db/repositories/error.repository.js';
4
- import type { SolutionRepository } from '../db/repositories/solution.repository.js';
5
- import type { CodeModuleRepository } from '../db/repositories/code-module.repository.js';
6
- import type { InsightRepository } from '../db/repositories/insight.repository.js';
7
- import { getLogger } from '../utils/logger.js';
8
-
9
- /**
10
- * Generates project suggestions, tool ideas, and optimization hints.
11
- */
12
- export class InsightGenerator {
13
- private logger = getLogger();
14
-
15
- constructor(
16
- private projectRepo: ProjectRepository,
17
- private errorRepo: ErrorRepository,
18
- private solutionRepo: SolutionRepository,
19
- private codeModuleRepo: CodeModuleRepository,
20
- private insightRepo: InsightRepository,
21
- private config: ResearchConfig,
22
- ) {}
23
-
24
- generate(): number {
25
- let insightsCreated = 0;
26
-
27
- insightsCreated += this.suggestRefactoring();
28
- insightsCreated += this.suggestErrorTypeTools();
29
- this.reprioritizeInsights();
30
-
31
- this.logger.info(`Insight generation complete: ${insightsCreated} new insights`);
32
- return insightsCreated;
33
- }
34
-
35
- private suggestRefactoring(): number {
36
- const projects = this.projectRepo.getAll();
37
- let count = 0;
38
- const expiresAt = new Date(Date.now() + this.config.insightExpiryDays * 86400000).toISOString();
39
-
40
- for (const project of projects) {
41
- const modules = this.codeModuleRepo.findByProject(project.id);
42
- const problematic = modules.filter(m =>
43
- (m.complexity ?? 0) > 10 && m.reusability_score < 0.3 && m.lines_of_code > 50,
44
- );
45
-
46
- if (problematic.length > 0) {
47
- this.insightRepo.create({
48
- type: 'optimization',
49
- title: `${problematic.length} complex modules need refactoring in ${project.name}`,
50
- description: `These modules have high complexity (>10), low reusability (<30%), and are non-trivial (>50 LOC). Refactoring would improve maintainability.`,
51
- evidence: JSON.stringify({
52
- modules: problematic.map(m => ({
53
- id: m.id,
54
- name: m.name,
55
- complexity: m.complexity,
56
- reusability: m.reusability_score,
57
- loc: m.lines_of_code,
58
- })),
59
- }),
60
- priority: Math.min(70, 30 + problematic.length * 10),
61
- project_id: project.id,
62
- active: 1,
63
- expires_at: expiresAt,
64
- });
65
- count++;
66
- }
67
- }
68
-
69
- return count;
70
- }
71
-
72
- private suggestErrorTypeTools(): number {
73
- const projects = this.projectRepo.getAll();
74
- let count = 0;
75
- const expiresAt = new Date(Date.now() + this.config.insightExpiryDays * 86400000).toISOString();
76
-
77
- for (const project of projects) {
78
- const errors = this.errorRepo.findByProject(project.id);
79
- if (errors.length < this.config.minDataPoints) continue;
80
-
81
- // Group errors by type
82
- const byType = new Map<string, number>();
83
- for (const error of errors) {
84
- byType.set(error.type, (byType.get(error.type) ?? 0) + error.occurrence_count);
85
- }
86
-
87
- // Find dominant error types
88
- for (const [errorType, totalOccurrences] of byType) {
89
- if (totalOccurrences >= this.config.gapMinOccurrences * 3) {
90
- this.insightRepo.create({
91
- type: 'suggestion',
92
- title: `Frequent error type: ${errorType} in ${project.name}`,
93
- description: `${errorType} has ${totalOccurrences} total occurrences. Consider adding linting rules, type checking, or tooling to prevent this class of errors.`,
94
- evidence: JSON.stringify({ errorType, totalOccurrences, projectId: project.id }),
95
- priority: Math.min(65, 30 + Math.round(totalOccurrences / 5)),
96
- project_id: project.id,
97
- active: 1,
98
- expires_at: expiresAt,
99
- });
100
- count++;
101
- }
102
- }
103
- }
104
-
105
- return count;
106
- }
107
-
108
- private reprioritizeInsights(): void {
109
- const activeInsights = this.insightRepo.findActive();
110
-
111
- for (const insight of activeInsights) {
112
- if (insight.type === 'warning') {
113
- const ageMs = Date.now() - new Date(insight.created_at).getTime();
114
- const ageDays = ageMs / 86400000;
115
- if (ageDays > 3 && insight.priority < 80) {
116
- this.insightRepo.update(insight.id, {
117
- priority: Math.min(85, insight.priority + 10),
118
- });
119
- }
120
- }
121
- }
122
- }
123
- }
@@ -1,116 +0,0 @@
1
- import type { ResearchConfig } from '../types/config.types.js';
2
- import type { ErrorRepository } from '../db/repositories/error.repository.js';
3
- import type { SolutionRepository } from '../db/repositories/solution.repository.js';
4
- import type { ProjectRepository } from '../db/repositories/project.repository.js';
5
- import type { CodeModuleRepository } from '../db/repositories/code-module.repository.js';
6
- import type { SynapseRepository } from '../db/repositories/synapse.repository.js';
7
- import type { InsightRepository } from '../db/repositories/insight.repository.js';
8
- import type { SynapseManager } from '../synapses/synapse-manager.js';
9
- import type { ResearchCycleResult } from '../types/research.types.js';
10
- import { TrendAnalyzer } from './trend-analyzer.js';
11
- import { GapAnalyzer } from './gap-analyzer.js';
12
- import { SynergyDetector } from './synergy-detector.js';
13
- import { TemplateExtractor } from './template-extractor.js';
14
- import { InsightGenerator } from './insight-generator.js';
15
- import { getLogger } from '../utils/logger.js';
16
-
17
- export class ResearchEngine {
18
- private timer: ReturnType<typeof setInterval> | null = null;
19
- private delayTimer: ReturnType<typeof setTimeout> | null = null;
20
- private logger = getLogger();
21
-
22
- private trendAnalyzer: TrendAnalyzer;
23
- private gapAnalyzer: GapAnalyzer;
24
- private synergyDetector: SynergyDetector;
25
- private templateExtractor: TemplateExtractor;
26
- private insightGenerator: InsightGenerator;
27
-
28
- constructor(
29
- private config: ResearchConfig,
30
- private errorRepo: ErrorRepository,
31
- private solutionRepo: SolutionRepository,
32
- private projectRepo: ProjectRepository,
33
- private codeModuleRepo: CodeModuleRepository,
34
- private synapseRepo: SynapseRepository,
35
- private insightRepo: InsightRepository,
36
- private synapseManager: SynapseManager,
37
- ) {
38
- this.trendAnalyzer = new TrendAnalyzer(errorRepo, solutionRepo, projectRepo, insightRepo, config);
39
- this.gapAnalyzer = new GapAnalyzer(errorRepo, solutionRepo, synapseRepo, projectRepo, insightRepo, config);
40
- this.synergyDetector = new SynergyDetector(synapseRepo, codeModuleRepo, solutionRepo, errorRepo, projectRepo, insightRepo, config);
41
- this.templateExtractor = new TemplateExtractor(codeModuleRepo, projectRepo, insightRepo, config);
42
- this.insightGenerator = new InsightGenerator(projectRepo, errorRepo, solutionRepo, codeModuleRepo, insightRepo, config);
43
- }
44
-
45
- start(): void {
46
- this.logger.info(`Research engine starting (interval: ${this.config.intervalMs}ms, initial delay: ${this.config.initialDelayMs}ms)`);
47
- this.delayTimer = setTimeout(() => {
48
- this.runCycle();
49
- this.timer = setInterval(() => this.runCycle(), this.config.intervalMs);
50
- }, this.config.initialDelayMs);
51
- }
52
-
53
- stop(): void {
54
- if (this.delayTimer) {
55
- clearTimeout(this.delayTimer);
56
- this.delayTimer = null;
57
- }
58
- if (this.timer) {
59
- clearInterval(this.timer);
60
- this.timer = null;
61
- }
62
- this.logger.info('Research engine stopped');
63
- }
64
-
65
- runCycle(): ResearchCycleResult {
66
- const start = Date.now();
67
- this.logger.info('Research cycle starting');
68
-
69
- const result: ResearchCycleResult = {
70
- insightsGenerated: 0,
71
- patternsFound: 0,
72
- correlationsFound: 0,
73
- duration: 0,
74
- };
75
-
76
- // Phase 1: Trend analysis
77
- const trends = this.trendAnalyzer.analyze();
78
- result.patternsFound += trends;
79
- result.insightsGenerated += trends;
80
-
81
- // Phase 2: Gap analysis
82
- const gaps = this.gapAnalyzer.analyze();
83
- result.insightsGenerated += gaps;
84
-
85
- // Phase 3: Synergy detection
86
- const synergies = this.synergyDetector.detect();
87
- result.correlationsFound += synergies;
88
- result.insightsGenerated += synergies;
89
-
90
- // Phase 4: Template extraction
91
- const templates = this.templateExtractor.extract();
92
- result.patternsFound += templates;
93
- result.insightsGenerated += templates;
94
-
95
- // Phase 5: Insight generation
96
- const generated = this.insightGenerator.generate();
97
- result.insightsGenerated += generated;
98
-
99
- // Phase 6: Insight prioritization (expire old insights)
100
- const expired = this.insightRepo.expire();
101
- if (expired > 0) {
102
- this.logger.info(`Expired ${expired} outdated insights`);
103
- }
104
-
105
- // Phase 7: Synapse maintenance
106
- const decay = this.synapseManager.runDecay();
107
- this.logger.debug(`Synapse maintenance: ${decay.decayed} decayed, ${decay.pruned} pruned`);
108
-
109
- result.duration = Date.now() - start;
110
- this.logger.info(
111
- `Research cycle complete: ${result.insightsGenerated} insights, ${result.patternsFound} patterns, ${result.correlationsFound} correlations (${result.duration}ms)`,
112
- );
113
-
114
- return result;
115
- }
116
- }