pikakit 3.0.3 → 3.0.5

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.
@@ -1,55 +1,39 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Dashboard Server v6.0 - AutoLearn Precision Learning Engine
3
+ * Dashboard Server v7.0 - PikaKit Precision Learning Engine
4
4
  *
5
- * Serves real-time metrics from the new v6.0 modules:
6
- * - metrics-collector.js (18 KPIs)
7
- * - dashboard-data.js (aggregation)
8
- * - causality-engine.js (patterns)
9
- * - reinforcement.js (loop stats)
10
- * - ab-testing.js (experiment stats)
11
- * - precision-skill-generator.js (skills)
5
+ * Modern ES Modules server with REST API endpoints.
6
+ * Serves real-time metrics from PikaKit learning system.
12
7
  *
13
- * Usage:
14
- * node dashboard_server.js --start
15
- * node dashboard_server.js --port 3030
8
+ * @version 7.0.0
9
+ * @author PikaKit
16
10
  */
17
11
 
12
+ import http from 'http';
18
13
  import fs from 'fs';
19
14
  import path from 'path';
20
- import http from 'http';
21
15
  import { fileURLToPath } from 'url';
22
16
 
23
- // Import v6.0 modules
24
- import { getDashboardData, getSummary, getMetricHistory } from '../lib/metrics-collector.js';
25
- import { getFullDashboardData, getKeyTrends, generateAlerts, getGaugeWidgets, getCounterWidgets } from '../lib/dashboard-data.js';
26
- import { getReinforcementStats } from '../lib/reinforcement.js';
27
- import { getABTestStats, getActiveTests } from '../lib/ab-testing.js';
28
- import { getSkillStats, loadAutoSkills } from '../lib/precision-skill-generator.js';
29
- import { loadCausalPatterns } from '../lib/causality-engine.js';
30
-
31
17
  const __filename = fileURLToPath(import.meta.url);
32
18
  const __dirname = path.dirname(__filename);
33
19
 
34
- // Colors
20
+ // Colors for terminal
35
21
  const c = {
36
22
  reset: '\x1b[0m',
37
- red: '\x1b[31m',
23
+ bold: '\x1b[1m',
24
+ cyan: '\x1b[36m',
38
25
  green: '\x1b[32m',
39
26
  yellow: '\x1b[33m',
40
- cyan: '\x1b[36m',
41
- gray: '\x1b[90m',
42
- bold: '\x1b[1m'
27
+ gray: '\x1b[90m'
43
28
  };
44
29
 
45
30
  // Find project root
46
31
  function findProjectRoot() {
47
- let current = process.cwd();
48
- while (current !== path.dirname(current)) {
49
- if (fs.existsSync(path.join(current, '.agent'))) {
50
- return current;
51
- }
52
- current = path.dirname(current);
32
+ let dir = process.cwd();
33
+ while (dir !== path.dirname(dir)) {
34
+ if (fs.existsSync(path.join(dir, '.agent'))) return dir;
35
+ if (fs.existsSync(path.join(dir, 'package.json'))) return dir;
36
+ dir = path.dirname(dir);
53
37
  }
54
38
  return process.cwd();
55
39
  }
@@ -58,159 +42,146 @@ const projectRoot = findProjectRoot();
58
42
  const dashboardPath = path.join(__dirname, '..', 'dashboard');
59
43
 
60
44
  // ============================================================================
61
- // API v6.0 HANDLERS
45
+ // DATA PROVIDERS
46
+ // ============================================================================
47
+
48
+ // Safe import helper
49
+ async function safeImport(modulePath) {
50
+ try {
51
+ return await import(modulePath);
52
+ } catch (e) {
53
+ return null;
54
+ }
55
+ }
56
+
57
+ // Load data modules dynamically
58
+ let metricsCollector = null;
59
+ let causalityEngine = null;
60
+ let skillGenerator = null;
61
+ let abTesting = null;
62
+ let reinforcement = null;
63
+
64
+ async function loadModules() {
65
+ const libPath = path.join(__dirname, '..', 'lib');
66
+ metricsCollector = await safeImport(path.join(libPath, 'metrics-collector.js'));
67
+ causalityEngine = await safeImport(path.join(libPath, 'causality-engine.js'));
68
+ skillGenerator = await safeImport(path.join(libPath, 'skill-generator.js'));
69
+ abTesting = await safeImport(path.join(libPath, 'ab-testing.js'));
70
+ reinforcement = await safeImport(path.join(libPath, 'reinforcement.js'));
71
+ }
72
+
73
+ // ============================================================================
74
+ // API HANDLERS
62
75
  // ============================================================================
63
76
 
64
77
  const api = {
65
- // Full dashboard data (all metrics aggregated)
78
+ // Full dashboard data
66
79
  '/api/dashboard': () => {
67
80
  try {
68
- return getFullDashboardData();
81
+ const kpis = metricsCollector?.getKPIs?.() || { kpis: {} };
82
+ const summary = {
83
+ totalTasks: metricsCollector?.getMetricValue?.('total_tasks') || 0,
84
+ patternsLearned: causalityEngine?.getPatternCount?.() || 0,
85
+ skillsGenerated: skillGenerator?.getSkillCount?.() || 0,
86
+ version: '7.0.0'
87
+ };
88
+ return { kpis: { kpis }, summary, version: '7.0.0' };
69
89
  } catch (e) {
70
- return { error: e.message, version: '6.0.0' };
90
+ return { kpis: { kpis: {} }, summary: {}, error: e.message, version: '7.0.0' };
71
91
  }
72
92
  },
73
93
 
74
94
  // KPIs only
75
95
  '/api/kpis': () => {
76
96
  try {
77
- return getDashboardData();
78
- } catch (e) {
79
- return { error: e.message };
80
- }
81
- },
82
-
83
- // Summary stats
84
- '/api/summary': () => {
85
- try {
86
- return getSummary();
87
- } catch (e) {
88
- return { error: e.message };
89
- }
90
- },
91
-
92
- // Trends over time
93
- '/api/trends': () => {
94
- try {
95
- return getKeyTrends();
97
+ return metricsCollector?.getKPIs?.() || { kpis: {} };
96
98
  } catch (e) {
97
- return { error: e.message };
99
+ return { kpis: {}, error: e.message };
98
100
  }
99
101
  },
100
102
 
101
- // Active alerts
103
+ // Alerts
102
104
  '/api/alerts': () => {
103
105
  try {
104
- return { alerts: generateAlerts() };
105
- } catch (e) {
106
- return { alerts: [], error: e.message };
107
- }
108
- },
106
+ const kpis = metricsCollector?.getKPIs?.()?.kpis || {};
107
+ const alerts = [];
109
108
 
110
- // Gauge widget data
111
- '/api/gauges': () => {
112
- try {
113
- return { gauges: getGaugeWidgets() };
114
- } catch (e) {
115
- return { gauges: [], error: e.message };
116
- }
117
- },
109
+ // Generate alerts based on KPI thresholds
110
+ if (kpis.task_success_rate && parseFloat(kpis.task_success_rate.value) < 80) {
111
+ alerts.push({ id: 'low_success', severity: 'warning', message: 'Task success rate below 80%' });
112
+ }
113
+ if (kpis.error_repeat_rate && parseFloat(kpis.error_repeat_rate.value) > 10) {
114
+ alerts.push({ id: 'high_error', severity: 'warning', message: 'Error repeat rate above 10%' });
115
+ }
118
116
 
119
- // Counter widget data
120
- '/api/counters': () => {
121
- try {
122
- return { counters: getCounterWidgets() };
117
+ return { alerts, count: alerts.length };
123
118
  } catch (e) {
124
- return { counters: [], error: e.message };
119
+ return { alerts: [], error: e.message };
125
120
  }
126
121
  },
127
122
 
128
- // Reinforcement loop stats
129
- '/api/reinforcement': () => {
123
+ // Skills
124
+ '/api/skills': () => {
130
125
  try {
131
- return getReinforcementStats();
126
+ const skills = skillGenerator?.getAllSkills?.() || [];
127
+ return {
128
+ skills,
129
+ stats: { total: skills.length }
130
+ };
132
131
  } catch (e) {
133
- return { error: e.message };
132
+ return { skills: [], stats: { total: 0 }, error: e.message };
134
133
  }
135
134
  },
136
135
 
137
- // A/B testing stats
136
+ // A/B Testing
138
137
  '/api/ab-testing': () => {
139
138
  try {
139
+ const active = abTesting?.getActiveTests?.() || [];
140
+ const completed = abTesting?.getCompletedTests?.() || [];
140
141
  return {
141
- stats: getABTestStats(),
142
- active: getActiveTests()
142
+ active,
143
+ completed,
144
+ stats: { running: active.length, completed: completed.length }
143
145
  };
144
146
  } catch (e) {
145
- return { error: e.message };
147
+ return { active: [], completed: [], stats: { running: 0, completed: 0 }, error: e.message };
146
148
  }
147
149
  },
148
150
 
149
- // Auto-generated skills
150
- '/api/skills': () => {
151
+ // Reinforcement Loop
152
+ '/api/reinforcement': () => {
151
153
  try {
154
+ const stats = reinforcement?.getStats?.() || {};
152
155
  return {
153
- stats: getSkillStats(),
154
- skills: loadAutoSkills()
156
+ totalRewards: stats.rewards || 0,
157
+ totalPenalties: stats.penalties || 0,
158
+ averageConfidence: stats.avgConfidence || null
155
159
  };
156
160
  } catch (e) {
157
- return { error: e.message };
161
+ return { totalRewards: 0, totalPenalties: 0, error: e.message };
158
162
  }
159
163
  },
160
164
 
161
- // Causal patterns
165
+ // Patterns
162
166
  '/api/patterns': () => {
163
167
  try {
164
- const patterns = loadCausalPatterns();
165
- return {
166
- total: patterns.length,
167
- patterns: patterns.slice(0, 20) // Limit to 20 most recent
168
- };
168
+ const patterns = causalityEngine?.loadCausalPatterns?.() || [];
169
+ return { total: patterns.length, patterns: patterns.slice(0, 20) };
169
170
  } catch (e) {
170
171
  return { total: 0, patterns: [], error: e.message };
171
172
  }
172
173
  },
173
174
 
174
- // Metric history (query param: ?metric=task_success_rate&limit=168)
175
- '/api/history': (query) => {
176
- try {
177
- const metric = query.get('metric') || 'task_success_rate';
178
- const limit = parseInt(query.get('limit') || '168', 10);
179
- return {
180
- metric,
181
- history: getMetricHistory(metric, limit)
182
- };
183
- } catch (e) {
184
- return { error: e.message };
185
- }
175
+ // Summary (legacy support)
176
+ '/api/summary': () => {
177
+ return { status: 'ok', version: '7.0.0', server: 'PikaKit Dashboard Server' };
186
178
  }
187
179
  };
188
180
 
189
181
  // ============================================================================
190
- // LEGACY API COMPATIBILITY (v4.0 endpoints that still work)
182
+ // MIME TYPES
191
183
  // ============================================================================
192
184
 
193
- const legacyApi = {
194
- '/api/errors': () => ({
195
- deprecation: 'Use /api/patterns instead',
196
- redirect: '/api/patterns'
197
- }),
198
- '/api/corrections': () => ({
199
- deprecation: 'Use /api/patterns instead',
200
- redirect: '/api/patterns'
201
- }),
202
- '/api/lessons': () => {
203
- const filePath = path.join(projectRoot, '.agent', 'knowledge', 'lessons-learned.json');
204
- try {
205
- if (fs.existsSync(filePath)) {
206
- return JSON.parse(fs.readFileSync(filePath, 'utf8'));
207
- }
208
- } catch { }
209
- return { lessons: [] };
210
- }
211
- };
212
-
213
- // MIME types
214
185
  const mimeTypes = {
215
186
  '.html': 'text/html',
216
187
  '.css': 'text/css',
@@ -221,124 +192,121 @@ const mimeTypes = {
221
192
  '.svg': 'image/svg+xml'
222
193
  };
223
194
 
224
- // Create server
225
- function createServer(port) {
226
- const server = http.createServer((req, res) => {
227
- const urlParts = req.url.split('?');
228
- const url = urlParts[0];
229
- const query = new URLSearchParams(urlParts[1] || '');
195
+ // ============================================================================
196
+ // SERVER
197
+ // ============================================================================
230
198
 
231
- // CORS headers for local development
199
+ function createServer(port) {
200
+ const server = http.createServer(async (req, res) => {
201
+ // CORS headers
232
202
  res.setHeader('Access-Control-Allow-Origin', '*');
233
203
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
234
204
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
235
205
 
236
- // Handle API requests
237
- if (url.startsWith('/api/')) {
238
- const handler = api[url] || legacyApi[url];
239
- if (handler) {
240
- res.setHeader('Content-Type', 'application/json');
241
- res.writeHead(200);
242
- res.end(JSON.stringify(handler(query)));
243
- } else {
244
- res.writeHead(404);
245
- res.end(JSON.stringify({ error: 'Not found', availableEndpoints: Object.keys(api) }));
246
- }
206
+ if (req.method === 'OPTIONS') {
207
+ res.writeHead(204);
208
+ res.end();
209
+ return;
210
+ }
211
+
212
+ const url = new URL(req.url, `http://localhost:${port}`);
213
+ const pathname = url.pathname;
214
+
215
+ // API routes
216
+ if (api[pathname]) {
217
+ const data = api[pathname](url.searchParams);
218
+ res.writeHead(200, { 'Content-Type': 'application/json' });
219
+ res.end(JSON.stringify(data, null, 2));
247
220
  return;
248
221
  }
249
222
 
250
- // Serve static files
251
- let filePath = url === '/' ? '/index.html' : url;
223
+ // Static files
224
+ let filePath = pathname === '/' ? 'index.html' : pathname.slice(1);
252
225
  filePath = path.join(dashboardPath, filePath);
253
226
 
254
227
  if (fs.existsSync(filePath)) {
255
228
  const ext = path.extname(filePath);
256
- const mimeType = mimeTypes[ext] || 'text/plain';
257
-
258
- res.setHeader('Content-Type', mimeType);
259
- res.writeHead(200);
260
- res.end(fs.readFileSync(filePath));
261
- } else {
262
- res.writeHead(404);
263
- res.end('Not found');
229
+ const contentType = mimeTypes[ext] || 'application/octet-stream';
230
+ const content = fs.readFileSync(filePath);
231
+ res.writeHead(200, { 'Content-Type': contentType });
232
+ res.end(content);
233
+ return;
264
234
  }
235
+
236
+ // 404
237
+ res.writeHead(404, { 'Content-Type': 'application/json' });
238
+ res.end(JSON.stringify({ error: 'Not found', path: pathname }));
265
239
  });
266
240
 
267
241
  return server;
268
242
  }
269
243
 
270
- function startServer(port = 3030) {
244
+ async function startServer(port = 3030) {
245
+ await loadModules();
246
+
271
247
  const server = createServer(port);
272
248
 
273
249
  server.listen(port, () => {
274
- console.log(`${c.cyan}╔════════════════════════════════════════════════════╗${c.reset}`);
275
- console.log(`${c.cyan}║${c.reset} 🧠 AutoLearn v6.0 Dashboard Server ${c.cyan}║${c.reset}`);
276
- console.log(`${c.cyan}║${c.reset} ${c.green}Precision Learning Engine${c.reset} ${c.cyan}║${c.reset}`);
277
- console.log(`${c.cyan}╚════════════════════════════════════════════════════╝${c.reset}\n`);
278
- console.log(`${c.green}✓ Server running at:${c.reset}`);
279
- console.log(` ${c.bold}http://localhost:${port}${c.reset}\n`);
280
- console.log(`${c.gray}API Endpoints (v6.0):${c.reset}`);
281
- console.log(` GET /api/dashboard - Full dashboard data`);
282
- console.log(` GET /api/kpis - 18 KPIs`);
283
- console.log(` GET /api/summary - Summary stats`);
284
- console.log(` GET /api/trends - Key trends`);
285
- console.log(` GET /api/alerts - Active alerts`);
286
- console.log(` GET /api/reinforcement - Reinforcement loop`);
287
- console.log(` GET /api/ab-testing - A/B experiments`);
288
- console.log(` GET /api/skills - Auto-generated skills`);
289
- console.log(` GET /api/patterns - Causal patterns\n`);
290
- console.log(`${c.yellow}Press Ctrl+C to stop${c.reset}`);
250
+ console.log(`
251
+ ${c.bold}${c.cyan}╔════════════════════════════════════════════════════════════╗${c.reset}
252
+ ${c.bold}${c.cyan}║${c.reset} ${c.cyan}║${c.reset}
253
+ ${c.bold}${c.cyan}║${c.reset} 🧠 ${c.bold}PikaKit Dashboard Server v7.0${c.reset} ${c.cyan}║${c.reset}
254
+ ${c.bold}${c.cyan}║${c.reset} ${c.cyan}║${c.reset}
255
+ ${c.bold}${c.cyan}║${c.reset} ${c.green}→${c.reset} Dashboard: ${c.yellow}http://localhost:${port}${c.reset} ${c.cyan}║${c.reset}
256
+ ${c.bold}${c.cyan}║${c.reset} ${c.green}→${c.reset} API Base: ${c.yellow}http://localhost:${port}/api${c.reset} ${c.cyan}║${c.reset}
257
+ ${c.bold}${c.cyan}║${c.reset} ${c.cyan}║${c.reset}
258
+ ${c.bold}${c.cyan}║${c.reset} ${c.gray}Press Ctrl+C to stop${c.reset} ${c.cyan}║${c.reset}
259
+ ${c.bold}${c.cyan}║${c.reset} ${c.cyan}║${c.reset}
260
+ ${c.bold}${c.cyan}╚════════════════════════════════════════════════════════════╝${c.reset}
261
+ `);
291
262
  });
292
263
 
293
- server.on('error', (err) => {
294
- if (err.code === 'EADDRINUSE') {
295
- console.log(`${c.red}Error: Port ${port} is already in use${c.reset}`);
296
- console.log(`${c.gray}Try: node dashboard_server.js --port ${port + 1}${c.reset}`);
264
+ server.on('error', (e) => {
265
+ if (e.code === 'EADDRINUSE') {
266
+ console.log(`${c.yellow}Port ${port} in use, trying ${port + 1}...${c.reset}`);
267
+ startServer(port + 1);
297
268
  } else {
298
- console.error(`${c.red}Server error:${c.reset}`, err);
269
+ console.error(`${c.red}Server error:${c.reset}`, e.message);
299
270
  }
300
- process.exit(1);
301
271
  });
302
272
 
303
273
  return server;
304
274
  }
305
275
 
306
- // Parse CLI args
276
+ // CLI handling
307
277
  const args = process.argv.slice(2);
308
278
 
309
- if (args.includes('--start') || args.includes('-s') || args.length === 0 || args.includes('--port') || args.includes('-p')) {
310
- let port = 3030;
311
- const portIdx = args.findIndex(a => a === '--port' || a === '-p');
312
- if (portIdx >= 0 && args[portIdx + 1]) {
313
- port = parseInt(args[portIdx + 1], 10);
314
- }
315
- startServer(port);
316
- } else if (args.includes('--help') || args.includes('-h')) {
317
- console.log(`${c.cyan}AutoLearn v6.0 Dashboard Server${c.reset}
279
+ if (args.includes('--help') || args.includes('-h')) {
280
+ console.log(`
281
+ ${c.bold}PikaKit Dashboard Server v7.0${c.reset}
318
282
 
319
283
  ${c.bold}Usage:${c.reset}
320
- node dashboard_server.js Start server (default port 3030)
321
- node dashboard_server.js --port 8080 Start on custom port
322
- node dashboard_server.js --help Show this help
323
-
324
- ${c.bold}API Endpoints (v6.0):${c.reset}
325
- GET /api/dashboard - Full dashboard aggregation
326
- GET /api/kpis - 18 KPIs for Dashboard
327
- GET /api/summary - Summary statistics
328
- GET /api/trends - Week-over-week trends
329
- GET /api/alerts - Active alerts
330
- GET /api/gauges - Gauge widget data
331
- GET /api/counters - Counter widget data
332
- GET /api/reinforcement - Reinforcement loop stats
333
- GET /api/ab-testing - A/B testing experiments
334
- GET /api/skills - Auto-generated skills
335
- GET /api/patterns - Causal patterns
336
- GET /api/history?metric=X - Metric history
284
+ node dashboard-server.js [options]
285
+
286
+ ${c.bold}Options:${c.reset}
287
+ --port, -p <number> Port to run on (default: 3030)
288
+ --help, -h Show this help
289
+
290
+ ${c.bold}API Endpoints:${c.reset}
291
+ GET /api/dashboard Full dashboard data
292
+ GET /api/kpis KPI metrics only
293
+ GET /api/alerts Active alerts
294
+ GET /api/skills Auto-generated skills
295
+ GET /api/ab-testing A/B test experiments
296
+ GET /api/reinforcement Reinforcement loop stats
297
+ GET /api/patterns Causal patterns
298
+ GET /api/summary Server status
337
299
 
338
300
  ${c.bold}Example:${c.reset}
339
- node dashboard_server.js --port 3030
340
- # Open http://localhost:3030 in browser
301
+ node dashboard-server.js --port 3030
341
302
  `);
303
+ } else {
304
+ let port = 3030;
305
+ const portIdx = args.findIndex(a => a === '--port' || a === '-p');
306
+ if (portIdx !== -1 && args[portIdx + 1]) {
307
+ port = parseInt(args[portIdx + 1], 10) || 3030;
308
+ }
309
+ startServer(port);
342
310
  }
343
311
 
344
312
  export { createServer, startServer };