@timmeck/brain-core 2.36.12 → 2.36.14

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 (125) hide show
  1. package/dist/cross-brain/__tests__/borg-sync-engine.test.d.ts +1 -0
  2. package/dist/cross-brain/__tests__/borg-sync-engine.test.js +240 -0
  3. package/dist/cross-brain/__tests__/borg-sync-engine.test.js.map +1 -0
  4. package/dist/cross-brain/borg-sync-engine.d.ts +62 -0
  5. package/dist/cross-brain/borg-sync-engine.js +215 -0
  6. package/dist/cross-brain/borg-sync-engine.js.map +1 -0
  7. package/dist/cross-brain/borg-types.d.ts +37 -0
  8. package/dist/cross-brain/borg-types.js +9 -0
  9. package/dist/cross-brain/borg-types.js.map +1 -0
  10. package/dist/embeddings/engine.js +2 -1
  11. package/dist/embeddings/engine.js.map +1 -1
  12. package/dist/index.d.ts +18 -1
  13. package/dist/index.js +14 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/llm/__tests__/anthropic-provider.test.d.ts +1 -0
  16. package/dist/llm/__tests__/anthropic-provider.test.js +121 -0
  17. package/dist/llm/__tests__/anthropic-provider.test.js.map +1 -0
  18. package/dist/llm/__tests__/llm-service.test.js +181 -40
  19. package/dist/llm/__tests__/llm-service.test.js.map +1 -1
  20. package/dist/llm/__tests__/ollama-embedding.test.d.ts +1 -0
  21. package/dist/llm/__tests__/ollama-embedding.test.js +128 -0
  22. package/dist/llm/__tests__/ollama-embedding.test.js.map +1 -0
  23. package/dist/llm/__tests__/ollama-provider.test.d.ts +1 -0
  24. package/dist/llm/__tests__/ollama-provider.test.js +213 -0
  25. package/dist/llm/__tests__/ollama-provider.test.js.map +1 -0
  26. package/dist/llm/__tests__/provider.test.d.ts +1 -0
  27. package/dist/llm/__tests__/provider.test.js +126 -0
  28. package/dist/llm/__tests__/provider.test.js.map +1 -0
  29. package/dist/llm/anthropic-provider.d.ts +41 -0
  30. package/dist/llm/anthropic-provider.js +86 -0
  31. package/dist/llm/anthropic-provider.js.map +1 -0
  32. package/dist/llm/index.d.ts +9 -1
  33. package/dist/llm/index.js +4 -0
  34. package/dist/llm/index.js.map +1 -1
  35. package/dist/llm/llm-service.d.ts +55 -7
  36. package/dist/llm/llm-service.js +184 -82
  37. package/dist/llm/llm-service.js.map +1 -1
  38. package/dist/llm/ollama-embedding.d.ts +46 -0
  39. package/dist/llm/ollama-embedding.js +93 -0
  40. package/dist/llm/ollama-embedding.js.map +1 -0
  41. package/dist/llm/ollama-provider.d.ts +80 -0
  42. package/dist/llm/ollama-provider.js +178 -0
  43. package/dist/llm/ollama-provider.js.map +1 -0
  44. package/dist/llm/provider.d.ts +120 -0
  45. package/dist/llm/provider.js +104 -0
  46. package/dist/llm/provider.js.map +1 -0
  47. package/dist/missions/mission-engine.d.ts +4 -0
  48. package/dist/missions/mission-engine.js +30 -8
  49. package/dist/missions/mission-engine.js.map +1 -1
  50. package/dist/notifications/__tests__/notification-service.test.d.ts +1 -0
  51. package/dist/notifications/__tests__/notification-service.test.js +176 -0
  52. package/dist/notifications/__tests__/notification-service.test.js.map +1 -0
  53. package/dist/notifications/discord-provider.d.ts +30 -0
  54. package/dist/notifications/discord-provider.js +89 -0
  55. package/dist/notifications/discord-provider.js.map +1 -0
  56. package/dist/notifications/email-provider.d.ts +41 -0
  57. package/dist/notifications/email-provider.js +101 -0
  58. package/dist/notifications/email-provider.js.map +1 -0
  59. package/dist/notifications/index.d.ts +8 -0
  60. package/dist/notifications/index.js +5 -0
  61. package/dist/notifications/index.js.map +1 -0
  62. package/dist/notifications/notification-provider.d.ts +75 -0
  63. package/dist/notifications/notification-provider.js +47 -0
  64. package/dist/notifications/notification-provider.js.map +1 -0
  65. package/dist/notifications/notification-service.d.ts +85 -0
  66. package/dist/notifications/notification-service.js +184 -0
  67. package/dist/notifications/notification-service.js.map +1 -0
  68. package/dist/notifications/telegram-provider.d.ts +30 -0
  69. package/dist/notifications/telegram-provider.js +78 -0
  70. package/dist/notifications/telegram-provider.js.map +1 -0
  71. package/dist/plugin/__tests__/plugin-registry.test.d.ts +1 -0
  72. package/dist/plugin/__tests__/plugin-registry.test.js +166 -0
  73. package/dist/plugin/__tests__/plugin-registry.test.js.map +1 -0
  74. package/dist/plugin/plugin-registry.d.ts +38 -0
  75. package/dist/plugin/plugin-registry.js +185 -0
  76. package/dist/plugin/plugin-registry.js.map +1 -0
  77. package/dist/plugin/types.d.ts +59 -0
  78. package/dist/plugin/types.js +2 -0
  79. package/dist/plugin/types.js.map +1 -0
  80. package/dist/research/adapters/__tests__/web-adapters.test.d.ts +1 -0
  81. package/dist/research/adapters/__tests__/web-adapters.test.js +106 -0
  82. package/dist/research/adapters/__tests__/web-adapters.test.js.map +1 -0
  83. package/dist/research/adapters/firecrawl-adapter.d.ts +57 -0
  84. package/dist/research/adapters/firecrawl-adapter.js +137 -0
  85. package/dist/research/adapters/firecrawl-adapter.js.map +1 -0
  86. package/dist/research/adapters/index.d.ts +3 -0
  87. package/dist/research/adapters/index.js +2 -0
  88. package/dist/research/adapters/index.js.map +1 -1
  89. package/dist/research/adapters/playwright-adapter.d.ts +54 -0
  90. package/dist/research/adapters/playwright-adapter.js +130 -0
  91. package/dist/research/adapters/playwright-adapter.js.map +1 -0
  92. package/dist/research/research-orchestrator.d.ts +3 -0
  93. package/dist/research/research-orchestrator.js +19 -1
  94. package/dist/research/research-orchestrator.js.map +1 -1
  95. package/dist/techradar/__tests__/techradar-engine.test.d.ts +1 -0
  96. package/dist/techradar/__tests__/techradar-engine.test.js +246 -0
  97. package/dist/techradar/__tests__/techradar-engine.test.js.map +1 -0
  98. package/dist/techradar/daily-digest.d.ts +18 -0
  99. package/dist/techradar/daily-digest.js +100 -0
  100. package/dist/techradar/daily-digest.js.map +1 -0
  101. package/dist/techradar/index.d.ts +5 -0
  102. package/dist/techradar/index.js +5 -0
  103. package/dist/techradar/index.js.map +1 -0
  104. package/dist/techradar/relevance-scorer.d.ts +29 -0
  105. package/dist/techradar/relevance-scorer.js +139 -0
  106. package/dist/techradar/relevance-scorer.js.map +1 -0
  107. package/dist/techradar/repo-watcher.d.ts +24 -0
  108. package/dist/techradar/repo-watcher.js +87 -0
  109. package/dist/techradar/repo-watcher.js.map +1 -0
  110. package/dist/techradar/techradar-engine.d.ts +69 -0
  111. package/dist/techradar/techradar-engine.js +382 -0
  112. package/dist/techradar/techradar-engine.js.map +1 -0
  113. package/dist/techradar/types.d.ts +87 -0
  114. package/dist/techradar/types.js +5 -0
  115. package/dist/techradar/types.js.map +1 -0
  116. package/dist/watchdog/__tests__/watchdog-service.test.d.ts +1 -0
  117. package/dist/watchdog/__tests__/watchdog-service.test.js +113 -0
  118. package/dist/watchdog/__tests__/watchdog-service.test.js.map +1 -0
  119. package/dist/watchdog/watchdog-service.d.ts +60 -0
  120. package/dist/watchdog/watchdog-service.js +275 -0
  121. package/dist/watchdog/watchdog-service.js.map +1 -0
  122. package/dist/watchdog/windows-service.d.ts +39 -0
  123. package/dist/watchdog/windows-service.js +179 -0
  124. package/dist/watchdog/windows-service.js.map +1 -0
  125. package/package.json +20 -2
@@ -0,0 +1,113 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { WatchdogService, createDefaultWatchdogConfig } from '../watchdog-service.js';
3
+ // Mock child_process
4
+ vi.mock('node:child_process', () => ({
5
+ spawn: vi.fn().mockReturnValue({
6
+ pid: 12345,
7
+ unref: vi.fn(),
8
+ on: vi.fn(),
9
+ }),
10
+ }));
11
+ // Mock IpcClient
12
+ vi.mock('../../ipc/client.js', () => ({
13
+ IpcClient: vi.fn().mockImplementation(() => ({
14
+ connect: vi.fn().mockResolvedValue(undefined),
15
+ request: vi.fn().mockResolvedValue({ status: 'ok' }),
16
+ disconnect: vi.fn(),
17
+ })),
18
+ }));
19
+ function createTestConfig() {
20
+ return {
21
+ daemons: [
22
+ {
23
+ name: 'test-brain',
24
+ entryPoint: '/fake/path/index.js',
25
+ args: ['daemon'],
26
+ pidPath: '/tmp/test-brain.pid',
27
+ pipeName: '\\\\.\\pipe\\test-brain',
28
+ },
29
+ {
30
+ name: 'test-trading',
31
+ entryPoint: '/fake/path/trading/index.js',
32
+ args: ['daemon'],
33
+ pidPath: '/tmp/test-trading.pid',
34
+ pipeName: '\\\\.\\pipe\\test-trading',
35
+ },
36
+ ],
37
+ maxRestarts: 3,
38
+ restartWindowMs: 60_000,
39
+ baseBackoffMs: 100,
40
+ healthCheckIntervalMs: 1000,
41
+ };
42
+ }
43
+ describe('WatchdogService', () => {
44
+ beforeEach(() => {
45
+ vi.clearAllMocks();
46
+ });
47
+ it('creates with configured daemons', () => {
48
+ const config = createTestConfig();
49
+ const watchdog = new WatchdogService(config);
50
+ const status = watchdog.getStatus();
51
+ expect(status).toHaveLength(2);
52
+ expect(status[0].name).toBe('test-brain');
53
+ expect(status[1].name).toBe('test-trading');
54
+ expect(status[0].running).toBe(false);
55
+ expect(status[0].restarts).toBe(0);
56
+ });
57
+ it('returns null for unknown daemon', () => {
58
+ const watchdog = new WatchdogService(createTestConfig());
59
+ expect(watchdog.getDaemonStatus('nonexistent')).toBeNull();
60
+ });
61
+ it('gets individual daemon status', () => {
62
+ const watchdog = new WatchdogService(createTestConfig());
63
+ const status = watchdog.getDaemonStatus('test-brain');
64
+ expect(status).not.toBeNull();
65
+ expect(status.name).toBe('test-brain');
66
+ expect(status.pid).toBeNull();
67
+ expect(status.healthy).toBe(false);
68
+ });
69
+ it('restartDaemon returns false for unknown daemon', () => {
70
+ const watchdog = new WatchdogService(createTestConfig());
71
+ expect(watchdog.restartDaemon('nonexistent')).toBe(false);
72
+ });
73
+ it('stop is safe when not started', () => {
74
+ const watchdog = new WatchdogService(createTestConfig());
75
+ expect(() => watchdog.stop()).not.toThrow();
76
+ });
77
+ it('getStatus returns uptime as null when not started', () => {
78
+ const watchdog = new WatchdogService(createTestConfig());
79
+ const status = watchdog.getStatus();
80
+ for (const s of status) {
81
+ expect(s.uptime).toBeNull();
82
+ expect(s.lastCrash).toBeNull();
83
+ }
84
+ });
85
+ });
86
+ describe('createDefaultWatchdogConfig', () => {
87
+ it('creates config with 3 brain daemons', () => {
88
+ const config = createDefaultWatchdogConfig();
89
+ expect(config.daemons).toHaveLength(3);
90
+ expect(config.daemons.map(d => d.name)).toEqual([
91
+ 'brain',
92
+ 'trading-brain',
93
+ 'marketing-brain',
94
+ ]);
95
+ });
96
+ it('each daemon has required fields', () => {
97
+ const config = createDefaultWatchdogConfig();
98
+ for (const d of config.daemons) {
99
+ expect(d.name).toBeTruthy();
100
+ expect(d.entryPoint).toBeTruthy();
101
+ expect(d.args).toContain('daemon');
102
+ expect(d.pidPath).toBeTruthy();
103
+ expect(d.pipeName).toBeTruthy();
104
+ }
105
+ });
106
+ it('pipe names contain daemon name', () => {
107
+ const config = createDefaultWatchdogConfig();
108
+ expect(config.daemons[0].pipeName).toContain('brain');
109
+ expect(config.daemons[1].pipeName).toContain('trading');
110
+ expect(config.daemons[2].pipeName).toContain('marketing');
111
+ });
112
+ });
113
+ //# sourceMappingURL=watchdog-service.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watchdog-service.test.js","sourceRoot":"","sources":["../../../src/watchdog/__tests__/watchdog-service.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ export interface DaemonConfig {
2
+ name: string;
3
+ entryPoint: string;
4
+ args: string[];
5
+ pidPath: string;
6
+ pipeName: string;
7
+ healthCheckIntervalMs?: number;
8
+ }
9
+ export interface DaemonStatus {
10
+ name: string;
11
+ pid: number | null;
12
+ running: boolean;
13
+ healthy: boolean;
14
+ uptime: number | null;
15
+ restarts: number;
16
+ lastCrash: string | null;
17
+ }
18
+ export interface WatchdogConfig {
19
+ daemons: DaemonConfig[];
20
+ maxRestarts?: number;
21
+ restartWindowMs?: number;
22
+ baseBackoffMs?: number;
23
+ healthCheckIntervalMs?: number;
24
+ }
25
+ /**
26
+ * WatchdogService — monitors and auto-restarts multiple Brain daemons.
27
+ * Provides health checks via IPC ping, exponential backoff on crashes,
28
+ * and unified status reporting.
29
+ */
30
+ export declare class WatchdogService {
31
+ private daemons;
32
+ private healthTimer;
33
+ private running;
34
+ private logger;
35
+ private maxRestarts;
36
+ private restartWindowMs;
37
+ private baseBackoffMs;
38
+ private healthCheckIntervalMs;
39
+ constructor(config: WatchdogConfig);
40
+ /** Start all configured daemons and begin health monitoring. */
41
+ start(): void;
42
+ /** Stop all daemons and health monitoring. */
43
+ stop(): void;
44
+ /** Get status of all daemons. */
45
+ getStatus(): DaemonStatus[];
46
+ /** Get status of a single daemon. */
47
+ getDaemonStatus(name: string): DaemonStatus | null;
48
+ /** Restart a specific daemon. */
49
+ restartDaemon(name: string): boolean;
50
+ private launchDaemon;
51
+ /** Health check — ping each daemon via IPC. */
52
+ private checkHealth;
53
+ private readPid;
54
+ private isProcessAlive;
55
+ }
56
+ /**
57
+ * Create a default WatchdogConfig for the Brain Ecosystem.
58
+ * Discovers installed brains by checking for their entry points.
59
+ */
60
+ export declare function createDefaultWatchdogConfig(): WatchdogConfig;
@@ -0,0 +1,275 @@
1
+ import { spawn } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { getLogger } from '../utils/logger.js';
5
+ import { IpcClient } from '../ipc/client.js';
6
+ import { getPipeName } from '../utils/paths.js';
7
+ /**
8
+ * WatchdogService — monitors and auto-restarts multiple Brain daemons.
9
+ * Provides health checks via IPC ping, exponential backoff on crashes,
10
+ * and unified status reporting.
11
+ */
12
+ export class WatchdogService {
13
+ daemons = new Map();
14
+ healthTimer = null;
15
+ running = false;
16
+ logger = getLogger();
17
+ maxRestarts;
18
+ restartWindowMs;
19
+ baseBackoffMs;
20
+ healthCheckIntervalMs;
21
+ constructor(config) {
22
+ this.maxRestarts = config.maxRestarts ?? 5;
23
+ this.restartWindowMs = config.restartWindowMs ?? 5 * 60 * 1000;
24
+ this.baseBackoffMs = config.baseBackoffMs ?? 1000;
25
+ this.healthCheckIntervalMs = config.healthCheckIntervalMs ?? 30_000;
26
+ for (const d of config.daemons) {
27
+ this.daemons.set(d.name, {
28
+ config: d,
29
+ process: null,
30
+ pid: null,
31
+ running: false,
32
+ healthy: false,
33
+ startedAt: null,
34
+ restarts: 0,
35
+ restartTimes: [],
36
+ lastCrash: null,
37
+ });
38
+ }
39
+ }
40
+ /** Start all configured daemons and begin health monitoring. */
41
+ start() {
42
+ if (this.running)
43
+ return;
44
+ this.running = true;
45
+ this.logger.info(`Watchdog starting (${this.daemons.size} daemons)`);
46
+ for (const [name] of this.daemons) {
47
+ this.launchDaemon(name);
48
+ }
49
+ this.healthTimer = setInterval(() => {
50
+ this.checkHealth().catch(err => this.logger.error(`Health check error: ${err}`));
51
+ }, this.healthCheckIntervalMs);
52
+ }
53
+ /** Stop all daemons and health monitoring. */
54
+ stop() {
55
+ this.running = false;
56
+ if (this.healthTimer) {
57
+ clearInterval(this.healthTimer);
58
+ this.healthTimer = null;
59
+ }
60
+ for (const [name, state] of this.daemons) {
61
+ if (state.pid) {
62
+ try {
63
+ process.kill(state.pid, 'SIGTERM');
64
+ this.logger.info(`Sent SIGTERM to ${name} (PID: ${state.pid})`);
65
+ }
66
+ catch {
67
+ // Already dead
68
+ }
69
+ }
70
+ state.running = false;
71
+ state.process = null;
72
+ }
73
+ this.logger.info('Watchdog stopped');
74
+ }
75
+ /** Get status of all daemons. */
76
+ getStatus() {
77
+ const result = [];
78
+ for (const [, state] of this.daemons) {
79
+ result.push({
80
+ name: state.config.name,
81
+ pid: state.pid,
82
+ running: state.running,
83
+ healthy: state.healthy,
84
+ uptime: state.startedAt ? Date.now() - state.startedAt : null,
85
+ restarts: state.restarts,
86
+ lastCrash: state.lastCrash,
87
+ });
88
+ }
89
+ return result;
90
+ }
91
+ /** Get status of a single daemon. */
92
+ getDaemonStatus(name) {
93
+ const state = this.daemons.get(name);
94
+ if (!state)
95
+ return null;
96
+ return {
97
+ name: state.config.name,
98
+ pid: state.pid,
99
+ running: state.running,
100
+ healthy: state.healthy,
101
+ uptime: state.startedAt ? Date.now() - state.startedAt : null,
102
+ restarts: state.restarts,
103
+ lastCrash: state.lastCrash,
104
+ };
105
+ }
106
+ /** Restart a specific daemon. */
107
+ restartDaemon(name) {
108
+ const state = this.daemons.get(name);
109
+ if (!state)
110
+ return false;
111
+ if (state.pid) {
112
+ try {
113
+ process.kill(state.pid, 'SIGTERM');
114
+ }
115
+ catch { /* already dead */ }
116
+ }
117
+ state.running = false;
118
+ state.process = null;
119
+ this.launchDaemon(name);
120
+ return true;
121
+ }
122
+ launchDaemon(name) {
123
+ const state = this.daemons.get(name);
124
+ if (!state)
125
+ return;
126
+ const { config } = state;
127
+ // Check if already running via PID file
128
+ const existingPid = this.readPid(config.pidPath);
129
+ if (existingPid && this.isProcessAlive(existingPid)) {
130
+ this.logger.info(`${name} already running (PID: ${existingPid})`);
131
+ state.pid = existingPid;
132
+ state.running = true;
133
+ state.startedAt = Date.now();
134
+ return;
135
+ }
136
+ // Clean stale PID
137
+ try {
138
+ fs.unlinkSync(config.pidPath);
139
+ }
140
+ catch { /* ignore */ }
141
+ // Spawn
142
+ const isTsSource = !fs.existsSync(config.entryPoint);
143
+ let cmdArgs;
144
+ if (isTsSource) {
145
+ const tsEntry = config.entryPoint.replace(/\.js$/, '.ts');
146
+ cmdArgs = ['--import', 'tsx', tsEntry, ...config.args];
147
+ }
148
+ else {
149
+ cmdArgs = [config.entryPoint, ...config.args];
150
+ }
151
+ const child = spawn(process.execPath, cmdArgs, {
152
+ detached: true,
153
+ stdio: 'ignore',
154
+ });
155
+ child.unref();
156
+ state.process = child;
157
+ state.pid = child.pid ?? null;
158
+ state.running = true;
159
+ state.startedAt = Date.now();
160
+ this.logger.info(`${name} launched (PID: ${child.pid})`);
161
+ child.on('exit', (code) => {
162
+ if (!this.running)
163
+ return; // watchdog stopped, don't restart
164
+ state.running = false;
165
+ state.healthy = false;
166
+ state.process = null;
167
+ if (code === 0 || code === null) {
168
+ this.logger.info(`${name} stopped normally`);
169
+ return;
170
+ }
171
+ state.lastCrash = new Date().toISOString();
172
+ state.restarts++;
173
+ this.logger.warn(`${name} crashed (code ${code})`);
174
+ // Rate limit restarts
175
+ const now = Date.now();
176
+ state.restartTimes.push(now);
177
+ const recent = state.restartTimes.filter(t => now - t < this.restartWindowMs);
178
+ state.restartTimes = recent;
179
+ if (recent.length > this.maxRestarts) {
180
+ this.logger.error(`${name} crashed ${this.maxRestarts} times in ${this.restartWindowMs / 1000}s — giving up`);
181
+ try {
182
+ fs.unlinkSync(config.pidPath);
183
+ }
184
+ catch { /* ignore */ }
185
+ return;
186
+ }
187
+ const backoff = this.baseBackoffMs * Math.pow(2, recent.length - 1);
188
+ this.logger.info(`${name} restarting in ${backoff}ms (attempt ${recent.length}/${this.maxRestarts})`);
189
+ setTimeout(() => {
190
+ if (this.running)
191
+ this.launchDaemon(name);
192
+ }, backoff);
193
+ });
194
+ }
195
+ /** Health check — ping each daemon via IPC. */
196
+ async checkHealth() {
197
+ for (const [name, state] of this.daemons) {
198
+ if (!state.running || !state.pid) {
199
+ state.healthy = false;
200
+ continue;
201
+ }
202
+ // First check if process is alive
203
+ if (!this.isProcessAlive(state.pid)) {
204
+ state.healthy = false;
205
+ state.running = false;
206
+ this.logger.warn(`${name} PID ${state.pid} no longer alive`);
207
+ if (this.running)
208
+ this.launchDaemon(name);
209
+ continue;
210
+ }
211
+ // IPC health ping
212
+ const client = new IpcClient(state.config.pipeName, 3000);
213
+ try {
214
+ await client.connect();
215
+ await client.request('status');
216
+ state.healthy = true;
217
+ }
218
+ catch {
219
+ state.healthy = false;
220
+ this.logger.debug(`${name} IPC health check failed (process alive but IPC unreachable)`);
221
+ }
222
+ finally {
223
+ client.disconnect();
224
+ }
225
+ }
226
+ }
227
+ readPid(pidPath) {
228
+ try {
229
+ const content = fs.readFileSync(pidPath, 'utf-8').trim();
230
+ const pid = parseInt(content, 10);
231
+ return isNaN(pid) ? null : pid;
232
+ }
233
+ catch {
234
+ return null;
235
+ }
236
+ }
237
+ isProcessAlive(pid) {
238
+ try {
239
+ process.kill(pid, 0);
240
+ return true;
241
+ }
242
+ catch {
243
+ return false;
244
+ }
245
+ }
246
+ }
247
+ /**
248
+ * Create a default WatchdogConfig for the Brain Ecosystem.
249
+ * Discovers installed brains by checking for their entry points.
250
+ */
251
+ export function createDefaultWatchdogConfig() {
252
+ const daemons = [];
253
+ // Try to discover brain packages relative to brain-core
254
+ const coreDir = path.resolve(import.meta.dirname, '../..');
255
+ const packagesDir = path.resolve(coreDir, '..');
256
+ const brainDefs = [
257
+ { name: 'brain', pkg: 'brain', dataDir: '.brain', pipeSuffix: 'brain' },
258
+ { name: 'trading-brain', pkg: 'trading-brain', dataDir: '.trading-brain', pipeSuffix: 'trading-brain' },
259
+ { name: 'marketing-brain', pkg: 'marketing-brain', dataDir: '.marketing-brain', pipeSuffix: 'marketing-brain' },
260
+ ];
261
+ for (const def of brainDefs) {
262
+ const entryPoint = path.join(packagesDir, def.pkg, 'dist', 'index.js');
263
+ const homeDir = process.env['HOME'] || process.env['USERPROFILE'] || '';
264
+ const pidPath = path.join(homeDir, def.dataDir, `${def.name}.pid`);
265
+ daemons.push({
266
+ name: def.name,
267
+ entryPoint,
268
+ args: ['daemon'],
269
+ pidPath,
270
+ pipeName: getPipeName(def.pipeSuffix),
271
+ });
272
+ }
273
+ return { daemons };
274
+ }
275
+ //# sourceMappingURL=watchdog-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watchdog-service.js","sourceRoot":"","sources":["../../src/watchdog/watchdog-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ export interface ServiceConfig {
2
+ name: string;
3
+ displayName: string;
4
+ description: string;
5
+ entryPoint: string;
6
+ args: string[];
7
+ }
8
+ export interface ServiceStatus {
9
+ name: string;
10
+ installed: boolean;
11
+ state: 'running' | 'stopped' | 'pending' | 'unknown';
12
+ }
13
+ /**
14
+ * WindowsServiceManager — installs/manages Brain daemons as Windows services.
15
+ * Uses NSSM (Non-Sucking Service Manager) or SC.exe for service management.
16
+ * Optional: only works on Windows, graceful no-op on other platforms.
17
+ */
18
+ export declare class WindowsServiceManager {
19
+ private logger;
20
+ private nssmPath;
21
+ constructor();
22
+ /** Check if we're on Windows and can manage services. */
23
+ isAvailable(): boolean;
24
+ /** Install a Brain daemon as a Windows service. */
25
+ install(config: ServiceConfig): boolean;
26
+ /** Uninstall a Brain service. */
27
+ uninstall(name: string): boolean;
28
+ /** Start a service. */
29
+ startService(name: string): boolean;
30
+ /** Stop a service. */
31
+ stopService(name: string): boolean;
32
+ /** Query service status. */
33
+ queryStatus(name: string): ServiceStatus;
34
+ /** Query status of all Brain services. */
35
+ queryAll(): ServiceStatus[];
36
+ private findNssm;
37
+ private createWrapperScript;
38
+ private getLogPath;
39
+ }