@timmeck/brain-core 2.36.11 → 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 (127) 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/self-modification/self-modification-engine.js +28 -4
  96. package/dist/self-modification/self-modification-engine.js.map +1 -1
  97. package/dist/techradar/__tests__/techradar-engine.test.d.ts +1 -0
  98. package/dist/techradar/__tests__/techradar-engine.test.js +246 -0
  99. package/dist/techradar/__tests__/techradar-engine.test.js.map +1 -0
  100. package/dist/techradar/daily-digest.d.ts +18 -0
  101. package/dist/techradar/daily-digest.js +100 -0
  102. package/dist/techradar/daily-digest.js.map +1 -0
  103. package/dist/techradar/index.d.ts +5 -0
  104. package/dist/techradar/index.js +5 -0
  105. package/dist/techradar/index.js.map +1 -0
  106. package/dist/techradar/relevance-scorer.d.ts +29 -0
  107. package/dist/techradar/relevance-scorer.js +139 -0
  108. package/dist/techradar/relevance-scorer.js.map +1 -0
  109. package/dist/techradar/repo-watcher.d.ts +24 -0
  110. package/dist/techradar/repo-watcher.js +87 -0
  111. package/dist/techradar/repo-watcher.js.map +1 -0
  112. package/dist/techradar/techradar-engine.d.ts +69 -0
  113. package/dist/techradar/techradar-engine.js +382 -0
  114. package/dist/techradar/techradar-engine.js.map +1 -0
  115. package/dist/techradar/types.d.ts +87 -0
  116. package/dist/techradar/types.js +5 -0
  117. package/dist/techradar/types.js.map +1 -0
  118. package/dist/watchdog/__tests__/watchdog-service.test.d.ts +1 -0
  119. package/dist/watchdog/__tests__/watchdog-service.test.js +113 -0
  120. package/dist/watchdog/__tests__/watchdog-service.test.js.map +1 -0
  121. package/dist/watchdog/watchdog-service.d.ts +60 -0
  122. package/dist/watchdog/watchdog-service.js +275 -0
  123. package/dist/watchdog/watchdog-service.js.map +1 -0
  124. package/dist/watchdog/windows-service.d.ts +39 -0
  125. package/dist/watchdog/windows-service.js +179 -0
  126. package/dist/watchdog/windows-service.js.map +1 -0
  127. package/package.json +20 -2
@@ -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
+ }
@@ -0,0 +1,179 @@
1
+ import { execSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { getLogger } from '../utils/logger.js';
5
+ /**
6
+ * WindowsServiceManager — installs/manages Brain daemons as Windows services.
7
+ * Uses NSSM (Non-Sucking Service Manager) or SC.exe for service management.
8
+ * Optional: only works on Windows, graceful no-op on other platforms.
9
+ */
10
+ export class WindowsServiceManager {
11
+ logger = getLogger();
12
+ nssmPath = null;
13
+ constructor() {
14
+ if (process.platform === 'win32') {
15
+ this.nssmPath = this.findNssm();
16
+ }
17
+ }
18
+ /** Check if we're on Windows and can manage services. */
19
+ isAvailable() {
20
+ return process.platform === 'win32';
21
+ }
22
+ /** Install a Brain daemon as a Windows service. */
23
+ install(config) {
24
+ if (!this.isAvailable()) {
25
+ this.logger.warn('Windows service management only available on Windows');
26
+ return false;
27
+ }
28
+ const serviceName = `BrainEcosystem_${config.name}`;
29
+ // Create a wrapper script that node can execute
30
+ const wrapperPath = this.createWrapperScript(config);
31
+ try {
32
+ if (this.nssmPath) {
33
+ // NSSM approach (preferred — proper service lifecycle)
34
+ execSync(`"${this.nssmPath}" install "${serviceName}" "${process.execPath}" "${wrapperPath}"`, { stdio: 'pipe' });
35
+ execSync(`"${this.nssmPath}" set "${serviceName}" DisplayName "${config.displayName}"`, { stdio: 'pipe' });
36
+ execSync(`"${this.nssmPath}" set "${serviceName}" Description "${config.description}"`, { stdio: 'pipe' });
37
+ execSync(`"${this.nssmPath}" set "${serviceName}" AppStdout "${this.getLogPath(config.name)}"`, { stdio: 'pipe' });
38
+ execSync(`"${this.nssmPath}" set "${serviceName}" AppStderr "${this.getLogPath(config.name)}"`, { stdio: 'pipe' });
39
+ execSync(`"${this.nssmPath}" set "${serviceName}" Start SERVICE_AUTO_START`, { stdio: 'pipe' });
40
+ }
41
+ else {
42
+ // SC.exe fallback
43
+ const binPath = `"${process.execPath}" "${wrapperPath}"`;
44
+ execSync(`sc create "${serviceName}" binPath= ${binPath} DisplayName= "${config.displayName}" start= auto`, { stdio: 'pipe' });
45
+ execSync(`sc description "${serviceName}" "${config.description}"`, { stdio: 'pipe' });
46
+ }
47
+ this.logger.info(`Service ${serviceName} installed`);
48
+ return true;
49
+ }
50
+ catch (err) {
51
+ this.logger.error(`Failed to install service: ${err.message}`);
52
+ return false;
53
+ }
54
+ }
55
+ /** Uninstall a Brain service. */
56
+ uninstall(name) {
57
+ if (!this.isAvailable())
58
+ return false;
59
+ const serviceName = `BrainEcosystem_${name}`;
60
+ try {
61
+ this.stopService(name);
62
+ if (this.nssmPath) {
63
+ execSync(`"${this.nssmPath}" remove "${serviceName}" confirm`, { stdio: 'pipe' });
64
+ }
65
+ else {
66
+ execSync(`sc delete "${serviceName}"`, { stdio: 'pipe' });
67
+ }
68
+ this.logger.info(`Service ${serviceName} uninstalled`);
69
+ return true;
70
+ }
71
+ catch (err) {
72
+ this.logger.error(`Failed to uninstall service: ${err.message}`);
73
+ return false;
74
+ }
75
+ }
76
+ /** Start a service. */
77
+ startService(name) {
78
+ if (!this.isAvailable())
79
+ return false;
80
+ const serviceName = `BrainEcosystem_${name}`;
81
+ try {
82
+ execSync(`sc start "${serviceName}"`, { stdio: 'pipe' });
83
+ return true;
84
+ }
85
+ catch {
86
+ return false;
87
+ }
88
+ }
89
+ /** Stop a service. */
90
+ stopService(name) {
91
+ if (!this.isAvailable())
92
+ return false;
93
+ const serviceName = `BrainEcosystem_${name}`;
94
+ try {
95
+ execSync(`sc stop "${serviceName}"`, { stdio: 'pipe' });
96
+ return true;
97
+ }
98
+ catch {
99
+ return false;
100
+ }
101
+ }
102
+ /** Query service status. */
103
+ queryStatus(name) {
104
+ const serviceName = `BrainEcosystem_${name}`;
105
+ const result = { name, installed: false, state: 'unknown' };
106
+ if (!this.isAvailable())
107
+ return result;
108
+ try {
109
+ const output = execSync(`sc query "${serviceName}"`, { stdio: 'pipe', encoding: 'utf-8' });
110
+ result.installed = true;
111
+ if (output.includes('RUNNING'))
112
+ result.state = 'running';
113
+ else if (output.includes('STOPPED'))
114
+ result.state = 'stopped';
115
+ else if (output.includes('PENDING'))
116
+ result.state = 'pending';
117
+ }
118
+ catch {
119
+ result.installed = false;
120
+ result.state = 'unknown';
121
+ }
122
+ return result;
123
+ }
124
+ /** Query status of all Brain services. */
125
+ queryAll() {
126
+ return ['brain', 'trading-brain', 'marketing-brain'].map(name => this.queryStatus(name));
127
+ }
128
+ findNssm() {
129
+ try {
130
+ execSync('nssm version', { stdio: 'pipe' });
131
+ return 'nssm';
132
+ }
133
+ catch {
134
+ // Check common install locations
135
+ const paths = [
136
+ 'C:\\nssm\\nssm.exe',
137
+ 'C:\\tools\\nssm\\nssm.exe',
138
+ path.join(process.env['PROGRAMFILES'] ?? '', 'nssm', 'nssm.exe'),
139
+ ];
140
+ for (const p of paths) {
141
+ if (fs.existsSync(p))
142
+ return p;
143
+ }
144
+ return null;
145
+ }
146
+ }
147
+ createWrapperScript(config) {
148
+ const homeDir = process.env['USERPROFILE'] ?? process.env['HOME'] ?? '';
149
+ const wrapperDir = path.join(homeDir, '.brain', 'services');
150
+ fs.mkdirSync(wrapperDir, { recursive: true });
151
+ const wrapperPath = path.join(wrapperDir, `${config.name}-service.js`);
152
+ const content = `
153
+ // Auto-generated Windows service wrapper for ${config.name}
154
+ const { spawn } = require('child_process');
155
+ const path = require('path');
156
+
157
+ const child = spawn(process.execPath, ${JSON.stringify([config.entryPoint, ...config.args])}, {
158
+ stdio: 'inherit',
159
+ cwd: path.dirname(${JSON.stringify(config.entryPoint)}),
160
+ });
161
+
162
+ child.on('exit', (code) => {
163
+ process.exit(code ?? 0);
164
+ });
165
+
166
+ process.on('SIGTERM', () => child.kill('SIGTERM'));
167
+ process.on('SIGINT', () => child.kill('SIGINT'));
168
+ `;
169
+ fs.writeFileSync(wrapperPath, content, 'utf-8');
170
+ return wrapperPath;
171
+ }
172
+ getLogPath(name) {
173
+ const homeDir = process.env['USERPROFILE'] ?? process.env['HOME'] ?? '';
174
+ const logDir = path.join(homeDir, '.brain', 'services', 'logs');
175
+ fs.mkdirSync(logDir, { recursive: true });
176
+ return path.join(logDir, `${name}-service.log`);
177
+ }
178
+ }
179
+ //# sourceMappingURL=windows-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-service.js","sourceRoot":"","sources":["../../src/watchdog/windows-service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timmeck/brain-core",
3
- "version": "2.36.11",
3
+ "version": "2.36.14",
4
4
  "description": "Shared core infrastructure for the Brain ecosystem — IPC, MCP, CLI, DB connection, and utilities",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -83,22 +83,40 @@
83
83
  "directory": "packages/brain-core"
84
84
  },
85
85
  "peerDependencies": {
86
- "@huggingface/transformers": "^3.0.0"
86
+ "@huggingface/transformers": "^3.0.0",
87
+ "discord.js": "^14.0.0",
88
+ "grammy": "^1.0.0",
89
+ "nodemailer": "^6.0.0 || ^7.0.0 || ^8.0.0",
90
+ "playwright": "^1.40.0"
87
91
  },
88
92
  "peerDependenciesMeta": {
89
93
  "@huggingface/transformers": {
90
94
  "optional": true
95
+ },
96
+ "discord.js": {
97
+ "optional": true
98
+ },
99
+ "grammy": {
100
+ "optional": true
101
+ },
102
+ "nodemailer": {
103
+ "optional": true
104
+ },
105
+ "playwright": {
106
+ "optional": true
91
107
  }
92
108
  },
93
109
  "dependencies": {
94
110
  "@modelcontextprotocol/sdk": "^1.0.0",
95
111
  "better-sqlite3": "^11.7.0",
96
112
  "chalk": "^5.6.2",
113
+ "ollama": "^0.6.3",
97
114
  "winston": "^3.17.0"
98
115
  },
99
116
  "devDependencies": {
100
117
  "@types/better-sqlite3": "^7.6.12",
101
118
  "@types/node": "^22.0.0",
119
+ "@types/nodemailer": "^7.0.11",
102
120
  "@vitest/coverage-v8": "^3.2.4",
103
121
  "eslint": "^9.39.3",
104
122
  "tsx": "^4.19.0",