@timmeck/brain-core 2.36.57 → 2.36.58
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/README.md +6 -0
- package/command-center.html +133 -2
- package/dist/action/__tests__/content-handler.test.d.ts +1 -0
- package/dist/action/__tests__/content-handler.test.js +100 -0
- package/dist/action/__tests__/content-handler.test.js.map +1 -0
- package/dist/action/__tests__/trade-handler.test.d.ts +1 -0
- package/dist/action/__tests__/trade-handler.test.js +165 -0
- package/dist/action/__tests__/trade-handler.test.js.map +1 -0
- package/dist/action/action-bridge.d.ts +2 -2
- package/dist/action/action-bridge.js +1 -0
- package/dist/action/action-bridge.js.map +1 -1
- package/dist/action/handlers/content-handler.d.ts +23 -0
- package/dist/action/handlers/content-handler.js +30 -0
- package/dist/action/handlers/content-handler.js.map +1 -0
- package/dist/action/handlers/index.d.ts +4 -0
- package/dist/action/handlers/index.js +3 -0
- package/dist/action/handlers/index.js.map +1 -0
- package/dist/action/handlers/trade-handler.d.ts +43 -0
- package/dist/action/handlers/trade-handler.js +43 -0
- package/dist/action/handlers/trade-handler.js.map +1 -0
- package/dist/action/index.d.ts +2 -0
- package/dist/action/index.js +1 -0
- package/dist/action/index.js.map +1 -1
- package/dist/agent-training/__tests__/agent-trainer.test.d.ts +1 -0
- package/dist/agent-training/__tests__/agent-trainer.test.js +158 -0
- package/dist/agent-training/__tests__/agent-trainer.test.js.map +1 -0
- package/dist/agent-training/__tests__/sub-agent-factory.test.d.ts +1 -0
- package/dist/agent-training/__tests__/sub-agent-factory.test.js +100 -0
- package/dist/agent-training/__tests__/sub-agent-factory.test.js.map +1 -0
- package/dist/agent-training/__tests__/sub-agent.test.d.ts +1 -0
- package/dist/agent-training/__tests__/sub-agent.test.js +102 -0
- package/dist/agent-training/__tests__/sub-agent.test.js.map +1 -0
- package/dist/agent-training/index.d.ts +4 -0
- package/dist/agent-training/index.js +2 -0
- package/dist/agent-training/index.js.map +1 -1
- package/dist/agent-training/sub-agent-factory.d.ts +36 -0
- package/dist/agent-training/sub-agent-factory.js +128 -0
- package/dist/agent-training/sub-agent-factory.js.map +1 -0
- package/dist/agent-training/sub-agent.d.ts +57 -0
- package/dist/agent-training/sub-agent.js +135 -0
- package/dist/agent-training/sub-agent.js.map +1 -0
- package/dist/chat/__tests__/chat-engine.test.d.ts +1 -0
- package/dist/chat/__tests__/chat-engine.test.js +128 -0
- package/dist/chat/__tests__/chat-engine.test.js.map +1 -0
- package/dist/chat/chat-engine.d.ts +55 -0
- package/dist/chat/chat-engine.js +186 -0
- package/dist/chat/chat-engine.js.map +1 -0
- package/dist/chat/index.d.ts +2 -0
- package/dist/chat/index.js +2 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/content/__tests__/auto-publisher.test.d.ts +1 -0
- package/dist/content/__tests__/auto-publisher.test.js +125 -0
- package/dist/content/__tests__/auto-publisher.test.js.map +1 -0
- package/dist/content/auto-publisher.d.ts +51 -0
- package/dist/content/auto-publisher.js +147 -0
- package/dist/content/auto-publisher.js.map +1 -0
- package/dist/content/content-forge.d.ts +2 -0
- package/dist/content/content-forge.js +19 -0
- package/dist/content/content-forge.js.map +1 -1
- package/dist/content/index.d.ts +2 -0
- package/dist/content/index.js +1 -0
- package/dist/content/index.js.map +1 -1
- package/dist/creative/__tests__/creative-engine.test.d.ts +1 -0
- package/dist/creative/__tests__/creative-engine.test.js +151 -0
- package/dist/creative/__tests__/creative-engine.test.js.map +1 -0
- package/dist/cross-brain/__tests__/signal-router.test.d.ts +1 -0
- package/dist/cross-brain/__tests__/signal-router.test.js +159 -0
- package/dist/cross-brain/__tests__/signal-router.test.js.map +1 -0
- package/dist/cross-brain/signal-router.d.ts +57 -0
- package/dist/cross-brain/signal-router.js +148 -0
- package/dist/cross-brain/signal-router.js.map +1 -0
- package/dist/dashboard/__tests__/command-center-server.test.js +31 -0
- package/dist/dashboard/__tests__/command-center-server.test.js.map +1 -1
- package/dist/dashboard/command-center-server.d.ts +11 -0
- package/dist/dashboard/command-center-server.js +72 -0
- package/dist/dashboard/command-center-server.js.map +1 -1
- package/dist/dream/__tests__/dream-engine.test.d.ts +1 -0
- package/dist/dream/__tests__/dream-engine.test.js +184 -0
- package/dist/dream/__tests__/dream-engine.test.js.map +1 -0
- package/dist/feedback/__tests__/feedback-router.test.d.ts +1 -0
- package/dist/feedback/__tests__/feedback-router.test.js +173 -0
- package/dist/feedback/__tests__/feedback-router.test.js.map +1 -0
- package/dist/feedback/feedback-router.d.ts +53 -0
- package/dist/feedback/feedback-router.js +193 -0
- package/dist/feedback/feedback-router.js.map +1 -0
- package/dist/feedback/index.d.ts +2 -0
- package/dist/feedback/index.js +1 -0
- package/dist/feedback/index.js.map +1 -1
- package/dist/goals/__tests__/goal-engine.test.d.ts +1 -0
- package/dist/goals/__tests__/goal-engine.test.js +203 -0
- package/dist/goals/__tests__/goal-engine.test.js.map +1 -0
- package/dist/guardrails/__tests__/guardrail-engine.test.d.ts +1 -0
- package/dist/guardrails/__tests__/guardrail-engine.test.js +343 -0
- package/dist/guardrails/__tests__/guardrail-engine.test.js.map +1 -0
- package/dist/index.d.ts +14 -6
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/dist/metacognition/__tests__/auto-experiment-engine.test.d.ts +1 -0
- package/dist/metacognition/__tests__/auto-experiment-engine.test.js +218 -0
- package/dist/metacognition/__tests__/auto-experiment-engine.test.js.map +1 -0
- package/dist/metacognition/__tests__/evolution-engine.test.d.ts +1 -0
- package/dist/metacognition/__tests__/evolution-engine.test.js +473 -0
- package/dist/metacognition/__tests__/evolution-engine.test.js.map +1 -0
- package/dist/metacognition/__tests__/parameter-registry.test.d.ts +1 -0
- package/dist/metacognition/__tests__/parameter-registry.test.js +223 -0
- package/dist/metacognition/__tests__/parameter-registry.test.js.map +1 -0
- package/dist/prediction/__tests__/prediction-engine.test.d.ts +1 -0
- package/dist/prediction/__tests__/prediction-engine.test.js +244 -0
- package/dist/prediction/__tests__/prediction-engine.test.js.map +1 -0
- package/dist/research/research-orchestrator.js +2 -1
- package/dist/research/research-orchestrator.js.map +1 -1
- package/dist/sandbox/__tests__/code-sandbox.test.d.ts +1 -0
- package/dist/sandbox/__tests__/code-sandbox.test.js +182 -0
- package/dist/sandbox/__tests__/code-sandbox.test.js.map +1 -0
- package/dist/scanner/__tests__/signal-scanner.test.d.ts +1 -0
- package/dist/scanner/__tests__/signal-scanner.test.js +142 -0
- package/dist/scanner/__tests__/signal-scanner.test.js.map +1 -0
- package/dist/self-modification/__tests__/self-modification-engine.test.d.ts +1 -0
- package/dist/self-modification/__tests__/self-modification-engine.test.js +255 -0
- package/dist/self-modification/__tests__/self-modification-engine.test.js.map +1 -0
- package/dist/strategy/__tests__/strategy-forge.test.js +69 -0
- package/dist/strategy/__tests__/strategy-forge.test.js.map +1 -1
- package/dist/strategy/__tests__/strategy-mutator.test.d.ts +1 -0
- package/dist/strategy/__tests__/strategy-mutator.test.js +141 -0
- package/dist/strategy/__tests__/strategy-mutator.test.js.map +1 -0
- package/dist/strategy/index.d.ts +2 -0
- package/dist/strategy/index.js +1 -0
- package/dist/strategy/index.js.map +1 -1
- package/dist/strategy/strategy-forge.d.ts +4 -1
- package/dist/strategy/strategy-forge.js +34 -2
- package/dist/strategy/strategy-forge.js.map +1 -1
- package/dist/strategy/strategy-mutator.d.ts +42 -0
- package/dist/strategy/strategy-mutator.js +140 -0
- package/dist/strategy/strategy-mutator.js.map +1 -0
- package/package.json +1 -1
package/dist/content/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/content/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAM5E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import Database from 'better-sqlite3';
|
|
3
|
+
vi.mock('../../utils/logger.js', () => ({
|
|
4
|
+
getLogger: () => ({ info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }),
|
|
5
|
+
}));
|
|
6
|
+
import { CreativeEngine, runCreativeMigration } from '../creative-engine.js';
|
|
7
|
+
describe('CreativeEngine', () => {
|
|
8
|
+
let db;
|
|
9
|
+
beforeEach(() => { db = new Database(':memory:'); });
|
|
10
|
+
afterEach(() => { db.close(); });
|
|
11
|
+
it('creates an instance without errors', () => {
|
|
12
|
+
const engine = new CreativeEngine(db, { brainName: 'test' });
|
|
13
|
+
expect(engine).toBeDefined();
|
|
14
|
+
});
|
|
15
|
+
it('getStatus returns initial empty state', () => {
|
|
16
|
+
const engine = new CreativeEngine(db, { brainName: 'test' });
|
|
17
|
+
const status = engine.getStatus();
|
|
18
|
+
expect(status.totalInsights).toBe(0);
|
|
19
|
+
expect(status.byType).toEqual({});
|
|
20
|
+
expect(status.byStatus).toEqual({});
|
|
21
|
+
expect(status.topInsights).toEqual([]);
|
|
22
|
+
});
|
|
23
|
+
it('crossPollinate returns empty array without distiller', () => {
|
|
24
|
+
const engine = new CreativeEngine(db, { brainName: 'test' });
|
|
25
|
+
const result = engine.crossPollinate();
|
|
26
|
+
expect(result).toEqual([]);
|
|
27
|
+
});
|
|
28
|
+
it('crossPollinate returns insights when distiller provides multi-domain principles', () => {
|
|
29
|
+
const engine = new CreativeEngine(db, { brainName: 'test', overlapThreshold: 1.0 });
|
|
30
|
+
engine.setKnowledgeDistiller({
|
|
31
|
+
distill: () => ({
|
|
32
|
+
principles: [
|
|
33
|
+
{ statement: 'caching improves performance significantly', domain: 'engineering' },
|
|
34
|
+
{ statement: 'diversification reduces portfolio variance', domain: 'finance' },
|
|
35
|
+
{ statement: 'redundancy prevents catastrophic system failure', domain: 'engineering' },
|
|
36
|
+
{ statement: 'hedging minimizes downside exposure risk', domain: 'finance' },
|
|
37
|
+
],
|
|
38
|
+
}),
|
|
39
|
+
});
|
|
40
|
+
const insights = engine.crossPollinate();
|
|
41
|
+
expect(insights.length).toBeGreaterThan(0);
|
|
42
|
+
expect(insights[0].type).toBe('cross_pollination');
|
|
43
|
+
expect(insights[0].status).toBe('raw');
|
|
44
|
+
expect(insights[0].noveltyScore).toBeGreaterThan(0);
|
|
45
|
+
expect(insights[0].id).toBeGreaterThan(0);
|
|
46
|
+
// Verify stored in DB
|
|
47
|
+
const status = engine.getStatus();
|
|
48
|
+
expect(status.totalInsights).toBe(insights.length);
|
|
49
|
+
expect(status.byType['cross_pollination']).toBe(insights.length);
|
|
50
|
+
});
|
|
51
|
+
it('findAnalogies returns empty array without distiller', () => {
|
|
52
|
+
const engine = new CreativeEngine(db, { brainName: 'test' });
|
|
53
|
+
const result = engine.findAnalogies('some concept');
|
|
54
|
+
expect(result).toEqual([]);
|
|
55
|
+
});
|
|
56
|
+
it('findAnalogies finds structurally similar principles', () => {
|
|
57
|
+
const engine = new CreativeEngine(db, { brainName: 'test' });
|
|
58
|
+
engine.setKnowledgeDistiller({
|
|
59
|
+
distill: () => ({
|
|
60
|
+
principles: [
|
|
61
|
+
{ statement: 'caching improves response times significantly', domain: 'engineering' },
|
|
62
|
+
{ statement: 'caching improves database query performance', domain: 'databases' },
|
|
63
|
+
{ statement: 'something completely unrelated', domain: 'art' },
|
|
64
|
+
],
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
67
|
+
const analogies = engine.findAnalogies('caching improves application performance');
|
|
68
|
+
expect(analogies.length).toBeGreaterThan(0);
|
|
69
|
+
for (const a of analogies) {
|
|
70
|
+
expect(a.concept).toBe('caching improves application performance');
|
|
71
|
+
expect(a.similarity).toBeGreaterThan(0.1);
|
|
72
|
+
expect(a.similarity).toBeLessThan(0.6);
|
|
73
|
+
expect(a.explanation).toContain('Shared concepts');
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
it('getInsights returns empty list initially', () => {
|
|
77
|
+
const engine = new CreativeEngine(db, { brainName: 'test' });
|
|
78
|
+
const insights = engine.getInsights();
|
|
79
|
+
expect(insights).toEqual([]);
|
|
80
|
+
});
|
|
81
|
+
it('getInsights returns stored insights after crossPollinate', () => {
|
|
82
|
+
const engine = new CreativeEngine(db, { brainName: 'test', overlapThreshold: 1.0 });
|
|
83
|
+
engine.setKnowledgeDistiller({
|
|
84
|
+
distill: () => ({
|
|
85
|
+
principles: [
|
|
86
|
+
{ statement: 'parallel processing speeds computation', domain: 'computing' },
|
|
87
|
+
{ statement: 'teamwork divides workload effectively', domain: 'management' },
|
|
88
|
+
],
|
|
89
|
+
}),
|
|
90
|
+
});
|
|
91
|
+
engine.crossPollinate();
|
|
92
|
+
const insights = engine.getInsights();
|
|
93
|
+
expect(insights.length).toBeGreaterThan(0);
|
|
94
|
+
expect(insights[0].id).toBeDefined();
|
|
95
|
+
expect(insights[0].createdAt).toBeDefined();
|
|
96
|
+
expect(insights[0].sourceA.domain).toBeDefined();
|
|
97
|
+
expect(insights[0].sourceB.domain).toBeDefined();
|
|
98
|
+
});
|
|
99
|
+
it('getInsights filters by status', () => {
|
|
100
|
+
const engine = new CreativeEngine(db, { brainName: 'test', overlapThreshold: 1.0 });
|
|
101
|
+
engine.setKnowledgeDistiller({
|
|
102
|
+
distill: () => ({
|
|
103
|
+
principles: [
|
|
104
|
+
{ statement: 'abstraction hides complexity behind interfaces', domain: 'software' },
|
|
105
|
+
{ statement: 'delegation assigns responsibility to subordinates', domain: 'leadership' },
|
|
106
|
+
],
|
|
107
|
+
}),
|
|
108
|
+
});
|
|
109
|
+
engine.crossPollinate();
|
|
110
|
+
const raw = engine.getInsights(20, 'raw');
|
|
111
|
+
expect(raw.length).toBeGreaterThan(0);
|
|
112
|
+
const tested = engine.getInsights(20, 'tested');
|
|
113
|
+
expect(tested).toEqual([]);
|
|
114
|
+
});
|
|
115
|
+
it('migration is idempotent', () => {
|
|
116
|
+
const engine = new CreativeEngine(db, { brainName: 'test', overlapThreshold: 1.0 });
|
|
117
|
+
engine.setKnowledgeDistiller({
|
|
118
|
+
distill: () => ({
|
|
119
|
+
principles: [
|
|
120
|
+
{ statement: 'monitoring detects anomalies early', domain: 'ops' },
|
|
121
|
+
{ statement: 'early diagnosis improves treatment outcomes', domain: 'medicine' },
|
|
122
|
+
],
|
|
123
|
+
}),
|
|
124
|
+
});
|
|
125
|
+
engine.crossPollinate();
|
|
126
|
+
// Running migration again should not destroy data
|
|
127
|
+
runCreativeMigration(db);
|
|
128
|
+
const status = engine.getStatus();
|
|
129
|
+
expect(status.totalInsights).toBeGreaterThan(0);
|
|
130
|
+
});
|
|
131
|
+
it('getStatus reflects insights by type and status', () => {
|
|
132
|
+
const engine = new CreativeEngine(db, { brainName: 'test' });
|
|
133
|
+
// Manually insert insights of different types
|
|
134
|
+
db.prepare(`
|
|
135
|
+
INSERT INTO creative_insights (type, source_a_domain, source_a_principle, source_b_domain, source_b_principle, insight, novelty_score, plausibility, status)
|
|
136
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
137
|
+
`).run('cross_pollination', 'domA', 'prinA', 'domB', 'prinB', 'insight1', 0.8, 0.5, 'raw');
|
|
138
|
+
db.prepare(`
|
|
139
|
+
INSERT INTO creative_insights (type, source_a_domain, source_a_principle, source_b_domain, source_b_principle, insight, novelty_score, plausibility, status)
|
|
140
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
141
|
+
`).run('imagination', 'domC', 'prinC', 'domD', 'prinD', 'insight2', 0.9, 0.6, 'tested');
|
|
142
|
+
const status = engine.getStatus();
|
|
143
|
+
expect(status.totalInsights).toBe(2);
|
|
144
|
+
expect(status.byType['cross_pollination']).toBe(1);
|
|
145
|
+
expect(status.byType['imagination']).toBe(1);
|
|
146
|
+
expect(status.byStatus['raw']).toBe(1);
|
|
147
|
+
expect(status.byStatus['tested']).toBe(1);
|
|
148
|
+
expect(status.topInsights.length).toBe(2);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
//# sourceMappingURL=creative-engine.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"creative-engine.test.js","sourceRoot":"","sources":["../../../src/creative/__tests__/creative-engine.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import Database from 'better-sqlite3';
|
|
3
|
+
vi.mock('../../utils/logger.js', () => ({
|
|
4
|
+
getLogger: () => ({ info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() }),
|
|
5
|
+
}));
|
|
6
|
+
import { CrossBrainSignalRouter, runSignalRouterMigration } from '../signal-router.js';
|
|
7
|
+
describe('CrossBrainSignalRouter', () => {
|
|
8
|
+
let db;
|
|
9
|
+
beforeEach(() => { db = new Database(':memory:'); });
|
|
10
|
+
afterEach(() => { db.close(); });
|
|
11
|
+
it('creates and runs migration', () => {
|
|
12
|
+
const router = new CrossBrainSignalRouter(db, 'test-brain');
|
|
13
|
+
const status = router.getStatus();
|
|
14
|
+
expect(status.totalSignals).toBe(0);
|
|
15
|
+
expect(status.handlerCount).toBe(0);
|
|
16
|
+
});
|
|
17
|
+
it('emits a signal and persists it', async () => {
|
|
18
|
+
const router = new CrossBrainSignalRouter(db, 'trading-brain');
|
|
19
|
+
const id = await router.emit({
|
|
20
|
+
targetBrain: 'marketing-brain',
|
|
21
|
+
signalType: 'trade_signal',
|
|
22
|
+
payload: { symbol: 'BTC', direction: 'bullish' },
|
|
23
|
+
confidence: 0.8,
|
|
24
|
+
});
|
|
25
|
+
expect(id).toMatch(/^sig-/);
|
|
26
|
+
const history = router.getHistory();
|
|
27
|
+
expect(history).toHaveLength(1);
|
|
28
|
+
expect(history[0].sourceBrain).toBe('trading-brain');
|
|
29
|
+
expect(history[0].targetBrain).toBe('marketing-brain');
|
|
30
|
+
expect(history[0].signalType).toBe('trade_signal');
|
|
31
|
+
expect(history[0].payload.symbol).toBe('BTC');
|
|
32
|
+
});
|
|
33
|
+
it('handles incoming signals and dispatches to handlers', async () => {
|
|
34
|
+
const router = new CrossBrainSignalRouter(db, 'marketing-brain');
|
|
35
|
+
const handler = vi.fn();
|
|
36
|
+
router.onSignal('trade_signal', handler);
|
|
37
|
+
await router.handleIncoming({
|
|
38
|
+
id: 'sig-test-1',
|
|
39
|
+
sourceBrain: 'trading-brain',
|
|
40
|
+
targetBrain: 'marketing-brain',
|
|
41
|
+
signalType: 'trade_signal',
|
|
42
|
+
payload: { symbol: 'ETH', direction: 'bearish' },
|
|
43
|
+
confidence: 0.7,
|
|
44
|
+
timestamp: Date.now(),
|
|
45
|
+
processed: false,
|
|
46
|
+
});
|
|
47
|
+
expect(handler).toHaveBeenCalledOnce();
|
|
48
|
+
expect(handler.mock.calls[0][0].payload.symbol).toBe('ETH');
|
|
49
|
+
});
|
|
50
|
+
it('registers multiple handlers for same signal type', async () => {
|
|
51
|
+
const router = new CrossBrainSignalRouter(db, 'test-brain');
|
|
52
|
+
const handler1 = vi.fn();
|
|
53
|
+
const handler2 = vi.fn();
|
|
54
|
+
router.onSignal('trade_signal', handler1);
|
|
55
|
+
router.onSignal('trade_signal', handler2);
|
|
56
|
+
await router.handleIncoming({
|
|
57
|
+
id: 'sig-test-2',
|
|
58
|
+
sourceBrain: 'other-brain',
|
|
59
|
+
targetBrain: 'test-brain',
|
|
60
|
+
signalType: 'trade_signal',
|
|
61
|
+
payload: {},
|
|
62
|
+
confidence: 0.5,
|
|
63
|
+
timestamp: Date.now(),
|
|
64
|
+
processed: false,
|
|
65
|
+
});
|
|
66
|
+
expect(handler1).toHaveBeenCalledOnce();
|
|
67
|
+
expect(handler2).toHaveBeenCalledOnce();
|
|
68
|
+
});
|
|
69
|
+
it('handles handler errors gracefully', async () => {
|
|
70
|
+
const router = new CrossBrainSignalRouter(db, 'test-brain');
|
|
71
|
+
router.onSignal('bad_signal', () => { throw new Error('Handler crash'); });
|
|
72
|
+
// Should not throw
|
|
73
|
+
await router.handleIncoming({
|
|
74
|
+
id: 'sig-test-3',
|
|
75
|
+
sourceBrain: 'other',
|
|
76
|
+
targetBrain: 'test-brain',
|
|
77
|
+
signalType: 'bad_signal',
|
|
78
|
+
payload: {},
|
|
79
|
+
confidence: 0.5,
|
|
80
|
+
timestamp: Date.now(),
|
|
81
|
+
processed: false,
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
it('processQueue processes unprocessed signals', async () => {
|
|
85
|
+
const router = new CrossBrainSignalRouter(db, 'test-brain');
|
|
86
|
+
const handler = vi.fn();
|
|
87
|
+
router.onSignal('test_signal', handler);
|
|
88
|
+
// Directly insert an unprocessed signal
|
|
89
|
+
await router.emit({ targetBrain: 'test-brain', signalType: 'test_signal', payload: { x: 1 } });
|
|
90
|
+
const processed = await router.processQueue();
|
|
91
|
+
expect(processed).toBe(1);
|
|
92
|
+
expect(handler).toHaveBeenCalledOnce();
|
|
93
|
+
});
|
|
94
|
+
it('marks signals as processed', async () => {
|
|
95
|
+
const router = new CrossBrainSignalRouter(db, 'test-brain');
|
|
96
|
+
await router.emit({ targetBrain: 'test-brain', signalType: 'test', payload: {} });
|
|
97
|
+
await router.processQueue();
|
|
98
|
+
// Second process should find nothing
|
|
99
|
+
const processed = await router.processQueue();
|
|
100
|
+
expect(processed).toBe(0);
|
|
101
|
+
});
|
|
102
|
+
it('getStatus returns signal counts by type', async () => {
|
|
103
|
+
const router = new CrossBrainSignalRouter(db, 'brain');
|
|
104
|
+
await router.emit({ targetBrain: 'marketing', signalType: 'trade_signal', payload: {} });
|
|
105
|
+
await router.emit({ targetBrain: 'marketing', signalType: 'trade_signal', payload: {} });
|
|
106
|
+
await router.emit({ targetBrain: 'trading', signalType: 'engagement_signal', payload: {} });
|
|
107
|
+
const status = router.getStatus();
|
|
108
|
+
expect(status.totalSignals).toBe(3);
|
|
109
|
+
expect(status.byType).toHaveLength(2);
|
|
110
|
+
});
|
|
111
|
+
it('getHistory respects limit', async () => {
|
|
112
|
+
const router = new CrossBrainSignalRouter(db, 'brain');
|
|
113
|
+
for (let i = 0; i < 5; i++) {
|
|
114
|
+
await router.emit({ targetBrain: 'other', signalType: 'sig', payload: { i } });
|
|
115
|
+
}
|
|
116
|
+
expect(router.getHistory(3)).toHaveLength(3);
|
|
117
|
+
expect(router.getHistory()).toHaveLength(5);
|
|
118
|
+
});
|
|
119
|
+
it('emits with notifier when set', async () => {
|
|
120
|
+
const router = new CrossBrainSignalRouter(db, 'brain');
|
|
121
|
+
const notifier = { notifyPeer: vi.fn().mockResolvedValue(undefined), notify: vi.fn() };
|
|
122
|
+
router.setNotifier(notifier);
|
|
123
|
+
await router.emit({ targetBrain: 'marketing-brain', signalType: 'test', payload: { foo: 'bar' } });
|
|
124
|
+
expect(notifier.notifyPeer).toHaveBeenCalledOnce();
|
|
125
|
+
expect(notifier.notifyPeer.mock.calls[0][0]).toBe('marketing-brain');
|
|
126
|
+
expect(notifier.notifyPeer.mock.calls[0][1]).toBe('signal:test');
|
|
127
|
+
});
|
|
128
|
+
it('handles notifier failure gracefully', async () => {
|
|
129
|
+
const router = new CrossBrainSignalRouter(db, 'brain');
|
|
130
|
+
const notifier = { notifyPeer: vi.fn().mockRejectedValue(new Error('offline')), notify: vi.fn() };
|
|
131
|
+
router.setNotifier(notifier);
|
|
132
|
+
// Should not throw
|
|
133
|
+
const id = await router.emit({ targetBrain: 'offline-brain', signalType: 'test', payload: {} });
|
|
134
|
+
expect(id).toMatch(/^sig-/);
|
|
135
|
+
});
|
|
136
|
+
it('handles duplicate incoming signal IDs', async () => {
|
|
137
|
+
const router = new CrossBrainSignalRouter(db, 'brain');
|
|
138
|
+
const signal = {
|
|
139
|
+
id: 'sig-dup-1',
|
|
140
|
+
sourceBrain: 'other',
|
|
141
|
+
targetBrain: 'brain',
|
|
142
|
+
signalType: 'test',
|
|
143
|
+
payload: {},
|
|
144
|
+
confidence: 0.5,
|
|
145
|
+
timestamp: Date.now(),
|
|
146
|
+
processed: false,
|
|
147
|
+
};
|
|
148
|
+
await router.handleIncoming(signal);
|
|
149
|
+
// Second call with same ID should not throw
|
|
150
|
+
await router.handleIncoming(signal);
|
|
151
|
+
});
|
|
152
|
+
it('migration is idempotent', () => {
|
|
153
|
+
const router = new CrossBrainSignalRouter(db, 'brain');
|
|
154
|
+
runSignalRouterMigration(db); // Run again
|
|
155
|
+
const status = router.getStatus();
|
|
156
|
+
expect(status.totalSignals).toBe(0);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
//# sourceMappingURL=signal-router.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal-router.test.js","sourceRoot":"","sources":["../../../src/cross-brain/__tests__/signal-router.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import type { CrossBrainNotifier } from './notifications.js';
|
|
3
|
+
export interface CrossBrainSignal {
|
|
4
|
+
id: string;
|
|
5
|
+
sourceBrain: string;
|
|
6
|
+
targetBrain: string;
|
|
7
|
+
signalType: string;
|
|
8
|
+
payload: Record<string, unknown>;
|
|
9
|
+
confidence: number;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
processed: boolean;
|
|
12
|
+
}
|
|
13
|
+
export type SignalHandler = (signal: CrossBrainSignal) => void | Promise<void>;
|
|
14
|
+
export declare function runSignalRouterMigration(db: Database.Database): void;
|
|
15
|
+
/**
|
|
16
|
+
* CrossBrainSignalRouter — bidirectional signal routing between brains.
|
|
17
|
+
* Registers handlers for signal types and dispatches incoming signals.
|
|
18
|
+
* Persists signal history to SQLite.
|
|
19
|
+
*/
|
|
20
|
+
export declare class CrossBrainSignalRouter {
|
|
21
|
+
private readonly db;
|
|
22
|
+
private readonly brainName;
|
|
23
|
+
private readonly handlers;
|
|
24
|
+
private notifier;
|
|
25
|
+
private readonly stmtInsert;
|
|
26
|
+
private readonly stmtMarkProcessed;
|
|
27
|
+
private readonly stmtGetHistory;
|
|
28
|
+
private readonly stmtGetUnprocessed;
|
|
29
|
+
private readonly stmtCountByType;
|
|
30
|
+
constructor(db: Database.Database, brainName: string);
|
|
31
|
+
/** Set the notifier for outgoing signals */
|
|
32
|
+
setNotifier(notifier: CrossBrainNotifier): void;
|
|
33
|
+
/** Register a handler for a signal type */
|
|
34
|
+
onSignal(signalType: string, handler: SignalHandler): void;
|
|
35
|
+
/** Emit a signal to a target brain */
|
|
36
|
+
emit(signal: {
|
|
37
|
+
targetBrain: string;
|
|
38
|
+
signalType: string;
|
|
39
|
+
payload: Record<string, unknown>;
|
|
40
|
+
confidence?: number;
|
|
41
|
+
}): Promise<string>;
|
|
42
|
+
/** Handle an incoming signal (called by IPC handler) */
|
|
43
|
+
handleIncoming(signal: CrossBrainSignal): Promise<void>;
|
|
44
|
+
/** Process all unprocessed incoming signals */
|
|
45
|
+
processQueue(limit?: number): Promise<number>;
|
|
46
|
+
/** Get signal history */
|
|
47
|
+
getHistory(limit?: number): CrossBrainSignal[];
|
|
48
|
+
/** Get status overview */
|
|
49
|
+
getStatus(): {
|
|
50
|
+
totalSignals: number;
|
|
51
|
+
byType: Array<{
|
|
52
|
+
signalType: string;
|
|
53
|
+
count: number;
|
|
54
|
+
}>;
|
|
55
|
+
handlerCount: number;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { getLogger } from '../utils/logger.js';
|
|
2
|
+
// ── Migration ──────────────────────────────────────────────
|
|
3
|
+
export function runSignalRouterMigration(db) {
|
|
4
|
+
db.exec(`
|
|
5
|
+
CREATE TABLE IF NOT EXISTS cross_brain_signals (
|
|
6
|
+
id TEXT PRIMARY KEY,
|
|
7
|
+
source_brain TEXT NOT NULL,
|
|
8
|
+
target_brain TEXT NOT NULL,
|
|
9
|
+
signal_type TEXT NOT NULL,
|
|
10
|
+
payload TEXT DEFAULT '{}',
|
|
11
|
+
confidence REAL DEFAULT 0,
|
|
12
|
+
timestamp INTEGER NOT NULL,
|
|
13
|
+
processed INTEGER DEFAULT 0
|
|
14
|
+
);
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_signal_source ON cross_brain_signals(source_brain);
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_signal_target ON cross_brain_signals(target_brain);
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_signal_type ON cross_brain_signals(signal_type);
|
|
18
|
+
CREATE INDEX IF NOT EXISTS idx_signal_processed ON cross_brain_signals(processed);
|
|
19
|
+
`);
|
|
20
|
+
}
|
|
21
|
+
// ── SignalRouter ──────────────────────────────────────────
|
|
22
|
+
const log = getLogger();
|
|
23
|
+
/**
|
|
24
|
+
* CrossBrainSignalRouter — bidirectional signal routing between brains.
|
|
25
|
+
* Registers handlers for signal types and dispatches incoming signals.
|
|
26
|
+
* Persists signal history to SQLite.
|
|
27
|
+
*/
|
|
28
|
+
export class CrossBrainSignalRouter {
|
|
29
|
+
db;
|
|
30
|
+
brainName;
|
|
31
|
+
handlers = new Map();
|
|
32
|
+
notifier = null;
|
|
33
|
+
stmtInsert;
|
|
34
|
+
stmtMarkProcessed;
|
|
35
|
+
stmtGetHistory;
|
|
36
|
+
stmtGetUnprocessed;
|
|
37
|
+
stmtCountByType;
|
|
38
|
+
constructor(db, brainName) {
|
|
39
|
+
this.db = db;
|
|
40
|
+
this.brainName = brainName;
|
|
41
|
+
runSignalRouterMigration(db);
|
|
42
|
+
this.stmtInsert = db.prepare(`
|
|
43
|
+
INSERT INTO cross_brain_signals (id, source_brain, target_brain, signal_type, payload, confidence, timestamp, processed)
|
|
44
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, 0)
|
|
45
|
+
`);
|
|
46
|
+
this.stmtMarkProcessed = db.prepare(`UPDATE cross_brain_signals SET processed = 1 WHERE id = ?`);
|
|
47
|
+
this.stmtGetHistory = db.prepare(`SELECT * FROM cross_brain_signals ORDER BY timestamp DESC LIMIT ?`);
|
|
48
|
+
this.stmtGetUnprocessed = db.prepare(`SELECT * FROM cross_brain_signals WHERE target_brain = ? AND processed = 0 ORDER BY timestamp ASC LIMIT ?`);
|
|
49
|
+
this.stmtCountByType = db.prepare(`SELECT signal_type, COUNT(*) as count FROM cross_brain_signals GROUP BY signal_type`);
|
|
50
|
+
}
|
|
51
|
+
/** Set the notifier for outgoing signals */
|
|
52
|
+
setNotifier(notifier) {
|
|
53
|
+
this.notifier = notifier;
|
|
54
|
+
}
|
|
55
|
+
/** Register a handler for a signal type */
|
|
56
|
+
onSignal(signalType, handler) {
|
|
57
|
+
const existing = this.handlers.get(signalType) ?? [];
|
|
58
|
+
existing.push(handler);
|
|
59
|
+
this.handlers.set(signalType, existing);
|
|
60
|
+
}
|
|
61
|
+
/** Emit a signal to a target brain */
|
|
62
|
+
async emit(signal) {
|
|
63
|
+
const id = `sig-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
64
|
+
const now = Date.now();
|
|
65
|
+
const fullSignal = {
|
|
66
|
+
id,
|
|
67
|
+
sourceBrain: this.brainName,
|
|
68
|
+
targetBrain: signal.targetBrain,
|
|
69
|
+
signalType: signal.signalType,
|
|
70
|
+
payload: signal.payload,
|
|
71
|
+
confidence: signal.confidence ?? 0.5,
|
|
72
|
+
timestamp: now,
|
|
73
|
+
processed: false,
|
|
74
|
+
};
|
|
75
|
+
// Persist
|
|
76
|
+
this.stmtInsert.run(id, fullSignal.sourceBrain, fullSignal.targetBrain, fullSignal.signalType, JSON.stringify(fullSignal.payload), fullSignal.confidence, now);
|
|
77
|
+
// Notify target brain via cross-brain IPC
|
|
78
|
+
if (this.notifier) {
|
|
79
|
+
try {
|
|
80
|
+
await this.notifier.notifyPeer(signal.targetBrain, `signal:${signal.signalType}`, fullSignal);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
log.debug(`[signal-router] Failed to notify ${signal.targetBrain} (may be offline)`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
log.info(`[signal-router] Emitted ${signal.signalType} → ${signal.targetBrain} (conf=${fullSignal.confidence.toFixed(2)})`);
|
|
87
|
+
return id;
|
|
88
|
+
}
|
|
89
|
+
/** Handle an incoming signal (called by IPC handler) */
|
|
90
|
+
async handleIncoming(signal) {
|
|
91
|
+
// Persist incoming signal
|
|
92
|
+
try {
|
|
93
|
+
this.stmtInsert.run(signal.id, signal.sourceBrain, signal.targetBrain, signal.signalType, JSON.stringify(signal.payload), signal.confidence, signal.timestamp);
|
|
94
|
+
}
|
|
95
|
+
catch { /* duplicate id — already recorded */ }
|
|
96
|
+
// Dispatch to handlers
|
|
97
|
+
const handlers = this.handlers.get(signal.signalType) ?? [];
|
|
98
|
+
for (const handler of handlers) {
|
|
99
|
+
try {
|
|
100
|
+
await handler(signal);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
log.warn(`[signal-router] Handler error for ${signal.signalType}: ${err.message}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Mark as processed
|
|
107
|
+
this.stmtMarkProcessed.run(signal.id);
|
|
108
|
+
log.info(`[signal-router] Processed incoming ${signal.signalType} from ${signal.sourceBrain}`);
|
|
109
|
+
}
|
|
110
|
+
/** Process all unprocessed incoming signals */
|
|
111
|
+
async processQueue(limit) {
|
|
112
|
+
const rows = this.stmtGetUnprocessed.all(this.brainName, limit ?? 50);
|
|
113
|
+
let processed = 0;
|
|
114
|
+
for (const row of rows) {
|
|
115
|
+
const signal = deserializeSignal(row);
|
|
116
|
+
await this.handleIncoming(signal);
|
|
117
|
+
processed++;
|
|
118
|
+
}
|
|
119
|
+
return processed;
|
|
120
|
+
}
|
|
121
|
+
/** Get signal history */
|
|
122
|
+
getHistory(limit) {
|
|
123
|
+
return this.stmtGetHistory.all(limit ?? 50).map(deserializeSignal);
|
|
124
|
+
}
|
|
125
|
+
/** Get status overview */
|
|
126
|
+
getStatus() {
|
|
127
|
+
const byType = this.stmtCountByType.all();
|
|
128
|
+
const totalSignals = byType.reduce((sum, r) => sum + r.count, 0);
|
|
129
|
+
return {
|
|
130
|
+
totalSignals,
|
|
131
|
+
byType: byType.map(r => ({ signalType: r.signal_type, count: r.count })),
|
|
132
|
+
handlerCount: this.handlers.size,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function deserializeSignal(row) {
|
|
137
|
+
return {
|
|
138
|
+
id: row.id,
|
|
139
|
+
sourceBrain: row.source_brain,
|
|
140
|
+
targetBrain: row.target_brain,
|
|
141
|
+
signalType: row.signal_type,
|
|
142
|
+
payload: JSON.parse(row.payload || '{}'),
|
|
143
|
+
confidence: row.confidence,
|
|
144
|
+
timestamp: row.timestamp,
|
|
145
|
+
processed: row.processed === 1,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=signal-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signal-router.js","sourceRoot":"","sources":["../../src/cross-brain/signal-router.ts"],"names":[],"mappings":"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"}
|
|
@@ -487,5 +487,36 @@ describe('CommandCenterServer', () => {
|
|
|
487
487
|
server = null;
|
|
488
488
|
await expect(request(result.port, '/')).rejects.toThrow();
|
|
489
489
|
});
|
|
490
|
+
// ─── Session 99: Forge API ─────────────────────────────
|
|
491
|
+
it('GET /api/forge returns forge status data', async () => {
|
|
492
|
+
const result = await startServer({
|
|
493
|
+
getActionBridgeStatus: () => ({ queueSize: 3, executed24h: 12, successRate: 0.85, autoExecuteEnabled: true, topSources: [] }),
|
|
494
|
+
getContentForgeStatus: () => ({ drafts: 5, scheduled: 2, published: 10, avgEngagement: 4.5 }),
|
|
495
|
+
getStrategyForgeStatus: () => ({ active: 2, total: 8, avgPerformance: 0.65, topStrategy: 'btc-dca' }),
|
|
496
|
+
getSignalRouterStatus: () => ({ totalSignals: 15, byType: [{ signalType: 'trade_signal', count: 10 }], handlerCount: 2 }),
|
|
497
|
+
});
|
|
498
|
+
const res = await request(result.port, '/api/forge');
|
|
499
|
+
expect(res.statusCode).toBe(200);
|
|
500
|
+
const data = JSON.parse(res.body);
|
|
501
|
+
expect(data.actionBridge.queueSize).toBe(3);
|
|
502
|
+
expect(data.contentForge.published).toBe(10);
|
|
503
|
+
expect(data.strategyForge.topStrategy).toBe('btc-dca');
|
|
504
|
+
expect(data.signalRouter.totalSignals).toBe(15);
|
|
505
|
+
});
|
|
506
|
+
it('GET /api/forge returns nulls when no getters provided', async () => {
|
|
507
|
+
const result = await startServer({});
|
|
508
|
+
const res = await request(result.port, '/api/forge');
|
|
509
|
+
expect(res.statusCode).toBe(200);
|
|
510
|
+
const data = JSON.parse(res.body);
|
|
511
|
+
expect(data.actionBridge).toBeNull();
|
|
512
|
+
expect(data.contentForge).toBeNull();
|
|
513
|
+
expect(data.strategyForge).toBeNull();
|
|
514
|
+
expect(data.signalRouter).toBeNull();
|
|
515
|
+
});
|
|
516
|
+
it('returns 404 for unknown routes', async () => {
|
|
517
|
+
const result = await startServer({});
|
|
518
|
+
const res = await request(result.port, '/api/nonexistent');
|
|
519
|
+
expect(res.statusCode).toBe(404);
|
|
520
|
+
});
|
|
490
521
|
});
|
|
491
522
|
//# sourceMappingURL=command-center-server.test.js.map
|