@agentskillkit/agent-skills 3.2.2 → 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.
- package/.agent/skills/mobile-design/scripts/mobile_audit.js +333 -0
- package/.agent/skills/typescript-expert/scripts/ts_diagnostic.js +227 -0
- package/README.md +197 -720
- package/package.json +4 -4
- package/packages/cli/lib/audit.js +2 -2
- package/packages/cli/lib/auto-learn.js +8 -8
- package/packages/cli/lib/eslint-fix.js +1 -1
- package/packages/cli/lib/fix.js +5 -5
- package/packages/cli/lib/hooks/install-hooks.js +4 -4
- package/packages/cli/lib/hooks/lint-learn.js +4 -4
- package/packages/cli/lib/knowledge-index.js +4 -4
- package/packages/cli/lib/knowledge-metrics.js +2 -2
- package/packages/cli/lib/knowledge-retention.js +3 -3
- package/packages/cli/lib/knowledge-validator.js +3 -3
- package/packages/cli/lib/learn.js +10 -10
- package/packages/cli/lib/recall.js +1 -1
- package/packages/cli/lib/skill-learn.js +2 -2
- package/packages/cli/lib/stats.js +3 -3
- package/packages/cli/lib/ui/dashboard-ui.js +222 -0
- package/packages/cli/lib/ui/help-ui.js +41 -18
- package/packages/cli/lib/ui/index.js +57 -5
- package/packages/cli/lib/ui/settings-ui.js +292 -14
- package/packages/cli/lib/ui/stats-ui.js +93 -43
- package/packages/cli/lib/watcher.js +2 -2
- package/packages/kit/kit.js +89 -0
- package/packages/kit/lib/agents.js +208 -0
- package/packages/kit/lib/commands/analyze.js +70 -0
- package/packages/kit/lib/commands/cache.js +65 -0
- package/packages/kit/lib/commands/doctor.js +75 -0
- package/packages/kit/lib/commands/help.js +155 -0
- package/packages/kit/lib/commands/info.js +38 -0
- package/packages/kit/lib/commands/init.js +39 -0
- package/packages/kit/lib/commands/install.js +803 -0
- package/packages/kit/lib/commands/list.js +43 -0
- package/packages/kit/lib/commands/lock.js +57 -0
- package/packages/kit/lib/commands/uninstall.js +307 -0
- package/packages/kit/lib/commands/update.js +55 -0
- package/packages/kit/lib/commands/validate.js +69 -0
- package/packages/kit/lib/commands/verify.js +56 -0
- package/packages/kit/lib/config.js +81 -0
- package/packages/kit/lib/helpers.js +196 -0
- package/packages/kit/lib/helpers.test.js +60 -0
- package/packages/kit/lib/installer.js +164 -0
- package/packages/kit/lib/skills.js +119 -0
- package/packages/kit/lib/skills.test.js +109 -0
- package/packages/kit/lib/types.js +82 -0
- package/packages/kit/lib/ui.js +329 -0
- package/.agent/skills/mobile-design/scripts/mobile_audit.py +0 -670
- package/.agent/skills/requirements-python.txt +0 -25
- package/.agent/skills/requirements.txt +0 -96
- 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
|
-
|
|
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 "
|
|
98
|
-
await
|
|
149
|
+
case "dashboard":
|
|
150
|
+
await runDashboardUI();
|
|
99
151
|
break;
|
|
100
152
|
}
|
|
101
153
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Settings UI -
|
|
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
|
|
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: "
|
|
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
|
|
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
|
-
`
|
|
65
|
-
|
|
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-
|
|
79
|
-
placeholder: "
|
|
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 >
|
|
84
|
-
return "Please enter a number between 1 and
|
|
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 ${
|
|
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 -
|
|
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
|
-
//
|
|
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
|
-
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
//
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
|
55
|
+
// Top 5 by hit count
|
|
39
56
|
const topHits = lessons
|
|
40
|
-
.filter(
|
|
57
|
+
.filter(p => p.hitCount && p.hitCount > 0)
|
|
41
58
|
.sort((a, b) => b.hitCount - a.hitCount)
|
|
42
|
-
.slice(0,
|
|
59
|
+
.slice(0, 5);
|
|
60
|
+
|
|
61
|
+
spinner.stopSuccess("Stats loaded");
|
|
43
62
|
|
|
44
|
-
//
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
.
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
162
|
+
agent watch [directory]
|
|
163
163
|
|
|
164
164
|
Options:
|
|
165
165
|
--help Show this help
|