@timmeck/brain 3.36.55 → 3.36.56

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.
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Lifecycle helpers — extracted from BrainCore.logCrash, runRetentionCleanup, cleanup, restart, stop.
3
+ * Pure extraction, no logic changes.
4
+ */
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import { getLogger } from '../utils/logger.js';
8
+ // ── Standalone helpers (no BrainCore refs needed) ──────────
9
+ export function logCrash(config, type, err) {
10
+ if (!config)
11
+ return;
12
+ const crashLog = path.join(path.dirname(config.dbPath), 'crashes.log');
13
+ const entry = `[${new Date().toISOString()}] ${type}: ${err.message}\n${err.stack ?? ''}\n\n`;
14
+ try {
15
+ // Rotate crash log if > 5MB (max 1 rotation = 10MB total)
16
+ try {
17
+ const stat = fs.statSync(crashLog);
18
+ if (stat.size > 5 * 1024 * 1024) {
19
+ const rotated = crashLog.replace('.log', '.1.log');
20
+ try {
21
+ fs.unlinkSync(rotated);
22
+ }
23
+ catch { /* no previous rotation */ }
24
+ fs.renameSync(crashLog, rotated);
25
+ }
26
+ }
27
+ catch { /* file doesn't exist yet */ }
28
+ fs.appendFileSync(crashLog, entry);
29
+ }
30
+ catch { /* best effort */ }
31
+ }
32
+ export function runRetentionCleanup(db, config) {
33
+ const logger = getLogger();
34
+ try {
35
+ const now = Date.now();
36
+ const errorCutoff = new Date(now - config.retention.errorDays * 86_400_000).toISOString();
37
+ const insightCutoff = new Date(now - config.retention.insightDays * 2 * 86_400_000).toISOString();
38
+ // Delete resolved errors older than retention period
39
+ const errResult = db.prepare("DELETE FROM errors WHERE status = 'resolved' AND created_at < ?").run(errorCutoff);
40
+ // Delete inactive insights older than 2× insightDays
41
+ const insResult = db.prepare("DELETE FROM insights WHERE status = 'inactive' AND created_at < ?").run(insightCutoff);
42
+ if (Number(errResult.changes) > 0 || Number(insResult.changes) > 0) {
43
+ logger.info(`[retention] Cleaned up ${errResult.changes} old errors, ${insResult.changes} old insights`);
44
+ }
45
+ // Optimize DB
46
+ db.pragma('optimize');
47
+ logger.debug('[retention] DB optimized');
48
+ }
49
+ catch (err) {
50
+ logger.warn(`[retention] Cleanup failed (non-critical): ${err.message}`);
51
+ }
52
+ }
53
+ export function cleanup(refs) {
54
+ if (refs.cleanupTimer) {
55
+ clearInterval(refs.cleanupTimer);
56
+ refs.cleanupTimer = null;
57
+ }
58
+ if (refs.retentionTimer) {
59
+ clearInterval(refs.retentionTimer);
60
+ refs.retentionTimer = null;
61
+ }
62
+ refs.borgSync?.stop();
63
+ // Stop messaging bots
64
+ refs.telegramBot?.stop().catch(() => { });
65
+ refs.discordBot?.stop().catch(() => { });
66
+ refs.peerNetwork?.stopDiscovery();
67
+ // Unload all plugins gracefully
68
+ if (refs.pluginRegistry?.size) {
69
+ for (const p of refs.pluginRegistry.list()) {
70
+ refs.pluginRegistry.unloadPlugin(p.name).catch(() => { });
71
+ }
72
+ }
73
+ refs.subscriptionManager?.disconnectAll();
74
+ refs.attentionEngine?.stop();
75
+ refs.commandCenter?.stop();
76
+ refs.orchestrator?.stop();
77
+ refs.researchScheduler?.stop();
78
+ refs.researchEngine?.stop();
79
+ refs.embeddingEngine?.stop();
80
+ refs.learningEngine?.stop();
81
+ refs.mcpHttpServer?.stop();
82
+ refs.apiServer?.stop();
83
+ refs.ipcServer?.stop();
84
+ refs.db?.close();
85
+ }
86
+ // ── Crash recovery: process-level error handlers ──────────
87
+ export function setupCrashRecovery(config, onRestart) {
88
+ const logger = getLogger();
89
+ process.on('uncaughtException', (err) => {
90
+ // EPIPE = writing to closed stdout/stderr (daemon mode) — ignore silently
91
+ if (err.code === 'EPIPE')
92
+ return;
93
+ try {
94
+ logger.error('Uncaught exception', { error: err.message, stack: err.stack });
95
+ }
96
+ catch { /* logger may be broken */ }
97
+ logCrash(config, 'uncaughtException', err);
98
+ // Don't restart on port conflicts — it will just loop
99
+ if (err.code === 'EADDRINUSE') {
100
+ try {
101
+ logger.error('Port conflict during restart — stopping to prevent crash loop');
102
+ }
103
+ catch { /* ignore */ }
104
+ return;
105
+ }
106
+ onRestart();
107
+ });
108
+ process.on('unhandledRejection', (reason) => {
109
+ try {
110
+ logger.error('Unhandled rejection', { reason: String(reason) });
111
+ }
112
+ catch { /* logger may be broken */ }
113
+ logCrash(config, 'unhandledRejection', reason instanceof Error ? reason : new Error(String(reason)));
114
+ onRestart();
115
+ });
116
+ }
117
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/init/lifecycle.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timmeck/brain",
3
- "version": "3.36.55",
3
+ "version": "3.36.56",
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",