@agentskillkit/agent-skills 3.2.1 → 3.2.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.
Files changed (51) hide show
  1. package/.agent/skills/mobile-design/scripts/mobile_audit.js +333 -0
  2. package/.agent/skills/typescript-expert/scripts/ts_diagnostic.js +227 -0
  3. package/README.md +197 -720
  4. package/package.json +4 -4
  5. package/packages/cli/lib/audit.js +2 -2
  6. package/packages/cli/lib/auto-learn.js +8 -8
  7. package/packages/cli/lib/eslint-fix.js +1 -1
  8. package/packages/cli/lib/fix.js +5 -5
  9. package/packages/cli/lib/hooks/install-hooks.js +4 -4
  10. package/packages/cli/lib/hooks/lint-learn.js +4 -4
  11. package/packages/cli/lib/knowledge-index.js +4 -4
  12. package/packages/cli/lib/knowledge-metrics.js +2 -2
  13. package/packages/cli/lib/knowledge-retention.js +3 -3
  14. package/packages/cli/lib/knowledge-validator.js +3 -3
  15. package/packages/cli/lib/learn.js +10 -10
  16. package/packages/cli/lib/recall.js +1 -1
  17. package/packages/cli/lib/skill-learn.js +2 -2
  18. package/packages/cli/lib/stats.js +3 -3
  19. package/packages/cli/lib/ui/dashboard-ui.js +222 -0
  20. package/packages/cli/lib/ui/help-ui.js +41 -18
  21. package/packages/cli/lib/ui/index.js +57 -5
  22. package/packages/cli/lib/ui/settings-ui.js +292 -14
  23. package/packages/cli/lib/ui/stats-ui.js +93 -43
  24. package/packages/cli/lib/watcher.js +2 -2
  25. package/packages/kit/kit.js +89 -0
  26. package/packages/kit/lib/agents.js +208 -0
  27. package/packages/kit/lib/commands/analyze.js +70 -0
  28. package/packages/kit/lib/commands/cache.js +65 -0
  29. package/packages/kit/lib/commands/doctor.js +75 -0
  30. package/packages/kit/lib/commands/help.js +155 -0
  31. package/packages/kit/lib/commands/info.js +38 -0
  32. package/packages/kit/lib/commands/init.js +39 -0
  33. package/packages/kit/lib/commands/install.js +803 -0
  34. package/packages/kit/lib/commands/list.js +43 -0
  35. package/packages/kit/lib/commands/lock.js +57 -0
  36. package/packages/kit/lib/commands/uninstall.js +307 -0
  37. package/packages/kit/lib/commands/update.js +55 -0
  38. package/packages/kit/lib/commands/validate.js +69 -0
  39. package/packages/kit/lib/commands/verify.js +56 -0
  40. package/packages/kit/lib/config.js +81 -0
  41. package/packages/kit/lib/helpers.js +196 -0
  42. package/packages/kit/lib/helpers.test.js +60 -0
  43. package/packages/kit/lib/installer.js +164 -0
  44. package/packages/kit/lib/skills.js +119 -0
  45. package/packages/kit/lib/skills.test.js +109 -0
  46. package/packages/kit/lib/types.js +82 -0
  47. package/packages/kit/lib/ui.js +329 -0
  48. package/.agent/skills/mobile-design/scripts/mobile_audit.py +0 -670
  49. package/.agent/skills/requirements-python.txt +0 -25
  50. package/.agent/skills/requirements.txt +0 -96
  51. package/.agent/skills/typescript-expert/scripts/ts_diagnostic.py +0 -203
@@ -23,9 +23,44 @@ import { runLessonsUI } from "./lessons-ui.js";
23
23
  import { runEvolutionSignalsUI } from "./evolution-signals-ui.js";
24
24
  import { runKnowledgeUI } from "./knowledge-ui.js";
25
25
  import { runHelpUI } from "./help-ui.js";
26
+ import { runDashboardUI } from "./dashboard-ui.js";
26
27
  import routingUI from "./routing-ui.js";
27
28
  import * as p from "@clack/prompts";
28
29
  import { VERSION } from "../config.js";
30
+ import gradient from 'gradient-string';
31
+
32
+ // ============================================================================
33
+ // ASCII BANNER
34
+ // ============================================================================
35
+
36
+ const AGENT_BANNER = `
37
+ _ _
38
+ / \\ __ _ ___ _ __ | |_
39
+ / _ \\ / _\` |/ _ \\ '_ \\| __|
40
+ / ___ \\ (_| | __/ | | | |_
41
+ /_/ \\_\\__, |\\___|_| |_|\\__|
42
+ |___/
43
+ `;
44
+
45
+ // Custom gradient: white → gray (like PikaKit style)
46
+ const agentGradient = gradient(['#ffffff', '#bbbbbb', '#888888', '#555555']);
47
+
48
+ function showAgentBanner() {
49
+ // Extra clear to remove Clack prompt residuals
50
+ process.stdout.write('\x1B[2J\x1B[0f');
51
+ console.clear();
52
+ console.log(''); // Extra space at top
53
+ const lines = AGENT_BANNER.split('\n').filter(l => l.trim() !== '');
54
+
55
+ // Print all lines except last with gradient
56
+ for (let i = 0; i < lines.length - 1; i++) {
57
+ console.log(agentGradient(lines[i]));
58
+ }
59
+
60
+ // Last line + version (aligned like PikaKit)
61
+ console.log(agentGradient(lines[lines.length - 1]) + theme.dim(` v${VERSION}`));
62
+ console.log(''); // Empty line to break vertical connector
63
+ }
29
64
 
30
65
  // ============================================================================
31
66
  // MAIN MENU
@@ -36,14 +71,23 @@ import { VERSION } from "../config.js";
36
71
  */
37
72
  export async function showMainMenu() {
38
73
  while (true) {
39
- showIntro(`🧠 Agent Skill Kit v${VERSION}`);
74
+ showAgentBanner();
40
75
 
41
76
  // Load settings to check auto-learning status
42
77
  const settings = loadSettings();
43
78
  const autoLearningEnabled = settings.autoLearn !== false; // Default to true
44
79
 
45
80
  // Build menu options dynamically
46
- const menuOptions = [];
81
+ const menuOptions = [
82
+ // ═════════════════════════════════════════════
83
+ // 🔍 SCANNING & ACTIONS
84
+ // ═════════════════════════════════════════════
85
+ { value: "scanall", label: "🔎 Scan All", hint: "Check & fix violations" },
86
+
87
+ // ═════════════════════════════════════════════
88
+ // 📚 LEARNING & KNOWLEDGE
89
+ // ═════════════════════════════════════════════
90
+ ];
47
91
 
48
92
  // Only show Learn if auto-learning is OFF
49
93
  if (!autoLearningEnabled) {
@@ -63,6 +107,12 @@ export async function showMainMenu() {
63
107
  // ═════════════════════════════════════════════
64
108
  { value: "settings", label: "⚙️ Settings", hint: "Configure behavior" },
65
109
  { value: "backup", label: "💾 Backup", hint: "Data management" },
110
+
111
+ // ═════════════════════════════════════════════
112
+ // 📊 DASHBOARD
113
+ // ═════════════════════════════════════════════
114
+ { value: "dashboard", label: "📊 Dashboard", hint: "Web UI & Help" },
115
+
66
116
  { value: "exit", label: "👋 Exit" }
67
117
  );
68
118
 
@@ -84,7 +134,9 @@ export async function showMainMenu() {
84
134
  case "lessons":
85
135
  await runLessonsUI();
86
136
  break;
87
-
137
+ case "scanall":
138
+ await runRecallUI(true); // Auto-scan mode with fix option
139
+ break;
88
140
  case "stats":
89
141
  await runStatsUI(); // Now includes signals
90
142
  break;
@@ -94,8 +146,8 @@ export async function showMainMenu() {
94
146
  case "backup":
95
147
  await runBackupUI();
96
148
  break;
97
- case "help":
98
- await runHelpUI();
149
+ case "dashboard":
150
+ await runDashboardUI();
99
151
  break;
100
152
  }
101
153
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Settings UI - Minimal Interactive settings configuration
2
+ * Settings UI - Interactive settings configuration
3
3
  */
4
4
  import * as p from "@clack/prompts";
5
5
  import pc from "picocolors";
@@ -7,23 +7,160 @@ import {
7
7
  loadSettings,
8
8
  saveSettings,
9
9
  toggleAutoLearning,
10
- toggleAutoUpdating
10
+ toggleAutoUpdating,
11
+ setApiKey,
12
+ getApiKey,
13
+ removeApiKey
11
14
  } from "../settings.js";
15
+ import fs from 'fs';
16
+ import path from 'path';
17
+ import os from 'os';
18
+
19
+ // ============================================================================
20
+ // HELPERS
21
+ // ============================================================================
22
+
23
+ /**
24
+ * Mask API key for display (show first 4 and last 4 chars)
25
+ */
26
+ function maskApiKey(key) {
27
+ if (!key) return pc.dim("[Not Set]");
28
+ if (key.length < 12) return "***...***";
29
+ return `${key.substring(0, 4)}...${key.substring(key.length - 4)}`;
30
+ }
31
+
32
+ /**
33
+ * Get Antigravity OAuth credentials (if available)
34
+ * @returns {{accessToken: string, expiryDate: number} | null}
35
+ */
36
+ function getAntigravityOAuthToken() {
37
+ try {
38
+ const credPath = path.join(os.homedir(), '.gemini', 'oauth_creds.json');
39
+
40
+ if (!fs.existsSync(credPath)) return null;
41
+
42
+ const creds = JSON.parse(fs.readFileSync(credPath, 'utf8'));
43
+
44
+ // Check if token is still valid
45
+ if (creds.access_token && creds.expiry_date) {
46
+ const now = Date.now();
47
+ if (now < creds.expiry_date) {
48
+ return {
49
+ accessToken: creds.access_token,
50
+ expiryDate: creds.expiry_date
51
+ };
52
+ }
53
+ }
54
+
55
+ return null;
56
+ } catch (e) {
57
+ return null;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Detect which API key Agent is actively using (from environment)
63
+ * Checks multiple sources in priority order:
64
+ * 1. Current process environment
65
+ * 2. Exported Settings API key
66
+ * 3. SelfEvolution .env file
67
+ * @returns {'gemini' | 'claude' | null}
68
+ */
69
+ function getActiveApiKey() {
70
+ // Priority 1: Current process environment (Agent session)
71
+ if (process.env.GEMINI_API_KEY) return 'gemini';
72
+ if (process.env.CLAUDE_API_KEY || process.env.ANTHROPIC_API_KEY) return 'claude';
73
+
74
+ // Priority 2: Check if we have exported keys from Settings
75
+ const geminiKey = getApiKey('gemini');
76
+ const claudeKey = getApiKey('claude');
77
+
78
+ // If Settings has a key configured, consider it "active"
79
+ // (because we auto-export to SelfEvolution)
80
+ if (geminiKey) return 'gemini';
81
+ if (claudeKey) return 'claude';
82
+
83
+ // Priority 3: Check Antigravity OAuth credentials
84
+ const oauthCreds = getAntigravityOAuthToken();
85
+ if (oauthCreds) return 'gemini'; // Antigravity uses Google OAuth
86
+
87
+ return null;
88
+ }
89
+
90
+ /**
91
+ * Format API key status (ON if active, OFF if not)
92
+ */
93
+ function formatApiKeyStatus(provider, storedKey) {
94
+ const activeKey = getActiveApiKey();
95
+ const isActive = activeKey === provider;
96
+
97
+ if (!storedKey) {
98
+ return pc.dim("[Not Set]");
99
+ }
100
+
101
+ if (isActive) {
102
+ return `${pc.green("[ON]")} ${maskApiKey(storedKey)}`;
103
+ } else {
104
+ return `${pc.dim("[OFF]")} ${maskApiKey(storedKey)}`;
105
+ }
106
+ }
12
107
 
13
108
  // ============================================================================
14
109
  // SETTINGS MENU
15
110
  // ============================================================================
16
111
 
17
112
  /**
18
- * Interactive settings menu - Minimal version
113
+ * Interactive settings menu with Clack icons
19
114
  */
20
115
  export async function runSettingsUI() {
116
+ // No intro - go straight to settings menu
117
+
118
+ // Display active API key info ONCE at the start
119
+ const geminiKey = getApiKey('gemini');
120
+ const claudeKey = getApiKey('claude');
121
+
122
+ let bannerMsg;
123
+
124
+ // Priority 1: Check if running in Antigravity (check for oauth_creds.json)
125
+ try {
126
+ const credPath = path.join(os.homedir(), '.gemini', 'oauth_creds.json');
127
+ if (fs.existsSync(credPath)) {
128
+ // Running in Antigravity - always show this message
129
+ bannerMsg = pc.green(
130
+ `✓ Agent Coding is using system credentials\n` +
131
+ ` Source: Antigravity Session (in-memory)\n` +
132
+ ` → Configure permanent API key below for SelfEvolution features`
133
+ );
134
+ } else {
135
+ // Not in Antigravity, check for configured keys
136
+ if (geminiKey) {
137
+ bannerMsg = pc.green(`✓ Using Gemini API Key (Configured)\n → SelfEvolution features enabled`);
138
+ } else if (claudeKey) {
139
+ bannerMsg = pc.green(`✓ Using Claude API Key (Configured)\n → SelfEvolution features enabled`);
140
+ } else {
141
+ bannerMsg = pc.yellow(`⚠ No API Key Configured\n → Set up API key below to enable SelfEvolution features`);
142
+ }
143
+ }
144
+ } catch (e) {
145
+ // Fallback: check configured keys
146
+ if (geminiKey) {
147
+ bannerMsg = pc.green(`✓ Using Gemini API Key (Configured)\n → SelfEvolution features enabled`);
148
+ } else if (claudeKey) {
149
+ bannerMsg = pc.green(`✓ Using Claude API Key (Configured)\n → SelfEvolution features enabled`);
150
+ } else {
151
+ bannerMsg = pc.yellow(`⚠ No API Key Configured\n → Set up API key below to enable SelfEvolution features`);
152
+ }
153
+ }
154
+
155
+ p.note(bannerMsg, "🔑 Active API Key");
156
+
21
157
  while (true) {
22
158
  const settings = loadSettings();
23
159
 
24
160
  const action = await p.select({
25
161
  message: "⚙️ Settings",
26
162
  options: [
163
+ // AI BEHAVIOR GROUP
27
164
  {
28
165
  value: "autoLearn",
29
166
  label: `🤖 Auto-Learning: ${settings.autoLearning ? pc.green("[ON]") : pc.dim("[OFF]")}`,
@@ -32,12 +169,29 @@ export async function runSettingsUI() {
32
169
  {
33
170
  value: "autoUpdate",
34
171
  label: `🔄 Auto-Updating: ${settings.autoUpdating ? pc.green("[ON]") : pc.dim("[OFF]")}`,
35
- hint: "Auto-escalate patterns"
172
+ hint: "Update threshold hits"
36
173
  },
37
174
  {
38
175
  value: "threshold",
39
176
  label: `📈 Update Threshold: ${pc.cyan(settings.updateThreshold)}`,
40
- hint: "Hits before escalation"
177
+ hint: "Hits before update"
178
+ },
179
+
180
+ // API CONFIGURATION GROUP
181
+ {
182
+ value: "geminiKey",
183
+ label: `🔑 Gemini API: ${formatApiKeyStatus('gemini', getApiKey('gemini'))}`,
184
+ hint: "For agent coding"
185
+ },
186
+ {
187
+ value: "claudeKey",
188
+ label: `🔑 Claude API: ${formatApiKeyStatus('claude', getApiKey('claude'))}`,
189
+ hint: "Alternative AI provider"
190
+ },
191
+ {
192
+ value: "testOptimization",
193
+ label: "🧪 Test AI Optimization",
194
+ hint: "Verify SelfEvolution integration"
41
195
  },
42
196
  { value: "back", label: "← Back", hint: "Return to main menu" }
43
197
  ]
@@ -54,15 +208,17 @@ export async function runSettingsUI() {
54
208
  `Auto-Learning is now ${newValue ? pc.green("ON") : pc.red("OFF")}`,
55
209
  "Setting Updated"
56
210
  );
57
- break;
211
+ break; // Continue loop to show menu again
58
212
  }
59
213
  case "autoUpdate": {
60
214
  const newValue = toggleAutoUpdating();
61
215
  if (newValue) {
62
216
  p.note(
63
217
  `Auto-Updating is now ${pc.green("ON")}\n\n` +
64
- `Patterns will auto-escalate WARNING ERROR\n` +
65
- `when violations exceed threshold.`,
218
+ `When patterns become valuable, Agent will:\n` +
219
+ `• Analyze learned lessons\n` +
220
+ `• Generate update proposals\n` +
221
+ `• Notify you for approval`,
66
222
  "Setting Updated"
67
223
  );
68
224
  } else {
@@ -71,17 +227,17 @@ export async function runSettingsUI() {
71
227
  "Setting Updated"
72
228
  );
73
229
  }
74
- break;
230
+ break; // Continue loop
75
231
  }
76
232
  case "threshold": {
77
233
  const newThreshold = await p.text({
78
- message: "Set new threshold (1-50):",
79
- placeholder: "10",
234
+ message: "Set new threshold (1-20):",
235
+ placeholder: "5",
80
236
  initialValue: String(settings.updateThreshold),
81
237
  validate: (value) => {
82
238
  const num = parseInt(value);
83
- if (isNaN(num) || num < 1 || num > 50) {
84
- return "Please enter a number between 1 and 50";
239
+ if (isNaN(num) || num < 1 || num > 20) {
240
+ return "Please enter a number between 1 and 20";
85
241
  }
86
242
  }
87
243
  });
@@ -90,10 +246,132 @@ export async function runSettingsUI() {
90
246
  settings.updateThreshold = parseInt(newThreshold);
91
247
  saveSettings(settings);
92
248
  p.note(
93
- `Update threshold set to ${pc.cyan(settings.updateThreshold)}`,
249
+ `Update threshold set to ${settings.updateThreshold}`,
94
250
  "Setting Updated"
95
251
  );
96
252
  }
253
+ break; // Continue loop
254
+ }
255
+ case "geminiKey":
256
+ case "claudeKey": {
257
+ const provider = action === "geminiKey" ? "gemini" : "claude";
258
+ const providerName = provider.charAt(0).toUpperCase() + provider.slice(1);
259
+ const currentKey = getApiKey(provider);
260
+
261
+ // Ask user action
262
+ const keyAction = await p.select({
263
+ message: `${providerName} API Key:`,
264
+ options: [
265
+ { value: "set", label: "Set/Update Key", hint: "Configure API key" },
266
+ ...(currentKey ? [{ value: "remove", label: "Remove Key", hint: "Clear stored key" }] : []),
267
+ { value: "cancel", label: "Cancel", hint: "Go back" }
268
+ ]
269
+ });
270
+
271
+ if (p.isCancel(keyAction) || keyAction === "cancel") {
272
+ break; // Return to settings menu
273
+ }
274
+
275
+ if (keyAction === "set") {
276
+ const apiKey = await p.password({
277
+ message: `Enter ${providerName} API Key:`,
278
+ mask: "*",
279
+ validate: (value) => {
280
+ if (!value || value.length < 10) {
281
+ return "API key must be at least 10 characters";
282
+ }
283
+ }
284
+ });
285
+
286
+ if (!p.isCancel(apiKey)) {
287
+ const success = setApiKey(provider, apiKey);
288
+ if (success) {
289
+ p.note(
290
+ `${providerName} API key ${currentKey ? 'updated' : 'set'} successfully!\n\n` +
291
+ `Key: ${maskApiKey(apiKey)}\n` +
292
+ `Stored in: .agent/knowledge/settings.yaml`,
293
+ pc.green("✓ API Key Saved")
294
+ );
295
+ } else {
296
+ p.note(
297
+ `Failed to save ${providerName} API key`,
298
+ pc.red("✗ Error")
299
+ );
300
+ }
301
+ }
302
+ } else if (keyAction === "remove") {
303
+ const confirm = await p.confirm({
304
+ message: `Remove ${providerName} API key?`,
305
+ });
306
+
307
+ if (confirm && !p.isCancel(confirm)) {
308
+ removeApiKey(provider);
309
+ p.note(
310
+ `${providerName} API key removed`,
311
+ "Key Removed"
312
+ );
313
+ }
314
+ }
315
+ break;
316
+ }
317
+ case "testOptimization": {
318
+ const { exportApiKeysToSelfEvolution, verifySelfEvolutionAccess } =
319
+ await import('../selfevolution-bridge.js');
320
+
321
+ // Step 1: Export keys
322
+ const spinner = p.spinner();
323
+ spinner.start('Exporting API keys to SelfEvolution...');
324
+
325
+ const exportResult = exportApiKeysToSelfEvolution();
326
+
327
+ if (!exportResult.success) {
328
+ spinner.stop('Export failed');
329
+ p.note(
330
+ `❌ No API keys configured\n\n` +
331
+ `Please set Gemini or Claude API key first.\n\n` +
332
+ `Reason: ${exportResult.reason}`,
333
+ pc.red('✗ Cannot Test')
334
+ );
335
+ break;
336
+ }
337
+
338
+ spinner.message('Keys exported. Verifying Python access...');
339
+
340
+ // Step 2: Verify Python can access
341
+ const verifyResult = await verifySelfEvolutionAccess();
342
+
343
+ if (verifyResult.success && verifyResult.keyDetected) {
344
+ spinner.stop('Verification complete');
345
+
346
+ const exportedKeys = [];
347
+ if (exportResult.exported.gemini) exportedKeys.push('Gemini');
348
+ if (exportResult.exported.claude) exportedKeys.push('Claude');
349
+
350
+ p.note(
351
+ `✅ **API Key Integration Working!**\n\n` +
352
+ `Exported: ${exportedKeys.join(', ')}\n` +
353
+ `Location: ${exportResult.path}\n\n` +
354
+ `SelfEvolution can now:\n` +
355
+ `• Auto-learn from mistakes\n` +
356
+ `• AI-powered lesson optimization\n` +
357
+ `• Self-improve knowledge base\n\n` +
358
+ `${pc.dim('Python Output:')}\n${pc.dim(verifyResult.output)}`,
359
+ pc.green('✓ Optimization Ready')
360
+ );
361
+ } else {
362
+ spinner.stop('Verification failed');
363
+ p.note(
364
+ `⚠️ **Export OK, but verification failed**\n\n` +
365
+ `Keys exported to: ${exportResult.path}\n` +
366
+ `But Python script couldn't detect them.\n\n` +
367
+ `Error: ${verifyResult.error || 'Unknown'}\n\n` +
368
+ `Possible causes:\n` +
369
+ `• Python not installed\n` +
370
+ `• SelfEvolution scripts missing\n` +
371
+ `• Environment variable issue`,
372
+ pc.yellow('⚠ Partial Success')
373
+ );
374
+ }
97
375
  break;
98
376
  }
99
377
  }
@@ -1,73 +1,123 @@
1
1
  /**
2
- * Stats UI - Compact single-screen insight using Clack boxes
2
+ * Stats UI - Knowledge base statistics display
3
3
  */
4
- import { getKnowledge } from "./common.js";
5
- import { showIntro, createSpinner } from "./clack-helpers.js";
4
+ import { ICONS, getKnowledge, line, VERSION } from "./common.js";
5
+ import { showIntro, showInfoNote, showSuccessNote, createSpinner, theme } from "./clack-helpers.js";
6
+ import { signalQueue, getEvolutionStats } from "../evolution-signal.js";
6
7
  import * as p from "@clack/prompts";
7
8
  import pc from "picocolors";
8
9
 
9
10
  // ============================================================================
10
- // INSIGHT - SINGLE SCREEN WITH CLACK BOXES
11
+ // STATS DISPLAY
11
12
  // ============================================================================
12
13
 
14
+ /**
15
+ * Stats UI - Show knowledge base statistics with cognitive insights
16
+ */
13
17
  export async function runStatsUI() {
14
- process.stdout.write('\x1Bc');
15
- showIntro("📊 Insight");
18
+ // Clear terminal và reset cursor về top-left
19
+ process.stdout.write('\x1Bc'); // Full terminal reset
20
+
21
+ showIntro("📊 Knowledge Base Stats");
16
22
 
17
- const spinner = createSpinner("Loading...");
23
+ const spinner = createSpinner("Loading statistics...");
18
24
 
19
25
  try {
20
26
  const db = getKnowledge();
21
27
  const lessons = db.lessons || [];
22
- const total = lessons.length;
23
28
 
24
- spinner.stopSuccess("Loaded");
29
+ // Calculate statistics with cognitive awareness
30
+ const totalLessons = lessons.length;
31
+ const mistakes = lessons.filter(l => l.type === 'mistake');
32
+ const improvements = lessons.filter(l => l.type === 'improvement');
25
33
 
26
- if (total === 0) {
27
- p.note(pc.dim("No patterns learned yet."), "Empty");
28
- await waitBack();
29
- return;
30
- }
34
+ // Cognitive grouping - Intent
35
+ const byIntent = lessons.reduce((acc, l) => {
36
+ const intent = l.intent || 'unknown';
37
+ acc[intent] = (acc[intent] || 0) + 1;
38
+ return acc;
39
+ }, {});
40
+
41
+ // Cognitive grouping - Pattern Type
42
+ const byPatternType = lessons.reduce((acc, l) => {
43
+ const type = l.patternType || 'general';
44
+ acc[type] = (acc[type] || 0) + 1;
45
+ return acc;
46
+ }, {});
31
47
 
32
- // Quick counts
33
- const mistakes = lessons.filter(l => l.type === 'mistake').length;
34
- const improvements = lessons.filter(l => l.type === 'improvement').length;
35
- const errors = lessons.filter(l => l.severity === 'ERROR').length;
36
- const warnings = lessons.filter(l => l.severity === 'WARNING').length;
48
+ // Cognitive grouping - Maturity
49
+ const byMaturity = lessons.reduce((acc, l) => {
50
+ const maturity = l.cognitive?.maturity || 'learning';
51
+ acc[maturity] = (acc[maturity] || 0) + 1;
52
+ return acc;
53
+ }, {});
37
54
 
38
- // Top hits
55
+ // Top 5 by hit count
39
56
  const topHits = lessons
40
- .filter(l => l.hitCount && l.hitCount > 0)
57
+ .filter(p => p.hitCount && p.hitCount > 0)
41
58
  .sort((a, b) => b.hitCount - a.hitCount)
42
- .slice(0, 3);
59
+ .slice(0, 5);
60
+
61
+ spinner.stopSuccess("Stats loaded");
43
62
 
44
- // ========== CLACK NOTE BOX ==========
45
- const summaryContent = [
46
- `${pc.red('●')} ${mistakes} Mistakes ${pc.green('●')} ${improvements} Improvements`,
47
- `${pc.red('⊘')} ${errors} Errors ${pc.yellow('⚠')} ${warnings} Warnings`
48
- ].join('\n');
63
+ // Compact single-line display
64
+ console.log(`\n${pc.bold('📊 Knowledge Stats')} ${pc.dim(`(${totalLessons} lessons)`)}\n`);
49
65
 
50
- p.note(summaryContent, `📈 Summary (${total} patterns)`);
66
+ console.log(
67
+ `${pc.red('●')} ${mistakes.length} Mistakes ` +
68
+ `${pc.green('●')} ${improvements.length} Improvements ` +
69
+ `${pc.dim('│')} ` +
70
+ `${pc.red('🛡️')} ${byIntent.prevent || 0} Prevent ` +
71
+ `${pc.yellow('⚠️')} ${byIntent.warn || 0} Warn ` +
72
+ `${pc.green('⚡')} ${byIntent.optimize || 0} Optimize\n`
73
+ );
51
74
 
52
- // Top Patterns box
75
+ console.log(
76
+ `${pc.dim('Types:')} ` +
77
+ `${byPatternType.security ? `🔒${byPatternType.security} ` : ''}` +
78
+ `${byPatternType.dependency ? `📦${byPatternType.dependency} ` : ''}` +
79
+ `${byPatternType.structure ? `🏗️${byPatternType.structure} ` : ''}` +
80
+ `${byPatternType.quality ? `✨${byPatternType.quality} ` : ''}` +
81
+ `${byPatternType.performance ? `⚡${byPatternType.performance} ` : ''}` +
82
+ `${byPatternType.general ? pc.dim(`📝${byPatternType.general}`) : ''}\n`
83
+ );
84
+
85
+ console.log(
86
+ `${pc.dim('Maturity:')} ` +
87
+ `${pc.green('✓')} ${byMaturity.stable || 0} Stable ` +
88
+ `${pc.cyan('📚')} ${byMaturity.learning || 0} Learning\n`
89
+ );
90
+
91
+ // Show top 3 hits in compact format
53
92
  if (topHits.length > 0) {
54
- const topContent = topHits
55
- .map((l, i) => `${i + 1}. ${pc.dim(l.id?.slice(0, 12) || '?')} → ${pc.bold(l.hitCount)}× hits`)
56
- .join('\n');
57
- p.note(topContent, "🔥 Top Patterns");
93
+ console.log(`${pc.bold('🔥 Top Patterns')}`);
94
+ topHits.slice(0, 3).forEach((p, i) => {
95
+ console.log(` ${i + 1}. ${pc.dim(p.id)} ${pc.bold(p.hitCount)}×`);
96
+ });
97
+ console.log('');
58
98
  }
59
99
 
60
- await waitBack();
100
+ // Show signal queue summary
101
+ const signalStats = getEvolutionStats();
102
+ const pending = signalQueue.getPending();
103
+
104
+ console.log(`${pc.bold('📡 Signal Queue')}`);
105
+ console.log(
106
+ ` ${pc.yellow('⏳')} ${signalStats.pending} Pending ` +
107
+ `${pc.green('✓')} ${signalStats.approved} Approved ` +
108
+ `${pc.red('✗')} ${signalStats.rejected} Rejected\n`
109
+ );
110
+
111
+ // User can choose next action
112
+ await p.select({
113
+ message: "What's next?",
114
+ options: [
115
+ { value: "back", label: "← Back to Main Menu" }
116
+ ]
117
+ });
61
118
 
62
119
  } catch (error) {
63
- spinner.stopError("Failed");
64
- p.note(error.message, "Error");
120
+ spinner.stopError("Failed to load stats");
121
+ console.error(error);
65
122
  }
66
123
  }
67
-
68
- async function waitBack() {
69
- await p.select({
70
- message: "",
71
- options: [{ value: "back", label: "← Back" }]
72
- });
73
- }
@@ -8,7 +8,7 @@
8
8
  * - Pattern frequency tracking
9
9
  * - Live feedback on violations
10
10
  *
11
- * Usage: ag-smart watch [directory]
11
+ * Usage: agent watch [directory]
12
12
  */
13
13
 
14
14
  import fs from "fs";
@@ -159,7 +159,7 @@ if (args.includes("--help")) {
159
159
  👁️ Smart Watcher - Real-Time Monitor
160
160
 
161
161
  Usage:
162
- ag-smart watch [directory]
162
+ agent watch [directory]
163
163
 
164
164
  Options:
165
165
  --help Show this help