@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.
- package/README.md +33 -0
- package/brain.log +3876 -0
- package/{src/cli/commands/dashboard.ts → dashboard.html} +694 -807
- package/dist/api/server.d.ts +4 -18
- package/dist/api/server.js +4 -173
- package/dist/api/server.js.map +1 -1
- package/dist/brain.d.ts +2 -0
- package/dist/brain.js +15 -4
- package/dist/brain.js.map +1 -1
- package/dist/cli/colors.d.ts +4 -25
- package/dist/cli/colors.js +3 -89
- package/dist/cli/colors.js.map +1 -1
- package/dist/cli/commands/dashboard.js +21 -2
- package/dist/cli/commands/dashboard.js.map +1 -1
- package/dist/cli/commands/peers.d.ts +2 -0
- package/dist/cli/commands/peers.js +38 -0
- package/dist/cli/commands/peers.js.map +1 -0
- package/dist/cli/commands/status.js +0 -1
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/config.js +2 -29
- package/dist/config.js.map +1 -1
- package/dist/db/connection.d.ts +1 -2
- package/dist/db/connection.js +1 -18
- package/dist/db/connection.js.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/ipc/__tests__/protocol.test.d.ts +1 -0
- package/dist/ipc/__tests__/protocol.test.js +117 -0
- package/dist/ipc/__tests__/protocol.test.js.map +1 -0
- package/dist/ipc/client.d.ts +1 -16
- package/dist/ipc/client.js +1 -100
- package/dist/ipc/client.js.map +1 -1
- package/dist/ipc/protocol.d.ts +1 -8
- package/dist/ipc/protocol.js +1 -28
- package/dist/ipc/protocol.js.map +1 -1
- package/dist/ipc/router.d.ts +2 -0
- package/dist/ipc/router.js +30 -0
- package/dist/ipc/router.js.map +1 -1
- package/dist/ipc/server.d.ts +1 -22
- package/dist/ipc/server.js +1 -163
- package/dist/ipc/server.js.map +1 -1
- package/dist/learning/confidence-scorer.d.ts +2 -5
- package/dist/learning/confidence-scorer.js +4 -19
- package/dist/learning/confidence-scorer.js.map +1 -1
- package/dist/learning/decay.js +2 -3
- package/dist/learning/decay.js.map +1 -1
- package/dist/learning/learning-engine.d.ts +2 -5
- package/dist/learning/learning-engine.js +3 -15
- package/dist/learning/learning-engine.js.map +1 -1
- package/dist/mcp/http-server.d.ts +1 -7
- package/dist/mcp/http-server.js +6 -117
- package/dist/mcp/http-server.js.map +1 -1
- package/dist/mcp/server.js +5 -61
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.js +36 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/parsing/parsers/compiler.js +1 -1
- package/dist/parsing/parsers/compiler.js.map +1 -1
- package/dist/research/research-engine.d.ts +2 -6
- package/dist/research/research-engine.js +3 -23
- package/dist/research/research-engine.js.map +1 -1
- package/dist/services/synapse.service.d.ts +3 -3
- package/dist/signals/__tests__/fingerprint.test.d.ts +1 -0
- package/dist/signals/__tests__/fingerprint.test.js +118 -0
- package/dist/signals/__tests__/fingerprint.test.js.map +1 -0
- package/dist/synapses/activation.d.ts +3 -13
- package/dist/synapses/activation.js +2 -49
- package/dist/synapses/activation.js.map +1 -1
- package/dist/synapses/decay.d.ts +2 -11
- package/dist/synapses/decay.js +2 -26
- package/dist/synapses/decay.js.map +1 -1
- package/dist/synapses/hebbian.d.ts +2 -13
- package/dist/synapses/hebbian.js +2 -35
- package/dist/synapses/hebbian.js.map +1 -1
- package/dist/synapses/pathfinder.d.ts +2 -14
- package/dist/synapses/pathfinder.js +2 -49
- package/dist/synapses/pathfinder.js.map +1 -1
- package/dist/synapses/synapse-manager.d.ts +7 -23
- package/dist/synapses/synapse-manager.js +6 -63
- package/dist/synapses/synapse-manager.js.map +1 -1
- package/dist/types/ipc.types.d.ts +1 -11
- package/dist/utils/__tests__/hash.test.d.ts +1 -0
- package/dist/utils/__tests__/hash.test.js +32 -0
- package/dist/utils/__tests__/hash.test.js.map +1 -0
- package/dist/utils/__tests__/paths.test.d.ts +1 -0
- package/dist/utils/__tests__/paths.test.js +75 -0
- package/dist/utils/__tests__/paths.test.js.map +1 -0
- package/dist/utils/events.d.ts +4 -8
- package/dist/utils/events.js +2 -14
- package/dist/utils/events.js.map +1 -1
- package/dist/utils/hash.d.ts +1 -1
- package/dist/utils/hash.js +1 -4
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/logger.d.ts +3 -2
- package/dist/utils/logger.js +8 -35
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/paths.d.ts +2 -1
- package/dist/utils/paths.js +4 -13
- package/dist/utils/paths.js.map +1 -1
- package/eslint.config.js +14 -0
- package/package.json +56 -49
- package/BRAIN_PLAN.md +0 -3324
- package/reddit_post.md +0 -45
- package/src/api/server.ts +0 -395
- package/src/brain.ts +0 -313
- package/src/cli/colors.ts +0 -116
- package/src/cli/commands/config.ts +0 -169
- package/src/cli/commands/doctor.ts +0 -124
- package/src/cli/commands/explain.ts +0 -83
- package/src/cli/commands/export.ts +0 -31
- package/src/cli/commands/import.ts +0 -199
- package/src/cli/commands/insights.ts +0 -65
- package/src/cli/commands/learn.ts +0 -24
- package/src/cli/commands/modules.ts +0 -53
- package/src/cli/commands/network.ts +0 -67
- package/src/cli/commands/projects.ts +0 -42
- package/src/cli/commands/query.ts +0 -120
- package/src/cli/commands/start.ts +0 -105
- package/src/cli/commands/status.ts +0 -75
- package/src/cli/commands/stop.ts +0 -34
- package/src/cli/ipc-helper.ts +0 -22
- package/src/cli/update-check.ts +0 -63
- package/src/code/analyzer.ts +0 -117
- package/src/code/fingerprint.ts +0 -87
- package/src/code/matcher.ts +0 -129
- package/src/code/parsers/generic.ts +0 -29
- package/src/code/parsers/python.ts +0 -54
- package/src/code/parsers/typescript.ts +0 -65
- package/src/code/registry.ts +0 -60
- package/src/code/scorer.ts +0 -120
- package/src/config.ts +0 -135
- package/src/dashboard/server.ts +0 -142
- package/src/db/connection.ts +0 -22
- package/src/db/migrations/001_core_schema.ts +0 -120
- package/src/db/migrations/002_learning_schema.ts +0 -38
- package/src/db/migrations/003_code_schema.ts +0 -53
- package/src/db/migrations/004_synapses_schema.ts +0 -57
- package/src/db/migrations/005_fts_indexes.ts +0 -78
- package/src/db/migrations/006_synapses_phase3.ts +0 -17
- package/src/db/migrations/007_feedback.ts +0 -13
- package/src/db/migrations/008_git_integration.ts +0 -38
- package/src/db/migrations/009_embeddings.ts +0 -8
- package/src/db/migrations/index.ts +0 -70
- package/src/db/repositories/antipattern.repository.ts +0 -66
- package/src/db/repositories/code-module.repository.ts +0 -142
- package/src/db/repositories/error.repository.ts +0 -189
- package/src/db/repositories/insight.repository.ts +0 -99
- package/src/db/repositories/notification.repository.ts +0 -66
- package/src/db/repositories/project.repository.ts +0 -93
- package/src/db/repositories/rule.repository.ts +0 -108
- package/src/db/repositories/solution.repository.ts +0 -154
- package/src/db/repositories/synapse.repository.ts +0 -163
- package/src/db/repositories/terminal.repository.ts +0 -101
- package/src/embeddings/engine.ts +0 -238
- package/src/hooks/post-tool-use.ts +0 -92
- package/src/hooks/post-write.ts +0 -129
- package/src/index.ts +0 -63
- package/src/ipc/client.ts +0 -118
- package/src/ipc/protocol.ts +0 -35
- package/src/ipc/router.ts +0 -133
- package/src/ipc/server.ts +0 -176
- package/src/learning/confidence-scorer.ts +0 -80
- package/src/learning/decay.ts +0 -46
- package/src/learning/learning-engine.ts +0 -170
- package/src/learning/pattern-extractor.ts +0 -90
- package/src/learning/rule-generator.ts +0 -74
- package/src/main.rs:10:5 +0 -0
- package/src/matching/error-matcher.ts +0 -166
- package/src/matching/fingerprint.ts +0 -34
- package/src/matching/similarity.ts +0 -61
- package/src/matching/tfidf.ts +0 -74
- package/src/matching/tokenizer.ts +0 -41
- package/src/mcp/auto-detect.ts +0 -93
- package/src/mcp/http-server.ts +0 -140
- package/src/mcp/server.ts +0 -73
- package/src/mcp/tools.ts +0 -328
- package/src/parsing/error-parser.ts +0 -28
- package/src/parsing/parsers/compiler.ts +0 -93
- package/src/parsing/parsers/generic.ts +0 -28
- package/src/parsing/parsers/go.ts +0 -97
- package/src/parsing/parsers/node.ts +0 -69
- package/src/parsing/parsers/python.ts +0 -62
- package/src/parsing/parsers/rust.ts +0 -50
- package/src/parsing/parsers/shell.ts +0 -42
- package/src/parsing/types.ts +0 -47
- package/src/research/gap-analyzer.ts +0 -135
- package/src/research/insight-generator.ts +0 -123
- package/src/research/research-engine.ts +0 -116
- package/src/research/synergy-detector.ts +0 -126
- package/src/research/template-extractor.ts +0 -130
- package/src/research/trend-analyzer.ts +0 -127
- package/src/services/analytics.service.ts +0 -226
- package/src/services/code.service.ts +0 -271
- package/src/services/error.service.ts +0 -266
- package/src/services/git.service.ts +0 -132
- package/src/services/notification.service.ts +0 -41
- package/src/services/prevention.service.ts +0 -159
- package/src/services/research.service.ts +0 -98
- package/src/services/solution.service.ts +0 -174
- package/src/services/synapse.service.ts +0 -59
- package/src/services/terminal.service.ts +0 -81
- package/src/synapses/activation.ts +0 -80
- package/src/synapses/decay.ts +0 -38
- package/src/synapses/hebbian.ts +0 -69
- package/src/synapses/pathfinder.ts +0 -81
- package/src/synapses/synapse-manager.ts +0 -113
- package/src/types/code.types.ts +0 -52
- package/src/types/config.types.ts +0 -103
- package/src/types/error.types.ts +0 -67
- package/src/types/ipc.types.ts +0 -8
- package/src/types/mcp.types.ts +0 -53
- package/src/types/research.types.ts +0 -28
- package/src/types/solution.types.ts +0 -30
- package/src/types/synapse.types.ts +0 -50
- package/src/utils/events.ts +0 -45
- package/src/utils/hash.ts +0 -5
- package/src/utils/logger.ts +0 -48
- package/src/utils/paths.ts +0 -19
- package/tests/e2e/test_code_intelligence.py +0 -1015
- package/tests/e2e/test_error_memory.py +0 -451
- package/tests/e2e/test_full_integration.py +0 -534
- package/tests/fixtures/code-modules/modules.ts +0 -83
- package/tests/fixtures/errors/go.ts +0 -9
- package/tests/fixtures/errors/node.ts +0 -24
- package/tests/fixtures/errors/python.ts +0 -21
- package/tests/fixtures/errors/rust.ts +0 -25
- package/tests/fixtures/errors/shell.ts +0 -15
- package/tests/fixtures/solutions/solutions.ts +0 -27
- package/tests/helpers/setup-db.ts +0 -52
- package/tests/integration/code-flow.test.ts +0 -86
- package/tests/integration/error-flow.test.ts +0 -83
- package/tests/integration/ipc-flow.test.ts +0 -166
- package/tests/integration/learning-cycle.test.ts +0 -82
- package/tests/integration/synapse-flow.test.ts +0 -117
- package/tests/unit/code/analyzer.test.ts +0 -58
- package/tests/unit/code/fingerprint.test.ts +0 -51
- package/tests/unit/code/scorer.test.ts +0 -55
- package/tests/unit/learning/confidence-scorer.test.ts +0 -60
- package/tests/unit/learning/decay.test.ts +0 -45
- package/tests/unit/learning/pattern-extractor.test.ts +0 -50
- package/tests/unit/matching/error-matcher.test.ts +0 -69
- package/tests/unit/matching/fingerprint.test.ts +0 -47
- package/tests/unit/matching/similarity.test.ts +0 -65
- package/tests/unit/matching/tfidf.test.ts +0 -71
- package/tests/unit/matching/tokenizer.test.ts +0 -83
- package/tests/unit/parsing/parsers.test.ts +0 -113
- package/tests/unit/research/gap-analyzer.test.ts +0 -45
- package/tests/unit/research/trend-analyzer.test.ts +0 -45
- package/tests/unit/synapses/activation.test.ts +0 -80
- package/tests/unit/synapses/decay.test.ts +0 -27
- package/tests/unit/synapses/hebbian.test.ts +0 -96
- package/tests/unit/synapses/pathfinder.test.ts +0 -72
- 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
|
-
}
|