@timmeck/brain 1.8.5 → 1.9.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/.dockerignore ADDED
@@ -0,0 +1,11 @@
1
+ node_modules
2
+ src
3
+ tests
4
+ *.db
5
+ *.log
6
+ .env
7
+ .git
8
+ .gitignore
9
+ dashboard.html
10
+ gen_avatar.py
11
+ BRAIN_PLAN.md
package/Dockerfile ADDED
@@ -0,0 +1,21 @@
1
+ FROM node:22-slim
2
+
3
+ # better-sqlite3 needs build tools
4
+ RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/*
5
+
6
+ WORKDIR /app
7
+
8
+ COPY package.json package-lock.json ./
9
+ RUN npm ci --omit=dev
10
+
11
+ COPY dist/ dist/
12
+ COPY package.json ./
13
+
14
+ # Data directory for brain.db
15
+ RUN mkdir -p /data
16
+ ENV BRAIN_DATA_DIR=/data
17
+
18
+ EXPOSE 7777 7778
19
+
20
+ ENTRYPOINT ["node", "dist/index.js"]
21
+ CMD ["mcp-server"]
Binary file
Binary file
Binary file
package/dist/brain.d.ts CHANGED
@@ -8,7 +8,12 @@ export declare class BrainCore {
8
8
  private researchEngine;
9
9
  private cleanupTimer;
10
10
  private config;
11
+ private configPath?;
12
+ private restarting;
11
13
  start(configPath?: string): void;
14
+ private logCrash;
15
+ private cleanup;
16
+ restart(): void;
12
17
  stop(): void;
13
18
  private setupEventListeners;
14
19
  }
package/dist/brain.js CHANGED
@@ -50,7 +50,10 @@ export class BrainCore {
50
50
  researchEngine = null;
51
51
  cleanupTimer = null;
52
52
  config = null;
53
+ configPath;
54
+ restarting = false;
53
55
  start(configPath) {
56
+ this.configPath = configPath;
54
57
  // 1. Config
55
58
  this.config = loadConfig(configPath);
56
59
  const config = this.config;
@@ -145,11 +148,30 @@ export class BrainCore {
145
148
  // 15. Graceful shutdown
146
149
  process.on('SIGINT', () => this.stop());
147
150
  process.on('SIGTERM', () => this.stop());
151
+ // 16. Crash recovery — auto-restart on uncaught errors
152
+ process.on('uncaughtException', (err) => {
153
+ logger.error('Uncaught exception — restarting', { error: err.message, stack: err.stack });
154
+ this.logCrash('uncaughtException', err);
155
+ this.restart();
156
+ });
157
+ process.on('unhandledRejection', (reason) => {
158
+ logger.error('Unhandled rejection — restarting', { reason: String(reason) });
159
+ this.logCrash('unhandledRejection', reason instanceof Error ? reason : new Error(String(reason)));
160
+ this.restart();
161
+ });
148
162
  logger.info(`Brain daemon started (PID: ${process.pid})`);
149
163
  }
150
- stop() {
151
- const logger = getLogger();
152
- logger.info('Shutting down...');
164
+ logCrash(type, err) {
165
+ if (!this.config)
166
+ return;
167
+ const crashLog = path.join(path.dirname(this.config.dbPath), 'crashes.log');
168
+ const entry = `[${new Date().toISOString()}] ${type}: ${err.message}\n${err.stack ?? ''}\n\n`;
169
+ try {
170
+ fs.appendFileSync(crashLog, entry);
171
+ }
172
+ catch { /* best effort */ }
173
+ }
174
+ cleanup() {
153
175
  if (this.cleanupTimer) {
154
176
  clearInterval(this.cleanupTimer);
155
177
  this.cleanupTimer = null;
@@ -161,6 +183,31 @@ export class BrainCore {
161
183
  this.apiServer?.stop();
162
184
  this.ipcServer?.stop();
163
185
  this.db?.close();
186
+ this.db = null;
187
+ this.ipcServer = null;
188
+ this.apiServer = null;
189
+ this.mcpHttpServer = null;
190
+ this.embeddingEngine = null;
191
+ this.learningEngine = null;
192
+ this.researchEngine = null;
193
+ }
194
+ restart() {
195
+ if (this.restarting)
196
+ return;
197
+ this.restarting = true;
198
+ const logger = getLogger();
199
+ logger.info('Restarting Brain daemon...');
200
+ try {
201
+ this.cleanup();
202
+ }
203
+ catch { /* best effort cleanup */ }
204
+ this.restarting = false;
205
+ this.start(this.configPath);
206
+ }
207
+ stop() {
208
+ const logger = getLogger();
209
+ logger.info('Shutting down...');
210
+ this.cleanup();
164
211
  // Remove PID file
165
212
  if (this.config) {
166
213
  const pidPath = path.join(path.dirname(this.config.dbPath), 'brain.pid');
package/dist/brain.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"brain.js","sourceRoot":"","sources":["../src/brain.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"brain.js","sourceRoot":"","sources":["../src/brain.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,58 @@ import path from 'node:path';
5
5
  import { getDataDir } from '../../utils/paths.js';
6
6
  import { c, icons } from '../colors.js';
7
7
  import { checkForUpdate } from '../update-check.js';
8
+ const MAX_RESTARTS = 5;
9
+ const RESTART_WINDOW_MS = 5 * 60 * 1000; // 5 minutes
10
+ const BASE_BACKOFF_MS = 1000;
11
+ function spawnDaemon(entryPoint, args) {
12
+ const child = spawn(process.execPath, [entryPoint, ...args], {
13
+ detached: true,
14
+ stdio: 'ignore',
15
+ });
16
+ child.unref();
17
+ return child;
18
+ }
19
+ function startWatchdog(entryPoint, args, pidPath) {
20
+ const restartTimes = [];
21
+ function launch() {
22
+ const child = spawnDaemon(entryPoint, args);
23
+ console.log(`${icons.brain} ${c.info('Brain daemon starting')} ${c.dim(`(PID: ${child.pid})`)}`);
24
+ child.on('exit', (code) => {
25
+ // Normal shutdown (code 0 or SIGTERM) — don't restart
26
+ if (code === 0 || code === null)
27
+ return;
28
+ const now = Date.now();
29
+ restartTimes.push(now);
30
+ // Only count restarts within the window
31
+ const recentRestarts = restartTimes.filter((t) => now - t < RESTART_WINDOW_MS);
32
+ restartTimes.length = 0;
33
+ restartTimes.push(...recentRestarts);
34
+ if (recentRestarts.length > MAX_RESTARTS) {
35
+ console.error(`${icons.error} ${c.error(`Brain daemon crashed ${MAX_RESTARTS} times in 5 minutes — giving up.`)}`);
36
+ // Clean up stale PID file
37
+ try {
38
+ fs.unlinkSync(pidPath);
39
+ }
40
+ catch { /* ignore */ }
41
+ return;
42
+ }
43
+ const backoff = BASE_BACKOFF_MS * Math.pow(2, recentRestarts.length - 1);
44
+ console.log(`${icons.warn} ${c.warn(`Brain daemon exited (code ${code}) — restarting in ${backoff / 1000}s...`)}`);
45
+ setTimeout(launch, backoff);
46
+ });
47
+ }
48
+ launch();
49
+ // Wait briefly for PID file to appear
50
+ setTimeout(async () => {
51
+ if (fs.existsSync(pidPath)) {
52
+ console.log(`${icons.ok} ${c.success('Brain daemon started successfully.')} ${c.dim('(watchdog active)')}`);
53
+ }
54
+ else {
55
+ console.log(`${icons.clock} ${c.warn('Brain daemon may still be starting.')} Check: ${c.cyan('brain status')}`);
56
+ }
57
+ await checkForUpdate();
58
+ }, 1000);
59
+ }
8
60
  export function startCommand() {
9
61
  return new Command('start')
10
62
  .description('Start the Brain daemon')
@@ -33,27 +85,12 @@ export function startCommand() {
33
85
  });
34
86
  return;
35
87
  }
36
- // Spawn detached daemon
88
+ // Spawn detached daemon with watchdog
37
89
  const args = ['daemon'];
38
90
  if (opts.config)
39
91
  args.push('-c', opts.config);
40
92
  const entryPoint = path.resolve(import.meta.dirname, '../../index.js');
41
- const child = spawn(process.execPath, [entryPoint, ...args], {
42
- detached: true,
43
- stdio: 'ignore',
44
- });
45
- child.unref();
46
- console.log(`${icons.brain} ${c.info('Brain daemon starting')} ${c.dim(`(PID: ${child.pid})`)}`);
47
- // Wait briefly for PID file to appear
48
- setTimeout(async () => {
49
- if (fs.existsSync(pidPath)) {
50
- console.log(`${icons.ok} ${c.success('Brain daemon started successfully.')}`);
51
- }
52
- else {
53
- console.log(`${icons.clock} ${c.warn('Brain daemon may still be starting.')} Check: ${c.cyan('brain status')}`);
54
- }
55
- await checkForUpdate();
56
- }, 1000);
93
+ startWatchdog(entryPoint, args, pidPath);
57
94
  });
58
95
  }
59
96
  //# sourceMappingURL=start.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/cli/commands/start.ts"],"names":[],"mappings":"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"}
package/gen_avatar.py ADDED
@@ -0,0 +1,142 @@
1
+ """Generate a circular Brain avatar for GitHub/X profile pictures."""
2
+ from PIL import Image, ImageDraw, ImageFilter, ImageFont
3
+ import math
4
+ import random
5
+
6
+ random.seed(42)
7
+
8
+ SIZE = 1024
9
+ CENTER = SIZE // 2
10
+ R = SIZE // 2 - 20 # circle radius
11
+
12
+ img = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
13
+ draw = ImageDraw.Draw(img)
14
+
15
+ # --- Background circle with dark gradient ---
16
+ bg = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
17
+ bg_draw = ImageDraw.Draw(bg)
18
+ for r in range(R, 0, -1):
19
+ t = r / R
20
+ c1 = (10, 12, 28) # center
21
+ c2 = (18, 20, 42) # edge
22
+ color = tuple(int(c1[i] * t + c2[i] * (1 - t)) for i in range(3))
23
+ bg_draw.ellipse([CENTER - r, CENTER - r, CENTER + r, CENTER + r], fill=(*color, 255))
24
+ img = Image.alpha_composite(img, bg)
25
+
26
+ # --- Generate synapse network nodes ---
27
+ node_types = {
28
+ 'project': {'color': (255, 179, 71), 'count': 4, 'radius': (18, 28)},
29
+ 'code_module': {'color': (180, 122, 255), 'count': 22, 'radius': (6, 12)},
30
+ 'error': {'color': (255, 85, 119), 'count': 10, 'radius': (7, 13)},
31
+ 'solution': {'color': (61, 255, 160), 'count': 6, 'radius': (7, 11)},
32
+ 'rule': {'color': (91, 156, 255), 'count': 5, 'radius': (5, 9)},
33
+ }
34
+
35
+ nodes = []
36
+ for ntype, cfg in node_types.items():
37
+ for _ in range(cfg['count']):
38
+ # Place within circle
39
+ for _attempt in range(50):
40
+ angle = random.uniform(0, 2 * math.pi)
41
+ dist = random.uniform(40, R - 50)
42
+ x = CENTER + math.cos(angle) * dist
43
+ y = CENTER + math.sin(angle) * dist
44
+ # Check no overlap
45
+ too_close = False
46
+ for n in nodes:
47
+ if math.hypot(x - n['x'], y - n['y']) < 35:
48
+ too_close = True
49
+ break
50
+ if not too_close:
51
+ break
52
+ r = random.randint(*cfg['radius'])
53
+ nodes.append({'x': x, 'y': y, 'r': r, 'type': ntype, 'color': cfg['color']})
54
+
55
+ # --- Create edges between nearby nodes ---
56
+ edges = []
57
+ for i, n1 in enumerate(nodes):
58
+ distances = []
59
+ for j, n2 in enumerate(nodes):
60
+ if i == j:
61
+ continue
62
+ d = math.hypot(n1['x'] - n2['x'], n1['y'] - n2['y'])
63
+ distances.append((d, j))
64
+ distances.sort()
65
+ # Connect to 2-4 nearest
66
+ count = random.randint(2, 4) if n1['type'] == 'project' else random.randint(1, 3)
67
+ for d, j in distances[:count]:
68
+ if d < R * 1.2:
69
+ edge = tuple(sorted([i, j]))
70
+ if edge not in edges:
71
+ edges.append(edge)
72
+
73
+ # --- Draw on a separate layer for glow ---
74
+ glow_layer = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
75
+ glow_draw = ImageDraw.Draw(glow_layer)
76
+
77
+ # Edge colors by type combination
78
+ EDGE_COLORS = {
79
+ 'project': (91, 156, 255, 50),
80
+ 'code_module': (140, 100, 220, 40),
81
+ 'error': (200, 80, 100, 40),
82
+ 'solution': (50, 200, 130, 45),
83
+ 'rule': (70, 130, 220, 40),
84
+ }
85
+
86
+ # Draw edges
87
+ for i, j in edges:
88
+ n1, n2 = nodes[i], nodes[j]
89
+ ec = EDGE_COLORS.get(n1['type'], (91, 156, 255, 40))
90
+ glow_draw.line([(n1['x'], n1['y']), (n2['x'], n2['y'])], fill=ec, width=2)
91
+
92
+ # Draw edge glow
93
+ edge_glow = glow_layer.filter(ImageFilter.GaussianBlur(4))
94
+ img = Image.alpha_composite(img, edge_glow)
95
+ img = Image.alpha_composite(img, glow_layer)
96
+
97
+ # --- Draw nodes with glow ---
98
+ for n in nodes:
99
+ color = n['color']
100
+ r = n['r']
101
+ x, y = int(n['x']), int(n['y'])
102
+
103
+ # Outer glow
104
+ glow = Image.new('RGBA', (SIZE, SIZE), (0, 0, 0, 0))
105
+ g_draw = ImageDraw.Draw(glow)
106
+ glow_r = r + 12
107
+ g_draw.ellipse([x - glow_r, y - glow_r, x + glow_r, y + glow_r],
108
+ fill=(*color, 40))
109
+ glow = glow.filter(ImageFilter.GaussianBlur(10))
110
+ img = Image.alpha_composite(img, glow)
111
+
112
+ # Core node
113
+ draw = ImageDraw.Draw(img)
114
+ draw.ellipse([x - r, y - r, x + r, y + r], fill=(*color, 220))
115
+
116
+ # Inner highlight
117
+ hr = max(2, r // 3)
118
+ hx, hy = x - r // 4, y - r // 4
119
+ draw.ellipse([hx - hr, hy - hr, hx + hr, hy + hr], fill=(255, 255, 255, 70))
120
+
121
+ # --- Circular mask ---
122
+ mask = Image.new('L', (SIZE, SIZE), 0)
123
+ mask_draw = ImageDraw.Draw(mask)
124
+ mask_draw.ellipse([CENTER - R, CENTER - R, CENTER + R, CENTER + R], fill=255)
125
+ img.putalpha(mask)
126
+
127
+ # --- Subtle border ring ---
128
+ draw = ImageDraw.Draw(img)
129
+ for offset in range(3):
130
+ alpha = 80 - offset * 25
131
+ draw.ellipse([CENTER - R + offset, CENTER - R + offset, CENTER + R - offset, CENTER + R - offset],
132
+ outline=(91, 156, 255, max(alpha, 10)), width=1)
133
+
134
+ # --- Save ---
135
+ img.save('C:/Users/mecklenburg/Desktop/brain/assets/brain-avatar.png')
136
+
137
+ # Also save smaller sizes for different platforms
138
+ for size, name in [(512, 'brain-avatar-512.png'), (256, 'brain-avatar-256.png')]:
139
+ resized = img.resize((size, size), Image.LANCZOS)
140
+ resized.save(f'C:/Users/mecklenburg/Desktop/brain/assets/{name}')
141
+
142
+ print(f'Generated: brain-avatar.png (1024px), brain-avatar-512.png, brain-avatar-256.png')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timmeck/brain",
3
- "version": "1.8.5",
3
+ "version": "1.9.0",
4
4
  "description": "Adaptive error memory and code intelligence system with Hebbian synapse network, hybrid search, and REST API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/reddit_post.md ADDED
@@ -0,0 +1,45 @@
1
+ # Reddit Post for r/ClaudeAI
2
+
3
+ ## Title:
4
+ I built a persistent memory system for Claude Code — it remembers every error, solution, and code module across all your projects
5
+
6
+ ## Body:
7
+
8
+ Claude Code starts fresh every session. After months of hitting the same errors and rewriting the same code, I built **Brain** — an MCP server that gives Claude Code a persistent memory.
9
+
10
+ ### What it does
11
+
12
+ - **Error Memory** — Brain remembers every error you've encountered and every solution that worked. Next time you hit the same bug, it suggests the fix with a confidence score.
13
+ - **Cross-Project Learning** — Fixed a bug in project A? Brain suggests the same fix when a similar error appears in project B.
14
+ - **Code Intelligence** — Before writing new code, Brain checks if similar modules already exist across your 36 projects. No more reinventing the wheel.
15
+ - **Hebbian Synapse Network** — 37,000+ weighted connections between errors, solutions, and code modules. Connections strengthen with use, like biological synapses.
16
+ - **Proactive Prevention** — Post-write hooks check your code against known antipatterns *before* errors occur.
17
+ - **Auto-Detect** — Hooks catch errors in real-time from Bash output and report them to Brain automatically. You don't have to do anything.
18
+
19
+ ### The stack
20
+
21
+ - TypeScript, better-sqlite3, MCP SDK
22
+ - 13 MCP tools for Claude Code
23
+ - REST API (30+ endpoints) + MCP over HTTP/SSE (works with Cursor, Windsurf, Cline)
24
+ - Local embeddings (all-MiniLM-L6-v2) for hybrid search — no cloud, no API keys
25
+ - Interactive dashboard with live synapse network visualization
26
+ - Full CLI: `brain status`, `brain query`, `brain explain`, `brain dashboard`
27
+
28
+ ### Real numbers from my setup
29
+
30
+ - 18,160 code modules indexed across 36 projects
31
+ - 37,277 synapse connections
32
+ - 4,902 research insights generated automatically
33
+ - 139 tests, all passing
34
+
35
+ ### Install
36
+
37
+ ```
38
+ npm install -g @timmeck/brain
39
+ ```
40
+
41
+ Setup takes 2 minutes — add the MCP server + hooks to your Claude Code settings and run `brain start`. That's it.
42
+
43
+ GitHub: https://github.com/timmeck/brain
44
+
45
+ MIT licensed, open source. Would love feedback — especially on what MCP tools would be most useful to add next.
package/src/brain.ts CHANGED
@@ -60,8 +60,11 @@ export class BrainCore {
60
60
  private researchEngine: ResearchEngine | null = null;
61
61
  private cleanupTimer: ReturnType<typeof setInterval> | null = null;
62
62
  private config: BrainConfig | null = null;
63
+ private configPath?: string;
64
+ private restarting = false;
63
65
 
64
66
  start(configPath?: string): void {
67
+ this.configPath = configPath;
65
68
  // 1. Config
66
69
  this.config = loadConfig(configPath);
67
70
  const config = this.config;
@@ -184,13 +187,29 @@ export class BrainCore {
184
187
  process.on('SIGINT', () => this.stop());
185
188
  process.on('SIGTERM', () => this.stop());
186
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
+
187
202
  logger.info(`Brain daemon started (PID: ${process.pid})`);
188
203
  }
189
204
 
190
- stop(): void {
191
- const logger = getLogger();
192
- logger.info('Shutting down...');
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
+ }
193
211
 
212
+ private cleanup(): void {
194
213
  if (this.cleanupTimer) {
195
214
  clearInterval(this.cleanupTimer);
196
215
  this.cleanupTimer = null;
@@ -204,6 +223,34 @@ export class BrainCore {
204
223
  this.ipcServer?.stop();
205
224
  this.db?.close();
206
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
+
207
254
  // Remove PID file
208
255
  if (this.config) {
209
256
  const pidPath = path.join(path.dirname(this.config.dbPath), 'brain.pid');
@@ -1,11 +1,70 @@
1
1
  import { Command } from 'commander';
2
- import { spawn } from 'node:child_process';
2
+ import { spawn, type ChildProcess } from 'node:child_process';
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { getDataDir } from '../../utils/paths.js';
6
6
  import { c, icons } from '../colors.js';
7
7
  import { checkForUpdate } from '../update-check.js';
8
8
 
9
+ const MAX_RESTARTS = 5;
10
+ const RESTART_WINDOW_MS = 5 * 60 * 1000; // 5 minutes
11
+ const BASE_BACKOFF_MS = 1000;
12
+
13
+ function spawnDaemon(entryPoint: string, args: string[]): ChildProcess {
14
+ const child = spawn(process.execPath, [entryPoint, ...args], {
15
+ detached: true,
16
+ stdio: 'ignore',
17
+ });
18
+ child.unref();
19
+ return child;
20
+ }
21
+
22
+ function startWatchdog(entryPoint: string, args: string[], pidPath: string): void {
23
+ const restartTimes: number[] = [];
24
+
25
+ function launch(): void {
26
+ const child = spawnDaemon(entryPoint, args);
27
+ console.log(`${icons.brain} ${c.info('Brain daemon starting')} ${c.dim(`(PID: ${child.pid})`)}`);
28
+
29
+ child.on('exit', (code) => {
30
+ // Normal shutdown (code 0 or SIGTERM) — don't restart
31
+ if (code === 0 || code === null) return;
32
+
33
+ const now = Date.now();
34
+ restartTimes.push(now);
35
+
36
+ // Only count restarts within the window
37
+ const recentRestarts = restartTimes.filter((t) => now - t < RESTART_WINDOW_MS);
38
+ restartTimes.length = 0;
39
+ restartTimes.push(...recentRestarts);
40
+
41
+ if (recentRestarts.length > MAX_RESTARTS) {
42
+ console.error(`${icons.error} ${c.error(`Brain daemon crashed ${MAX_RESTARTS} times in 5 minutes — giving up.`)}`);
43
+ // Clean up stale PID file
44
+ try { fs.unlinkSync(pidPath); } catch { /* ignore */ }
45
+ return;
46
+ }
47
+
48
+ const backoff = BASE_BACKOFF_MS * Math.pow(2, recentRestarts.length - 1);
49
+ console.log(`${icons.warn} ${c.warn(`Brain daemon exited (code ${code}) — restarting in ${backoff / 1000}s...`)}`);
50
+
51
+ setTimeout(launch, backoff);
52
+ });
53
+ }
54
+
55
+ launch();
56
+
57
+ // Wait briefly for PID file to appear
58
+ setTimeout(async () => {
59
+ if (fs.existsSync(pidPath)) {
60
+ console.log(`${icons.ok} ${c.success('Brain daemon started successfully.')} ${c.dim('(watchdog active)')}`);
61
+ } else {
62
+ console.log(`${icons.clock} ${c.warn('Brain daemon may still be starting.')} Check: ${c.cyan('brain status')}`);
63
+ }
64
+ await checkForUpdate();
65
+ }, 1000);
66
+ }
67
+
9
68
  export function startCommand(): Command {
10
69
  return new Command('start')
11
70
  .description('Start the Brain daemon')
@@ -36,27 +95,11 @@ export function startCommand(): Command {
36
95
  return;
37
96
  }
38
97
 
39
- // Spawn detached daemon
98
+ // Spawn detached daemon with watchdog
40
99
  const args = ['daemon'];
41
100
  if (opts.config) args.push('-c', opts.config);
42
-
43
101
  const entryPoint = path.resolve(import.meta.dirname, '../../index.js');
44
- const child = spawn(process.execPath, [entryPoint, ...args], {
45
- detached: true,
46
- stdio: 'ignore',
47
- });
48
- child.unref();
49
-
50
- console.log(`${icons.brain} ${c.info('Brain daemon starting')} ${c.dim(`(PID: ${child.pid})`)}`);
51
-
52
- // Wait briefly for PID file to appear
53
- setTimeout(async () => {
54
- if (fs.existsSync(pidPath)) {
55
- console.log(`${icons.ok} ${c.success('Brain daemon started successfully.')}`);
56
- } else {
57
- console.log(`${icons.clock} ${c.warn('Brain daemon may still be starting.')} Check: ${c.cyan('brain status')}`);
58
- }
59
- await checkForUpdate();
60
- }, 1000);
102
+
103
+ startWatchdog(entryPoint, args, pidPath);
61
104
  });
62
105
  }