@timmeck/brain-core 2.36.56 → 2.36.57

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 (43) hide show
  1. package/dist/action/__tests__/action-bridge.test.d.ts +1 -0
  2. package/dist/action/__tests__/action-bridge.test.js +145 -0
  3. package/dist/action/__tests__/action-bridge.test.js.map +1 -0
  4. package/dist/action/action-bridge.d.ts +95 -0
  5. package/dist/action/action-bridge.js +241 -0
  6. package/dist/action/action-bridge.js.map +1 -0
  7. package/dist/action/index.d.ts +2 -0
  8. package/dist/action/index.js +2 -0
  9. package/dist/action/index.js.map +1 -0
  10. package/dist/codegen/__tests__/code-forge.test.d.ts +1 -0
  11. package/dist/codegen/__tests__/code-forge.test.js +105 -0
  12. package/dist/codegen/__tests__/code-forge.test.js.map +1 -0
  13. package/dist/codegen/code-forge.d.ts +87 -0
  14. package/dist/codegen/code-forge.js +211 -0
  15. package/dist/codegen/code-forge.js.map +1 -0
  16. package/dist/codegen/index.d.ts +2 -0
  17. package/dist/codegen/index.js +1 -0
  18. package/dist/codegen/index.js.map +1 -1
  19. package/dist/content/__tests__/content-forge.test.d.ts +1 -0
  20. package/dist/content/__tests__/content-forge.test.js +117 -0
  21. package/dist/content/__tests__/content-forge.test.js.map +1 -0
  22. package/dist/content/content-forge.d.ts +104 -0
  23. package/dist/content/content-forge.js +213 -0
  24. package/dist/content/content-forge.js.map +1 -0
  25. package/dist/content/index.d.ts +2 -0
  26. package/dist/content/index.js +2 -0
  27. package/dist/content/index.js.map +1 -0
  28. package/dist/index.d.ts +8 -0
  29. package/dist/index.js +8 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/research/research-orchestrator.d.ts +12 -0
  32. package/dist/research/research-orchestrator.js +108 -0
  33. package/dist/research/research-orchestrator.js.map +1 -1
  34. package/dist/strategy/__tests__/strategy-forge.test.d.ts +1 -0
  35. package/dist/strategy/__tests__/strategy-forge.test.js +121 -0
  36. package/dist/strategy/__tests__/strategy-forge.test.js.map +1 -0
  37. package/dist/strategy/index.d.ts +2 -0
  38. package/dist/strategy/index.js +2 -0
  39. package/dist/strategy/index.js.map +1 -0
  40. package/dist/strategy/strategy-forge.d.ts +111 -0
  41. package/dist/strategy/strategy-forge.js +264 -0
  42. package/dist/strategy/strategy-forge.js.map +1 -0
  43. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,145 @@
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 { ActionBridgeEngine, runActionBridgeMigration } from '../action-bridge.js';
7
+ describe('ActionBridgeEngine', () => {
8
+ let db;
9
+ beforeEach(() => { db = new Database(':memory:'); });
10
+ afterEach(() => { db.close(); });
11
+ it('proposes an action and retrieves it', () => {
12
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
13
+ const id = engine.propose({ source: 'proactive', type: 'adjust_parameter', title: 'Increase learning rate', confidence: 0.8 });
14
+ expect(id).toBeGreaterThan(0);
15
+ const queue = engine.getQueue('pending');
16
+ expect(queue).toHaveLength(1);
17
+ expect(queue[0].title).toBe('Increase learning rate');
18
+ expect(queue[0].riskLevel).toBe('low');
19
+ });
20
+ it('evaluates risk correctly for each type', () => {
21
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
22
+ expect(engine.evaluateRisk('adjust_parameter')).toBe('low');
23
+ expect(engine.evaluateRisk('create_goal')).toBe('low');
24
+ expect(engine.evaluateRisk('start_mission')).toBe('low');
25
+ expect(engine.evaluateRisk('publish_content')).toBe('medium');
26
+ expect(engine.evaluateRisk('execute_trade')).toBe('medium');
27
+ expect(engine.evaluateRisk('apply_code')).toBe('high');
28
+ });
29
+ it('auto-executes qualifying low-risk actions', async () => {
30
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
31
+ const handler = vi.fn().mockResolvedValue({ adjusted: true });
32
+ engine.registerHandler('adjust_parameter', handler);
33
+ engine.propose({ source: 'proactive', type: 'adjust_parameter', title: 'Auto test', confidence: 0.8 });
34
+ const executed = await engine.processQueue();
35
+ expect(executed).toBe(1);
36
+ expect(handler).toHaveBeenCalled();
37
+ const history = engine.getHistory();
38
+ expect(history).toHaveLength(1);
39
+ expect(history[0].status).toBe('completed');
40
+ });
41
+ it('does not auto-execute when confidence too low', async () => {
42
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
43
+ engine.registerHandler('adjust_parameter', vi.fn());
44
+ engine.propose({ source: 'proactive', type: 'adjust_parameter', title: 'Low conf', confidence: 0.3 });
45
+ const executed = await engine.processQueue();
46
+ expect(executed).toBe(0);
47
+ });
48
+ it('does not auto-execute apply_code (always high risk)', async () => {
49
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
50
+ engine.registerHandler('apply_code', vi.fn());
51
+ engine.propose({ source: 'codegen', type: 'apply_code', title: 'Refactor', confidence: 0.99 });
52
+ const executed = await engine.processQueue();
53
+ expect(executed).toBe(0); // never auto for apply_code
54
+ });
55
+ it('executes action manually', async () => {
56
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
57
+ engine.registerHandler('publish_content', vi.fn().mockResolvedValue({ published: true }));
58
+ const id = engine.propose({ source: 'creative', type: 'publish_content', title: 'Post insight', confidence: 0.5 });
59
+ const result = await engine.executeAction(id);
60
+ expect(result.success).toBe(true);
61
+ });
62
+ it('records failed execution', async () => {
63
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
64
+ engine.registerHandler('publish_content', vi.fn().mockRejectedValue(new Error('API down')));
65
+ const id = engine.propose({ source: 'creative', type: 'publish_content', title: 'Fail test', confidence: 0.9 });
66
+ const result = await engine.executeAction(id);
67
+ expect(result.success).toBe(false);
68
+ const action = engine.getAction(id);
69
+ expect(action?.status).toBe('failed');
70
+ });
71
+ it('returns error when no handler registered', async () => {
72
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
73
+ const id = engine.propose({ source: 'proactive', type: 'start_mission', title: 'No handler', confidence: 0.9 });
74
+ const result = await engine.executeAction(id);
75
+ expect(result.success).toBe(false);
76
+ expect(result.result).toBe('No handler registered');
77
+ });
78
+ it('rolls back a completed action', async () => {
79
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
80
+ engine.registerHandler('adjust_parameter', vi.fn().mockResolvedValue({}));
81
+ const id = engine.propose({ source: 'proactive', type: 'adjust_parameter', title: 'Rollback test', confidence: 0.9 });
82
+ await engine.executeAction(id);
83
+ engine.rollback(id);
84
+ const action = engine.getAction(id);
85
+ expect(action?.status).toBe('rolled_back');
86
+ });
87
+ it('cannot rollback a pending action', () => {
88
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
89
+ const id = engine.propose({ source: 'proactive', type: 'adjust_parameter', title: 'No rollback', confidence: 0.5 });
90
+ expect(() => engine.rollback(id)).toThrow('cannot be rolled back');
91
+ });
92
+ it('tracks success rate', async () => {
93
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
94
+ engine.registerHandler('adjust_parameter', vi.fn().mockResolvedValue({}));
95
+ engine.registerHandler('create_goal', vi.fn().mockRejectedValue(new Error('fail')));
96
+ const id1 = engine.propose({ source: 'proactive', type: 'adjust_parameter', title: 'Success', confidence: 0.9 });
97
+ const id2 = engine.propose({ source: 'proactive', type: 'create_goal', title: 'Fail', confidence: 0.9 });
98
+ await engine.executeAction(id1);
99
+ await engine.executeAction(id2);
100
+ expect(engine.getSuccessRate()).toBe(0.5);
101
+ expect(engine.getSuccessRate('adjust_parameter')).toBe(1);
102
+ expect(engine.getSuccessRate(undefined, 'proactive')).toBe(0.5);
103
+ });
104
+ it('records outcome manually', () => {
105
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
106
+ const id = engine.propose({ source: 'mission', type: 'start_mission', title: 'Outcome test', confidence: 0.7 });
107
+ // Manually mark as executing first by internal exec
108
+ engine.registerHandler('start_mission', vi.fn().mockResolvedValue({}));
109
+ engine.recordOutcome(id, { success: true, result: { missionId: 42 }, learnedLesson: 'Missions work' });
110
+ const action = engine.getAction(id);
111
+ expect(action?.status).toBe('completed');
112
+ expect(action?.outcome?.learnedLesson).toBe('Missions work');
113
+ });
114
+ it('rejects proposal when queue is full', () => {
115
+ const engine = new ActionBridgeEngine(db, { brainName: 'test', maxPendingActions: 2 });
116
+ engine.propose({ source: 'proactive', type: 'adjust_parameter', title: 'One', confidence: 0.5 });
117
+ engine.propose({ source: 'proactive', type: 'adjust_parameter', title: 'Two', confidence: 0.5 });
118
+ const id = engine.propose({ source: 'proactive', type: 'adjust_parameter', title: 'Three', confidence: 0.5 });
119
+ expect(id).toBe(-1);
120
+ });
121
+ it('disables auto-execute when configured', async () => {
122
+ const engine = new ActionBridgeEngine(db, { brainName: 'test', autoExecuteEnabled: false });
123
+ engine.registerHandler('adjust_parameter', vi.fn());
124
+ engine.propose({ source: 'proactive', type: 'adjust_parameter', title: 'No auto', confidence: 0.9 });
125
+ const executed = await engine.processQueue();
126
+ expect(executed).toBe(0);
127
+ });
128
+ it('getStatus returns overview', () => {
129
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
130
+ engine.propose({ source: 'proactive', type: 'adjust_parameter', title: 'Test', confidence: 0.5 });
131
+ const status = engine.getStatus();
132
+ expect(status.queueSize).toBe(1);
133
+ expect(status.autoExecuteEnabled).toBe(true);
134
+ expect(status.topSources).toHaveLength(1);
135
+ expect(status.topSources[0].source).toBe('proactive');
136
+ });
137
+ it('migration is idempotent', () => {
138
+ const engine = new ActionBridgeEngine(db, { brainName: 'test' });
139
+ engine.propose({ source: 'proactive', type: 'start_mission', title: 'Survives', confidence: 0.5 });
140
+ runActionBridgeMigration(db);
141
+ const queue = engine.getQueue('pending');
142
+ expect(queue).toHaveLength(1);
143
+ });
144
+ });
145
+ //# sourceMappingURL=action-bridge.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-bridge.test.js","sourceRoot":"","sources":["../../../src/action/__tests__/action-bridge.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ import type Database from 'better-sqlite3';
2
+ export interface ProposedAction {
3
+ id: number;
4
+ source: 'proactive' | 'creative' | 'mission' | 'selfmod' | 'codegen' | 'research';
5
+ type: 'publish_content' | 'apply_code' | 'execute_trade' | 'adjust_parameter' | 'create_goal' | 'start_mission';
6
+ title: string;
7
+ description: string;
8
+ confidence: number;
9
+ riskLevel: 'low' | 'medium' | 'high';
10
+ payload: Record<string, unknown>;
11
+ status: 'pending' | 'approved' | 'executing' | 'completed' | 'failed' | 'rolled_back';
12
+ outcome?: ActionOutcome;
13
+ executedAt?: string;
14
+ createdAt?: string;
15
+ }
16
+ export interface ActionOutcome {
17
+ success: boolean;
18
+ result: unknown;
19
+ metrics?: Record<string, number>;
20
+ learnedLesson?: string;
21
+ }
22
+ export interface ActionBridgeConfig {
23
+ brainName: string;
24
+ maxPendingActions?: number;
25
+ autoExecuteEnabled?: boolean;
26
+ }
27
+ export interface ActionBridgeStatus {
28
+ queueSize: number;
29
+ executed24h: number;
30
+ successRate: number;
31
+ topSources: Array<{
32
+ source: string;
33
+ count: number;
34
+ }>;
35
+ autoExecuteEnabled: boolean;
36
+ }
37
+ type ActionType = ProposedAction['type'];
38
+ type ActionSource = ProposedAction['source'];
39
+ type RiskLevel = ProposedAction['riskLevel'];
40
+ export declare function runActionBridgeMigration(db: Database.Database): void;
41
+ export declare class ActionBridgeEngine {
42
+ private readonly db;
43
+ private readonly config;
44
+ private readonly log;
45
+ private handlers;
46
+ private readonly stmtInsert;
47
+ private readonly stmtGetById;
48
+ private readonly stmtUpdateStatus;
49
+ private readonly stmtSetOutcome;
50
+ private readonly stmtGetQueue;
51
+ private readonly stmtGetHistory;
52
+ private readonly stmtSuccessRate;
53
+ private readonly stmtSuccessRateByType;
54
+ private readonly stmtSuccessRateBySource;
55
+ private readonly stmtExecuted24h;
56
+ private readonly stmtTopSources;
57
+ constructor(db: Database.Database, config: ActionBridgeConfig);
58
+ /** Register an execution handler for an action type */
59
+ registerHandler(type: ActionType, handler: (payload: Record<string, unknown>) => Promise<unknown> | unknown): void;
60
+ /** Propose a new action — returns the action ID */
61
+ propose(action: {
62
+ source: ActionSource;
63
+ type: ActionType;
64
+ title: string;
65
+ description?: string;
66
+ confidence: number;
67
+ payload?: Record<string, unknown>;
68
+ }): number;
69
+ /** Evaluate risk level for an action type */
70
+ evaluateRisk(type: ActionType, _confidence?: number): RiskLevel;
71
+ /** Check if an action qualifies for auto-execution */
72
+ canAutoExecute(action: ProposedAction): boolean;
73
+ /** Execute a specific action by ID */
74
+ executeAction(actionId: number): Promise<{
75
+ success: boolean;
76
+ result: unknown;
77
+ }>;
78
+ /** Process pending queue — auto-execute qualifying actions */
79
+ processQueue(): Promise<number>;
80
+ /** Record outcome for an already-executed action */
81
+ recordOutcome(actionId: number, outcome: ActionOutcome): void;
82
+ /** Rollback a completed action */
83
+ rollback(actionId: number): void;
84
+ /** Get success rate (optionally filtered by type or source) */
85
+ getSuccessRate(type?: string, source?: string): number;
86
+ /** Get queue items by status */
87
+ getQueue(status?: string): ProposedAction[];
88
+ /** Get action history (completed/failed/rolled_back) */
89
+ getHistory(limit?: number): ProposedAction[];
90
+ /** Get a single action by ID */
91
+ getAction(id: number): ProposedAction | null;
92
+ /** Get status overview */
93
+ getStatus(): ActionBridgeStatus;
94
+ }
95
+ export {};
@@ -0,0 +1,241 @@
1
+ import { getLogger } from '../utils/logger.js';
2
+ // Risk thresholds: type → { risk, minConfidence }
3
+ const RISK_MAP = {
4
+ adjust_parameter: { risk: 'low', minConfidence: 0.7 },
5
+ create_goal: { risk: 'low', minConfidence: 0.6 },
6
+ start_mission: { risk: 'low', minConfidence: 0.5 },
7
+ publish_content: { risk: 'medium', minConfidence: 0.8 },
8
+ execute_trade: { risk: 'medium', minConfidence: 0.8 },
9
+ apply_code: { risk: 'high', minConfidence: 1.1 }, // never auto (>1.0)
10
+ };
11
+ // ── Migration ──────────────────────────────────────────────
12
+ export function runActionBridgeMigration(db) {
13
+ db.exec(`
14
+ CREATE TABLE IF NOT EXISTS action_queue (
15
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
16
+ source TEXT NOT NULL,
17
+ type TEXT NOT NULL,
18
+ title TEXT NOT NULL,
19
+ description TEXT,
20
+ confidence REAL DEFAULT 0,
21
+ risk_level TEXT DEFAULT 'medium',
22
+ payload TEXT,
23
+ status TEXT DEFAULT 'pending',
24
+ outcome TEXT,
25
+ executed_at TEXT,
26
+ created_at TEXT DEFAULT (datetime('now'))
27
+ );
28
+ CREATE INDEX IF NOT EXISTS idx_action_status ON action_queue(status);
29
+ CREATE INDEX IF NOT EXISTS idx_action_source ON action_queue(source);
30
+ CREATE INDEX IF NOT EXISTS idx_action_type ON action_queue(type);
31
+ CREATE INDEX IF NOT EXISTS idx_action_created ON action_queue(created_at);
32
+ `);
33
+ }
34
+ // ── Engine ──────────────────────────────────────────────────
35
+ export class ActionBridgeEngine {
36
+ db;
37
+ config;
38
+ log = getLogger();
39
+ // Execution handlers keyed by action type
40
+ handlers = new Map();
41
+ // Prepared statements
42
+ stmtInsert;
43
+ stmtGetById;
44
+ stmtUpdateStatus;
45
+ stmtSetOutcome;
46
+ stmtGetQueue;
47
+ stmtGetHistory;
48
+ stmtSuccessRate;
49
+ stmtSuccessRateByType;
50
+ stmtSuccessRateBySource;
51
+ stmtExecuted24h;
52
+ stmtTopSources;
53
+ constructor(db, config) {
54
+ this.db = db;
55
+ this.config = {
56
+ brainName: config.brainName,
57
+ maxPendingActions: config.maxPendingActions ?? 100,
58
+ autoExecuteEnabled: config.autoExecuteEnabled ?? true,
59
+ };
60
+ runActionBridgeMigration(db);
61
+ this.stmtInsert = db.prepare(`
62
+ INSERT INTO action_queue (source, type, title, description, confidence, risk_level, payload, status)
63
+ VALUES (?, ?, ?, ?, ?, ?, ?, 'pending')
64
+ `);
65
+ this.stmtGetById = db.prepare(`SELECT * FROM action_queue WHERE id = ?`);
66
+ this.stmtUpdateStatus = db.prepare(`UPDATE action_queue SET status = ? WHERE id = ?`);
67
+ this.stmtSetOutcome = db.prepare(`UPDATE action_queue SET status = ?, outcome = ?, executed_at = datetime('now') WHERE id = ?`);
68
+ this.stmtGetQueue = db.prepare(`SELECT * FROM action_queue WHERE status = ? ORDER BY confidence DESC, created_at ASC LIMIT ?`);
69
+ this.stmtGetHistory = db.prepare(`SELECT * FROM action_queue WHERE status IN ('completed', 'failed', 'rolled_back') ORDER BY executed_at DESC LIMIT ?`);
70
+ this.stmtSuccessRate = db.prepare(`SELECT COUNT(*) as total, SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as successes FROM action_queue WHERE status IN ('completed', 'failed')`);
71
+ this.stmtSuccessRateByType = db.prepare(`SELECT COUNT(*) as total, SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as successes FROM action_queue WHERE status IN ('completed', 'failed') AND type = ?`);
72
+ this.stmtSuccessRateBySource = db.prepare(`SELECT COUNT(*) as total, SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as successes FROM action_queue WHERE status IN ('completed', 'failed') AND source = ?`);
73
+ this.stmtExecuted24h = db.prepare(`SELECT COUNT(*) as count FROM action_queue WHERE executed_at > datetime('now', '-1 day')`);
74
+ this.stmtTopSources = db.prepare(`SELECT source, COUNT(*) as count FROM action_queue GROUP BY source ORDER BY count DESC LIMIT 5`);
75
+ }
76
+ /** Register an execution handler for an action type */
77
+ registerHandler(type, handler) {
78
+ this.handlers.set(type, handler);
79
+ }
80
+ /** Propose a new action — returns the action ID */
81
+ propose(action) {
82
+ const risk = this.evaluateRisk(action.type, action.confidence);
83
+ // Check queue limit
84
+ const pending = this.getQueue('pending');
85
+ if (pending.length >= this.config.maxPendingActions) {
86
+ this.log.warn(`[action-bridge] Queue full (${pending.length}/${this.config.maxPendingActions}), rejecting: ${action.title}`);
87
+ return -1;
88
+ }
89
+ const result = this.stmtInsert.run(action.source, action.type, action.title, action.description ?? '', action.confidence, risk, JSON.stringify(action.payload ?? {}));
90
+ const id = Number(result.lastInsertRowid);
91
+ this.log.info(`[action-bridge] Proposed #${id}: ${action.title} (${action.source}/${action.type}, risk=${risk}, conf=${action.confidence.toFixed(2)})`);
92
+ return id;
93
+ }
94
+ /** Evaluate risk level for an action type */
95
+ evaluateRisk(type, _confidence) {
96
+ return RISK_MAP[type]?.risk ?? 'high';
97
+ }
98
+ /** Check if an action qualifies for auto-execution */
99
+ canAutoExecute(action) {
100
+ if (!this.config.autoExecuteEnabled)
101
+ return false;
102
+ const rule = RISK_MAP[action.type];
103
+ if (!rule)
104
+ return false;
105
+ return action.confidence >= rule.minConfidence;
106
+ }
107
+ /** Execute a specific action by ID */
108
+ async executeAction(actionId) {
109
+ const row = this.stmtGetById.get(actionId);
110
+ if (!row)
111
+ throw new Error(`Action #${actionId} not found`);
112
+ const action = deserializeAction(row);
113
+ if (action.status !== 'pending' && action.status !== 'approved') {
114
+ throw new Error(`Action #${actionId} cannot be executed (status=${action.status})`);
115
+ }
116
+ const handler = this.handlers.get(action.type);
117
+ if (!handler) {
118
+ this.log.warn(`[action-bridge] No handler for type: ${action.type}`);
119
+ this.stmtSetOutcome.run('failed', JSON.stringify({ success: false, result: 'No handler registered' }), actionId);
120
+ return { success: false, result: 'No handler registered' };
121
+ }
122
+ this.stmtUpdateStatus.run('executing', actionId);
123
+ try {
124
+ const result = await handler(action.payload);
125
+ const outcome = { success: true, result };
126
+ this.stmtSetOutcome.run('completed', JSON.stringify(outcome), actionId);
127
+ this.log.info(`[action-bridge] Executed #${actionId}: ${action.title} → success`);
128
+ return { success: true, result };
129
+ }
130
+ catch (err) {
131
+ const outcome = { success: false, result: err.message };
132
+ this.stmtSetOutcome.run('failed', JSON.stringify(outcome), actionId);
133
+ this.log.warn(`[action-bridge] Executed #${actionId}: ${action.title} → failed: ${err.message}`);
134
+ return { success: false, result: err.message };
135
+ }
136
+ }
137
+ /** Process pending queue — auto-execute qualifying actions */
138
+ async processQueue() {
139
+ if (!this.config.autoExecuteEnabled)
140
+ return 0;
141
+ const pending = this.getQueue('pending');
142
+ let executed = 0;
143
+ for (const action of pending) {
144
+ if (this.canAutoExecute(action)) {
145
+ try {
146
+ await this.executeAction(action.id);
147
+ executed++;
148
+ }
149
+ catch (err) {
150
+ this.log.warn(`[action-bridge] Auto-execute error for #${action.id}: ${err.message}`);
151
+ }
152
+ }
153
+ }
154
+ if (executed > 0) {
155
+ this.log.info(`[action-bridge] Auto-executed ${executed} action(s)`);
156
+ }
157
+ return executed;
158
+ }
159
+ /** Record outcome for an already-executed action */
160
+ recordOutcome(actionId, outcome) {
161
+ const row = this.stmtGetById.get(actionId);
162
+ if (!row)
163
+ throw new Error(`Action #${actionId} not found`);
164
+ const status = outcome.success ? 'completed' : 'failed';
165
+ this.stmtSetOutcome.run(status, JSON.stringify(outcome), actionId);
166
+ this.log.info(`[action-bridge] Outcome recorded for #${actionId}: ${status}`);
167
+ }
168
+ /** Rollback a completed action */
169
+ rollback(actionId) {
170
+ const row = this.stmtGetById.get(actionId);
171
+ if (!row)
172
+ throw new Error(`Action #${actionId} not found`);
173
+ if (row.status !== 'completed' && row.status !== 'failed') {
174
+ throw new Error(`Action #${actionId} cannot be rolled back (status=${row.status})`);
175
+ }
176
+ this.stmtUpdateStatus.run('rolled_back', actionId);
177
+ this.log.info(`[action-bridge] Rolled back #${actionId}`);
178
+ }
179
+ /** Get success rate (optionally filtered by type or source) */
180
+ getSuccessRate(type, source) {
181
+ let row;
182
+ if (type) {
183
+ row = this.stmtSuccessRateByType.get(type);
184
+ }
185
+ else if (source) {
186
+ row = this.stmtSuccessRateBySource.get(source);
187
+ }
188
+ else {
189
+ row = this.stmtSuccessRate.get();
190
+ }
191
+ if (!row || row.total === 0)
192
+ return 0;
193
+ return row.successes / row.total;
194
+ }
195
+ /** Get queue items by status */
196
+ getQueue(status) {
197
+ const rows = this.stmtGetQueue.all(status ?? 'pending', 100);
198
+ return rows.map(deserializeAction);
199
+ }
200
+ /** Get action history (completed/failed/rolled_back) */
201
+ getHistory(limit) {
202
+ const rows = this.stmtGetHistory.all(limit ?? 50);
203
+ return rows.map(deserializeAction);
204
+ }
205
+ /** Get a single action by ID */
206
+ getAction(id) {
207
+ const row = this.stmtGetById.get(id);
208
+ return row ? deserializeAction(row) : null;
209
+ }
210
+ /** Get status overview */
211
+ getStatus() {
212
+ const queueSize = (this.getQueue('pending')).length;
213
+ const executed24h = this.stmtExecuted24h.get().count;
214
+ const successRate = this.getSuccessRate();
215
+ const topSources = this.stmtTopSources.all();
216
+ return {
217
+ queueSize,
218
+ executed24h,
219
+ successRate,
220
+ topSources,
221
+ autoExecuteEnabled: this.config.autoExecuteEnabled,
222
+ };
223
+ }
224
+ }
225
+ function deserializeAction(row) {
226
+ return {
227
+ id: row.id,
228
+ source: row.source,
229
+ type: row.type,
230
+ title: row.title,
231
+ description: row.description,
232
+ confidence: row.confidence,
233
+ riskLevel: row.risk_level,
234
+ payload: JSON.parse(row.payload || '{}'),
235
+ status: row.status,
236
+ outcome: row.outcome ? JSON.parse(row.outcome) : undefined,
237
+ executedAt: row.executed_at ?? undefined,
238
+ createdAt: row.created_at,
239
+ };
240
+ }
241
+ //# sourceMappingURL=action-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-bridge.js","sourceRoot":"","sources":["../../src/action/action-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { ActionBridgeEngine, runActionBridgeMigration } from './action-bridge.js';
2
+ export type { ProposedAction, ActionOutcome, ActionBridgeConfig, ActionBridgeStatus, } from './action-bridge.js';
@@ -0,0 +1,2 @@
1
+ export { ActionBridgeEngine, runActionBridgeMigration } from './action-bridge.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/action/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,105 @@
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 { CodeForge, runCodeForgeMigration } from '../code-forge.js';
7
+ describe('CodeForge', () => {
8
+ let db;
9
+ beforeEach(() => { db = new Database(':memory:'); });
10
+ afterEach(() => { db.close(); });
11
+ it('adds a pattern and retrieves it', () => {
12
+ const forge = new CodeForge(db, { brainName: 'test' });
13
+ const id = forge.addPattern('retry logic', 4, ['a.ts', 'b.ts', 'c.ts', 'd.ts'], 0.85);
14
+ expect(id).toBeGreaterThan(0);
15
+ const patterns = forge.extractPatterns();
16
+ expect(patterns).toHaveLength(1);
17
+ expect(patterns[0].pattern).toBe('retry logic');
18
+ expect(patterns[0].occurrences).toBe(4);
19
+ });
20
+ it('generates a utility from a pattern', () => {
21
+ const forge = new CodeForge(db, { brainName: 'test' });
22
+ const pattern = { id: 1, pattern: 'error handler', occurrences: 3, files: ['a.ts', 'b.ts'], similarity: 0.7 };
23
+ const product = forge.generateUtility(pattern);
24
+ expect(product.id).toBeGreaterThan(0);
25
+ expect(product.type).toBe('utility');
26
+ expect(product.status).toBe('generated');
27
+ expect(product.files).toHaveLength(1);
28
+ });
29
+ it('scaffolds a project', () => {
30
+ const forge = new CodeForge(db, { brainName: 'test' });
31
+ const product = forge.scaffoldProject('brain-plugin', { name: 'my-plugin' });
32
+ expect(product.type).toBe('scaffold');
33
+ expect(product.files.length).toBeGreaterThanOrEqual(3);
34
+ expect(product.files.some(f => f.path.includes('package.json'))).toBe(true);
35
+ });
36
+ it('generates a test file', () => {
37
+ const forge = new CodeForge(db, { brainName: 'test' });
38
+ const product = forge.generateTest('src/utils/retry.ts');
39
+ expect(product.type).toBe('test');
40
+ expect(product.files).toHaveLength(1);
41
+ expect(product.files[0].path).toContain('__tests__');
42
+ });
43
+ it('applies a product', () => {
44
+ const forge = new CodeForge(db, { brainName: 'test' });
45
+ const product = forge.scaffoldProject('template', { name: 'test-proj' });
46
+ const result = forge.applyProduct(product.id);
47
+ expect(result.success).toBe(true);
48
+ const products = forge.getProducts('applied');
49
+ expect(products).toHaveLength(1);
50
+ });
51
+ it('blocks apply on protected paths', () => {
52
+ const forge = new CodeForge(db, { brainName: 'test' });
53
+ forge.setGuardrailEngine({ isProtectedPath: (path) => path.includes('package.json') });
54
+ const product = forge.scaffoldProject('template', { name: 'protected-proj' });
55
+ const result = forge.applyProduct(product.id);
56
+ expect(result.success).toBe(false);
57
+ });
58
+ it('rolls back a product', () => {
59
+ const forge = new CodeForge(db, { brainName: 'test' });
60
+ const product = forge.scaffoldProject('template', { name: 'rollback-test' });
61
+ forge.applyProduct(product.id);
62
+ forge.rollback(product.id);
63
+ const products = forge.getProducts('rolled_back');
64
+ expect(products).toHaveLength(1);
65
+ });
66
+ it('auto-applies a selfmod proposal', () => {
67
+ const forge = new CodeForge(db, { brainName: 'test' });
68
+ const mockSelfMod = { proposeModification: vi.fn(), applyModification: vi.fn() };
69
+ forge.setSelfModificationEngine(mockSelfMod);
70
+ const result = forge.autoApplyProposal(42);
71
+ expect(result.success).toBe(true);
72
+ expect(result.productId).toBeGreaterThan(0);
73
+ expect(mockSelfMod.applyModification).toHaveBeenCalledWith(42);
74
+ });
75
+ it('handles auto-apply failure', () => {
76
+ const forge = new CodeForge(db, { brainName: 'test' });
77
+ forge.setSelfModificationEngine({
78
+ proposeModification: vi.fn(),
79
+ applyModification: vi.fn().mockImplementation(() => { throw new Error('Tests failed'); }),
80
+ });
81
+ const result = forge.autoApplyProposal(42);
82
+ expect(result.success).toBe(false);
83
+ });
84
+ it('returns empty when no selfmod engine', () => {
85
+ const forge = new CodeForge(db, { brainName: 'test' });
86
+ const result = forge.autoApplyProposal(42);
87
+ expect(result.success).toBe(false);
88
+ });
89
+ it('getStatus returns overview', () => {
90
+ const forge = new CodeForge(db, { brainName: 'test' });
91
+ forge.scaffoldProject('t1', { name: 'p1' });
92
+ forge.generateTest('src/foo.ts');
93
+ const status = forge.getStatus();
94
+ expect(status.products).toBe(2);
95
+ expect(status.applied).toBe(0);
96
+ });
97
+ it('migration is idempotent', () => {
98
+ const forge = new CodeForge(db, { brainName: 'test' });
99
+ forge.scaffoldProject('t1', { name: 'persist-test' });
100
+ runCodeForgeMigration(db);
101
+ const products = forge.getProducts();
102
+ expect(products.length).toBeGreaterThanOrEqual(1);
103
+ });
104
+ });
105
+ //# sourceMappingURL=code-forge.test.js.map