@timmeck/trading-brain 1.0.0 → 1.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.
Files changed (138) hide show
  1. package/README.md +20 -0
  2. package/dashboard.html +480 -0
  3. package/dist/api/server.d.ts +3 -16
  4. package/dist/api/server.js +4 -123
  5. package/dist/api/server.js.map +1 -1
  6. package/dist/cli/colors.d.ts +10 -26
  7. package/dist/cli/colors.js +3 -62
  8. package/dist/cli/colors.js.map +1 -1
  9. package/dist/cli/commands/dashboard.d.ts +2 -0
  10. package/dist/cli/commands/dashboard.js +159 -0
  11. package/dist/cli/commands/dashboard.js.map +1 -0
  12. package/dist/cli/commands/peers.d.ts +2 -0
  13. package/dist/cli/commands/peers.js +38 -0
  14. package/dist/cli/commands/peers.js.map +1 -0
  15. package/dist/dashboard/renderer.d.ts +17 -0
  16. package/dist/dashboard/renderer.js +130 -0
  17. package/dist/dashboard/renderer.js.map +1 -0
  18. package/dist/dashboard/server.d.ts +15 -0
  19. package/dist/dashboard/server.js +116 -0
  20. package/dist/dashboard/server.js.map +1 -0
  21. package/dist/db/connection.d.ts +1 -2
  22. package/dist/db/connection.js +1 -18
  23. package/dist/db/connection.js.map +1 -1
  24. package/dist/hooks/post-tool-use.d.ts +2 -0
  25. package/dist/hooks/post-tool-use.js +108 -0
  26. package/dist/hooks/post-tool-use.js.map +1 -0
  27. package/dist/index.js +5 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/ipc/__tests__/protocol.test.d.ts +1 -0
  30. package/dist/ipc/__tests__/protocol.test.js +89 -0
  31. package/dist/ipc/__tests__/protocol.test.js.map +1 -0
  32. package/dist/ipc/client.d.ts +1 -16
  33. package/dist/ipc/client.js +1 -94
  34. package/dist/ipc/client.js.map +1 -1
  35. package/dist/ipc/protocol.d.ts +1 -8
  36. package/dist/ipc/protocol.js +1 -28
  37. package/dist/ipc/protocol.js.map +1 -1
  38. package/dist/ipc/router.js +8 -0
  39. package/dist/ipc/router.js.map +1 -1
  40. package/dist/ipc/server.d.ts +1 -18
  41. package/dist/ipc/server.js +1 -141
  42. package/dist/ipc/server.js.map +1 -1
  43. package/dist/mcp/http-server.d.ts +1 -7
  44. package/dist/mcp/http-server.js +6 -111
  45. package/dist/mcp/http-server.js.map +1 -1
  46. package/dist/mcp/server.js +5 -60
  47. package/dist/mcp/server.js.map +1 -1
  48. package/dist/signals/__tests__/fingerprint.test.d.ts +1 -0
  49. package/dist/signals/__tests__/fingerprint.test.js +164 -0
  50. package/dist/signals/__tests__/fingerprint.test.js.map +1 -0
  51. package/dist/signals/__tests__/wilson-score.test.d.ts +1 -0
  52. package/dist/signals/__tests__/wilson-score.test.js +65 -0
  53. package/dist/signals/__tests__/wilson-score.test.js.map +1 -0
  54. package/dist/trading-core.d.ts +1 -0
  55. package/dist/trading-core.js +6 -1
  56. package/dist/trading-core.js.map +1 -1
  57. package/dist/types/ipc.types.d.ts +1 -11
  58. package/dist/utils/__tests__/hash.test.d.ts +1 -0
  59. package/dist/utils/__tests__/hash.test.js +23 -0
  60. package/dist/utils/__tests__/hash.test.js.map +1 -0
  61. package/dist/utils/__tests__/paths.test.d.ts +1 -0
  62. package/dist/utils/__tests__/paths.test.js +60 -0
  63. package/dist/utils/__tests__/paths.test.js.map +1 -0
  64. package/dist/utils/events.d.ts +4 -8
  65. package/dist/utils/events.js +2 -14
  66. package/dist/utils/events.js.map +1 -1
  67. package/dist/utils/hash.d.ts +1 -1
  68. package/dist/utils/hash.js +1 -4
  69. package/dist/utils/hash.js.map +1 -1
  70. package/dist/utils/logger.d.ts +3 -2
  71. package/dist/utils/logger.js +8 -35
  72. package/dist/utils/logger.js.map +1 -1
  73. package/dist/utils/paths.d.ts +2 -1
  74. package/dist/utils/paths.js +4 -13
  75. package/dist/utils/paths.js.map +1 -1
  76. package/package.json +2 -1
  77. package/src/api/server.ts +0 -160
  78. package/src/cli/colors.ts +0 -80
  79. package/src/cli/commands/config.ts +0 -76
  80. package/src/cli/commands/doctor.ts +0 -62
  81. package/src/cli/commands/export.ts +0 -24
  82. package/src/cli/commands/import.ts +0 -44
  83. package/src/cli/commands/insights.ts +0 -30
  84. package/src/cli/commands/network.ts +0 -43
  85. package/src/cli/commands/query.ts +0 -28
  86. package/src/cli/commands/rules.ts +0 -27
  87. package/src/cli/commands/start.ts +0 -93
  88. package/src/cli/commands/status.ts +0 -64
  89. package/src/cli/commands/stop.ts +0 -33
  90. package/src/cli/ipc-helper.ts +0 -22
  91. package/src/config.ts +0 -103
  92. package/src/db/connection.ts +0 -22
  93. package/src/db/migrations/001_core.ts +0 -43
  94. package/src/db/migrations/002_synapses.ts +0 -44
  95. package/src/db/migrations/003_learning.ts +0 -49
  96. package/src/db/migrations/004_research.ts +0 -30
  97. package/src/db/migrations/index.ts +0 -60
  98. package/src/db/repositories/calibration.repository.ts +0 -86
  99. package/src/db/repositories/chain.repository.ts +0 -70
  100. package/src/db/repositories/graph.repository.ts +0 -103
  101. package/src/db/repositories/insight.repository.ts +0 -80
  102. package/src/db/repositories/rule.repository.ts +0 -67
  103. package/src/db/repositories/signal.repository.ts +0 -48
  104. package/src/db/repositories/synapse.repository.ts +0 -71
  105. package/src/db/repositories/trade.repository.ts +0 -97
  106. package/src/graph/weighted-graph.ts +0 -194
  107. package/src/index.ts +0 -55
  108. package/src/ipc/client.ts +0 -112
  109. package/src/ipc/protocol.ts +0 -35
  110. package/src/ipc/router.ts +0 -113
  111. package/src/ipc/server.ts +0 -150
  112. package/src/learning/calibrator.ts +0 -57
  113. package/src/learning/chain-detector.ts +0 -43
  114. package/src/learning/learning-engine.ts +0 -94
  115. package/src/learning/pattern-extractor.ts +0 -53
  116. package/src/mcp/http-server.ts +0 -118
  117. package/src/mcp/server.ts +0 -72
  118. package/src/mcp/tools.ts +0 -256
  119. package/src/research/research-engine.ts +0 -223
  120. package/src/services/analytics.service.ts +0 -68
  121. package/src/services/insight.service.ts +0 -29
  122. package/src/services/signal.service.ts +0 -109
  123. package/src/services/strategy.service.ts +0 -130
  124. package/src/services/synapse.service.ts +0 -58
  125. package/src/services/trade.service.ts +0 -139
  126. package/src/signals/fingerprint.ts +0 -93
  127. package/src/signals/wilson-score.ts +0 -17
  128. package/src/synapses/decay.ts +0 -19
  129. package/src/synapses/hebbian.ts +0 -23
  130. package/src/synapses/synapse-manager.ts +0 -112
  131. package/src/trading-core.ts +0 -285
  132. package/src/types/config.types.ts +0 -60
  133. package/src/types/ipc.types.ts +0 -8
  134. package/src/utils/events.ts +0 -42
  135. package/src/utils/hash.ts +0 -5
  136. package/src/utils/logger.ts +0 -48
  137. package/src/utils/paths.ts +0 -19
  138. package/tsconfig.json +0 -18
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACrD,IAAI,MAAM;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,gBAAgB,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe,eAAe;IACxD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO,gBAAgB,IAAI,EAAE,CAAC;IAChC,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;AAChD,CAAC"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,IAAI,cAAc,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAElH,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,MAAM,UAAU,UAAU;IACxB,OAAO,cAAc,CAAC,wBAAwB,EAAE,gBAAgB,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe,eAAe;IACxD,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timmeck/trading-brain",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Adaptive trading intelligence system with Hebbian synapses, spreading activation, Wilson Score confidence, and adaptive calibration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -32,6 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@modelcontextprotocol/sdk": "^1.0.0",
35
+ "@timmeck/brain-core": "^1.1.0",
35
36
  "better-sqlite3": "^11.7.0",
36
37
  "chalk": "^5.6.2",
37
38
  "commander": "^13.0.0",
package/src/api/server.ts DELETED
@@ -1,160 +0,0 @@
1
- import http from 'node:http';
2
- import { getLogger } from '../utils/logger.js';
3
- import { getEventBus } from '../utils/events.js';
4
- import type { IpcRouter } from '../ipc/router.js';
5
-
6
- export interface ApiServerOptions {
7
- port: number;
8
- router: IpcRouter;
9
- apiKey?: string;
10
- }
11
-
12
- export class ApiServer {
13
- private server: http.Server | null = null;
14
- private logger = getLogger();
15
- private sseClients: Set<http.ServerResponse> = new Set();
16
- private statsTimer: ReturnType<typeof setInterval> | null = null;
17
-
18
- constructor(private options: ApiServerOptions) {}
19
-
20
- start(): void {
21
- const { port, apiKey } = this.options;
22
-
23
- this.server = http.createServer((req, res) => {
24
- res.setHeader('Access-Control-Allow-Origin', '*');
25
- res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
26
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-API-Key');
27
-
28
- if (req.method === 'OPTIONS') { res.writeHead(204); res.end(); return; }
29
-
30
- if (apiKey) {
31
- const provided = (req.headers['x-api-key'] as string) ?? req.headers.authorization?.replace('Bearer ', '');
32
- if (provided !== apiKey) {
33
- this.json(res, 401, { error: 'Unauthorized' });
34
- return;
35
- }
36
- }
37
-
38
- this.handleRequest(req, res).catch((err) => {
39
- this.logger.error('API error:', err);
40
- this.json(res, 500, { error: err instanceof Error ? err.message : String(err) });
41
- });
42
- });
43
-
44
- this.server.listen(port, () => {
45
- this.logger.info(`REST API server started on http://localhost:${port}`);
46
- });
47
-
48
- this.setupSSE();
49
- }
50
-
51
- stop(): void {
52
- if (this.statsTimer) { clearInterval(this.statsTimer); this.statsTimer = null; }
53
- for (const client of this.sseClients) { try { client.end(); } catch { /* ignore */ } }
54
- this.sseClients.clear();
55
- this.server?.close();
56
- this.server = null;
57
- this.logger.info('REST API server stopped');
58
- }
59
-
60
- private async handleRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
61
- const url = new URL(req.url ?? '/', 'http://localhost');
62
- const pathname = url.pathname;
63
- const method = req.method ?? 'GET';
64
-
65
- if (pathname === '/api/v1/health') {
66
- this.json(res, 200, { status: 'ok', timestamp: new Date().toISOString() });
67
- return;
68
- }
69
-
70
- if (pathname === '/api/v1/events' && method === 'GET') {
71
- res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' });
72
- res.write('data: {"type":"connected"}\n\n');
73
- this.sseClients.add(res);
74
- req.on('close', () => this.sseClients.delete(res));
75
- return;
76
- }
77
-
78
- if (pathname === '/api/v1/methods' && method === 'GET') {
79
- const methods = this.options.router.listMethods();
80
- this.json(res, 200, { methods, rpcEndpoint: '/api/v1/rpc' });
81
- return;
82
- }
83
-
84
- if (pathname === '/api/v1/rpc' && method === 'POST') {
85
- const body = await this.readBody(req);
86
- if (!body) { this.json(res, 400, { error: 'Empty request body' }); return; }
87
-
88
- const parsed = JSON.parse(body);
89
-
90
- if (Array.isArray(parsed)) {
91
- const results = parsed.map((call: { method: string; params?: unknown; id?: string | number }) => {
92
- try {
93
- const result = this.options.router.handle(call.method, call.params ?? {});
94
- return { id: call.id, result };
95
- } catch (err) {
96
- return { id: call.id, error: err instanceof Error ? err.message : String(err) };
97
- }
98
- });
99
- this.json(res, 200, results);
100
- return;
101
- }
102
-
103
- if (!parsed.method) { this.json(res, 400, { error: 'Missing "method" field' }); return; }
104
-
105
- try {
106
- const result = this.options.router.handle(parsed.method, parsed.params ?? {});
107
- this.json(res, 200, { result });
108
- } catch (err) {
109
- this.json(res, 400, { error: err instanceof Error ? err.message : String(err) });
110
- }
111
- return;
112
- }
113
-
114
- this.json(res, 404, { error: `No route for ${method} ${pathname}` });
115
- }
116
-
117
- private json(res: http.ServerResponse, status: number, data: unknown): void {
118
- res.writeHead(status, { 'Content-Type': 'application/json' });
119
- res.end(JSON.stringify(data));
120
- }
121
-
122
- private readBody(req: http.IncomingMessage): Promise<string> {
123
- return new Promise((resolve, reject) => {
124
- const chunks: Buffer[] = [];
125
- req.on('data', (chunk: Buffer) => chunks.push(chunk));
126
- req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
127
- req.on('error', reject);
128
- });
129
- }
130
-
131
- private setupSSE(): void {
132
- const bus = getEventBus();
133
- const eventNames = [
134
- 'trade:recorded', 'synapse:updated', 'rule:learned',
135
- 'chain:detected', 'insight:created', 'calibration:updated',
136
- ] as const;
137
-
138
- for (const eventName of eventNames) {
139
- bus.on(eventName, (data: unknown) => {
140
- this.broadcastSSE({ type: 'event', event: eventName, data });
141
- });
142
- }
143
-
144
- this.statsTimer = setInterval(() => {
145
- if (this.sseClients.size > 0) {
146
- try {
147
- const summary = this.options.router.handle('analytics.summary', {});
148
- this.broadcastSSE({ type: 'stats_update', stats: summary });
149
- } catch { /* ignore */ }
150
- }
151
- }, 30_000);
152
- }
153
-
154
- private broadcastSSE(data: unknown): void {
155
- const msg = `data: ${JSON.stringify(data)}\n\n`;
156
- for (const client of this.sseClients) {
157
- try { client.write(msg); } catch { this.sseClients.delete(client); }
158
- }
159
- }
160
- }
package/src/cli/colors.ts DELETED
@@ -1,80 +0,0 @@
1
- import chalk from 'chalk';
2
-
3
- export const c = {
4
- blue: chalk.hex('#5b9cff'),
5
- purple: chalk.hex('#b47aff'),
6
- cyan: chalk.hex('#47e5ff'),
7
- green: chalk.hex('#3dffa0'),
8
- red: chalk.hex('#ff5577'),
9
- orange: chalk.hex('#ffb347'),
10
- dim: chalk.hex('#8b8fb0'),
11
- dimmer: chalk.hex('#4a4d6e'),
12
-
13
- label: chalk.hex('#8b8fb0'),
14
- value: chalk.white.bold,
15
- heading: chalk.hex('#5b9cff').bold,
16
- success: chalk.hex('#3dffa0').bold,
17
- error: chalk.hex('#ff5577').bold,
18
- warn: chalk.hex('#ffb347').bold,
19
- info: chalk.hex('#47e5ff'),
20
- };
21
-
22
- export const icons = {
23
- brain: '🧠',
24
- chart: '📊',
25
- check: '✓',
26
- cross: '✗',
27
- arrow: '→',
28
- dot: '●',
29
- bar: '█',
30
- barLight: '░',
31
- dash: '─',
32
- pipe: '│',
33
- star: '★',
34
- bolt: '⚡',
35
- search: '🔍',
36
- gear: '⚙',
37
- synapse: '🔗',
38
- insight: '💡',
39
- warn: '⚠',
40
- error: '❌',
41
- ok: '✅',
42
- clock: '⏱',
43
- trade: '💹',
44
- rule: '📋',
45
- chain: '⛓',
46
- };
47
-
48
- export function header(title: string, icon?: string): string {
49
- const prefix = icon ? `${icon} ` : '';
50
- const line = c.dimmer(icons.dash.repeat(40));
51
- return `\n${line}\n${prefix}${c.heading(title)}\n${line}`;
52
- }
53
-
54
- export function keyValue(key: string, value: string | number, indent = 2): string {
55
- const pad = ' '.repeat(indent);
56
- return `${pad}${c.label(key + ':')} ${c.value(String(value))}`;
57
- }
58
-
59
- export function divider(width = 40): string {
60
- return c.dimmer(icons.dash.repeat(width));
61
- }
62
-
63
- function stripAnsi(str: string): string {
64
- // eslint-disable-next-line no-control-regex
65
- return str.replace(/\x1b\[[0-9;]*m/g, '');
66
- }
67
-
68
- export function table(rows: string[][], colWidths?: number[]): string {
69
- if (rows.length === 0) return '';
70
- const widths = colWidths ?? rows[0]!.map((_, i) =>
71
- Math.max(...rows.map(r => stripAnsi(r[i] ?? '').length))
72
- );
73
- return rows.map(row =>
74
- row.map((cell, i) => {
75
- const stripped = stripAnsi(cell);
76
- const pad = Math.max(0, (widths[i] ?? stripped.length) - stripped.length);
77
- return cell + ' '.repeat(pad);
78
- }).join(' ')
79
- ).join('\n');
80
- }
@@ -1,76 +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 { loadConfig } from '../../config.js';
6
- import { c, icons, header } from '../colors.js';
7
-
8
- export function configCommand(): Command {
9
- const cmd = new Command('config').description('Manage configuration');
10
-
11
- cmd.command('show')
12
- .description('Show current configuration')
13
- .action(() => {
14
- console.log(header('Configuration', icons.gear));
15
- const config = loadConfig();
16
- console.log(JSON.stringify(config, null, 2));
17
- });
18
-
19
- cmd.command('set')
20
- .description('Set a config value')
21
- .argument('<key>', 'Config key (dot notation, e.g. api.port)')
22
- .argument('<value>', 'Config value')
23
- .action((key, value) => {
24
- const configPath = path.join(getDataDir(), 'config.json');
25
- let config: Record<string, unknown> = {};
26
- if (fs.existsSync(configPath)) {
27
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
28
- }
29
-
30
- const parts = key.split('.');
31
- let obj = config;
32
- for (let i = 0; i < parts.length - 1; i++) {
33
- if (!obj[parts[i]!] || typeof obj[parts[i]!] !== 'object') {
34
- obj[parts[i]!] = {};
35
- }
36
- obj = obj[parts[i]!] as Record<string, unknown>;
37
- }
38
-
39
- // Auto-convert numbers and booleans
40
- let parsed: unknown = value;
41
- if (value === 'true') parsed = true;
42
- else if (value === 'false') parsed = false;
43
- else if (!isNaN(Number(value))) parsed = Number(value);
44
-
45
- obj[parts[parts.length - 1]!] = parsed;
46
-
47
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
48
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
49
- console.log(`${icons.ok} ${c.success(`Set ${key} = ${value}`)}`);
50
- });
51
-
52
- cmd.command('delete')
53
- .description('Delete a config key (revert to default)')
54
- .argument('<key>', 'Config key to delete')
55
- .action((key) => {
56
- const configPath = path.join(getDataDir(), 'config.json');
57
- if (!fs.existsSync(configPath)) {
58
- console.log(`${c.dim('No config file found.')}`);
59
- return;
60
- }
61
-
62
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
63
- const parts = key.split('.');
64
- let obj = config;
65
- for (let i = 0; i < parts.length - 1; i++) {
66
- if (!obj[parts[i]!]) return;
67
- obj = obj[parts[i]!];
68
- }
69
- delete obj[parts[parts.length - 1]!];
70
-
71
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
72
- console.log(`${icons.ok} ${c.success(`Deleted ${key} (reverted to default)`)}`);
73
- });
74
-
75
- return cmd;
76
- }
@@ -1,62 +0,0 @@
1
- import { Command } from 'commander';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import { getDataDir, getPipeName } from '../../utils/paths.js';
5
- import { c, icons, header } from '../colors.js';
6
-
7
- export function doctorCommand(): Command {
8
- return new Command('doctor')
9
- .description('Health check for Trading Brain')
10
- .action(async () => {
11
- console.log(header('Trading Brain Doctor', icons.gear));
12
- let issues = 0;
13
-
14
- // Check data dir
15
- const dataDir = getDataDir();
16
- if (fs.existsSync(dataDir)) {
17
- console.log(` ${icons.ok} Data dir exists: ${c.dim(dataDir)}`);
18
- } else {
19
- console.log(` ${icons.warn} Data dir missing: ${c.dim(dataDir)}`);
20
- issues++;
21
- }
22
-
23
- // Check DB
24
- const dbPath = path.join(dataDir, 'trading-brain.db');
25
- if (fs.existsSync(dbPath)) {
26
- const stat = fs.statSync(dbPath);
27
- console.log(` ${icons.ok} Database exists: ${c.dim(`${(stat.size / 1024).toFixed(0)} KB`)}`);
28
- } else {
29
- console.log(` ${icons.warn} Database not yet created ${c.dim('(will be created on first start)')}`);
30
- }
31
-
32
- // Check PID
33
- const pidPath = path.join(dataDir, 'trading-brain.pid');
34
- if (fs.existsSync(pidPath)) {
35
- const pid = parseInt(fs.readFileSync(pidPath, 'utf8').trim(), 10);
36
- try {
37
- process.kill(pid, 0);
38
- console.log(` ${icons.ok} Daemon running ${c.dim(`(PID ${pid})`)}`);
39
- } catch {
40
- console.log(` ${icons.warn} Stale PID file ${c.dim(`(PID ${pid} not running)`)}`);
41
- issues++;
42
- }
43
- } else {
44
- console.log(` ${icons.warn} Daemon not running`);
45
- }
46
-
47
- // Check pipe
48
- const pipeName = getPipeName();
49
- console.log(` ${c.dim('IPC:')} ${pipeName}`);
50
-
51
- // Check ports
52
- console.log(` ${c.dim('REST API:')} http://localhost:7779`);
53
- console.log(` ${c.dim('MCP HTTP:')} http://localhost:7780`);
54
-
55
- console.log();
56
- if (issues === 0) {
57
- console.log(` ${icons.ok} ${c.success('All checks passed!')}`);
58
- } else {
59
- console.log(` ${icons.warn} ${c.warn(`${issues} issue(s) found`)}`);
60
- }
61
- });
62
- }
@@ -1,24 +0,0 @@
1
- import { Command } from 'commander';
2
- import fs from 'node:fs';
3
- import { withIpc } from '../ipc-helper.js';
4
- import { c, icons } from '../colors.js';
5
-
6
- export function exportCommand(): Command {
7
- return new Command('export')
8
- .description('Export all brain data as JSON')
9
- .option('-o, --output <file>', 'Output file path', 'trading-brain-export.json')
10
- .action(async (opts) => {
11
- await withIpc(async (client) => {
12
- const summary = await client.request('analytics.summary', {});
13
- const rules = await client.request('rule.list', {});
14
- const chains = await client.request('chain.list', { limit: 100 });
15
- const insights = await client.request('insight.list', { limit: 100 });
16
- const network = await client.request('synapse.stats', {});
17
- const calibration = await client.request('calibration.get', {});
18
-
19
- const data = { summary, rules, chains, insights, network, calibration, exportedAt: new Date().toISOString() };
20
- fs.writeFileSync(opts.output, JSON.stringify(data, null, 2));
21
- console.log(`${icons.ok} ${c.success(`Exported to ${opts.output}`)}`);
22
- });
23
- });
24
- }
@@ -1,44 +0,0 @@
1
- import { Command } from 'commander';
2
- import fs from 'node:fs';
3
- import { withIpc } from '../ipc-helper.js';
4
- import { c, icons } from '../colors.js';
5
-
6
- export function importCommand(): Command {
7
- return new Command('import')
8
- .description('Import trades from JSON file')
9
- .argument('<file>', 'JSON file to import')
10
- .action(async (file) => {
11
- if (!fs.existsSync(file)) {
12
- console.error(`${icons.error} ${c.error(`File not found: ${file}`)}`);
13
- process.exit(1);
14
- }
15
-
16
- const raw = fs.readFileSync(file, 'utf-8');
17
- const data = JSON.parse(raw);
18
-
19
- if (!Array.isArray(data)) {
20
- console.error(`${icons.error} ${c.error('Expected JSON array of trade objects.')}`);
21
- process.exit(1);
22
- }
23
-
24
- await withIpc(async (client) => {
25
- let imported = 0;
26
- for (const trade of data) {
27
- try {
28
- await client.request('trade.recordOutcome', {
29
- signals: trade.signals ?? {},
30
- regime: trade.regime,
31
- profitPct: trade.profitPct ?? trade.profit_pct ?? 0,
32
- win: trade.win ?? false,
33
- botType: trade.botType ?? trade.bot_type ?? 'unknown',
34
- pair: trade.pair ?? 'unknown',
35
- });
36
- imported++;
37
- } catch (err) {
38
- console.error(`${icons.warn} ${c.warn(`Failed to import trade: ${err}`)}`);
39
- }
40
- }
41
- console.log(`${icons.ok} ${c.success(`Imported ${imported}/${data.length} trades`)}`);
42
- });
43
- });
44
- }
@@ -1,30 +0,0 @@
1
- import { Command } from 'commander';
2
- import { withIpc } from '../ipc-helper.js';
3
- import { c, icons, header } from '../colors.js';
4
-
5
- export function insightsCommand(): Command {
6
- return new Command('insights')
7
- .description('Show research insights')
8
- .option('-t, --type <type>', 'Filter by type (trend, gap, synergy, performance, regime_shift)')
9
- .option('-l, --limit <n>', 'Max results', '10')
10
- .action(async (opts) => {
11
- console.log(header('Research Insights', icons.insight));
12
-
13
- await withIpc(async (client) => {
14
- const method = opts.type ? 'insight.byType' : 'insight.list';
15
- const params = opts.type ? { type: opts.type } : { limit: Number(opts.limit) };
16
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
- const results: any = await client.request(method, params);
18
- if (!results?.length) {
19
- console.log(` ${c.dim('No insights found.')}`);
20
- return;
21
- }
22
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
- for (const ins of results) {
24
- const sev = ins.severity === 'high' ? c.red(`[${ins.severity}]`) : ins.severity === 'medium' ? c.orange(`[${ins.severity}]`) : c.dim(`[${ins.severity}]`);
25
- console.log(` ${sev} ${c.cyan(ins.type)} — ${c.value(ins.title)}`);
26
- console.log(` ${c.dim(ins.description)}`);
27
- }
28
- });
29
- });
30
- }
@@ -1,43 +0,0 @@
1
- import { Command } from 'commander';
2
- import { withIpc } from '../ipc-helper.js';
3
- import { c, icons, header, keyValue } from '../colors.js';
4
-
5
- export function networkCommand(): Command {
6
- return new Command('network')
7
- .description('Show synapse network overview')
8
- .option('-n, --node <id>', 'Explore from specific node')
9
- .action(async (opts) => {
10
- console.log(header('Synapse Network', icons.synapse));
11
-
12
- await withIpc(async (client) => {
13
- if (opts.node) {
14
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
- const activated: any = await client.request('synapse.explore', { query: opts.node });
16
- if (!activated?.length) {
17
- console.log(` ${c.dim(`No node found matching "${opts.node}"`)}`);
18
- return;
19
- }
20
- console.log(` ${c.info('Spreading Activation from:')} ${c.value(opts.node)}\n`);
21
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
- for (const node of activated.slice(0, 20)) {
23
- const bar = c.cyan('█'.repeat(Math.round(node.activation * 20)));
24
- console.log(` ${bar} ${c.dim(node.type)} ${c.value(node.label)} ${c.dim(`(${node.activation.toFixed(3)})`)}`);
25
- }
26
- } else {
27
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
- const stats: any = await client.request('synapse.stats', {});
29
- console.log(keyValue('Synapses', stats.totalSynapses));
30
- console.log(keyValue('Avg Weight', stats.avgWeight?.toFixed(3) ?? '0'));
31
- console.log(keyValue('Graph Nodes', stats.graphNodes));
32
- console.log(keyValue('Graph Edges', stats.graphEdges));
33
- if (stats.strongest?.length > 0) {
34
- console.log(`\n ${c.cyan.bold('Strongest Synapses:')}`);
35
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
- for (const s of stats.strongest) {
37
- console.log(` ${c.green(s.weight.toFixed(3))} ${c.dim(`(${s.activations}x)`)} ${c.value(s.id)}`);
38
- }
39
- }
40
- }
41
- });
42
- });
43
- }
@@ -1,28 +0,0 @@
1
- import { Command } from 'commander';
2
- import { withIpc } from '../ipc-helper.js';
3
- import { c, icons, header } from '../colors.js';
4
-
5
- export function queryCommand(): Command {
6
- return new Command('query')
7
- .description('Search trades and signals')
8
- .argument('<search>', 'Search query (fingerprint, pair, bot type)')
9
- .option('-l, --limit <n>', 'Max results', '20')
10
- .action(async (search, opts) => {
11
- console.log(header('Trade Search', icons.search));
12
-
13
- await withIpc(async (client) => {
14
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
- const results: any = await client.request('trade.query', { search, limit: Number(opts.limit) });
16
- if (!results?.length) {
17
- console.log(` ${c.dim('No trades found.')}`);
18
- return;
19
- }
20
- console.log(` ${c.info(`Found ${results.length} trades:`)}\n`);
21
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
- for (const t of results) {
23
- const badge = t.win ? c.green('WIN') : c.red('LOSS');
24
- console.log(` #${t.id} [${badge}] ${c.cyan(t.pair)} ${c.dim(t.fingerprint)} ${t.profit_pct.toFixed(2)}%`);
25
- }
26
- });
27
- });
28
- }
@@ -1,27 +0,0 @@
1
- import { Command } from 'commander';
2
- import { withIpc } from '../ipc-helper.js';
3
- import { c, icons, header } from '../colors.js';
4
-
5
- export function rulesCommand(): Command {
6
- return new Command('rules')
7
- .description('Show learned trading rules')
8
- .action(async () => {
9
- console.log(header('Learned Rules', icons.rule));
10
-
11
- await withIpc(async (client) => {
12
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
- const rules: any = await client.request('rule.list', {});
14
- if (!rules?.length) {
15
- console.log(` ${c.dim('No rules learned yet. Brain needs more trades.')}`);
16
- return;
17
- }
18
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
- for (const r of rules) {
20
- const conf = Math.round(r.confidence * 100);
21
- const wr = Math.round(r.win_rate * 100);
22
- const confColor = conf > 70 ? c.green : conf > 50 ? c.orange : c.red;
23
- console.log(` ${confColor(`${conf}%`)} conf ${c.dim('|')} ${c.cyan(`${wr}%`)} WR ${c.dim('|')} n=${r.sample_count} ${c.dim('|')} ${c.value(r.pattern)}`);
24
- }
25
- });
26
- });
27
- }