pikakit 3.0.5 → 3.7.2
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/README.md +1 -1
- package/bin/lib/commands/install.js +119 -242
- package/package.json +3 -4
- package/lib/agent-cli/bin/agent.js +0 -187
- package/lib/agent-cli/dashboard/dashboard_server.js +0 -312
- package/lib/agent-cli/lib/ab-testing.js +0 -364
- package/lib/agent-cli/lib/audit.js +0 -154
- package/lib/agent-cli/lib/audit.test.js +0 -100
- package/lib/agent-cli/lib/auto-learn.js +0 -319
- package/lib/agent-cli/lib/backup.js +0 -138
- package/lib/agent-cli/lib/backup.test.js +0 -78
- package/lib/agent-cli/lib/causality-engine.js +0 -331
- package/lib/agent-cli/lib/cognitive-lesson.js +0 -476
- package/lib/agent-cli/lib/completion.js +0 -149
- package/lib/agent-cli/lib/config.js +0 -35
- package/lib/agent-cli/lib/dashboard-data.js +0 -380
- package/lib/agent-cli/lib/eslint-fix.js +0 -238
- package/lib/agent-cli/lib/evolution-signal.js +0 -215
- package/lib/agent-cli/lib/export.js +0 -86
- package/lib/agent-cli/lib/export.test.js +0 -65
- package/lib/agent-cli/lib/fix.js +0 -337
- package/lib/agent-cli/lib/fix.test.js +0 -80
- package/lib/agent-cli/lib/gemini-export.js +0 -83
- package/lib/agent-cli/lib/generate-registry.js +0 -42
- package/lib/agent-cli/lib/hooks/install-hooks.js +0 -152
- package/lib/agent-cli/lib/hooks/lint-learn.js +0 -172
- package/lib/agent-cli/lib/icons.js +0 -93
- package/lib/agent-cli/lib/ignore.js +0 -116
- package/lib/agent-cli/lib/ignore.test.js +0 -58
- package/lib/agent-cli/lib/init.js +0 -124
- package/lib/agent-cli/lib/knowledge-index.js +0 -326
- package/lib/agent-cli/lib/knowledge-metrics.js +0 -335
- package/lib/agent-cli/lib/knowledge-retention.js +0 -398
- package/lib/agent-cli/lib/knowledge-validator.js +0 -312
- package/lib/agent-cli/lib/learn.js +0 -255
- package/lib/agent-cli/lib/learn.test.js +0 -70
- package/lib/agent-cli/lib/metrics-collector.js +0 -410
- package/lib/agent-cli/lib/proposals.js +0 -199
- package/lib/agent-cli/lib/proposals.test.js +0 -56
- package/lib/agent-cli/lib/recall.js +0 -835
- package/lib/agent-cli/lib/recall.test.js +0 -107
- package/lib/agent-cli/lib/reinforcement.js +0 -299
- package/lib/agent-cli/lib/selfevolution-bridge.js +0 -167
- package/lib/agent-cli/lib/settings.js +0 -203
- package/lib/agent-cli/lib/skill-generator.js +0 -379
- package/lib/agent-cli/lib/skill-learn.js +0 -296
- package/lib/agent-cli/lib/stats.js +0 -132
- package/lib/agent-cli/lib/stats.test.js +0 -94
- package/lib/agent-cli/lib/types.js +0 -33
- package/lib/agent-cli/lib/ui/audit-ui.js +0 -146
- package/lib/agent-cli/lib/ui/backup-ui.js +0 -107
- package/lib/agent-cli/lib/ui/clack-helpers.js +0 -317
- package/lib/agent-cli/lib/ui/common.js +0 -83
- package/lib/agent-cli/lib/ui/completion-ui.js +0 -126
- package/lib/agent-cli/lib/ui/custom-select.js +0 -69
- package/lib/agent-cli/lib/ui/dashboard-ui.js +0 -222
- package/lib/agent-cli/lib/ui/evolution-signals-ui.js +0 -107
- package/lib/agent-cli/lib/ui/export-ui.js +0 -94
- package/lib/agent-cli/lib/ui/fix-all-ui.js +0 -191
- package/lib/agent-cli/lib/ui/help-ui.js +0 -49
- package/lib/agent-cli/lib/ui/index.js +0 -199
- package/lib/agent-cli/lib/ui/init-ui.js +0 -56
- package/lib/agent-cli/lib/ui/knowledge-ui.js +0 -55
- package/lib/agent-cli/lib/ui/learn-ui.js +0 -706
- package/lib/agent-cli/lib/ui/lessons-ui.js +0 -148
- package/lib/agent-cli/lib/ui/pretty.js +0 -145
- package/lib/agent-cli/lib/ui/proposals-ui.js +0 -99
- package/lib/agent-cli/lib/ui/recall-ui.js +0 -342
- package/lib/agent-cli/lib/ui/routing-demo.js +0 -79
- package/lib/agent-cli/lib/ui/routing-ui.js +0 -325
- package/lib/agent-cli/lib/ui/settings-ui.js +0 -381
- package/lib/agent-cli/lib/ui/stats-ui.js +0 -123
- package/lib/agent-cli/lib/ui/watch-ui.js +0 -236
- package/lib/agent-cli/lib/watcher.js +0 -181
- package/lib/agent-cli/lib/watcher.test.js +0 -85
- package/lib/agent-cli/src/MIGRATION.md +0 -418
- package/lib/agent-cli/src/README.md +0 -367
- package/lib/agent-cli/src/core/evolution/evolution-signal.js +0 -42
- package/lib/agent-cli/src/core/evolution/index.js +0 -17
- package/lib/agent-cli/src/core/evolution/review-gate.js +0 -40
- package/lib/agent-cli/src/core/evolution/signal-detector.js +0 -137
- package/lib/agent-cli/src/core/evolution/signal-queue.js +0 -79
- package/lib/agent-cli/src/core/evolution/threshold-checker.js +0 -79
- package/lib/agent-cli/src/core/index.js +0 -15
- package/lib/agent-cli/src/core/learning/cognitive-enhancer.js +0 -282
- package/lib/agent-cli/src/core/learning/index.js +0 -12
- package/lib/agent-cli/src/core/learning/lesson-synthesizer.js +0 -83
- package/lib/agent-cli/src/core/scanning/index.js +0 -14
- package/lib/agent-cli/src/data/index.js +0 -13
- package/lib/agent-cli/src/data/repositories/index.js +0 -8
- package/lib/agent-cli/src/data/repositories/lesson-repository.js +0 -130
- package/lib/agent-cli/src/data/repositories/signal-repository.js +0 -119
- package/lib/agent-cli/src/data/storage/index.js +0 -8
- package/lib/agent-cli/src/data/storage/json-storage.js +0 -64
- package/lib/agent-cli/src/data/storage/yaml-storage.js +0 -66
- package/lib/agent-cli/src/infrastructure/index.js +0 -13
- package/lib/agent-cli/src/presentation/formatters/skill-formatter.js +0 -232
- package/lib/agent-cli/src/services/export-service.js +0 -162
- package/lib/agent-cli/src/services/index.js +0 -13
- package/lib/agent-cli/src/services/learning-service.js +0 -99
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Metrics Collector v7.0 - PikaKit Learning Metrics
|
|
3
|
-
*
|
|
4
|
-
* Collects and manages 18 KPIs for the Dashboard.
|
|
5
|
-
* Reads data from .agent/knowledge/ and .agent/metrics/
|
|
6
|
-
*
|
|
7
|
-
* @version 7.0.0
|
|
8
|
-
* @author PikaKit
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import fs from 'fs';
|
|
12
|
-
import path from 'path';
|
|
13
|
-
import { fileURLToPath } from 'url';
|
|
14
|
-
|
|
15
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
-
const __dirname = path.dirname(__filename);
|
|
17
|
-
|
|
18
|
-
// Find project root
|
|
19
|
-
function findProjectRoot() {
|
|
20
|
-
let dir = process.cwd();
|
|
21
|
-
while (dir !== path.dirname(dir)) {
|
|
22
|
-
if (fs.existsSync(path.join(dir, '.agent'))) return dir;
|
|
23
|
-
if (fs.existsSync(path.join(dir, 'package.json'))) return dir;
|
|
24
|
-
dir = path.dirname(dir);
|
|
25
|
-
}
|
|
26
|
-
return process.cwd();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const projectRoot = findProjectRoot();
|
|
30
|
-
const KNOWLEDGE_DIR = path.join(projectRoot, '.agent', 'knowledge');
|
|
31
|
-
const METRICS_DIR = path.join(projectRoot, '.agent', 'metrics');
|
|
32
|
-
|
|
33
|
-
// Ensure metrics directory exists
|
|
34
|
-
function ensureMetricsDir() {
|
|
35
|
-
if (!fs.existsSync(METRICS_DIR)) {
|
|
36
|
-
fs.mkdirSync(METRICS_DIR, { recursive: true });
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// ============================================================================
|
|
41
|
-
// DATA LOADERS
|
|
42
|
-
// ============================================================================
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Load lessons from knowledge base
|
|
46
|
-
*/
|
|
47
|
-
function loadLessons() {
|
|
48
|
-
const paths = [
|
|
49
|
-
path.join(KNOWLEDGE_DIR, 'lessons-learned.json'),
|
|
50
|
-
path.join(KNOWLEDGE_DIR, 'lessons-learned.yaml')
|
|
51
|
-
];
|
|
52
|
-
|
|
53
|
-
for (const filePath of paths) {
|
|
54
|
-
if (fs.existsSync(filePath)) {
|
|
55
|
-
try {
|
|
56
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
57
|
-
if (filePath.endsWith('.json')) {
|
|
58
|
-
return JSON.parse(content).lessons || [];
|
|
59
|
-
} else {
|
|
60
|
-
// Simple YAML parsing for lessons array
|
|
61
|
-
const lessons = [];
|
|
62
|
-
const lines = content.split('\n');
|
|
63
|
-
let currentLesson = null;
|
|
64
|
-
|
|
65
|
-
for (const line of lines) {
|
|
66
|
-
if (line.startsWith('- id:')) {
|
|
67
|
-
if (currentLesson) lessons.push(currentLesson);
|
|
68
|
-
currentLesson = { id: line.split(':')[1]?.trim() };
|
|
69
|
-
} else if (currentLesson && line.includes(':')) {
|
|
70
|
-
const [key, ...valueParts] = line.trim().split(':');
|
|
71
|
-
currentLesson[key.trim()] = valueParts.join(':').trim();
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (currentLesson) lessons.push(currentLesson);
|
|
75
|
-
return lessons;
|
|
76
|
-
}
|
|
77
|
-
} catch (e) {
|
|
78
|
-
console.error('Error loading lessons:', e.message);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return [];
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Load metrics history
|
|
87
|
-
*/
|
|
88
|
-
function loadMetricsHistory() {
|
|
89
|
-
const historyPath = path.join(METRICS_DIR, 'history.json');
|
|
90
|
-
if (fs.existsSync(historyPath)) {
|
|
91
|
-
try {
|
|
92
|
-
return JSON.parse(fs.readFileSync(historyPath, 'utf8'));
|
|
93
|
-
} catch (e) {
|
|
94
|
-
return { entries: [], lastUpdated: null };
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return { entries: [], lastUpdated: null };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Save metrics history
|
|
102
|
-
*/
|
|
103
|
-
function saveMetricsHistory(history) {
|
|
104
|
-
ensureMetricsDir();
|
|
105
|
-
const historyPath = path.join(METRICS_DIR, 'history.json');
|
|
106
|
-
history.lastUpdated = new Date().toISOString();
|
|
107
|
-
fs.writeFileSync(historyPath, JSON.stringify(history, null, 2));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Load current metrics snapshot
|
|
112
|
-
*/
|
|
113
|
-
function loadCurrentMetrics() {
|
|
114
|
-
const metricsPath = path.join(METRICS_DIR, 'current.json');
|
|
115
|
-
if (fs.existsSync(metricsPath)) {
|
|
116
|
-
try {
|
|
117
|
-
return JSON.parse(fs.readFileSync(metricsPath, 'utf8'));
|
|
118
|
-
} catch (e) {
|
|
119
|
-
return getDefaultMetrics();
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return getDefaultMetrics();
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Save current metrics
|
|
127
|
-
*/
|
|
128
|
-
function saveCurrentMetrics(metrics) {
|
|
129
|
-
ensureMetricsDir();
|
|
130
|
-
const metricsPath = path.join(METRICS_DIR, 'current.json');
|
|
131
|
-
metrics.timestamp = new Date().toISOString();
|
|
132
|
-
fs.writeFileSync(metricsPath, JSON.stringify(metrics, null, 2));
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Get default metrics structure
|
|
137
|
-
*/
|
|
138
|
-
function getDefaultMetrics() {
|
|
139
|
-
return {
|
|
140
|
-
// Task metrics
|
|
141
|
-
total_tasks: 0,
|
|
142
|
-
successful_tasks: 0,
|
|
143
|
-
failed_tasks: 0,
|
|
144
|
-
|
|
145
|
-
// Learning metrics
|
|
146
|
-
patterns_learned: 0,
|
|
147
|
-
skills_generated: 0,
|
|
148
|
-
lessons_count: 0,
|
|
149
|
-
|
|
150
|
-
// Performance metrics
|
|
151
|
-
task_success_rate: 0,
|
|
152
|
-
error_repeat_rate: 0,
|
|
153
|
-
first_time_success_rate: 0,
|
|
154
|
-
skill_effectiveness: 0,
|
|
155
|
-
|
|
156
|
-
// Reinforcement metrics
|
|
157
|
-
total_rewards: 0,
|
|
158
|
-
total_penalties: 0,
|
|
159
|
-
avg_confidence: 0,
|
|
160
|
-
|
|
161
|
-
// A/B Testing metrics
|
|
162
|
-
active_tests: 0,
|
|
163
|
-
completed_tests: 0,
|
|
164
|
-
|
|
165
|
-
// Timestamps
|
|
166
|
-
timestamp: new Date().toISOString(),
|
|
167
|
-
period_start: new Date().toISOString()
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// ============================================================================
|
|
172
|
-
// KPI CALCULATIONS
|
|
173
|
-
// ============================================================================
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Calculate all KPIs
|
|
177
|
-
*/
|
|
178
|
-
function calculateKPIs() {
|
|
179
|
-
const lessons = loadLessons();
|
|
180
|
-
const currentMetrics = loadCurrentMetrics();
|
|
181
|
-
|
|
182
|
-
// Count patterns from lessons
|
|
183
|
-
const patternsLearned = lessons.length;
|
|
184
|
-
|
|
185
|
-
// Calculate rates
|
|
186
|
-
const totalTasks = currentMetrics.total_tasks || 0;
|
|
187
|
-
const successfulTasks = currentMetrics.successful_tasks || 0;
|
|
188
|
-
const failedTasks = currentMetrics.failed_tasks || 0;
|
|
189
|
-
|
|
190
|
-
const taskSuccessRate = totalTasks > 0
|
|
191
|
-
? Math.round((successfulTasks / totalTasks) * 100)
|
|
192
|
-
: 0;
|
|
193
|
-
|
|
194
|
-
// Error repeat rate (lessons with severity > 1 occurrence)
|
|
195
|
-
const repeatedErrors = lessons.filter(l =>
|
|
196
|
-
(l.occurrences && parseInt(l.occurrences) > 1) ||
|
|
197
|
-
(l.severity === 'high' || l.severity === 'critical')
|
|
198
|
-
).length;
|
|
199
|
-
const errorRepeatRate = lessons.length > 0
|
|
200
|
-
? Math.round((repeatedErrors / lessons.length) * 100)
|
|
201
|
-
: 0;
|
|
202
|
-
|
|
203
|
-
// First-time success (tasks without retries)
|
|
204
|
-
const firstTimeSuccess = currentMetrics.first_time_success_rate || 0;
|
|
205
|
-
|
|
206
|
-
// Build KPIs object
|
|
207
|
-
return {
|
|
208
|
-
kpis: {
|
|
209
|
-
task_success_rate: {
|
|
210
|
-
value: `${taskSuccessRate}%`,
|
|
211
|
-
trend: taskSuccessRate >= 80 ? 'up' : 'down',
|
|
212
|
-
status: taskSuccessRate >= 80 ? 'good' : taskSuccessRate >= 50 ? 'warning' : 'bad'
|
|
213
|
-
},
|
|
214
|
-
error_repeat_rate: {
|
|
215
|
-
value: `${errorRepeatRate}%`,
|
|
216
|
-
trend: errorRepeatRate <= 10 ? 'down' : 'up',
|
|
217
|
-
status: errorRepeatRate <= 10 ? 'good' : errorRepeatRate <= 30 ? 'warning' : 'bad',
|
|
218
|
-
hint: 'Lower is better'
|
|
219
|
-
},
|
|
220
|
-
first_time_success: {
|
|
221
|
-
value: `${firstTimeSuccess}%`,
|
|
222
|
-
trend: firstTimeSuccess >= 70 ? 'up' : 'down',
|
|
223
|
-
status: firstTimeSuccess >= 70 ? 'good' : 'warning',
|
|
224
|
-
hint: 'No retries needed'
|
|
225
|
-
},
|
|
226
|
-
skill_effectiveness: {
|
|
227
|
-
value: `${currentMetrics.skill_effectiveness || 0}%`,
|
|
228
|
-
trend: 'stable',
|
|
229
|
-
status: 'neutral',
|
|
230
|
-
hint: 'Skills that help'
|
|
231
|
-
},
|
|
232
|
-
total_tasks: {
|
|
233
|
-
value: totalTasks,
|
|
234
|
-
icon: '📊'
|
|
235
|
-
},
|
|
236
|
-
patterns_learned: {
|
|
237
|
-
value: patternsLearned,
|
|
238
|
-
icon: '🧩'
|
|
239
|
-
},
|
|
240
|
-
skills_generated: {
|
|
241
|
-
value: currentMetrics.skills_generated || 0,
|
|
242
|
-
icon: '⚙️'
|
|
243
|
-
},
|
|
244
|
-
ab_tests_active: {
|
|
245
|
-
value: currentMetrics.active_tests || 0,
|
|
246
|
-
icon: '🧪'
|
|
247
|
-
}
|
|
248
|
-
},
|
|
249
|
-
summary: {
|
|
250
|
-
totalTasks,
|
|
251
|
-
patternsLearned,
|
|
252
|
-
skillsGenerated: currentMetrics.skills_generated || 0,
|
|
253
|
-
lessonsCount: lessons.length
|
|
254
|
-
},
|
|
255
|
-
timestamp: new Date().toISOString()
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Get KPIs for dashboard
|
|
261
|
-
*/
|
|
262
|
-
export function getKPIs() {
|
|
263
|
-
return calculateKPIs();
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Get dashboard data (alias)
|
|
268
|
-
*/
|
|
269
|
-
export function getDashboardData() {
|
|
270
|
-
return calculateKPIs();
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Get summary stats
|
|
275
|
-
*/
|
|
276
|
-
export function getSummary() {
|
|
277
|
-
const kpis = calculateKPIs();
|
|
278
|
-
return {
|
|
279
|
-
...kpis.summary,
|
|
280
|
-
version: '7.0.0',
|
|
281
|
-
status: 'ok'
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Get specific metric value
|
|
287
|
-
*/
|
|
288
|
-
export function getMetricValue(metricName) {
|
|
289
|
-
const currentMetrics = loadCurrentMetrics();
|
|
290
|
-
return currentMetrics[metricName] ?? null;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Get metric history for charts
|
|
295
|
-
*/
|
|
296
|
-
export function getMetricHistory(metricName, limit = 168) {
|
|
297
|
-
const history = loadMetricsHistory();
|
|
298
|
-
const entries = history.entries || [];
|
|
299
|
-
|
|
300
|
-
// Filter entries for specific metric
|
|
301
|
-
const metricHistory = entries
|
|
302
|
-
.filter(e => e[metricName] !== undefined)
|
|
303
|
-
.slice(-limit)
|
|
304
|
-
.map(e => ({
|
|
305
|
-
timestamp: e.timestamp,
|
|
306
|
-
value: e[metricName]
|
|
307
|
-
}));
|
|
308
|
-
|
|
309
|
-
return metricHistory;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// ============================================================================
|
|
313
|
-
// METRIC UPDATES
|
|
314
|
-
// ============================================================================
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Record a task completion
|
|
318
|
-
*/
|
|
319
|
-
export function recordTask(success, firstTime = true) {
|
|
320
|
-
const metrics = loadCurrentMetrics();
|
|
321
|
-
|
|
322
|
-
metrics.total_tasks = (metrics.total_tasks || 0) + 1;
|
|
323
|
-
|
|
324
|
-
if (success) {
|
|
325
|
-
metrics.successful_tasks = (metrics.successful_tasks || 0) + 1;
|
|
326
|
-
if (firstTime) {
|
|
327
|
-
const total = metrics.total_tasks;
|
|
328
|
-
const firstTimeCount = Math.round((metrics.first_time_success_rate || 0) * (total - 1) / 100) + 1;
|
|
329
|
-
metrics.first_time_success_rate = Math.round((firstTimeCount / total) * 100);
|
|
330
|
-
}
|
|
331
|
-
} else {
|
|
332
|
-
metrics.failed_tasks = (metrics.failed_tasks || 0) + 1;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Recalculate success rate
|
|
336
|
-
metrics.task_success_rate = Math.round(
|
|
337
|
-
(metrics.successful_tasks / metrics.total_tasks) * 100
|
|
338
|
-
);
|
|
339
|
-
|
|
340
|
-
saveCurrentMetrics(metrics);
|
|
341
|
-
recordHistoryEntry(metrics);
|
|
342
|
-
|
|
343
|
-
return metrics;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Record a pattern learned
|
|
348
|
-
*/
|
|
349
|
-
export function recordPatternLearned() {
|
|
350
|
-
const metrics = loadCurrentMetrics();
|
|
351
|
-
metrics.patterns_learned = (metrics.patterns_learned || 0) + 1;
|
|
352
|
-
saveCurrentMetrics(metrics);
|
|
353
|
-
return metrics;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Record a skill generated
|
|
358
|
-
*/
|
|
359
|
-
export function recordSkillGenerated() {
|
|
360
|
-
const metrics = loadCurrentMetrics();
|
|
361
|
-
metrics.skills_generated = (metrics.skills_generated || 0) + 1;
|
|
362
|
-
saveCurrentMetrics(metrics);
|
|
363
|
-
return metrics;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Record history entry (hourly snapshot)
|
|
368
|
-
*/
|
|
369
|
-
function recordHistoryEntry(metrics) {
|
|
370
|
-
const history = loadMetricsHistory();
|
|
371
|
-
const now = new Date();
|
|
372
|
-
|
|
373
|
-
// Only record once per hour
|
|
374
|
-
const lastEntry = history.entries[history.entries.length - 1];
|
|
375
|
-
if (lastEntry) {
|
|
376
|
-
const lastTime = new Date(lastEntry.timestamp);
|
|
377
|
-
const hoursDiff = (now - lastTime) / (1000 * 60 * 60);
|
|
378
|
-
if (hoursDiff < 1) return;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
history.entries.push({
|
|
382
|
-
timestamp: now.toISOString(),
|
|
383
|
-
task_success_rate: metrics.task_success_rate || 0,
|
|
384
|
-
error_repeat_rate: metrics.error_repeat_rate || 0,
|
|
385
|
-
patterns_learned: metrics.patterns_learned || 0,
|
|
386
|
-
total_tasks: metrics.total_tasks || 0
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
// Keep last 7 days (168 hours)
|
|
390
|
-
if (history.entries.length > 168) {
|
|
391
|
-
history.entries = history.entries.slice(-168);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
saveMetricsHistory(history);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// ============================================================================
|
|
398
|
-
// EXPORTS
|
|
399
|
-
// ============================================================================
|
|
400
|
-
|
|
401
|
-
export default {
|
|
402
|
-
getKPIs,
|
|
403
|
-
getDashboardData,
|
|
404
|
-
getSummary,
|
|
405
|
-
getMetricValue,
|
|
406
|
-
getMetricHistory,
|
|
407
|
-
recordTask,
|
|
408
|
-
recordPatternLearned,
|
|
409
|
-
recordSkillGenerated
|
|
410
|
-
};
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Proposal Generator for Auto-Updating Flow
|
|
3
|
-
* Generates markdown instructions for AI agents to update skills
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import fs from "fs";
|
|
7
|
-
import path from "path";
|
|
8
|
-
import yaml from "js-yaml";
|
|
9
|
-
import { KNOWLEDGE_DIR, LESSONS_PATH, AGENT_DIR } from "./config.js";
|
|
10
|
-
import { loadSettings } from "./settings.js";
|
|
11
|
-
import { loadKnowledge } from "./recall.js";
|
|
12
|
-
|
|
13
|
-
/** Proposals directory */
|
|
14
|
-
const PROPOSALS_DIR = path.join(KNOWLEDGE_DIR, "proposals");
|
|
15
|
-
|
|
16
|
-
/** Dismissed proposals file */
|
|
17
|
-
const DISMISSED_FILE = path.join(PROPOSALS_DIR, "dismissed.yaml");
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Get lessons that qualify for proposals (hitCount >= threshold)
|
|
21
|
-
* @returns {Array<{ lesson: object, proposalPath: string }>}
|
|
22
|
-
*/
|
|
23
|
-
export function getQualifyingLessons() {
|
|
24
|
-
const settings = loadSettings();
|
|
25
|
-
const threshold = settings.updateThreshold || 5;
|
|
26
|
-
const db = loadKnowledge();
|
|
27
|
-
|
|
28
|
-
if (!db.lessons) return [];
|
|
29
|
-
|
|
30
|
-
const dismissed = loadDismissed();
|
|
31
|
-
|
|
32
|
-
return db.lessons
|
|
33
|
-
.filter(l => (l.hitCount || 0) >= threshold && !dismissed.has(l.id))
|
|
34
|
-
.map(lesson => ({
|
|
35
|
-
lesson,
|
|
36
|
-
proposalPath: path.join(PROPOSALS_DIR, `${lesson.id}.md`)
|
|
37
|
-
}));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Load dismissed proposal IDs
|
|
42
|
-
* @returns {Set<string>}
|
|
43
|
-
*/
|
|
44
|
-
function loadDismissed() {
|
|
45
|
-
try {
|
|
46
|
-
if (fs.existsSync(DISMISSED_FILE)) {
|
|
47
|
-
const data = yaml.load(fs.readFileSync(DISMISSED_FILE, "utf8")) || {};
|
|
48
|
-
return new Set(data.dismissed || []);
|
|
49
|
-
}
|
|
50
|
-
} catch (e) { }
|
|
51
|
-
return new Set();
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Dismiss a proposal
|
|
56
|
-
* @param {string} lessonId
|
|
57
|
-
*/
|
|
58
|
-
export function dismissProposal(lessonId) {
|
|
59
|
-
fs.mkdirSync(PROPOSALS_DIR, { recursive: true });
|
|
60
|
-
const dismissed = loadDismissed();
|
|
61
|
-
dismissed.add(lessonId);
|
|
62
|
-
fs.writeFileSync(DISMISSED_FILE, yaml.dump({ dismissed: [...dismissed] }), "utf8");
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Generate proposal markdown for AI agent
|
|
67
|
-
* @param {object} lesson - Lesson object
|
|
68
|
-
* @returns {string} Markdown content
|
|
69
|
-
*/
|
|
70
|
-
export function generateProposalMarkdown(lesson) {
|
|
71
|
-
const skillHint = guessSkillFromLesson(lesson);
|
|
72
|
-
|
|
73
|
-
return `# 🤖 Skill Update Proposal
|
|
74
|
-
|
|
75
|
-
## Pattern Detected
|
|
76
|
-
| Field | Value |
|
|
77
|
-
|-------|-------|
|
|
78
|
-
| **ID** | \`${lesson.id}\` |
|
|
79
|
-
| **Hit Count** | ${lesson.hitCount || 0} |
|
|
80
|
-
| **Severity** | ${lesson.severity || "WARNING"} |
|
|
81
|
-
| **Last Hit** | ${lesson.lastHit || "N/A"} |
|
|
82
|
-
|
|
83
|
-
## Message
|
|
84
|
-
> ${lesson.message}
|
|
85
|
-
|
|
86
|
-
## Pattern (Regex)
|
|
87
|
-
\`\`\`
|
|
88
|
-
${lesson.pattern}
|
|
89
|
-
\`\`\`
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## 📝 Suggested Action for AI Agent
|
|
94
|
-
|
|
95
|
-
Please update the relevant skill file to include this rule:
|
|
96
|
-
|
|
97
|
-
### Target File
|
|
98
|
-
\`${skillHint}\`
|
|
99
|
-
|
|
100
|
-
### Add to Rules Section
|
|
101
|
-
\`\`\`markdown
|
|
102
|
-
### ${lesson.message}
|
|
103
|
-
- Pattern: \`${lesson.pattern}\`
|
|
104
|
-
- Severity: ${lesson.severity || "WARNING"}
|
|
105
|
-
- Auto-learned from violations
|
|
106
|
-
\`\`\`
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
## How to Apply
|
|
111
|
-
|
|
112
|
-
1. **Copy this entire proposal**
|
|
113
|
-
2. **Paste to your AI coding agent** (Claude, Gemini, etc.)
|
|
114
|
-
3. **Ask:** "Update the skill file with this rule"
|
|
115
|
-
|
|
116
|
-
The AI agent will modify the appropriate \`.agent/skills/*/SKILL.md\` file.
|
|
117
|
-
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
*Generated by PikaKit v2.1.0*
|
|
121
|
-
`;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Guess which skill file this lesson relates to
|
|
126
|
-
* @param {object} lesson
|
|
127
|
-
* @returns {string}
|
|
128
|
-
*/
|
|
129
|
-
function guessSkillFromLesson(lesson) {
|
|
130
|
-
const pattern = (lesson.pattern || "").toLowerCase();
|
|
131
|
-
const message = (lesson.message || "").toLowerCase();
|
|
132
|
-
const combined = pattern + " " + message;
|
|
133
|
-
|
|
134
|
-
// Frontend patterns
|
|
135
|
-
if (combined.includes("react") || combined.includes("component") || combined.includes("hook") || combined.includes("usestate") || combined.includes("useeffect")) {
|
|
136
|
-
return ".agent/skills/react-patterns/SKILL.md";
|
|
137
|
-
}
|
|
138
|
-
if (combined.includes("next") || combined.includes("getserverside") || combined.includes("getstaticprops") || combined.includes("app router")) {
|
|
139
|
-
return ".agent/skills/nextjs-best-practices/SKILL.md";
|
|
140
|
-
}
|
|
141
|
-
if (combined.includes("css") || combined.includes("style") || combined.includes("tailwind") || combined.includes("classname")) {
|
|
142
|
-
return ".agent/skills/frontend-design/SKILL.md";
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Backend patterns
|
|
146
|
-
if (combined.includes("api") || combined.includes("fetch") || combined.includes("http") || combined.includes("endpoint") || combined.includes("rest")) {
|
|
147
|
-
return ".agent/skills/api-patterns/SKILL.md";
|
|
148
|
-
}
|
|
149
|
-
if (combined.includes("database") || combined.includes("sql") || combined.includes("prisma") || combined.includes("query") || combined.includes("schema")) {
|
|
150
|
-
return ".agent/skills/database-design/SKILL.md";
|
|
151
|
-
}
|
|
152
|
-
if (combined.includes("node") || combined.includes("express") || combined.includes("server") || combined.includes("middleware")) {
|
|
153
|
-
return ".agent/skills/nodejs-best-practices/SKILL.md";
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Testing patterns
|
|
157
|
-
if (combined.includes("test") || combined.includes("mock") || combined.includes("jest") || combined.includes("vitest") || combined.includes("expect")) {
|
|
158
|
-
return ".agent/skills/testing-patterns/SKILL.md";
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// TypeScript patterns
|
|
162
|
-
if (combined.includes("typescript") || combined.includes("type") || combined.includes("interface") || combined.includes("generic") || combined.includes("any")) {
|
|
163
|
-
return ".agent/skills/typescript-expert/SKILL.md";
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Security patterns
|
|
167
|
-
if (combined.includes("security") || combined.includes("auth") || combined.includes("password") || combined.includes("token") || combined.includes("xss") || combined.includes("injection")) {
|
|
168
|
-
return ".agent/skills/vulnerability-scanner/SKILL.md";
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Performance patterns
|
|
172
|
-
if (combined.includes("performance") || combined.includes("memo") || combined.includes("lazy") || combined.includes("cache") || combined.includes("optimize")) {
|
|
173
|
-
return ".agent/skills/performance-profiling/SKILL.md";
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Git patterns
|
|
177
|
-
if (combined.includes("commit") || combined.includes("branch") || combined.includes("merge") || combined.includes("git")) {
|
|
178
|
-
return ".agent/skills/git-conventions/SKILL.md";
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Default to clean-code for general patterns
|
|
182
|
-
return ".agent/skills/clean-code/SKILL.md";
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Count pending proposals
|
|
187
|
-
* @returns {number}
|
|
188
|
-
*/
|
|
189
|
-
export function countPendingProposals() {
|
|
190
|
-
return getQualifyingLessons().length;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export default {
|
|
194
|
-
getQualifyingLessons,
|
|
195
|
-
dismissProposal,
|
|
196
|
-
generateProposalMarkdown,
|
|
197
|
-
countPendingProposals,
|
|
198
|
-
PROPOSALS_DIR
|
|
199
|
-
};
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Tests for proposals module
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect } from "vitest";
|
|
6
|
-
|
|
7
|
-
// Test proposal markdown generation without mocking
|
|
8
|
-
describe("proposals", () => {
|
|
9
|
-
describe("generateProposalMarkdown format", () => {
|
|
10
|
-
it("creates markdown with required sections", () => {
|
|
11
|
-
const lesson = {
|
|
12
|
-
id: "LEARN-001",
|
|
13
|
-
pattern: "console\\.log",
|
|
14
|
-
message: "No console.log in production",
|
|
15
|
-
hitCount: 5,
|
|
16
|
-
severity: "ERROR"
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// Simulate markdown generation
|
|
20
|
-
const md = `# 🤖 Skill Update Proposal\n\n## Pattern Detected\n| Field | Value |\n|-------|-------|\n| **ID** | \`${lesson.id}\` |\n| **Hit Count** | ${lesson.hitCount || 0} |\n\n## Message\n> ${lesson.message}`;
|
|
21
|
-
|
|
22
|
-
expect(md).toContain("LEARN-001");
|
|
23
|
-
expect(md).toContain("No console.log");
|
|
24
|
-
expect(md).toContain("5");
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it("includes AI agent instructions", () => {
|
|
28
|
-
const md = `## How to Apply\n1. **Copy this entire proposal**\n2. **Paste to your AI coding agent**`;
|
|
29
|
-
|
|
30
|
-
expect(md).toContain("Copy");
|
|
31
|
-
expect(md).toContain("Paste");
|
|
32
|
-
expect(md).toContain("AI");
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
describe("proposal threshold", () => {
|
|
37
|
-
it("default threshold is 5", () => {
|
|
38
|
-
const defaultThreshold = 5;
|
|
39
|
-
expect(defaultThreshold).toBe(5);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("lesson qualifies when hitCount >= threshold", () => {
|
|
43
|
-
const threshold = 5;
|
|
44
|
-
const lessons = [
|
|
45
|
-
{ id: "L1", hitCount: 5 },
|
|
46
|
-
{ id: "L2", hitCount: 3 },
|
|
47
|
-
{ id: "L3", hitCount: 10 }
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
const qualifying = lessons.filter(l => l.hitCount >= threshold);
|
|
51
|
-
expect(qualifying).toHaveLength(2);
|
|
52
|
-
expect(qualifying.map(l => l.id)).toContain("L1");
|
|
53
|
-
expect(qualifying.map(l => l.id)).toContain("L3");
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
});
|