@timmeck/brain 1.9.0 → 2.0.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 (214) hide show
  1. package/README.md +19 -0
  2. package/brain.log +1164 -0
  3. package/{src/cli/commands/dashboard.ts → dashboard.html} +688 -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 +1 -0
  8. package/dist/brain.js +6 -1
  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/peers.d.ts +2 -0
  14. package/dist/cli/commands/peers.js +38 -0
  15. package/dist/cli/commands/peers.js.map +1 -0
  16. package/dist/db/connection.d.ts +1 -2
  17. package/dist/db/connection.js +1 -18
  18. package/dist/db/connection.js.map +1 -1
  19. package/dist/index.js +3 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/ipc/__tests__/protocol.test.d.ts +1 -0
  22. package/dist/ipc/__tests__/protocol.test.js +117 -0
  23. package/dist/ipc/__tests__/protocol.test.js.map +1 -0
  24. package/dist/ipc/client.d.ts +1 -16
  25. package/dist/ipc/client.js +1 -100
  26. package/dist/ipc/client.js.map +1 -1
  27. package/dist/ipc/protocol.d.ts +1 -8
  28. package/dist/ipc/protocol.js +1 -28
  29. package/dist/ipc/protocol.js.map +1 -1
  30. package/dist/ipc/router.js +8 -0
  31. package/dist/ipc/router.js.map +1 -1
  32. package/dist/ipc/server.d.ts +1 -22
  33. package/dist/ipc/server.js +1 -163
  34. package/dist/ipc/server.js.map +1 -1
  35. package/dist/mcp/http-server.d.ts +1 -7
  36. package/dist/mcp/http-server.js +6 -117
  37. package/dist/mcp/http-server.js.map +1 -1
  38. package/dist/mcp/server.js +5 -61
  39. package/dist/mcp/server.js.map +1 -1
  40. package/dist/signals/__tests__/fingerprint.test.d.ts +1 -0
  41. package/dist/signals/__tests__/fingerprint.test.js +118 -0
  42. package/dist/signals/__tests__/fingerprint.test.js.map +1 -0
  43. package/dist/types/ipc.types.d.ts +1 -11
  44. package/dist/utils/__tests__/hash.test.d.ts +1 -0
  45. package/dist/utils/__tests__/hash.test.js +32 -0
  46. package/dist/utils/__tests__/hash.test.js.map +1 -0
  47. package/dist/utils/__tests__/paths.test.d.ts +1 -0
  48. package/dist/utils/__tests__/paths.test.js +75 -0
  49. package/dist/utils/__tests__/paths.test.js.map +1 -0
  50. package/dist/utils/events.d.ts +4 -8
  51. package/dist/utils/events.js +2 -14
  52. package/dist/utils/events.js.map +1 -1
  53. package/dist/utils/hash.d.ts +1 -1
  54. package/dist/utils/hash.js +1 -4
  55. package/dist/utils/hash.js.map +1 -1
  56. package/dist/utils/logger.d.ts +3 -2
  57. package/dist/utils/logger.js +8 -35
  58. package/dist/utils/logger.js.map +1 -1
  59. package/dist/utils/paths.d.ts +2 -1
  60. package/dist/utils/paths.js +4 -13
  61. package/dist/utils/paths.js.map +1 -1
  62. package/package.json +2 -1
  63. package/BRAIN_PLAN.md +0 -3324
  64. package/reddit_post.md +0 -45
  65. package/src/api/server.ts +0 -395
  66. package/src/brain.ts +0 -313
  67. package/src/cli/colors.ts +0 -116
  68. package/src/cli/commands/config.ts +0 -169
  69. package/src/cli/commands/doctor.ts +0 -124
  70. package/src/cli/commands/explain.ts +0 -83
  71. package/src/cli/commands/export.ts +0 -31
  72. package/src/cli/commands/import.ts +0 -199
  73. package/src/cli/commands/insights.ts +0 -65
  74. package/src/cli/commands/learn.ts +0 -24
  75. package/src/cli/commands/modules.ts +0 -53
  76. package/src/cli/commands/network.ts +0 -67
  77. package/src/cli/commands/projects.ts +0 -42
  78. package/src/cli/commands/query.ts +0 -120
  79. package/src/cli/commands/start.ts +0 -105
  80. package/src/cli/commands/status.ts +0 -75
  81. package/src/cli/commands/stop.ts +0 -34
  82. package/src/cli/ipc-helper.ts +0 -22
  83. package/src/cli/update-check.ts +0 -63
  84. package/src/code/analyzer.ts +0 -117
  85. package/src/code/fingerprint.ts +0 -87
  86. package/src/code/matcher.ts +0 -129
  87. package/src/code/parsers/generic.ts +0 -29
  88. package/src/code/parsers/python.ts +0 -54
  89. package/src/code/parsers/typescript.ts +0 -65
  90. package/src/code/registry.ts +0 -60
  91. package/src/code/scorer.ts +0 -120
  92. package/src/config.ts +0 -135
  93. package/src/dashboard/server.ts +0 -142
  94. package/src/db/connection.ts +0 -22
  95. package/src/db/migrations/001_core_schema.ts +0 -120
  96. package/src/db/migrations/002_learning_schema.ts +0 -38
  97. package/src/db/migrations/003_code_schema.ts +0 -53
  98. package/src/db/migrations/004_synapses_schema.ts +0 -57
  99. package/src/db/migrations/005_fts_indexes.ts +0 -78
  100. package/src/db/migrations/006_synapses_phase3.ts +0 -17
  101. package/src/db/migrations/007_feedback.ts +0 -13
  102. package/src/db/migrations/008_git_integration.ts +0 -38
  103. package/src/db/migrations/009_embeddings.ts +0 -8
  104. package/src/db/migrations/index.ts +0 -70
  105. package/src/db/repositories/antipattern.repository.ts +0 -66
  106. package/src/db/repositories/code-module.repository.ts +0 -142
  107. package/src/db/repositories/error.repository.ts +0 -189
  108. package/src/db/repositories/insight.repository.ts +0 -99
  109. package/src/db/repositories/notification.repository.ts +0 -66
  110. package/src/db/repositories/project.repository.ts +0 -93
  111. package/src/db/repositories/rule.repository.ts +0 -108
  112. package/src/db/repositories/solution.repository.ts +0 -154
  113. package/src/db/repositories/synapse.repository.ts +0 -163
  114. package/src/db/repositories/terminal.repository.ts +0 -101
  115. package/src/embeddings/engine.ts +0 -238
  116. package/src/hooks/post-tool-use.ts +0 -92
  117. package/src/hooks/post-write.ts +0 -129
  118. package/src/index.ts +0 -63
  119. package/src/ipc/client.ts +0 -118
  120. package/src/ipc/protocol.ts +0 -35
  121. package/src/ipc/router.ts +0 -133
  122. package/src/ipc/server.ts +0 -176
  123. package/src/learning/confidence-scorer.ts +0 -80
  124. package/src/learning/decay.ts +0 -46
  125. package/src/learning/learning-engine.ts +0 -170
  126. package/src/learning/pattern-extractor.ts +0 -90
  127. package/src/learning/rule-generator.ts +0 -74
  128. package/src/main.rs:10:5 +0 -0
  129. package/src/matching/error-matcher.ts +0 -166
  130. package/src/matching/fingerprint.ts +0 -34
  131. package/src/matching/similarity.ts +0 -61
  132. package/src/matching/tfidf.ts +0 -74
  133. package/src/matching/tokenizer.ts +0 -41
  134. package/src/mcp/auto-detect.ts +0 -93
  135. package/src/mcp/http-server.ts +0 -140
  136. package/src/mcp/server.ts +0 -73
  137. package/src/mcp/tools.ts +0 -328
  138. package/src/parsing/error-parser.ts +0 -28
  139. package/src/parsing/parsers/compiler.ts +0 -93
  140. package/src/parsing/parsers/generic.ts +0 -28
  141. package/src/parsing/parsers/go.ts +0 -97
  142. package/src/parsing/parsers/node.ts +0 -69
  143. package/src/parsing/parsers/python.ts +0 -62
  144. package/src/parsing/parsers/rust.ts +0 -50
  145. package/src/parsing/parsers/shell.ts +0 -42
  146. package/src/parsing/types.ts +0 -47
  147. package/src/research/gap-analyzer.ts +0 -135
  148. package/src/research/insight-generator.ts +0 -123
  149. package/src/research/research-engine.ts +0 -116
  150. package/src/research/synergy-detector.ts +0 -126
  151. package/src/research/template-extractor.ts +0 -130
  152. package/src/research/trend-analyzer.ts +0 -127
  153. package/src/services/analytics.service.ts +0 -226
  154. package/src/services/code.service.ts +0 -271
  155. package/src/services/error.service.ts +0 -266
  156. package/src/services/git.service.ts +0 -132
  157. package/src/services/notification.service.ts +0 -41
  158. package/src/services/prevention.service.ts +0 -159
  159. package/src/services/research.service.ts +0 -98
  160. package/src/services/solution.service.ts +0 -174
  161. package/src/services/synapse.service.ts +0 -59
  162. package/src/services/terminal.service.ts +0 -81
  163. package/src/synapses/activation.ts +0 -80
  164. package/src/synapses/decay.ts +0 -38
  165. package/src/synapses/hebbian.ts +0 -69
  166. package/src/synapses/pathfinder.ts +0 -81
  167. package/src/synapses/synapse-manager.ts +0 -113
  168. package/src/types/code.types.ts +0 -52
  169. package/src/types/config.types.ts +0 -103
  170. package/src/types/error.types.ts +0 -67
  171. package/src/types/ipc.types.ts +0 -8
  172. package/src/types/mcp.types.ts +0 -53
  173. package/src/types/research.types.ts +0 -28
  174. package/src/types/solution.types.ts +0 -30
  175. package/src/types/synapse.types.ts +0 -50
  176. package/src/utils/events.ts +0 -45
  177. package/src/utils/hash.ts +0 -5
  178. package/src/utils/logger.ts +0 -48
  179. package/src/utils/paths.ts +0 -19
  180. package/tests/e2e/test_code_intelligence.py +0 -1015
  181. package/tests/e2e/test_error_memory.py +0 -451
  182. package/tests/e2e/test_full_integration.py +0 -534
  183. package/tests/fixtures/code-modules/modules.ts +0 -83
  184. package/tests/fixtures/errors/go.ts +0 -9
  185. package/tests/fixtures/errors/node.ts +0 -24
  186. package/tests/fixtures/errors/python.ts +0 -21
  187. package/tests/fixtures/errors/rust.ts +0 -25
  188. package/tests/fixtures/errors/shell.ts +0 -15
  189. package/tests/fixtures/solutions/solutions.ts +0 -27
  190. package/tests/helpers/setup-db.ts +0 -52
  191. package/tests/integration/code-flow.test.ts +0 -86
  192. package/tests/integration/error-flow.test.ts +0 -83
  193. package/tests/integration/ipc-flow.test.ts +0 -166
  194. package/tests/integration/learning-cycle.test.ts +0 -82
  195. package/tests/integration/synapse-flow.test.ts +0 -117
  196. package/tests/unit/code/analyzer.test.ts +0 -58
  197. package/tests/unit/code/fingerprint.test.ts +0 -51
  198. package/tests/unit/code/scorer.test.ts +0 -55
  199. package/tests/unit/learning/confidence-scorer.test.ts +0 -60
  200. package/tests/unit/learning/decay.test.ts +0 -45
  201. package/tests/unit/learning/pattern-extractor.test.ts +0 -50
  202. package/tests/unit/matching/error-matcher.test.ts +0 -69
  203. package/tests/unit/matching/fingerprint.test.ts +0 -47
  204. package/tests/unit/matching/similarity.test.ts +0 -65
  205. package/tests/unit/matching/tfidf.test.ts +0 -71
  206. package/tests/unit/matching/tokenizer.test.ts +0 -83
  207. package/tests/unit/parsing/parsers.test.ts +0 -113
  208. package/tests/unit/research/gap-analyzer.test.ts +0 -45
  209. package/tests/unit/research/trend-analyzer.test.ts +0 -45
  210. package/tests/unit/synapses/activation.test.ts +0 -80
  211. package/tests/unit/synapses/decay.test.ts +0 -27
  212. package/tests/unit/synapses/hebbian.test.ts +0 -96
  213. package/tests/unit/synapses/pathfinder.test.ts +0 -72
  214. 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
- }