pikakit 3.0.1 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,344 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Dashboard Server v6.0 - AutoLearn Precision Learning Engine
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)
12
+ *
13
+ * Usage:
14
+ * node dashboard_server.js --start
15
+ * node dashboard_server.js --port 3030
16
+ */
17
+
18
+ import fs from 'fs';
19
+ import path from 'path';
20
+ import http from 'http';
21
+ import { fileURLToPath } from 'url';
22
+
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
+ const __filename = fileURLToPath(import.meta.url);
32
+ const __dirname = path.dirname(__filename);
33
+
34
+ // Colors
35
+ const c = {
36
+ reset: '\x1b[0m',
37
+ red: '\x1b[31m',
38
+ green: '\x1b[32m',
39
+ yellow: '\x1b[33m',
40
+ cyan: '\x1b[36m',
41
+ gray: '\x1b[90m',
42
+ bold: '\x1b[1m'
43
+ };
44
+
45
+ // Find project root
46
+ 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);
53
+ }
54
+ return process.cwd();
55
+ }
56
+
57
+ const projectRoot = findProjectRoot();
58
+ const dashboardPath = path.join(__dirname, '..', 'dashboard');
59
+
60
+ // ============================================================================
61
+ // API v6.0 HANDLERS
62
+ // ============================================================================
63
+
64
+ const api = {
65
+ // Full dashboard data (all metrics aggregated)
66
+ '/api/dashboard': () => {
67
+ try {
68
+ return getFullDashboardData();
69
+ } catch (e) {
70
+ return { error: e.message, version: '6.0.0' };
71
+ }
72
+ },
73
+
74
+ // KPIs only
75
+ '/api/kpis': () => {
76
+ 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();
96
+ } catch (e) {
97
+ return { error: e.message };
98
+ }
99
+ },
100
+
101
+ // Active alerts
102
+ '/api/alerts': () => {
103
+ try {
104
+ return { alerts: generateAlerts() };
105
+ } catch (e) {
106
+ return { alerts: [], error: e.message };
107
+ }
108
+ },
109
+
110
+ // Gauge widget data
111
+ '/api/gauges': () => {
112
+ try {
113
+ return { gauges: getGaugeWidgets() };
114
+ } catch (e) {
115
+ return { gauges: [], error: e.message };
116
+ }
117
+ },
118
+
119
+ // Counter widget data
120
+ '/api/counters': () => {
121
+ try {
122
+ return { counters: getCounterWidgets() };
123
+ } catch (e) {
124
+ return { counters: [], error: e.message };
125
+ }
126
+ },
127
+
128
+ // Reinforcement loop stats
129
+ '/api/reinforcement': () => {
130
+ try {
131
+ return getReinforcementStats();
132
+ } catch (e) {
133
+ return { error: e.message };
134
+ }
135
+ },
136
+
137
+ // A/B testing stats
138
+ '/api/ab-testing': () => {
139
+ try {
140
+ return {
141
+ stats: getABTestStats(),
142
+ active: getActiveTests()
143
+ };
144
+ } catch (e) {
145
+ return { error: e.message };
146
+ }
147
+ },
148
+
149
+ // Auto-generated skills
150
+ '/api/skills': () => {
151
+ try {
152
+ return {
153
+ stats: getSkillStats(),
154
+ skills: loadAutoSkills()
155
+ };
156
+ } catch (e) {
157
+ return { error: e.message };
158
+ }
159
+ },
160
+
161
+ // Causal patterns
162
+ '/api/patterns': () => {
163
+ try {
164
+ const patterns = loadCausalPatterns();
165
+ return {
166
+ total: patterns.length,
167
+ patterns: patterns.slice(0, 20) // Limit to 20 most recent
168
+ };
169
+ } catch (e) {
170
+ return { total: 0, patterns: [], error: e.message };
171
+ }
172
+ },
173
+
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
+ }
186
+ }
187
+ };
188
+
189
+ // ============================================================================
190
+ // LEGACY API COMPATIBILITY (v4.0 endpoints that still work)
191
+ // ============================================================================
192
+
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
+ const mimeTypes = {
215
+ '.html': 'text/html',
216
+ '.css': 'text/css',
217
+ '.js': 'application/javascript',
218
+ '.json': 'application/json',
219
+ '.png': 'image/png',
220
+ '.jpg': 'image/jpeg',
221
+ '.svg': 'image/svg+xml'
222
+ };
223
+
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] || '');
230
+
231
+ // CORS headers for local development
232
+ res.setHeader('Access-Control-Allow-Origin', '*');
233
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
234
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
235
+
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
+ }
247
+ return;
248
+ }
249
+
250
+ // Serve static files
251
+ let filePath = url === '/' ? '/index.html' : url;
252
+ filePath = path.join(dashboardPath, filePath);
253
+
254
+ if (fs.existsSync(filePath)) {
255
+ 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');
264
+ }
265
+ });
266
+
267
+ return server;
268
+ }
269
+
270
+ function startServer(port = 3030) {
271
+ const server = createServer(port);
272
+
273
+ 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}`);
291
+ });
292
+
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}`);
297
+ } else {
298
+ console.error(`${c.red}Server error:${c.reset}`, err);
299
+ }
300
+ process.exit(1);
301
+ });
302
+
303
+ return server;
304
+ }
305
+
306
+ // Parse CLI args
307
+ const args = process.argv.slice(2);
308
+
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}
318
+
319
+ ${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
337
+
338
+ ${c.bold}Example:${c.reset}
339
+ node dashboard_server.js --port 3030
340
+ # Open http://localhost:3030 in browser
341
+ `);
342
+ }
343
+
344
+ export { createServer, startServer };
@@ -27,7 +27,7 @@ export const RULES_DIR = path.join(AGENT_DIR, "rules");
27
27
  /** CLI version - read from package.json */
28
28
  export const VERSION = (() => {
29
29
  try { return require("../package.json").version; }
30
- catch { return "3.0.1"; }
30
+ catch { return "3.0.3"; }
31
31
  })();
32
32
 
33
33
  /** Debug mode */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pikakit",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "Enterprise-grade Agent Skill Manager with Antigravity Skills support, Progressive Disclosure detection, and semantic routing validation",
5
5
  "license": "MIT",
6
6
  "author": "pikakit <pikakit@gmail.com>",