pikakit 1.0.14 → 1.0.16

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,17 +1,14 @@
1
1
  /**
2
- * AutoLearn v6.0 - Dashboard Data Provider
2
+ * Dashboard Data v7.0 - PikaKit Data Aggregation
3
3
  *
4
4
  * Aggregates data from all engines for Dashboard display.
5
5
  * Provides real-time metrics, trends, and alerts.
6
6
  *
7
- * @version 6.0.0
7
+ * @version 7.0.0
8
8
  * @author PikaKit
9
9
  */
10
10
 
11
- import { getDashboardData, getMetricHistory, getSummary } from './metrics-collector.js';
12
- import { getReinforcementStats } from './reinforcement.js';
13
- import { getABTestStats, getActiveTests } from './ab-testing.js';
14
- import { getSkillStats, loadAutoSkills } from './precision-skill-generator.js';
11
+ import { getKPIs, getMetricValue, getMetricHistory } from './metrics-collector.js';
15
12
  import { loadCausalPatterns } from './causality-engine.js';
16
13
 
17
14
  // ============================================================================
@@ -23,122 +20,51 @@ import { loadCausalPatterns } from './causality-engine.js';
23
20
  * @returns {Object} - Full dashboard data
24
21
  */
25
22
  export function getFullDashboardData() {
26
- const data = {
27
- timestamp: new Date().toISOString(),
28
- version: '6.0.0',
29
-
30
- // Core KPIs
31
- kpis: getDashboardData(),
32
-
33
- // Summary
34
- summary: getSummary(),
35
-
36
- // Module Stats
37
- modules: {
38
- reinforcement: getReinforcementStats(),
39
- abTesting: getABTestStats(),
40
- skills: getSkillStats(),
41
- patterns: getPatternStats()
42
- },
43
-
44
- // Active items
45
- active: {
46
- abTests: getActiveTests().map(t => ({
47
- id: t.id,
48
- status: t.status,
49
- patternA: t.patternA.name || t.patternA.id,
50
- patternB: t.patternB.name || t.patternB.id,
51
- samplesA: t.metrics.patternA.applied,
52
- samplesB: t.metrics.patternB.applied
53
- })),
54
- skills: loadAutoSkills().slice(0, 10) // Last 10
55
- },
56
-
57
- // Alerts
58
- alerts: generateAlerts()
59
- };
60
-
61
- return data;
23
+ try {
24
+ const kpis = getKPIs();
25
+ const patterns = loadCausalPatterns();
26
+
27
+ return {
28
+ version: '7.0.0',
29
+ timestamp: new Date().toISOString(),
30
+ kpis,
31
+ summary: {
32
+ totalTasks: getMetricValue('total_tasks') || 0,
33
+ patternsLearned: patterns.length,
34
+ skillsGenerated: 0,
35
+ abTestsActive: 0
36
+ },
37
+ patterns: patterns.slice(0, 10)
38
+ };
39
+ } catch (e) {
40
+ return {
41
+ version: '7.0.0',
42
+ error: e.message,
43
+ kpis: { kpis: {} },
44
+ summary: {}
45
+ };
46
+ }
62
47
  }
63
48
 
64
49
  /**
65
50
  * Get pattern statistics
51
+ * @returns {Object} - Pattern stats
66
52
  */
67
- function getPatternStats() {
53
+ export function getPatternStats() {
68
54
  const patterns = loadCausalPatterns();
69
-
70
- if (patterns.length === 0) {
71
- return { total: 0, avgConfidence: 0, categories: [] };
72
- }
73
-
74
55
  return {
75
56
  total: patterns.length,
76
- avgConfidence: patterns.reduce((sum, p) => sum + p.confidence, 0) / patterns.length,
77
- categories: [...new Set(patterns.map(p => p.category || 'unknown'))]
78
- };
79
- }
80
-
81
- // ============================================================================
82
- // TREND DATA
83
- // ============================================================================
84
-
85
- /**
86
- * Get trend data for a specific metric
87
- * @param {string} metricId - Metric ID
88
- * @param {string} period - 'day' | 'week' | 'month'
89
- * @returns {Object} - Trend data
90
- */
91
- export function getMetricTrend(metricId, period = 'week') {
92
- const limits = { day: 24, week: 168, month: 720 };
93
- const limit = limits[period] || 168;
94
-
95
- const history = getMetricHistory(metricId, limit);
96
-
97
- if (history.length < 2) {
98
- return { trend: 'stable', change: 0, data: history };
99
- }
100
-
101
- // Calculate trend
102
- const firstValue = parseFloat(history[0].value) || 0;
103
- const lastValue = parseFloat(history[history.length - 1].value) || 0;
104
- const change = firstValue > 0 ? ((lastValue - firstValue) / firstValue * 100) : 0;
105
-
106
- let trend = 'stable';
107
- if (change > 5) trend = 'up';
108
- if (change < -5) trend = 'down';
109
-
110
- return {
111
- metricId,
112
- period,
113
- trend,
114
- change: change.toFixed(2),
115
- firstValue,
116
- lastValue,
117
- dataPoints: history.length,
118
- data: history
57
+ byCategory: patterns.reduce((acc, p) => {
58
+ const cat = p.category || 'other';
59
+ acc[cat] = (acc[cat] || 0) + 1;
60
+ return acc;
61
+ }, {}),
62
+ avgConfidence: patterns.length > 0
63
+ ? patterns.reduce((sum, p) => sum + (p.confidence || 0), 0) / patterns.length
64
+ : 0
119
65
  };
120
66
  }
121
67
 
122
- /**
123
- * Get all key trends
124
- * @returns {Object} - Key trends
125
- */
126
- export function getKeyTrends() {
127
- const keyMetrics = [
128
- 'task_success_rate',
129
- 'error_repeat_rate',
130
- 'skill_effectiveness',
131
- 'pattern_precision'
132
- ];
133
-
134
- const trends = {};
135
- for (const metricId of keyMetrics) {
136
- trends[metricId] = getMetricTrend(metricId, 'week');
137
- }
138
-
139
- return trends;
140
- }
141
-
142
68
  // ============================================================================
143
69
  // ALERTS
144
70
  // ============================================================================
@@ -146,33 +72,21 @@ export function getKeyTrends() {
146
72
  const ALERT_RULES = [
147
73
  {
148
74
  id: 'low_success_rate',
149
- check: (kpis) => parseFloat(kpis.task_success_rate?.value) < 80,
75
+ check: (kpis) => kpis.task_success_rate && parseFloat(kpis.task_success_rate.value) < 80,
150
76
  severity: 'warning',
151
77
  message: 'Task success rate below 80%'
152
78
  },
153
79
  {
154
80
  id: 'high_error_repeat',
155
- check: (kpis) => parseFloat(kpis.error_repeat_rate?.value) > 10,
81
+ check: (kpis) => kpis.error_repeat_rate && parseFloat(kpis.error_repeat_rate.value) > 10,
156
82
  severity: 'warning',
157
83
  message: 'Error repeat rate above 10%'
158
84
  },
159
85
  {
160
86
  id: 'low_skill_effectiveness',
161
- check: (kpis) => parseFloat(kpis.skill_effectiveness?.value) < 50,
87
+ check: (kpis) => kpis.skill_effectiveness && parseFloat(kpis.skill_effectiveness.value) < 50,
162
88
  severity: 'info',
163
89
  message: 'Skill effectiveness below 50%'
164
- },
165
- {
166
- id: 'high_false_positive',
167
- check: (kpis) => parseFloat(kpis.false_positive_rate?.value) > 15,
168
- severity: 'warning',
169
- message: 'False positive rate above 15%'
170
- },
171
- {
172
- id: 'pattern_confidence_low',
173
- check: (kpis) => parseFloat(kpis.pattern_confidence_avg?.value) < 0.5,
174
- severity: 'info',
175
- message: 'Average pattern confidence below 50%'
176
90
  }
177
91
  ];
178
92
 
@@ -181,12 +95,11 @@ const ALERT_RULES = [
181
95
  * @returns {Array} - Active alerts
182
96
  */
183
97
  export function generateAlerts() {
184
- const dashboard = getDashboardData();
185
- const kpis = dashboard.kpis;
186
- const alerts = [];
98
+ try {
99
+ const kpis = getKPIs().kpis || {};
100
+ const alerts = [];
187
101
 
188
- for (const rule of ALERT_RULES) {
189
- try {
102
+ for (const rule of ALERT_RULES) {
190
103
  if (rule.check(kpis)) {
191
104
  alerts.push({
192
105
  id: rule.id,
@@ -195,39 +108,16 @@ export function generateAlerts() {
195
108
  timestamp: new Date().toISOString()
196
109
  });
197
110
  }
198
- } catch {
199
- // Skip rules that fail
200
111
  }
201
- }
202
-
203
- // Check for skills needing attention
204
- const skills = loadAutoSkills();
205
- const underperforming = skills.filter(s => s.state === 'underperforming');
206
- if (underperforming.length > 0) {
207
- alerts.push({
208
- id: 'underperforming_skills',
209
- severity: 'info',
210
- message: `${underperforming.length} skills underperforming`,
211
- timestamp: new Date().toISOString()
212
- });
213
- }
214
112
 
215
- // Check for pending A/B tests
216
- const abStats = getABTestStats();
217
- if (abStats.running > 3) {
218
- alerts.push({
219
- id: 'too_many_ab_tests',
220
- severity: 'info',
221
- message: `${abStats.running} A/B tests running simultaneously`,
222
- timestamp: new Date().toISOString()
223
- });
113
+ return alerts;
114
+ } catch (e) {
115
+ return [];
224
116
  }
225
-
226
- return alerts;
227
117
  }
228
118
 
229
119
  // ============================================================================
230
- // DASHBOARD WIDGETS DATA
120
+ // WIDGET DATA
231
121
  // ============================================================================
232
122
 
233
123
  /**
@@ -235,17 +125,13 @@ export function generateAlerts() {
235
125
  * @returns {Array} - Gauge data
236
126
  */
237
127
  export function getGaugeWidgets() {
238
- const dashboard = getDashboardData();
239
- const kpis = dashboard.kpis;
240
-
241
- const gauges = [
242
- { id: 'task_success_rate', label: 'Success Rate', ...kpis.task_success_rate },
243
- { id: 'error_repeat_rate', label: 'Error Repeat', ...kpis.error_repeat_rate },
244
- { id: 'first_time_success', label: 'First-Time', ...kpis.first_time_success },
245
- { id: 'skill_effectiveness', label: 'Skill Effect', ...kpis.skill_effectiveness }
128
+ const kpis = getKPIs().kpis || {};
129
+ return [
130
+ { id: 'success_rate', label: 'Task Success', value: parseFloat(kpis.task_success_rate?.value) || 0, target: 85 },
131
+ { id: 'error_repeat', label: 'Error Repeat', value: parseFloat(kpis.error_repeat_rate?.value) || 0, target: 5, inverse: true },
132
+ { id: 'first_time', label: 'First-Time Success', value: parseFloat(kpis.first_time_success?.value) || 0, target: 80 },
133
+ { id: 'skill_eff', label: 'Skill Effectiveness', value: parseFloat(kpis.skill_effectiveness?.value) || 0, target: 70 }
246
134
  ];
247
-
248
- return gauges;
249
135
  }
250
136
 
251
137
  /**
@@ -253,15 +139,12 @@ export function getGaugeWidgets() {
253
139
  * @returns {Array} - Counter data
254
140
  */
255
141
  export function getCounterWidgets() {
256
- const dashboard = getDashboardData();
257
- const kpis = dashboard.kpis;
258
- const summary = getSummary();
259
-
142
+ const patterns = loadCausalPatterns();
260
143
  return [
261
- { id: 'total_tasks', label: 'Total Tasks', value: summary.totalTasks },
262
- { id: 'skills_generated', label: 'Skills Generated', value: kpis.skills_auto_generated?.value || 0 },
263
- { id: 'patterns_learned', label: 'Patterns', value: summary.patternsLearned },
264
- { id: 'skills_pruned', label: 'Skills Pruned', value: kpis.skills_pruned?.value || 0 }
144
+ { id: 'tasks', label: 'Total Tasks', value: getMetricValue('total_tasks') || 0 },
145
+ { id: 'patterns', label: 'Patterns', value: patterns.length },
146
+ { id: 'skills', label: 'Skills', value: 0 },
147
+ { id: 'tests', label: 'A/B Tests', value: 0 }
265
148
  ];
266
149
  }
267
150
 
@@ -270,36 +153,16 @@ export function getCounterWidgets() {
270
153
  * @returns {Object} - Chart data
271
154
  */
272
155
  export function getLearningVelocityChart() {
273
- const history = getMetricHistory('learning_velocity', 8);
274
-
275
- return {
276
- title: 'Learning Velocity (Patterns/Week)',
277
- labels: history.map((_, i) => `W${i + 1}`),
278
- data: history.map(h => parseFloat(h.value) || 0)
279
- };
280
- }
281
-
282
- /**
283
- * Get skill effectiveness breakdown
284
- * @returns {Object} - Breakdown data
285
- */
286
- export function getSkillEffectivenessBreakdown() {
287
- const skills = loadAutoSkills();
288
-
289
- const breakdown = {
290
- high: skills.filter(s => s.confidence >= 0.8).length,
291
- medium: skills.filter(s => s.confidence >= 0.5 && s.confidence < 0.8).length,
292
- low: skills.filter(s => s.confidence < 0.5).length
293
- };
294
-
156
+ const history = getMetricHistory('patterns_learned', 7);
295
157
  return {
296
- title: 'Skill Distribution',
297
- data: breakdown
158
+ labels: history.map(h => h.date),
159
+ values: history.map(h => h.value),
160
+ type: 'bar'
298
161
  };
299
162
  }
300
163
 
301
164
  // ============================================================================
302
- // FORMATTED OUTPUT FOR CLI
165
+ // CLI FORMAT
303
166
  // ============================================================================
304
167
 
305
168
  /**
@@ -308,44 +171,20 @@ export function getSkillEffectivenessBreakdown() {
308
171
  */
309
172
  export function formatDashboardForCLI() {
310
173
  const data = getFullDashboardData();
311
- const kpis = data.kpis.kpis;
312
-
313
- const lines = [
314
- '',
315
- '┌─────────────────────────────────────────────────────────────────┐',
316
- '│ 🧠 AutoLearn v6.0 Dashboard │',
317
- '├─────────────────────────────────────────────────────────────────┤',
318
- '│ │',
319
- `│ Task Success: ${formatValue(kpis.task_success_rate)} Error Repeat: ${formatValue(kpis.error_repeat_rate)} │`,
320
- `│ First-Time: ${formatValue(kpis.first_time_success)} Skill Effect: ${formatValue(kpis.skill_effectiveness)} │`,
321
- '│ │',
322
- '├─────────────────────────────────────────────────────────────────┤',
323
- `│ 📊 Patterns: ${data.modules.patterns.total} Skills: ${data.modules.skills.total} A/B Tests: ${data.modules.abTesting.running} │`,
324
- '│ │'
325
- ];
326
-
327
- // Add alerts
328
- if (data.alerts.length > 0) {
329
- lines.push('│ ⚠️ Alerts: │');
330
- for (const alert of data.alerts.slice(0, 3)) {
331
- lines.push(`│ • ${alert.message.padEnd(55)}│`);
332
- }
333
- } else {
334
- lines.push('│ ✅ No alerts │');
335
- }
336
-
337
- lines.push('│ │');
338
- lines.push('└─────────────────────────────────────────────────────────────────┘');
339
- lines.push('');
340
-
341
- return lines.join('\n');
342
- }
343
-
344
- function formatValue(kpi) {
345
- if (!kpi) return ' --.-%';
346
- const val = parseFloat(kpi.value).toFixed(1);
347
- const status = kpi.status === 'good' ? '✓' : kpi.status === 'critical' ? '✗' : '~';
348
- return `${status} ${val.padStart(5)}%`;
174
+ const kpis = data.kpis?.kpis || {};
175
+
176
+ const formatValue = (kpi) => kpi?.value ? `${parseFloat(kpi.value).toFixed(1)}%` : '--';
177
+
178
+ return `
179
+ ╔══════════════════════════════════════════════════════════════╗
180
+ ║ 🧠 PikaKit Dashboard v7.0 ║
181
+ ╠══════════════════════════════════════════════════════════════╣
182
+ Task Success: ${formatValue(kpis.task_success_rate).padEnd(8)}Error Repeat: ${formatValue(kpis.error_repeat_rate).padEnd(8)}
183
+ First-Time: ${formatValue(kpis.first_time_success).padEnd(8)}Skill Effect: ${formatValue(kpis.skill_effectiveness).padEnd(8)}
184
+ ╠══════════════════════════════════════════════════════════════╣
185
+ ║ Tasks: ${String(data.summary?.totalTasks || 0).padEnd(6)} Patterns: ${String(data.summary?.patternsLearned || 0).padEnd(6)} Skills: ${String(data.summary?.skillsGenerated || 0).padEnd(6)} ║
186
+ ╚══════════════════════════════════════════════════════════════╝
187
+ `;
349
188
  }
350
189
 
351
190
  // ============================================================================
@@ -354,12 +193,10 @@ function formatValue(kpi) {
354
193
 
355
194
  export default {
356
195
  getFullDashboardData,
357
- getMetricTrend,
358
- getKeyTrends,
196
+ getPatternStats,
359
197
  generateAlerts,
360
198
  getGaugeWidgets,
361
199
  getCounterWidgets,
362
200
  getLearningVelocityChart,
363
- getSkillEffectivenessBreakdown,
364
201
  formatDashboardForCLI
365
202
  };
@@ -1,5 +1,8 @@
1
1
  /**
2
- * Dashboard UI - Launch Auto-Learn Dashboard in browser
2
+ * Dashboard UI v7.0 - Launch PikaKit Dashboard in browser
3
+ *
4
+ * @version 7.0.0
5
+ * @author PikaKit
3
6
  */
4
7
  import * as p from "@clack/prompts";
5
8
  import { spawn, exec } from "child_process";
@@ -18,7 +21,6 @@ let runningPort = null;
18
21
  async function checkPortInUse(port) {
19
22
  return new Promise((resolve) => {
20
23
  const req = http.get(`http://localhost:${port}/api/summary`, (res) => {
21
- // If we get 200 response from /api/summary, it's our dashboard
22
24
  if (res.statusCode === 200) {
23
25
  resolve(true);
24
26
  } else {
@@ -29,7 +31,6 @@ async function checkPortInUse(port) {
29
31
  req.on('error', () => {
30
32
  resolve(false);
31
33
  });
32
- // Faster timeout - 500ms is enough for localhost
33
34
  req.setTimeout(500, () => {
34
35
  req.destroy();
35
36
  resolve(false);
@@ -41,15 +42,12 @@ async function checkPortInUse(port) {
41
42
  * Find existing dashboard server on ports 3030-3040
42
43
  */
43
44
  async function findExistingServer() {
44
- // Check ports in parallel for faster detection
45
45
  const portChecks = [];
46
46
  for (let port = 3030; port <= 3040; port++) {
47
47
  portChecks.push(checkPortInUse(port).then(inUse => inUse ? port : null));
48
48
  }
49
-
50
49
  const results = await Promise.all(portChecks);
51
- const existingPort = results.find(port => port !== null);
52
- return existingPort || null;
50
+ return results.find(port => port !== null) || null;
53
51
  }
54
52
 
55
53
  /**
@@ -71,21 +69,19 @@ async function findAvailablePort(startPort = 3030) {
71
69
  * Find dashboard server script
72
70
  */
73
71
  function findDashboardScript() {
74
- // Get the directory where this module is located
75
72
  const moduleDir = path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/i, '$1'));
76
73
  const cliRoot = path.resolve(moduleDir, '..', '..');
77
-
78
- // User home directory
79
74
  const homeDir = process.env.USERPROFILE || process.env.HOME || '';
80
75
 
81
76
  const possiblePaths = [
82
- // PRIORITY 1: Bundled with CLI package (always available)
83
- path.join(cliRoot, "dashboard", "dashboard_server.js"),
84
- // PRIORITY 2: Current project paths
85
- path.join(process.cwd(), ".agent", "skills", "auto-learner", "scripts", "dashboard_server.js"),
86
- path.join(process.cwd(), ".agent", "agentskillskit", ".agent", "skills", "auto-learner", "scripts", "dashboard_server.js"),
87
- // PRIORITY 3: Fallback user paths (Windows Desktop)
88
- path.join(homeDir, "Desktop", "agent-skill-kit", ".agent", "skills", "auto-learner", "scripts", "dashboard_server.js"),
77
+ // PRIORITY 1: New v7.0 script bundled with CLI package
78
+ path.join(cliRoot, "scripts", "dashboard-server.js"),
79
+ // PRIORITY 2: Dashboard folder (legacy)
80
+ path.join(cliRoot, "dashboard", "dashboard-server.js"),
81
+ // PRIORITY 3: Current project paths
82
+ path.join(process.cwd(), ".agent", "skills", "auto-learner", "scripts", "dashboard-server.js"),
83
+ // PRIORITY 4: Fallback - agent-skill-kit
84
+ path.join(homeDir, "Desktop", "agent-skill-kit", ".agent", "skills", "auto-learner", "scripts", "dashboard-server.js"),
89
85
  ];
90
86
 
91
87
  for (const searchPath of possiblePaths) {
@@ -102,7 +98,6 @@ function findDashboardScript() {
102
98
  function openBrowser(url) {
103
99
  const platform = process.platform;
104
100
  let command;
105
-
106
101
  if (platform === "win32") {
107
102
  command = `start "" "${url}"`;
108
103
  } else if (platform === "darwin") {
@@ -110,10 +105,9 @@ function openBrowser(url) {
110
105
  } else {
111
106
  command = `xdg-open "${url}"`;
112
107
  }
113
-
114
108
  exec(command, (err) => {
115
109
  if (err) {
116
- p.log.warn(`Could not open browser automatically. Visit: ${url}`);
110
+ p.log.warn(`Could not open browser. Visit: ${url}`);
117
111
  }
118
112
  });
119
113
  }
@@ -124,7 +118,7 @@ function openBrowser(url) {
124
118
  export async function runDashboardUI() {
125
119
  const spinner = p.spinner();
126
120
 
127
- // Check if there's already a server running
121
+ // Check for existing server
128
122
  spinner.start("Checking for existing dashboard server...");
129
123
  const existingPort = await findExistingServer();
130
124
 
@@ -132,10 +126,10 @@ export async function runDashboardUI() {
132
126
  spinner.stop(`Found existing server on port ${existingPort}`);
133
127
  const url = `http://localhost:${existingPort}`;
134
128
 
135
- p.log.success(`Dashboard already running at: ${url}`);
129
+ p.log.success(`Dashboard running at: ${url}`);
136
130
  openBrowser(url);
137
131
 
138
- p.note(`Server running on port ${existingPort}\nUsing existing server`, "📊 Auto-Learn Dashboard");
132
+ p.note(`Server running on port ${existingPort}\nUsing existing server`, "🧠 PikaKit Dashboard v7.0");
139
133
 
140
134
  const action = await p.select({
141
135
  message: "Dashboard is running. What would you like to do?",
@@ -146,7 +140,6 @@ export async function runDashboardUI() {
146
140
  });
147
141
 
148
142
  if (action === "stop") {
149
- // Kill all node processes on that port
150
143
  p.log.info("Stopping existing server...");
151
144
  if (process.platform === "win32") {
152
145
  exec(`for /f "tokens=5" %a in ('netstat -aon ^| findstr :${existingPort}') do taskkill /F /PID %a`, () => { });
@@ -166,7 +159,7 @@ export async function runDashboardUI() {
166
159
 
167
160
  if (!scriptPath) {
168
161
  p.log.error("Dashboard script not found!");
169
- p.log.info("Install auto-learner skill first or check .agent/skills/auto-learner/scripts/");
162
+ p.log.info("Looking for: dashboard-server.js in scripts folder");
170
163
  return;
171
164
  }
172
165
 
@@ -177,7 +170,7 @@ export async function runDashboardUI() {
177
170
  spinner.stop(`Using port ${port}`);
178
171
 
179
172
  // Start dashboard server
180
- spinner.start("Starting dashboard server...");
173
+ spinner.start("Starting PikaKit Dashboard v7.0...");
181
174
 
182
175
  const child = spawn("node", [scriptPath, "--port", String(port)], {
183
176
  stdio: ["ignore", "pipe", "pipe"],
@@ -193,14 +186,11 @@ export async function runDashboardUI() {
193
186
 
194
187
  const url = `http://localhost:${port}`;
195
188
 
196
- // Open browser
197
189
  p.log.success(`Dashboard running at: ${url}`);
198
190
  openBrowser(url);
199
191
 
200
- p.log.info("Dashboard opened in browser");
201
- p.note(`Server running on port ${port}\nPress Ctrl+C in terminal to stop`, "📊 Auto-Learn Dashboard");
192
+ p.note(`Server: http://localhost:${port}\nPress Ctrl+C to stop`, "🧠 PikaKit Dashboard v7.0");
202
193
 
203
- // Keep server running and wait for user
204
194
  const action = await p.select({
205
195
  message: "Dashboard is running. What would you like to do?",
206
196
  options: [