@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,41 +0,0 @@
1
- import type { NotificationRepository, NotificationRecord } from '../db/repositories/notification.repository.js';
2
- import { getLogger } from '../utils/logger.js';
3
-
4
- export interface CreateNotificationInput {
5
- type: string;
6
- title: string;
7
- message: string;
8
- priority?: number;
9
- projectId?: number;
10
- }
11
-
12
- export class NotificationService {
13
- private logger = getLogger();
14
-
15
- constructor(private notificationRepo: NotificationRepository) {}
16
-
17
- create(input: CreateNotificationInput): number {
18
- const id = this.notificationRepo.create({
19
- type: input.type,
20
- title: input.title,
21
- message: input.message,
22
- priority: input.priority ?? 0,
23
- project_id: input.projectId ?? null,
24
- });
25
-
26
- this.logger.info(`Notification created (id=${id}, type=${input.type})`);
27
- return id;
28
- }
29
-
30
- list(projectId?: number): NotificationRecord[] {
31
- return this.notificationRepo.findUnacknowledged(projectId);
32
- }
33
-
34
- acknowledge(id: number): void {
35
- this.notificationRepo.acknowledge(id);
36
- }
37
-
38
- getById(id: number): NotificationRecord | undefined {
39
- return this.notificationRepo.getById(id);
40
- }
41
- }
@@ -1,159 +0,0 @@
1
- import type { RuleRepository } from '../db/repositories/rule.repository.js';
2
- import type { AntipatternRepository } from '../db/repositories/antipattern.repository.js';
3
- import type { SynapseManager } from '../synapses/synapse-manager.js';
4
- import { getLogger } from '../utils/logger.js';
5
-
6
- export interface RuleCheckResult {
7
- matched: boolean;
8
- ruleId: number;
9
- action: string;
10
- description: string | null;
11
- confidence: number;
12
- }
13
-
14
- export interface AntipatternCheckResult {
15
- matched: boolean;
16
- antipatternId: number;
17
- pattern: string;
18
- description: string;
19
- severity: string;
20
- suggestion: string | null;
21
- }
22
-
23
- export class PreventionService {
24
- private logger = getLogger();
25
-
26
- constructor(
27
- private ruleRepo: RuleRepository,
28
- private antipatternRepo: AntipatternRepository,
29
- private synapseManager: SynapseManager,
30
- ) {}
31
-
32
- checkRules(errorType: string, message: string, projectId?: number): RuleCheckResult[] {
33
- const rules = this.ruleRepo.findActive(projectId);
34
- const results: RuleCheckResult[] = [];
35
-
36
- for (const rule of rules) {
37
- try {
38
- const pattern = new RegExp(rule.pattern, 'i');
39
- const input = `${errorType}: ${message}`;
40
-
41
- if (pattern.test(input)) {
42
- results.push({
43
- matched: true,
44
- ruleId: rule.id,
45
- action: rule.action,
46
- description: rule.description,
47
- confidence: rule.confidence,
48
- });
49
-
50
- this.logger.debug(`Rule ${rule.id} matched: ${rule.pattern}`);
51
- }
52
- } catch {
53
- // Invalid regex in rule pattern, skip
54
- this.logger.warn(`Invalid regex in rule ${rule.id}: ${rule.pattern}`);
55
- }
56
- }
57
-
58
- return results.sort((a, b) => b.confidence - a.confidence);
59
- }
60
-
61
- checkAntipatterns(errorType: string, message: string, projectId?: number): AntipatternCheckResult[] {
62
- const antipatterns = projectId
63
- ? [...this.antipatternRepo.findByProject(projectId), ...this.antipatternRepo.findGlobal()]
64
- : this.antipatternRepo.findGlobal();
65
-
66
- const results: AntipatternCheckResult[] = [];
67
- const input = `${errorType}: ${message}`;
68
-
69
- for (const ap of antipatterns) {
70
- try {
71
- const pattern = new RegExp(ap.pattern, 'i');
72
- if (pattern.test(input)) {
73
- results.push({
74
- matched: true,
75
- antipatternId: ap.id,
76
- pattern: ap.pattern,
77
- description: ap.description,
78
- severity: ap.severity,
79
- suggestion: ap.suggestion,
80
- });
81
- }
82
- } catch {
83
- this.logger.warn(`Invalid regex in antipattern ${ap.id}: ${ap.pattern}`);
84
- }
85
- }
86
-
87
- return results;
88
- }
89
-
90
- createRule(data: {
91
- pattern: string;
92
- action: string;
93
- description?: string;
94
- confidence?: number;
95
- projectId?: number;
96
- }): number {
97
- return this.ruleRepo.create({
98
- pattern: data.pattern,
99
- action: data.action,
100
- description: data.description ?? null,
101
- confidence: data.confidence ?? 0.5,
102
- occurrences: 0,
103
- active: 1,
104
- project_id: data.projectId ?? null,
105
- });
106
- }
107
-
108
- checkCodeForPatterns(source: string, filePath?: string): { warnings: Array<{ message: string; severity: string; ruleId?: number }> } {
109
- const warnings: Array<{ message: string; severity: string; ruleId?: number }> = [];
110
-
111
- // Check antipatterns against the code itself
112
- const globalAntipatterns = this.antipatternRepo.findGlobal();
113
- for (const ap of globalAntipatterns) {
114
- try {
115
- const pattern = new RegExp(ap.pattern, 'i');
116
- if (pattern.test(source)) {
117
- warnings.push({
118
- message: `Code matches known error pattern: ${ap.description}${ap.suggestion ? `. Suggestion: ${ap.suggestion}` : ''}`,
119
- severity: ap.severity,
120
- ruleId: undefined,
121
- });
122
- }
123
- } catch {
124
- // Invalid regex, skip
125
- }
126
- }
127
-
128
- // Check active rules
129
- const rules = this.ruleRepo.findActive();
130
- for (const rule of rules) {
131
- try {
132
- const pattern = new RegExp(rule.pattern, 'i');
133
- if (pattern.test(source)) {
134
- warnings.push({
135
- message: `Code matches learned rule: ${rule.description ?? rule.pattern}. Action: ${rule.action}`,
136
- severity: 'warning',
137
- ruleId: rule.id,
138
- });
139
- }
140
- } catch {
141
- // Invalid regex, skip
142
- }
143
- }
144
-
145
- return { warnings: warnings.slice(0, 5) };
146
- }
147
-
148
- reportPrevention(ruleId: number, errorId: number): void {
149
- const rule = this.ruleRepo.getById(ruleId);
150
- if (rule) {
151
- this.ruleRepo.update(ruleId, { occurrences: rule.occurrences + 1 });
152
- this.synapseManager.strengthen(
153
- { type: 'rule', id: ruleId },
154
- { type: 'error', id: errorId },
155
- 'prevents',
156
- );
157
- }
158
- }
159
- }
@@ -1,98 +0,0 @@
1
- import type { InsightRecord } from '../types/research.types.js';
2
- import type { InsightRepository } from '../db/repositories/insight.repository.js';
3
- import type { ErrorRepository } from '../db/repositories/error.repository.js';
4
- import type { SynapseManager } from '../synapses/synapse-manager.js';
5
- import { getLogger } from '../utils/logger.js';
6
-
7
- export interface InsightQuery {
8
- projectId?: number;
9
- type?: string;
10
- activeOnly?: boolean;
11
- limit?: number;
12
- }
13
-
14
- export interface TrendResult {
15
- errorType: string;
16
- count: number;
17
- direction: 'increasing' | 'decreasing' | 'stable';
18
- period: string;
19
- }
20
-
21
- export class ResearchService {
22
- private logger = getLogger();
23
-
24
- constructor(
25
- private insightRepo: InsightRepository,
26
- private errorRepo: ErrorRepository,
27
- private synapseManager: SynapseManager,
28
- ) {}
29
-
30
- getInsights(query: InsightQuery): InsightRecord[] {
31
- if (query.type) {
32
- return this.insightRepo.findByType(query.type);
33
- }
34
- if (query.activeOnly !== false) {
35
- return this.insightRepo.findActive(query.projectId);
36
- }
37
- return this.insightRepo.findActive(query.projectId);
38
- }
39
-
40
- createInsight(data: {
41
- type: string;
42
- title: string;
43
- description: string;
44
- evidence?: string;
45
- priority?: number;
46
- projectId?: number;
47
- expiresInDays?: number;
48
- }): number {
49
- const expiresAt = data.expiresInDays
50
- ? new Date(Date.now() + data.expiresInDays * 86400000).toISOString()
51
- : null;
52
-
53
- const id = this.insightRepo.create({
54
- type: data.type as InsightRecord['type'],
55
- title: data.title,
56
- description: data.description,
57
- evidence: data.evidence ?? '[]',
58
- priority: data.priority ?? 0,
59
- project_id: data.projectId ?? null,
60
- active: 1,
61
- expires_at: expiresAt,
62
- });
63
-
64
- this.logger.info(`Insight created (id=${id}, type=${data.type})`);
65
- return id;
66
- }
67
-
68
- getTrends(projectId?: number, windowDays: number = 7): TrendResult[] {
69
- const now = new Date();
70
- const currentStart = new Date(now.getTime() - windowDays * 86400000).toISOString();
71
- const previousStart = new Date(now.getTime() - windowDays * 2 * 86400000).toISOString();
72
-
73
- const currentCount = this.errorRepo.countSince(currentStart, projectId);
74
- const previousCount = this.errorRepo.countSince(previousStart, projectId) - currentCount;
75
-
76
- const direction = currentCount > previousCount * 1.2
77
- ? 'increasing' as const
78
- : currentCount < previousCount * 0.8
79
- ? 'decreasing' as const
80
- : 'stable' as const;
81
-
82
- return [{
83
- errorType: 'all',
84
- count: currentCount,
85
- direction,
86
- period: `${windowDays}d`,
87
- }];
88
- }
89
-
90
- expireOldInsights(): number {
91
- return this.insightRepo.expire();
92
- }
93
-
94
- rateInsight(id: number, rating: number, comment?: string): boolean {
95
- const clamped = Math.max(-1, Math.min(1, rating)); // -1 (bad), 0 (neutral), 1 (useful)
96
- return this.insightRepo.rate(id, clamped, comment);
97
- }
98
- }
@@ -1,174 +0,0 @@
1
- import type { SolutionRecord } from '../types/solution.types.js';
2
- import type { SolutionRepository } from '../db/repositories/solution.repository.js';
3
- import type { SynapseManager } from '../synapses/synapse-manager.js';
4
- import { getEventBus } from '../utils/events.js';
5
- import { getLogger } from '../utils/logger.js';
6
-
7
- export interface ReportSolutionInput {
8
- errorId: number;
9
- description: string;
10
- commands?: string;
11
- codeChange?: string;
12
- source?: string;
13
- }
14
-
15
- export interface RateOutcomeInput {
16
- errorId: number;
17
- solutionId: number;
18
- success: boolean;
19
- terminalId?: number;
20
- output?: string;
21
- durationMs?: number;
22
- }
23
-
24
- export class SolutionService {
25
- private logger = getLogger();
26
- private eventBus = getEventBus();
27
-
28
- constructor(
29
- private solutionRepo: SolutionRepository,
30
- private synapseManager: SynapseManager,
31
- ) {}
32
-
33
- report(input: ReportSolutionInput): number {
34
- const solutionId = this.solutionRepo.create({
35
- description: input.description,
36
- commands: input.commands ?? null,
37
- code_change: input.codeChange ?? null,
38
- source: input.source ?? 'manual',
39
- confidence: 0.5,
40
- });
41
-
42
- this.solutionRepo.linkToError(input.errorId, solutionId);
43
-
44
- // Create synapse: solution solves error
45
- this.synapseManager.strengthen(
46
- { type: 'solution', id: solutionId },
47
- { type: 'error', id: input.errorId },
48
- 'solves',
49
- );
50
-
51
- this.eventBus.emit('solution:created', { solutionId });
52
- this.logger.info(`Solution reported (id=${solutionId}) for error ${input.errorId}`);
53
-
54
- return solutionId;
55
- }
56
-
57
- rateOutcome(input: RateOutcomeInput): void {
58
- // Record the attempt
59
- const errorSolutions = this.solutionRepo.findForError(input.errorId);
60
- const link = errorSolutions.find(s => s.id === input.solutionId);
61
- if (!link) {
62
- this.solutionRepo.linkToError(input.errorId, input.solutionId);
63
- }
64
-
65
- // Find the error_solution link id via DB
66
- this.solutionRepo.recordAttempt({
67
- errorSolutionId: input.errorId, // will be resolved via link
68
- terminalId: input.terminalId,
69
- success: input.success ? 1 : 0,
70
- output: input.output,
71
- durationMs: input.durationMs,
72
- });
73
-
74
- // Update synapse
75
- if (input.success) {
76
- this.synapseManager.strengthen(
77
- { type: 'solution', id: input.solutionId },
78
- { type: 'error', id: input.errorId },
79
- 'solves',
80
- { outcome: 'success' },
81
- );
82
- // Update solution confidence based on success rate
83
- const rate = this.solutionRepo.successRate(input.solutionId);
84
- this.solutionRepo.update(input.solutionId, { confidence: rate });
85
- } else {
86
- const synapse = this.synapseManager.find(
87
- { type: 'solution', id: input.solutionId },
88
- { type: 'error', id: input.errorId },
89
- 'solves',
90
- );
91
- if (synapse) {
92
- this.synapseManager.weaken(synapse.id, 0.7);
93
- }
94
- const rate = this.solutionRepo.successRate(input.solutionId);
95
- this.solutionRepo.update(input.solutionId, { confidence: rate });
96
- }
97
-
98
- this.eventBus.emit('solution:applied', {
99
- errorId: input.errorId,
100
- solutionId: input.solutionId,
101
- success: input.success,
102
- });
103
- }
104
-
105
- findForError(errorId: number): SolutionRecord[] {
106
- return this.solutionRepo.findForError(errorId);
107
- }
108
-
109
- getById(id: number): SolutionRecord | undefined {
110
- return this.solutionRepo.getById(id);
111
- }
112
-
113
- successRate(solutionId: number): number {
114
- return this.solutionRepo.successRate(solutionId);
115
- }
116
-
117
- analyzeEfficiency(): {
118
- avgDurationMs: number;
119
- slowSolutions: Array<{ solutionId: number; avgDuration: number; description: string }>;
120
- successRateOverall: number;
121
- totalAttempts: number;
122
- } {
123
- const allSolutions = this.solutionRepo.getAll();
124
- let totalDuration = 0;
125
- let totalAttempts = 0;
126
- let totalSuccessRate = 0;
127
- let solutionCount = 0;
128
- const solutionDurations: Array<{ solutionId: number; avgDuration: number; description: string }> = [];
129
-
130
- for (const solution of allSolutions) {
131
- const rate = this.solutionRepo.successRate(solution.id);
132
- if (solution.success_count + solution.fail_count > 0) {
133
- totalSuccessRate += rate;
134
- solutionCount++;
135
- }
136
-
137
- // Check attempts for duration data
138
- const attempts = this.solutionRepo.getAttempts(solution.id);
139
- if (attempts.length > 0) {
140
- let solDuration = 0;
141
- let solAttemptCount = 0;
142
- for (const attempt of attempts) {
143
- if (attempt.duration_ms && attempt.duration_ms > 0) {
144
- solDuration += attempt.duration_ms;
145
- solAttemptCount++;
146
- totalDuration += attempt.duration_ms;
147
- totalAttempts++;
148
- }
149
- }
150
- if (solAttemptCount > 0) {
151
- solutionDurations.push({
152
- solutionId: solution.id,
153
- avgDuration: solDuration / solAttemptCount,
154
- description: solution.description,
155
- });
156
- }
157
- }
158
- }
159
-
160
- // Find slow solutions (above 2x average)
161
- const avgDurationMs = totalAttempts > 0 ? totalDuration / totalAttempts : 0;
162
- const slowSolutions = solutionDurations
163
- .filter(s => s.avgDuration > avgDurationMs * 2)
164
- .sort((a, b) => b.avgDuration - a.avgDuration)
165
- .slice(0, 10);
166
-
167
- return {
168
- avgDurationMs,
169
- slowSolutions,
170
- successRateOverall: solutionCount > 0 ? totalSuccessRate / solutionCount : 0,
171
- totalAttempts,
172
- };
173
- }
174
- }
@@ -1,59 +0,0 @@
1
- import type { NodeType, SynapseRecord, NetworkStats } from '../types/synapse.types.js';
2
- import type { SynapseManager } from '../synapses/synapse-manager.js';
3
- import type { ActivationResult } from '../synapses/activation.js';
4
- import type { SynapsePath } from '../synapses/pathfinder.js';
5
-
6
- export interface ErrorContext {
7
- solutions: ActivationResult[];
8
- relatedErrors: ActivationResult[];
9
- relevantModules: ActivationResult[];
10
- preventionRules: ActivationResult[];
11
- insights: ActivationResult[];
12
- }
13
-
14
- export interface RelatedQuery {
15
- nodeType: NodeType;
16
- nodeId: number;
17
- maxDepth?: number;
18
- minWeight?: number;
19
- }
20
-
21
- export class SynapseService {
22
- constructor(private manager: SynapseManager) {}
23
-
24
- getErrorContext(errorId: number): ErrorContext {
25
- return this.manager.getErrorContext(errorId);
26
- }
27
-
28
- findPath(
29
- fromType: NodeType,
30
- fromId: number,
31
- toType: NodeType,
32
- toId: number,
33
- ): SynapsePath | null {
34
- return this.manager.findPath(
35
- { type: fromType, id: fromId },
36
- { type: toType, id: toId },
37
- );
38
- }
39
-
40
- getRelated(query: RelatedQuery): ActivationResult[] {
41
- return this.manager.activate(
42
- { type: query.nodeType, id: query.nodeId },
43
- query.maxDepth,
44
- query.minWeight,
45
- );
46
- }
47
-
48
- getNetworkStats(): NetworkStats {
49
- return this.manager.getNetworkStats();
50
- }
51
-
52
- getStrongestSynapses(limit?: number): SynapseRecord[] {
53
- return this.manager.getStrongestSynapses(limit);
54
- }
55
-
56
- runDecay(): { decayed: number; pruned: number } {
57
- return this.manager.runDecay();
58
- }
59
- }
@@ -1,81 +0,0 @@
1
- import type { TerminalRepository } from '../db/repositories/terminal.repository.js';
2
- import { getEventBus } from '../utils/events.js';
3
- import { getLogger } from '../utils/logger.js';
4
-
5
- export interface RegisterTerminalInput {
6
- uuid: string;
7
- projectId?: number;
8
- pid?: number;
9
- shell?: string;
10
- cwd?: string;
11
- }
12
-
13
- export class TerminalService {
14
- private logger = getLogger();
15
- private eventBus = getEventBus();
16
-
17
- constructor(
18
- private terminalRepo: TerminalRepository,
19
- private staleTimeout: number,
20
- ) {}
21
-
22
- register(input: RegisterTerminalInput): number {
23
- const existing = this.terminalRepo.findByUuid(input.uuid);
24
- if (existing) {
25
- this.terminalRepo.update(existing.id, {
26
- last_seen: new Date().toISOString(),
27
- disconnected_at: null,
28
- project_id: input.projectId ?? existing.project_id,
29
- cwd: input.cwd ?? existing.cwd,
30
- });
31
- this.logger.info(`Terminal reconnected (id=${existing.id}, uuid=${input.uuid})`);
32
- this.eventBus.emit('terminal:connected', { terminalId: existing.id, uuid: input.uuid });
33
- return existing.id;
34
- }
35
-
36
- const id = this.terminalRepo.create({
37
- uuid: input.uuid,
38
- project_id: input.projectId ?? null,
39
- pid: input.pid ?? null,
40
- shell: input.shell ?? null,
41
- cwd: input.cwd ?? null,
42
- });
43
-
44
- this.logger.info(`Terminal registered (id=${id}, uuid=${input.uuid})`);
45
- this.eventBus.emit('terminal:connected', { terminalId: id, uuid: input.uuid });
46
- return id;
47
- }
48
-
49
- heartbeat(uuid: string): void {
50
- const terminal = this.terminalRepo.findByUuid(uuid);
51
- if (terminal) {
52
- this.terminalRepo.update(terminal.id, {
53
- last_seen: new Date().toISOString(),
54
- });
55
- }
56
- }
57
-
58
- disconnect(uuid: string): void {
59
- const terminal = this.terminalRepo.findByUuid(uuid);
60
- if (terminal) {
61
- this.terminalRepo.update(terminal.id, {
62
- disconnected_at: new Date().toISOString(),
63
- });
64
- this.eventBus.emit('terminal:disconnected', { terminalId: terminal.id });
65
- this.logger.info(`Terminal disconnected (id=${terminal.id}, uuid=${uuid})`);
66
- }
67
- }
68
-
69
- cleanup(): number {
70
- const cutoff = new Date(Date.now() - this.staleTimeout).toISOString();
71
- const count = this.terminalRepo.cleanupStale(cutoff);
72
- if (count > 0) {
73
- this.logger.info(`Cleaned up ${count} stale terminal(s)`);
74
- }
75
- return count;
76
- }
77
-
78
- getConnected() {
79
- return this.terminalRepo.findConnected();
80
- }
81
- }
@@ -1,80 +0,0 @@
1
- import type { NodeType } from '../types/synapse.types.js';
2
- import type { SynapseRepository } from '../db/repositories/synapse.repository.js';
3
-
4
- export interface ActivationNode {
5
- type: NodeType;
6
- id: number;
7
- }
8
-
9
- export interface ActivationResult {
10
- node: ActivationNode;
11
- activation: number;
12
- depth: number;
13
- path: string[];
14
- }
15
-
16
- export function spreadingActivation(
17
- repo: SynapseRepository,
18
- startNode: ActivationNode,
19
- maxDepth: number = 3,
20
- minWeight: number = 0.2,
21
- ): ActivationResult[] {
22
- const visited = new Set<string>();
23
- const results: ActivationResult[] = [];
24
-
25
- const queue: Array<{
26
- node: ActivationNode;
27
- depth: number;
28
- pathWeight: number;
29
- path: string[];
30
- }> = [{ node: startNode, depth: 0, pathWeight: 1.0, path: [] }];
31
-
32
- while (queue.length > 0) {
33
- const current = queue.shift()!;
34
- const key = `${current.node.type}:${current.node.id}`;
35
-
36
- if (visited.has(key)) continue;
37
- if (current.depth > maxDepth) continue;
38
- if (current.pathWeight < minWeight) continue;
39
-
40
- visited.add(key);
41
-
42
- if (current.depth > 0) {
43
- results.push({
44
- node: current.node,
45
- activation: current.pathWeight,
46
- depth: current.depth,
47
- path: current.path,
48
- });
49
- }
50
-
51
- const outgoing = repo.getOutgoing(current.node.type, current.node.id);
52
- const incoming = repo.getIncoming(current.node.type, current.node.id);
53
-
54
- for (const synapse of outgoing) {
55
- const nextWeight = current.pathWeight * synapse.weight;
56
- if (nextWeight >= minWeight) {
57
- queue.push({
58
- node: { type: synapse.target_type, id: synapse.target_id },
59
- depth: current.depth + 1,
60
- pathWeight: nextWeight,
61
- path: [...current.path, `--${synapse.synapse_type}-->`],
62
- });
63
- }
64
- }
65
-
66
- for (const synapse of incoming) {
67
- const nextWeight = current.pathWeight * synapse.weight;
68
- if (nextWeight >= minWeight) {
69
- queue.push({
70
- node: { type: synapse.source_type, id: synapse.source_id },
71
- depth: current.depth + 1,
72
- pathWeight: nextWeight,
73
- path: [...current.path, `<--${synapse.synapse_type}--`],
74
- });
75
- }
76
- }
77
- }
78
-
79
- return results.sort((a, b) => b.activation - a.activation);
80
- }