@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
package/src/brain.ts DELETED
@@ -1,313 +0,0 @@
1
- import path from 'node:path';
2
- import fs from 'node:fs';
3
- import type Database from 'better-sqlite3';
4
- import { loadConfig } from './config.js';
5
- import type { BrainConfig } from './types/config.types.js';
6
- import { createLogger, getLogger } from './utils/logger.js';
7
- import { getEventBus } from './utils/events.js';
8
- import { createConnection } from './db/connection.js';
9
- import { runMigrations } from './db/migrations/index.js';
10
-
11
- // Repositories
12
- import { ProjectRepository } from './db/repositories/project.repository.js';
13
- import { ErrorRepository } from './db/repositories/error.repository.js';
14
- import { SolutionRepository } from './db/repositories/solution.repository.js';
15
- import { RuleRepository } from './db/repositories/rule.repository.js';
16
- import { AntipatternRepository } from './db/repositories/antipattern.repository.js';
17
- import { TerminalRepository } from './db/repositories/terminal.repository.js';
18
- import { CodeModuleRepository } from './db/repositories/code-module.repository.js';
19
- import { SynapseRepository } from './db/repositories/synapse.repository.js';
20
- import { NotificationRepository } from './db/repositories/notification.repository.js';
21
- import { InsightRepository } from './db/repositories/insight.repository.js';
22
-
23
- // Services
24
- import { ErrorService } from './services/error.service.js';
25
- import { SolutionService } from './services/solution.service.js';
26
- import { TerminalService } from './services/terminal.service.js';
27
- import { PreventionService } from './services/prevention.service.js';
28
- import { CodeService } from './services/code.service.js';
29
- import { SynapseService } from './services/synapse.service.js';
30
- import { ResearchService } from './services/research.service.js';
31
- import { NotificationService } from './services/notification.service.js';
32
- import { AnalyticsService } from './services/analytics.service.js';
33
- import { GitService } from './services/git.service.js';
34
-
35
- // Synapses
36
- import { SynapseManager } from './synapses/synapse-manager.js';
37
-
38
- // Engines
39
- import { LearningEngine } from './learning/learning-engine.js';
40
- import { ResearchEngine } from './research/research-engine.js';
41
-
42
- // IPC
43
- import { IpcRouter, type Services } from './ipc/router.js';
44
- import { IpcServer } from './ipc/server.js';
45
-
46
- // API & MCP HTTP
47
- import { ApiServer } from './api/server.js';
48
- import { McpHttpServer } from './mcp/http-server.js';
49
-
50
- // Embeddings
51
- import { EmbeddingEngine } from './embeddings/engine.js';
52
-
53
- export class BrainCore {
54
- private db: Database.Database | null = null;
55
- private ipcServer: IpcServer | null = null;
56
- private apiServer: ApiServer | null = null;
57
- private mcpHttpServer: McpHttpServer | null = null;
58
- private embeddingEngine: EmbeddingEngine | null = null;
59
- private learningEngine: LearningEngine | null = null;
60
- private researchEngine: ResearchEngine | null = null;
61
- private cleanupTimer: ReturnType<typeof setInterval> | null = null;
62
- private config: BrainConfig | null = null;
63
- private configPath?: string;
64
- private restarting = false;
65
-
66
- start(configPath?: string): void {
67
- this.configPath = configPath;
68
- // 1. Config
69
- this.config = loadConfig(configPath);
70
- const config = this.config;
71
-
72
- // 2. Ensure data dir
73
- fs.mkdirSync(path.dirname(config.dbPath), { recursive: true });
74
-
75
- // 3. Logger
76
- createLogger({
77
- level: config.log.level,
78
- file: config.log.file,
79
- maxSize: config.log.maxSize,
80
- maxFiles: config.log.maxFiles,
81
- });
82
- const logger = getLogger();
83
-
84
- // 4. Database
85
- this.db = createConnection(config.dbPath);
86
- runMigrations(this.db);
87
- logger.info(`Database initialized: ${config.dbPath}`);
88
-
89
- // 5. Repositories
90
- const projectRepo = new ProjectRepository(this.db);
91
- const errorRepo = new ErrorRepository(this.db);
92
- const solutionRepo = new SolutionRepository(this.db);
93
- const ruleRepo = new RuleRepository(this.db);
94
- const antipatternRepo = new AntipatternRepository(this.db);
95
- const terminalRepo = new TerminalRepository(this.db);
96
- const codeModuleRepo = new CodeModuleRepository(this.db);
97
- const synapseRepo = new SynapseRepository(this.db);
98
- const notificationRepo = new NotificationRepository(this.db);
99
- const insightRepo = new InsightRepository(this.db);
100
-
101
- // 6. Synapse Manager
102
- const synapseManager = new SynapseManager(synapseRepo, config.synapses);
103
-
104
- // 7. Services
105
- const services: Services = {
106
- error: new ErrorService(errorRepo, projectRepo, synapseManager, config.matching),
107
- solution: new SolutionService(solutionRepo, synapseManager),
108
- terminal: new TerminalService(terminalRepo, config.terminal.staleTimeout),
109
- prevention: new PreventionService(ruleRepo, antipatternRepo, synapseManager),
110
- code: new CodeService(codeModuleRepo, projectRepo, synapseManager),
111
- synapse: new SynapseService(synapseManager),
112
- research: new ResearchService(insightRepo, errorRepo, synapseManager),
113
- notification: new NotificationService(notificationRepo),
114
- analytics: new AnalyticsService(
115
- errorRepo, solutionRepo, codeModuleRepo,
116
- ruleRepo, antipatternRepo, insightRepo,
117
- synapseManager,
118
- ),
119
- git: new GitService(this.db!, synapseManager),
120
- };
121
-
122
- // 8. Embedding Engine (local vector search)
123
- if (config.embeddings.enabled) {
124
- this.embeddingEngine = new EmbeddingEngine(config.embeddings, this.db!);
125
- this.embeddingEngine.start();
126
- // Wire embedding engine into services for hybrid search
127
- services.error.setEmbeddingEngine(this.embeddingEngine);
128
- services.code.setEmbeddingEngine(this.embeddingEngine);
129
- logger.info('Embedding engine started (model will load in background)');
130
- }
131
-
132
- // 9. Learning Engine
133
- this.learningEngine = new LearningEngine(
134
- config.learning, errorRepo, solutionRepo,
135
- ruleRepo, antipatternRepo, synapseManager,
136
- );
137
- this.learningEngine.start();
138
- logger.info(`Learning engine started (interval: ${config.learning.intervalMs}ms)`);
139
-
140
- // 10. Research Engine
141
- this.researchEngine = new ResearchEngine(
142
- config.research, errorRepo, solutionRepo, projectRepo,
143
- codeModuleRepo, synapseRepo, insightRepo, synapseManager,
144
- );
145
- this.researchEngine.start();
146
- logger.info(`Research engine started (interval: ${config.research.intervalMs}ms)`);
147
-
148
- // Expose learning engine to IPC
149
- services.learning = this.learningEngine;
150
-
151
- // 11. IPC Server
152
- const router = new IpcRouter(services);
153
- this.ipcServer = new IpcServer(router, config.ipc.pipeName);
154
- this.ipcServer.start();
155
-
156
- // 11a. REST API Server
157
- if (config.api.enabled) {
158
- this.apiServer = new ApiServer({
159
- port: config.api.port,
160
- router,
161
- apiKey: config.api.apiKey,
162
- });
163
- this.apiServer.start();
164
- logger.info(`REST API enabled on port ${config.api.port}`);
165
- }
166
-
167
- // 11b. MCP HTTP Server (SSE transport for Cursor, Windsurf, Cline, Continue)
168
- if (config.mcpHttp.enabled) {
169
- this.mcpHttpServer = new McpHttpServer(config.mcpHttp.port, router);
170
- this.mcpHttpServer.start();
171
- logger.info(`MCP HTTP (SSE) enabled on port ${config.mcpHttp.port}`);
172
- }
173
-
174
- // 12. Terminal cleanup timer
175
- this.cleanupTimer = setInterval(() => {
176
- services.terminal.cleanup();
177
- }, 60_000);
178
-
179
- // 13. Event listeners (synapse wiring)
180
- this.setupEventListeners(services, synapseManager);
181
-
182
- // 14. PID file
183
- const pidPath = path.join(path.dirname(config.dbPath), 'brain.pid');
184
- fs.writeFileSync(pidPath, String(process.pid));
185
-
186
- // 15. Graceful shutdown
187
- process.on('SIGINT', () => this.stop());
188
- process.on('SIGTERM', () => this.stop());
189
-
190
- // 16. Crash recovery — auto-restart on uncaught errors
191
- process.on('uncaughtException', (err) => {
192
- logger.error('Uncaught exception — restarting', { error: err.message, stack: err.stack });
193
- this.logCrash('uncaughtException', err);
194
- this.restart();
195
- });
196
- process.on('unhandledRejection', (reason) => {
197
- logger.error('Unhandled rejection — restarting', { reason: String(reason) });
198
- this.logCrash('unhandledRejection', reason instanceof Error ? reason : new Error(String(reason)));
199
- this.restart();
200
- });
201
-
202
- logger.info(`Brain daemon started (PID: ${process.pid})`);
203
- }
204
-
205
- private logCrash(type: string, err: Error): void {
206
- if (!this.config) return;
207
- const crashLog = path.join(path.dirname(this.config.dbPath), 'crashes.log');
208
- const entry = `[${new Date().toISOString()}] ${type}: ${err.message}\n${err.stack ?? ''}\n\n`;
209
- try { fs.appendFileSync(crashLog, entry); } catch { /* best effort */ }
210
- }
211
-
212
- private cleanup(): void {
213
- if (this.cleanupTimer) {
214
- clearInterval(this.cleanupTimer);
215
- this.cleanupTimer = null;
216
- }
217
-
218
- this.researchEngine?.stop();
219
- this.embeddingEngine?.stop();
220
- this.learningEngine?.stop();
221
- this.mcpHttpServer?.stop();
222
- this.apiServer?.stop();
223
- this.ipcServer?.stop();
224
- this.db?.close();
225
-
226
- this.db = null;
227
- this.ipcServer = null;
228
- this.apiServer = null;
229
- this.mcpHttpServer = null;
230
- this.embeddingEngine = null;
231
- this.learningEngine = null;
232
- this.researchEngine = null;
233
- }
234
-
235
- restart(): void {
236
- if (this.restarting) return;
237
- this.restarting = true;
238
-
239
- const logger = getLogger();
240
- logger.info('Restarting Brain daemon...');
241
-
242
- try { this.cleanup(); } catch { /* best effort cleanup */ }
243
-
244
- this.restarting = false;
245
- this.start(this.configPath);
246
- }
247
-
248
- stop(): void {
249
- const logger = getLogger();
250
- logger.info('Shutting down...');
251
-
252
- this.cleanup();
253
-
254
- // Remove PID file
255
- if (this.config) {
256
- const pidPath = path.join(path.dirname(this.config.dbPath), 'brain.pid');
257
- try { fs.unlinkSync(pidPath); } catch { /* ignore */ }
258
- }
259
-
260
- logger.info('Brain daemon stopped');
261
- process.exit(0);
262
- }
263
-
264
- private setupEventListeners(services: Services, synapseManager: SynapseManager): void {
265
- const bus = getEventBus();
266
-
267
- // Error → Project synapse
268
- bus.on('error:reported', ({ errorId, projectId }) => {
269
- synapseManager.strengthen(
270
- { type: 'error', id: errorId },
271
- { type: 'project', id: projectId },
272
- 'co_occurs',
273
- );
274
- });
275
-
276
- // Solution applied → strengthen or weaken
277
- bus.on('solution:applied', ({ errorId, solutionId, success }) => {
278
- if (success) {
279
- synapseManager.strengthen(
280
- { type: 'solution', id: solutionId },
281
- { type: 'error', id: errorId },
282
- 'solves',
283
- );
284
- } else {
285
- const synapse = synapseManager.find(
286
- { type: 'solution', id: solutionId },
287
- { type: 'error', id: errorId },
288
- 'solves',
289
- );
290
- if (synapse) synapseManager.weaken(synapse.id, 0.7);
291
- }
292
- });
293
-
294
- // Module registered → link to project
295
- bus.on('module:registered', ({ moduleId, projectId }) => {
296
- synapseManager.strengthen(
297
- { type: 'code_module', id: moduleId },
298
- { type: 'project', id: projectId },
299
- 'co_occurs',
300
- );
301
- });
302
-
303
- // Rule learned → log
304
- bus.on('rule:learned', ({ ruleId, pattern }) => {
305
- getLogger().info(`New rule #${ruleId} learned: ${pattern}`);
306
- });
307
-
308
- // Insight created → log
309
- bus.on('insight:created', ({ insightId, type }) => {
310
- getLogger().info(`New insight #${insightId} (${type})`);
311
- });
312
- }
313
- }
package/src/cli/colors.ts DELETED
@@ -1,116 +0,0 @@
1
- import chalk from 'chalk';
2
-
3
- // Brand colors matching the dashboard
4
- export const c = {
5
- // Primary palette
6
- blue: chalk.hex('#5b9cff'),
7
- purple: chalk.hex('#b47aff'),
8
- cyan: chalk.hex('#47e5ff'),
9
- green: chalk.hex('#3dffa0'),
10
- red: chalk.hex('#ff5577'),
11
- orange: chalk.hex('#ffb347'),
12
- dim: chalk.hex('#8b8fb0'),
13
- dimmer: chalk.hex('#4a4d6e'),
14
-
15
- // Semantic
16
- label: chalk.hex('#8b8fb0'),
17
- value: chalk.white.bold,
18
- heading: chalk.hex('#5b9cff').bold,
19
- success: chalk.hex('#3dffa0').bold,
20
- error: chalk.hex('#ff5577').bold,
21
- warn: chalk.hex('#ffb347').bold,
22
- info: chalk.hex('#47e5ff'),
23
- };
24
-
25
- export const icons = {
26
- brain: '🧠',
27
- check: '✓',
28
- cross: '✗',
29
- arrow: '→',
30
- dot: '●',
31
- circle: '○',
32
- bar: '█',
33
- barLight: '░',
34
- dash: '─',
35
- pipe: '│',
36
- corner: '└',
37
- tee: '├',
38
- star: '★',
39
- bolt: '⚡',
40
- search: '🔍',
41
- gear: '⚙',
42
- chart: '📊',
43
- module: '📦',
44
- synapse: '🔗',
45
- insight: '💡',
46
- warn: '⚠',
47
- error: '❌',
48
- ok: '✅',
49
- clock: '⏱',
50
- };
51
-
52
- export function header(title: string, icon?: string): string {
53
- const prefix = icon ? `${icon} ` : '';
54
- const line = c.dimmer(icons.dash.repeat(40));
55
- return `\n${line}\n${prefix}${c.heading(title)}\n${line}`;
56
- }
57
-
58
- export function keyValue(key: string, value: string | number, indent = 2): string {
59
- const pad = ' '.repeat(indent);
60
- return `${pad}${c.label(key + ':')} ${c.value(String(value))}`;
61
- }
62
-
63
- export function statusBadge(status: string): string {
64
- switch (status.toLowerCase()) {
65
- case 'resolved':
66
- case 'active':
67
- case 'running':
68
- return c.green(`[${status.toUpperCase()}]`);
69
- case 'open':
70
- case 'unresolved':
71
- return c.red(`[${status.toUpperCase()}]`);
72
- case 'warning':
73
- return c.warn(`[${status.toUpperCase()}]`);
74
- default:
75
- return c.dim(`[${status.toUpperCase()}]`);
76
- }
77
- }
78
-
79
- export function priorityBadge(priority: number | string): string {
80
- const p = typeof priority === 'string' ? priority.toLowerCase() : '';
81
- const n = typeof priority === 'number' ? priority : 0;
82
- if (p === 'critical' || n >= 9) return c.red.bold(`[CRITICAL]`);
83
- if (p === 'high' || n >= 7) return c.orange.bold(`[HIGH]`);
84
- if (p === 'medium' || n >= 4) return c.blue(`[MEDIUM]`);
85
- return c.dim(`[LOW]`);
86
- }
87
-
88
- export function progressBar(current: number, total: number, width = 20): string {
89
- const pct = Math.min(1, current / Math.max(1, total));
90
- const filled = Math.round(pct * width);
91
- const empty = width - filled;
92
- return c.cyan(icons.bar.repeat(filled)) + c.dimmer(icons.barLight.repeat(empty));
93
- }
94
-
95
- export function divider(width = 40): string {
96
- return c.dimmer(icons.dash.repeat(width));
97
- }
98
-
99
- export function table(rows: string[][], colWidths?: number[]): string {
100
- if (rows.length === 0) return '';
101
- const widths = colWidths ?? rows[0].map((_, i) =>
102
- Math.max(...rows.map(r => stripAnsi(r[i] ?? '').length))
103
- );
104
- return rows.map(row =>
105
- row.map((cell, i) => {
106
- const stripped = stripAnsi(cell);
107
- const pad = Math.max(0, (widths[i] ?? stripped.length) - stripped.length);
108
- return cell + ' '.repeat(pad);
109
- }).join(' ')
110
- ).join('\n');
111
- }
112
-
113
- function stripAnsi(str: string): string {
114
- // eslint-disable-next-line no-control-regex
115
- return str.replace(/\x1b\[[0-9;]*m/g, '');
116
- }
@@ -1,169 +0,0 @@
1
- import { Command } from 'commander';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import { getDataDir } from '../../utils/paths.js';
5
- import { c, icons, header, divider } from '../colors.js';
6
-
7
- function getConfigPath(): string {
8
- return path.join(getDataDir(), 'config.json');
9
- }
10
-
11
- function readConfig(): Record<string, unknown> {
12
- const configPath = getConfigPath();
13
- if (fs.existsSync(configPath)) {
14
- return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
15
- }
16
- return {};
17
- }
18
-
19
- function writeConfig(config: Record<string, unknown>): void {
20
- const configPath = getConfigPath();
21
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
22
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
23
- }
24
-
25
- function getNestedValue(obj: Record<string, unknown>, keyPath: string): unknown {
26
- const parts = keyPath.split('.');
27
- let current: unknown = obj;
28
- for (const part of parts) {
29
- if (current === null || current === undefined || typeof current !== 'object') return undefined;
30
- current = (current as Record<string, unknown>)[part];
31
- }
32
- return current;
33
- }
34
-
35
- function setNestedValue(obj: Record<string, unknown>, keyPath: string, value: unknown): void {
36
- const parts = keyPath.split('.');
37
- let current: Record<string, unknown> = obj;
38
- for (let i = 0; i < parts.length - 1; i++) {
39
- const part = parts[i];
40
- if (!current[part] || typeof current[part] !== 'object') {
41
- current[part] = {};
42
- }
43
- current = current[part] as Record<string, unknown>;
44
- }
45
- current[parts[parts.length - 1]] = value;
46
- }
47
-
48
- function deleteNestedValue(obj: Record<string, unknown>, keyPath: string): boolean {
49
- const parts = keyPath.split('.');
50
- let current: Record<string, unknown> = obj;
51
- for (let i = 0; i < parts.length - 1; i++) {
52
- const part = parts[i];
53
- if (!current[part] || typeof current[part] !== 'object') return false;
54
- current = current[part] as Record<string, unknown>;
55
- }
56
- const last = parts[parts.length - 1];
57
- if (last in current) {
58
- delete current[last];
59
- return true;
60
- }
61
- return false;
62
- }
63
-
64
- function parseValue(value: string): unknown {
65
- if (value === 'true') return true;
66
- if (value === 'false') return false;
67
- if (value === 'null') return null;
68
- const num = Number(value);
69
- if (!isNaN(num) && value.trim() !== '') return num;
70
- // Try JSON for arrays/objects
71
- if ((value.startsWith('[') && value.endsWith(']')) || (value.startsWith('{') && value.endsWith('}'))) {
72
- try { return JSON.parse(value); } catch { /* fall through */ }
73
- }
74
- return value;
75
- }
76
-
77
- function printObject(obj: unknown, indent = 0): void {
78
- const pad = ' '.repeat(indent);
79
- if (obj === null || obj === undefined) {
80
- console.log(`${pad}${c.dim('(not set)')}`);
81
- return;
82
- }
83
- if (typeof obj !== 'object') {
84
- console.log(`${pad}${c.value(String(obj))}`);
85
- return;
86
- }
87
- for (const [key, val] of Object.entries(obj as Record<string, unknown>)) {
88
- if (val && typeof val === 'object' && !Array.isArray(val)) {
89
- console.log(`${pad}${c.cyan(key + ':')}`);
90
- printObject(val, indent + 2);
91
- } else {
92
- const display = Array.isArray(val) ? JSON.stringify(val) : String(val);
93
- console.log(`${pad}${c.label(key + ':')} ${c.value(display)}`);
94
- }
95
- }
96
- }
97
-
98
- export function configCommand(): Command {
99
- const cmd = new Command('config')
100
- .description('View and modify Brain configuration');
101
-
102
- cmd
103
- .command('show')
104
- .description('Show current configuration')
105
- .argument('[key]', 'Specific config key (e.g., learning.intervalMs)')
106
- .action((key?: string) => {
107
- const config = readConfig();
108
-
109
- if (key) {
110
- const value = getNestedValue(config, key);
111
- if (value === undefined) {
112
- console.log(`${c.dim(`Key "${key}" is not set in config overrides.`)}`);
113
- } else {
114
- console.log(`${c.label(key + ':')} ${c.value(typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value))}`);
115
- }
116
- return;
117
- }
118
-
119
- console.log(header('Brain Configuration', icons.gear));
120
- console.log(` ${c.label('Config file:')} ${c.dim(getConfigPath())}\n`);
121
-
122
- if (Object.keys(config).length === 0) {
123
- console.log(` ${c.dim('No custom overrides. Using defaults.')}`);
124
- console.log(` ${c.dim('Set values with:')} ${c.cyan('brain config set <key> <value>')}`);
125
- } else {
126
- printObject(config, 2);
127
- }
128
- console.log(`\n${divider()}`);
129
- });
130
-
131
- cmd
132
- .command('set')
133
- .description('Set a configuration value')
134
- .argument('<key>', 'Config key path (e.g., learning.intervalMs)')
135
- .argument('<value>', 'Value to set')
136
- .action((key: string, value: string) => {
137
- const config = readConfig();
138
- const parsed = parseValue(value);
139
- setNestedValue(config, key, parsed);
140
- writeConfig(config);
141
-
142
- console.log(`${icons.ok} ${c.label(key)} ${c.dim(icons.arrow)} ${c.value(String(parsed))}`);
143
- console.log(` ${c.dim('Restart the daemon for changes to take effect:')} ${c.cyan('brain stop && brain start')}`);
144
- });
145
-
146
- cmd
147
- .command('delete')
148
- .description('Remove a configuration override (revert to default)')
149
- .argument('<key>', 'Config key path to remove')
150
- .action((key: string) => {
151
- const config = readConfig();
152
- if (deleteNestedValue(config, key)) {
153
- writeConfig(config);
154
- console.log(`${icons.ok} ${c.dim(`Removed "${key}" — will use default value.`)}`);
155
- console.log(` ${c.dim('Restart the daemon for changes to take effect:')} ${c.cyan('brain stop && brain start')}`);
156
- } else {
157
- console.log(`${c.dim(`Key "${key}" not found in config overrides.`)}`);
158
- }
159
- });
160
-
161
- cmd
162
- .command('path')
163
- .description('Show the config file path')
164
- .action(() => {
165
- console.log(getConfigPath());
166
- });
167
-
168
- return cmd;
169
- }