ccjk 5.2.2 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import process__default from 'node:process';
|
|
4
|
+
import ansis__default from 'ansis';
|
|
5
|
+
import { i18n } from './index2.mjs';
|
|
6
|
+
import 'node:fs';
|
|
7
|
+
import 'node:url';
|
|
8
|
+
import 'i18next';
|
|
9
|
+
import 'i18next-fs-backend';
|
|
10
|
+
import 'pathe';
|
|
11
|
+
|
|
12
|
+
class AnalyticsClient {
|
|
13
|
+
baseUrl;
|
|
14
|
+
apiKey;
|
|
15
|
+
timeout;
|
|
16
|
+
constructor(config = {}) {
|
|
17
|
+
this.baseUrl = config.baseUrl ?? "https://claude.iccjk.com";
|
|
18
|
+
this.apiKey = config.apiKey;
|
|
19
|
+
this.timeout = config.timeout ?? 3e4;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Set API key for authentication
|
|
23
|
+
*/
|
|
24
|
+
setApiKey(apiKey) {
|
|
25
|
+
this.apiKey = apiKey;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get request headers
|
|
29
|
+
*/
|
|
30
|
+
getHeaders() {
|
|
31
|
+
const headers = {
|
|
32
|
+
"Content-Type": "application/json"
|
|
33
|
+
};
|
|
34
|
+
if (this.apiKey) {
|
|
35
|
+
headers.Authorization = `Bearer ${this.apiKey}`;
|
|
36
|
+
}
|
|
37
|
+
return headers;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Make API request
|
|
41
|
+
*/
|
|
42
|
+
async request(path, options = {}) {
|
|
43
|
+
const url = `${this.baseUrl}${path}`;
|
|
44
|
+
const controller = new AbortController();
|
|
45
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
46
|
+
try {
|
|
47
|
+
const response = await fetch(url, {
|
|
48
|
+
...options,
|
|
49
|
+
headers: {
|
|
50
|
+
...this.getHeaders(),
|
|
51
|
+
...options.headers
|
|
52
|
+
},
|
|
53
|
+
signal: controller.signal
|
|
54
|
+
});
|
|
55
|
+
clearTimeout(timeoutId);
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
throw new Error(`API Error: ${response.status} ${response.statusText}`);
|
|
58
|
+
}
|
|
59
|
+
return await response.json();
|
|
60
|
+
} catch (error) {
|
|
61
|
+
clearTimeout(timeoutId);
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// ========================================================================
|
|
66
|
+
// Skills Analytics
|
|
67
|
+
// ========================================================================
|
|
68
|
+
/**
|
|
69
|
+
* Get skills usage statistics
|
|
70
|
+
* GET /api/v1/analytics/skills
|
|
71
|
+
*/
|
|
72
|
+
async getSkills(filters) {
|
|
73
|
+
const params = new URLSearchParams();
|
|
74
|
+
if (filters?.skillId)
|
|
75
|
+
params.append("skillId", filters.skillId);
|
|
76
|
+
if (filters?.period)
|
|
77
|
+
params.append("period", filters.period);
|
|
78
|
+
if (filters?.limit)
|
|
79
|
+
params.append("limit", filters.limit.toString());
|
|
80
|
+
const query = params.toString();
|
|
81
|
+
return this.request(`/api/v1/analytics/skills${query ? `?${query}` : ""}`);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get specific skill statistics
|
|
85
|
+
* GET /api/v1/analytics/skills/:id
|
|
86
|
+
*/
|
|
87
|
+
async getSkillStats(skillId, period) {
|
|
88
|
+
const query = period ? `?period=${period}` : "";
|
|
89
|
+
return this.request(`/api/v1/analytics/skills/${skillId}${query}`);
|
|
90
|
+
}
|
|
91
|
+
// ========================================================================
|
|
92
|
+
// MCP Analytics
|
|
93
|
+
// ========================================================================
|
|
94
|
+
/**
|
|
95
|
+
* Get MCP usage statistics
|
|
96
|
+
* GET /api/v1/analytics/mcp
|
|
97
|
+
*/
|
|
98
|
+
async getMcp(filters) {
|
|
99
|
+
const params = new URLSearchParams();
|
|
100
|
+
if (filters?.mcpId)
|
|
101
|
+
params.append("mcpId", filters.mcpId);
|
|
102
|
+
if (filters?.period)
|
|
103
|
+
params.append("period", filters.period);
|
|
104
|
+
if (filters?.limit)
|
|
105
|
+
params.append("limit", filters.limit.toString());
|
|
106
|
+
const query = params.toString();
|
|
107
|
+
return this.request(`/api/v1/analytics/mcp${query ? `?${query}` : ""}`);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get specific MCP statistics
|
|
111
|
+
* GET /api/v1/analytics/mcp/:id
|
|
112
|
+
*/
|
|
113
|
+
async getMcpStats(mcpId, period) {
|
|
114
|
+
const query = period ? `?period=${period}` : "";
|
|
115
|
+
return this.request(`/api/v1/analytics/mcp/${mcpId}${query}`);
|
|
116
|
+
}
|
|
117
|
+
// ========================================================================
|
|
118
|
+
// Agent Analytics
|
|
119
|
+
// ========================================================================
|
|
120
|
+
/**
|
|
121
|
+
* Get Agent execution statistics
|
|
122
|
+
* GET /api/v1/analytics/agents
|
|
123
|
+
*/
|
|
124
|
+
async getAgents(filters) {
|
|
125
|
+
const params = new URLSearchParams();
|
|
126
|
+
if (filters?.agentId)
|
|
127
|
+
params.append("agentId", filters.agentId);
|
|
128
|
+
if (filters?.period)
|
|
129
|
+
params.append("period", filters.period);
|
|
130
|
+
if (filters?.limit)
|
|
131
|
+
params.append("limit", filters.limit.toString());
|
|
132
|
+
const query = params.toString();
|
|
133
|
+
return this.request(`/api/v1/analytics/agents${query ? `?${query}` : ""}`);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get specific agent statistics
|
|
137
|
+
* GET /api/v1/analytics/agents/:id
|
|
138
|
+
*/
|
|
139
|
+
async getAgentStats(agentId, period) {
|
|
140
|
+
const query = period ? `?period=${period}` : "";
|
|
141
|
+
return this.request(`/api/v1/analytics/agents/${agentId}${query}`);
|
|
142
|
+
}
|
|
143
|
+
// ========================================================================
|
|
144
|
+
// Session Analytics
|
|
145
|
+
// ========================================================================
|
|
146
|
+
/**
|
|
147
|
+
* Get session statistics
|
|
148
|
+
* GET /api/v1/analytics/sessions
|
|
149
|
+
*/
|
|
150
|
+
async getSessions(period = "week") {
|
|
151
|
+
return this.request(`/api/v1/analytics/sessions?period=${period}`);
|
|
152
|
+
}
|
|
153
|
+
// ========================================================================
|
|
154
|
+
// Token Analytics
|
|
155
|
+
// ========================================================================
|
|
156
|
+
/**
|
|
157
|
+
* Get token statistics
|
|
158
|
+
* GET /api/v1/analytics/tokens
|
|
159
|
+
*/
|
|
160
|
+
async getTokens(period = "week") {
|
|
161
|
+
return this.request(`/api/v1/analytics/tokens?period=${period}`);
|
|
162
|
+
}
|
|
163
|
+
// ========================================================================
|
|
164
|
+
// Dashboard
|
|
165
|
+
// ========================================================================
|
|
166
|
+
/**
|
|
167
|
+
* Get analytics dashboard
|
|
168
|
+
* GET /api/v1/analytics/dashboard
|
|
169
|
+
*/
|
|
170
|
+
async getDashboard(period = "week") {
|
|
171
|
+
return this.request(`/api/v1/analytics/dashboard?period=${period}`);
|
|
172
|
+
}
|
|
173
|
+
// ========================================================================
|
|
174
|
+
// Utility Methods
|
|
175
|
+
// ========================================================================
|
|
176
|
+
/**
|
|
177
|
+
* Get summary across all categories
|
|
178
|
+
*/
|
|
179
|
+
async getSummary(period = "week") {
|
|
180
|
+
const [skills, mcp, agents, sessions, tokens] = await Promise.all([
|
|
181
|
+
this.getSkills({ period, limit: 10 }),
|
|
182
|
+
this.getMcp({ period, limit: 10 }),
|
|
183
|
+
this.getAgents({ period, limit: 10 }),
|
|
184
|
+
this.getSessions(period),
|
|
185
|
+
this.getTokens(period)
|
|
186
|
+
]);
|
|
187
|
+
return { skills, mcp, agents, sessions, tokens };
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get top used skills
|
|
191
|
+
*/
|
|
192
|
+
async getTopSkills(limit = 5, period) {
|
|
193
|
+
return this.getSkills({ limit, period });
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Get top used MCP services
|
|
197
|
+
*/
|
|
198
|
+
async getTopMcp(limit = 5, period) {
|
|
199
|
+
return this.getMcp({ limit, period });
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Get top executed agents
|
|
203
|
+
*/
|
|
204
|
+
async getTopAgents(limit = 5, period) {
|
|
205
|
+
return this.getAgents({ limit, period });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
let defaultClient = null;
|
|
209
|
+
function getAnalyticsClient() {
|
|
210
|
+
if (!defaultClient) {
|
|
211
|
+
defaultClient = new AnalyticsClient();
|
|
212
|
+
}
|
|
213
|
+
return defaultClient;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
class MetricsCollector {
|
|
217
|
+
metrics = /* @__PURE__ */ new Map();
|
|
218
|
+
taskMetrics = /* @__PURE__ */ new Map();
|
|
219
|
+
performanceMetrics = /* @__PURE__ */ new Map();
|
|
220
|
+
maxRecords;
|
|
221
|
+
retentionPeriod;
|
|
222
|
+
constructor(options = {}) {
|
|
223
|
+
this.maxRecords = options.maxRecords ?? 1e3;
|
|
224
|
+
this.retentionPeriod = options.retentionPeriod ?? 36e5;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Record a metric value
|
|
228
|
+
*/
|
|
229
|
+
recordMetric(agentId, metricName, value, metadata) {
|
|
230
|
+
if (!this.metrics.has(agentId)) {
|
|
231
|
+
this.metrics.set(agentId, /* @__PURE__ */ new Map());
|
|
232
|
+
}
|
|
233
|
+
const agentMetrics = this.metrics.get(agentId);
|
|
234
|
+
if (!agentMetrics.has(metricName)) {
|
|
235
|
+
agentMetrics.set(metricName, []);
|
|
236
|
+
}
|
|
237
|
+
const records = agentMetrics.get(metricName);
|
|
238
|
+
records.push({
|
|
239
|
+
timestamp: Date.now(),
|
|
240
|
+
value,
|
|
241
|
+
metadata
|
|
242
|
+
});
|
|
243
|
+
this.trimRecords(records);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Record CPU usage
|
|
247
|
+
*/
|
|
248
|
+
recordCpuUsage(agentId, usage) {
|
|
249
|
+
this.recordMetric(agentId, "cpu_usage", usage);
|
|
250
|
+
this.updatePerformanceMetrics(agentId, { cpuUsage: usage });
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Record memory usage
|
|
254
|
+
*/
|
|
255
|
+
recordMemoryUsage(agentId, usage) {
|
|
256
|
+
this.recordMetric(agentId, "memory_usage", usage);
|
|
257
|
+
this.updatePerformanceMetrics(agentId, { memoryUsage: usage });
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Record response time
|
|
261
|
+
*/
|
|
262
|
+
recordResponseTime(agentId, responseTime) {
|
|
263
|
+
this.recordMetric(agentId, "response_time", responseTime);
|
|
264
|
+
this.updatePerformanceMetrics(agentId, { responseTime });
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Record task completion
|
|
268
|
+
*/
|
|
269
|
+
recordTaskCompletion(agentId, success, duration) {
|
|
270
|
+
if (!this.taskMetrics.has(agentId)) {
|
|
271
|
+
this.taskMetrics.set(agentId, {
|
|
272
|
+
totalTasks: 0,
|
|
273
|
+
completedTasks: 0,
|
|
274
|
+
failedTasks: 0,
|
|
275
|
+
avgDuration: 0,
|
|
276
|
+
successRate: 0
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
const metrics = this.taskMetrics.get(agentId);
|
|
280
|
+
metrics.totalTasks++;
|
|
281
|
+
if (success) {
|
|
282
|
+
metrics.completedTasks++;
|
|
283
|
+
} else {
|
|
284
|
+
metrics.failedTasks++;
|
|
285
|
+
}
|
|
286
|
+
metrics.avgDuration = (metrics.avgDuration * (metrics.totalTasks - 1) + duration) / metrics.totalTasks;
|
|
287
|
+
metrics.successRate = metrics.completedTasks / metrics.totalTasks;
|
|
288
|
+
this.recordMetric(agentId, "task_duration", duration, { success });
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Record error
|
|
292
|
+
*/
|
|
293
|
+
recordError(agentId, errorType, errorMessage) {
|
|
294
|
+
this.recordMetric(agentId, "error", 1, { errorType, errorMessage });
|
|
295
|
+
this.updatePerformanceMetrics(agentId, { errorCount: 1 });
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Get agent metrics
|
|
299
|
+
*/
|
|
300
|
+
getAgentMetrics(agentId) {
|
|
301
|
+
const taskMetrics = this.taskMetrics.get(agentId);
|
|
302
|
+
const cpuRecords = this.getMetricRecords(agentId, "cpu_usage");
|
|
303
|
+
const memoryRecords = this.getMetricRecords(agentId, "memory_usage");
|
|
304
|
+
const responseTimeRecords = this.getMetricRecords(agentId, "response_time");
|
|
305
|
+
const cpuUsage = cpuRecords.length > 0 ? cpuRecords[cpuRecords.length - 1].value : 0;
|
|
306
|
+
const memoryUsage = memoryRecords.length > 0 ? memoryRecords[memoryRecords.length - 1].value : 0;
|
|
307
|
+
const avgResponseTime = this.calculateAverage(responseTimeRecords.map((r) => r.value));
|
|
308
|
+
const errorRate = taskMetrics ? taskMetrics.failedTasks / taskMetrics.totalTasks : 0;
|
|
309
|
+
return {
|
|
310
|
+
cpuUsage,
|
|
311
|
+
memoryUsage,
|
|
312
|
+
avgResponseTime,
|
|
313
|
+
errorRate,
|
|
314
|
+
taskCount: taskMetrics?.totalTasks ?? 0,
|
|
315
|
+
successRate: taskMetrics?.successRate ?? 0,
|
|
316
|
+
timestamp: Date.now()
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Get metric snapshot
|
|
321
|
+
*/
|
|
322
|
+
getMetricSnapshot(agentId, metricName, timeRange) {
|
|
323
|
+
const records = this.getMetricRecords(agentId, metricName, timeRange);
|
|
324
|
+
const values = records.map((r) => r.value);
|
|
325
|
+
if (values.length === 0) {
|
|
326
|
+
return {
|
|
327
|
+
metricName,
|
|
328
|
+
agentId,
|
|
329
|
+
timestamp: Date.now(),
|
|
330
|
+
current: 0,
|
|
331
|
+
min: 0,
|
|
332
|
+
max: 0,
|
|
333
|
+
avg: 0,
|
|
334
|
+
count: 0
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
metricName,
|
|
339
|
+
agentId,
|
|
340
|
+
timestamp: Date.now(),
|
|
341
|
+
current: values[values.length - 1],
|
|
342
|
+
min: Math.min(...values),
|
|
343
|
+
max: Math.max(...values),
|
|
344
|
+
avg: this.calculateAverage(values),
|
|
345
|
+
count: values.length
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Get aggregated metrics
|
|
350
|
+
*/
|
|
351
|
+
getAggregatedMetrics(agentId, metricName, timeRange) {
|
|
352
|
+
const records = this.getMetricRecords(agentId, metricName, timeRange);
|
|
353
|
+
const values = records.map((r) => r.value).sort((a, b) => a - b);
|
|
354
|
+
if (values.length === 0) {
|
|
355
|
+
return {
|
|
356
|
+
min: 0,
|
|
357
|
+
max: 0,
|
|
358
|
+
avg: 0,
|
|
359
|
+
median: 0,
|
|
360
|
+
p95: 0,
|
|
361
|
+
p99: 0,
|
|
362
|
+
count: 0
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
min: values[0],
|
|
367
|
+
max: values[values.length - 1],
|
|
368
|
+
avg: this.calculateAverage(values),
|
|
369
|
+
median: this.calculatePercentile(values, 50),
|
|
370
|
+
p95: this.calculatePercentile(values, 95),
|
|
371
|
+
p99: this.calculatePercentile(values, 99),
|
|
372
|
+
count: values.length
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Get task metrics
|
|
377
|
+
*/
|
|
378
|
+
getTaskMetrics(agentId) {
|
|
379
|
+
return this.taskMetrics.get(agentId);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Get performance metrics
|
|
383
|
+
*/
|
|
384
|
+
getPerformanceMetrics(agentId) {
|
|
385
|
+
return this.performanceMetrics.get(agentId);
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Get all agents with metrics
|
|
389
|
+
*/
|
|
390
|
+
getAllAgents() {
|
|
391
|
+
return Array.from(this.metrics.keys());
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Clear metrics for an agent
|
|
395
|
+
*/
|
|
396
|
+
clearAgentMetrics(agentId) {
|
|
397
|
+
this.metrics.delete(agentId);
|
|
398
|
+
this.taskMetrics.delete(agentId);
|
|
399
|
+
this.performanceMetrics.delete(agentId);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Clear all metrics
|
|
403
|
+
*/
|
|
404
|
+
clearAll() {
|
|
405
|
+
this.metrics.clear();
|
|
406
|
+
this.taskMetrics.clear();
|
|
407
|
+
this.performanceMetrics.clear();
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Export metrics to JSON
|
|
411
|
+
*/
|
|
412
|
+
exportMetrics(agentId) {
|
|
413
|
+
if (agentId) {
|
|
414
|
+
return {
|
|
415
|
+
agentId,
|
|
416
|
+
metrics: this.getAgentMetrics(agentId),
|
|
417
|
+
taskMetrics: this.getTaskMetrics(agentId),
|
|
418
|
+
performanceMetrics: this.getPerformanceMetrics(agentId),
|
|
419
|
+
timestamp: Date.now()
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
const allMetrics = {};
|
|
423
|
+
for (const id of this.getAllAgents()) {
|
|
424
|
+
allMetrics[id] = {
|
|
425
|
+
metrics: this.getAgentMetrics(id),
|
|
426
|
+
taskMetrics: this.getTaskMetrics(id),
|
|
427
|
+
performanceMetrics: this.getPerformanceMetrics(id)
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
return {
|
|
431
|
+
agents: allMetrics,
|
|
432
|
+
timestamp: Date.now()
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Get metric records
|
|
437
|
+
*/
|
|
438
|
+
getMetricRecords(agentId, metricName, timeRange) {
|
|
439
|
+
const agentMetrics = this.metrics.get(agentId);
|
|
440
|
+
if (!agentMetrics) {
|
|
441
|
+
return [];
|
|
442
|
+
}
|
|
443
|
+
const records = agentMetrics.get(metricName) ?? [];
|
|
444
|
+
if (timeRange) {
|
|
445
|
+
const cutoff = Date.now() - timeRange;
|
|
446
|
+
return records.filter((r) => r.timestamp >= cutoff);
|
|
447
|
+
}
|
|
448
|
+
return records;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Update performance metrics
|
|
452
|
+
*/
|
|
453
|
+
updatePerformanceMetrics(agentId, update) {
|
|
454
|
+
if (!this.performanceMetrics.has(agentId)) {
|
|
455
|
+
this.performanceMetrics.set(agentId, {
|
|
456
|
+
cpuUsage: 0,
|
|
457
|
+
memoryUsage: 0,
|
|
458
|
+
responseTime: 0,
|
|
459
|
+
errorCount: 0,
|
|
460
|
+
requestCount: 0,
|
|
461
|
+
timestamp: Date.now()
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
const metrics = this.performanceMetrics.get(agentId);
|
|
465
|
+
if (update.cpuUsage !== void 0) {
|
|
466
|
+
metrics.cpuUsage = update.cpuUsage;
|
|
467
|
+
}
|
|
468
|
+
if (update.memoryUsage !== void 0) {
|
|
469
|
+
metrics.memoryUsage = update.memoryUsage;
|
|
470
|
+
}
|
|
471
|
+
if (update.responseTime !== void 0) {
|
|
472
|
+
metrics.requestCount++;
|
|
473
|
+
metrics.responseTime = (metrics.responseTime * (metrics.requestCount - 1) + update.responseTime) / metrics.requestCount;
|
|
474
|
+
}
|
|
475
|
+
if (update.errorCount !== void 0) {
|
|
476
|
+
metrics.errorCount += update.errorCount;
|
|
477
|
+
}
|
|
478
|
+
metrics.timestamp = Date.now();
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Trim old records
|
|
482
|
+
*/
|
|
483
|
+
trimRecords(records) {
|
|
484
|
+
const cutoff = Date.now() - this.retentionPeriod;
|
|
485
|
+
while (records.length > 0 && records[0].timestamp < cutoff) {
|
|
486
|
+
records.shift();
|
|
487
|
+
}
|
|
488
|
+
while (records.length > this.maxRecords) {
|
|
489
|
+
records.shift();
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Calculate average
|
|
494
|
+
*/
|
|
495
|
+
calculateAverage(values) {
|
|
496
|
+
if (values.length === 0) {
|
|
497
|
+
return 0;
|
|
498
|
+
}
|
|
499
|
+
return values.reduce((sum, val) => sum + val, 0) / values.length;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Calculate percentile
|
|
503
|
+
*/
|
|
504
|
+
calculatePercentile(sortedValues, percentile) {
|
|
505
|
+
if (sortedValues.length === 0) {
|
|
506
|
+
return 0;
|
|
507
|
+
}
|
|
508
|
+
const index = Math.ceil(percentile / 100 * sortedValues.length) - 1;
|
|
509
|
+
return sortedValues[Math.max(0, index)];
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
let globalMetricsCollector;
|
|
513
|
+
function getMetricsCollector(options) {
|
|
514
|
+
if (!globalMetricsCollector) {
|
|
515
|
+
globalMetricsCollector = new MetricsCollector(options);
|
|
516
|
+
}
|
|
517
|
+
return globalMetricsCollector;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
async function exportMetrics(options = {}) {
|
|
521
|
+
const { format = "json", output, period = "week" } = options;
|
|
522
|
+
try {
|
|
523
|
+
console.log(ansis__default.cyan(i18n.t("metrics:exportingMetrics")));
|
|
524
|
+
const localMetrics = getMetricsCollector().exportMetrics();
|
|
525
|
+
const cloudClient = getAnalyticsClient();
|
|
526
|
+
const cloudMetrics = await cloudClient.getSummary(period).catch(() => null);
|
|
527
|
+
const data = {
|
|
528
|
+
local: localMetrics,
|
|
529
|
+
cloud: cloudMetrics,
|
|
530
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
531
|
+
period
|
|
532
|
+
};
|
|
533
|
+
const content = format === "csv" ? toCSV(data) : JSON.stringify(data, null, 2);
|
|
534
|
+
const ext = format === "csv" ? "csv" : "json";
|
|
535
|
+
const filename = output || `ccjk-metrics-${Date.now()}.${ext}`;
|
|
536
|
+
const filepath = resolve(process__default.cwd(), filename);
|
|
537
|
+
await writeFile(filepath, content, "utf-8");
|
|
538
|
+
console.log(ansis__default.green(i18n.t("metrics:exportSuccess", { file: filepath })));
|
|
539
|
+
} catch (error) {
|
|
540
|
+
console.error(ansis__default.red(i18n.t("metrics:exportFailed")));
|
|
541
|
+
throw error;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
function toCSV(data) {
|
|
545
|
+
const rows = ["Metric,Value,Timestamp"];
|
|
546
|
+
if (data.local?.agents) {
|
|
547
|
+
for (const [agentId, metrics] of Object.entries(data.local.agents)) {
|
|
548
|
+
const m = metrics;
|
|
549
|
+
rows.push(`${agentId}_cpu,${m.metrics?.cpuUsage || 0},${data.exportedAt}`);
|
|
550
|
+
rows.push(`${agentId}_memory,${m.metrics?.memoryUsage || 0},${data.exportedAt}`);
|
|
551
|
+
rows.push(`${agentId}_tasks,${m.taskMetrics?.totalTasks || 0},${data.exportedAt}`);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if (data.cloud) {
|
|
555
|
+
rows.push(`total_tokens,${data.cloud.tokens?.totalTokens || 0},${data.exportedAt}`);
|
|
556
|
+
rows.push(`total_sessions,${data.cloud.sessions?.totalSessions || 0},${data.exportedAt}`);
|
|
557
|
+
}
|
|
558
|
+
return rows.join("\n");
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
export { exportMetrics };
|
package/dist/chunks/index2.mjs
CHANGED
|
@@ -57,8 +57,10 @@ const NAMESPACES = [
|
|
|
57
57
|
"updater",
|
|
58
58
|
"workflow",
|
|
59
59
|
"cloud-sync",
|
|
60
|
-
"workspace"
|
|
60
|
+
"workspace",
|
|
61
61
|
// Workspace diagnostics and guide
|
|
62
|
+
"metrics"
|
|
63
|
+
// Metrics export and usage tracking
|
|
62
64
|
];
|
|
63
65
|
function ensureI18nInitialized() {
|
|
64
66
|
if (!i18n.isInitialized) {
|
package/dist/chunks/package.mjs
CHANGED
package/dist/cli.mjs
CHANGED
|
@@ -542,6 +542,13 @@ const COMMANDS = [
|
|
|
542
542
|
const { cleanupStats } = await import('./chunks/stats.mjs');
|
|
543
543
|
const days = options.days ? Number.parseInt(options.days, 10) : 90;
|
|
544
544
|
await cleanupStats(days);
|
|
545
|
+
} else if (actionStr === "export") {
|
|
546
|
+
const { exportMetrics } = await import('./chunks/export-metrics.mjs');
|
|
547
|
+
await exportMetrics({
|
|
548
|
+
format: options.format,
|
|
549
|
+
output: options.export,
|
|
550
|
+
period: options.period
|
|
551
|
+
});
|
|
545
552
|
} else {
|
|
546
553
|
const { stats } = await import('./chunks/stats.mjs');
|
|
547
554
|
await stats(options);
|
|
@@ -1119,39 +1126,11 @@ async function registerSpecialCommands(cli) {
|
|
|
1119
1126
|
console.log(" ccjk cloud plugins [action] - Plugin marketplace\n");
|
|
1120
1127
|
}
|
|
1121
1128
|
});
|
|
1122
|
-
cli.command("skills-sync [action]", '[DEPRECATED] Use "ccjk cloud skills"').action(async (_action, options) => {
|
|
1123
|
-
console.warn('\n\u26A0\uFE0F skills-sync \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528 "ccjk cloud skills" \u66FF\u4EE3\n');
|
|
1124
|
-
const { skillsSyncMenu } = await import('./chunks/skills-sync.mjs');
|
|
1125
|
-
await skillsSyncMenu(options);
|
|
1126
|
-
});
|
|
1127
|
-
cli.command("agents-sync [action]", '[DEPRECATED] Use "ccjk agents"').action(async () => {
|
|
1128
|
-
console.warn('\n\u26A0\uFE0F agents-sync \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528 "ccjk agents" \u66FF\u4EE3\n');
|
|
1129
|
-
console.log("\u{1F916} Agent Commands:");
|
|
1130
|
-
console.log(" ccjk agents list - List installed agents");
|
|
1131
|
-
console.log(" ccjk agents search - Search agents in cloud");
|
|
1132
|
-
console.log(" ccjk agents install - Install an agent");
|
|
1133
|
-
console.log(" ccjk agents sync - Sync with cloud\n");
|
|
1134
|
-
});
|
|
1135
|
-
cli.command("marketplace [action]", '[DEPRECATED] Use "ccjk cloud plugins"').action(async (action, options) => {
|
|
1136
|
-
console.warn('\n\u26A0\uFE0F marketplace \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528 "ccjk cloud plugins" \u66FF\u4EE3\n');
|
|
1137
|
-
const { marketplaceMenu } = await import('./chunks/marketplace.mjs');
|
|
1138
|
-
await marketplaceMenu(action, options);
|
|
1139
|
-
});
|
|
1140
1129
|
cli.command("plugin [action] [...args]", "Plugin marketplace (install/search/list)").option("--verbose, -v", "Show verbose output").option("--force, -f", "Force operation").option("--version, -V <version>", "Specify plugin version").action(async (action, args, _options) => {
|
|
1141
1130
|
const { handlePluginCommand } = await import('./chunks/plugin.mjs');
|
|
1142
1131
|
const allArgs = [action, ...args || []].filter(Boolean);
|
|
1143
1132
|
await handlePluginCommand(allArgs);
|
|
1144
1133
|
});
|
|
1145
|
-
cli.command("quick [specFile]", '[DEPRECATED] Use "ccjk interview -d quick"').action(async (specFile) => {
|
|
1146
|
-
console.warn('\n\u26A0\uFE0F quick \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528 "ccjk interview -d quick" \u66FF\u4EE3\n');
|
|
1147
|
-
const { quickInterview } = await import('./chunks/interview.mjs');
|
|
1148
|
-
await quickInterview(specFile, {});
|
|
1149
|
-
});
|
|
1150
|
-
cli.command("deep [specFile]", '[DEPRECATED] Use "ccjk interview -d deep"').action(async (specFile) => {
|
|
1151
|
-
console.warn('\n\u26A0\uFE0F deep \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528 "ccjk interview -d deep" \u66FF\u4EE3\n');
|
|
1152
|
-
const { deepInterview } = await import('./chunks/interview.mjs');
|
|
1153
|
-
await deepInterview(specFile, {});
|
|
1154
|
-
});
|
|
1155
1134
|
cli.command("system [action]", "System management (setup/upgrade/info)").alias("sys").action(async (action) => {
|
|
1156
1135
|
const actionStr = action || "info";
|
|
1157
1136
|
if (actionStr === "setup" || actionStr === "s") {
|
|
@@ -1187,42 +1166,6 @@ async function registerSpecialCommands(cli) {
|
|
|
1187
1166
|
console.log(" ccjk system workspace - Workspace diagnostics\n");
|
|
1188
1167
|
}
|
|
1189
1168
|
});
|
|
1190
|
-
cli.command("setup", '[DEPRECATED] Use "ccjk system setup"').action(async () => {
|
|
1191
|
-
console.warn('\n\u26A0\uFE0F setup \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528 "ccjk system setup" \u66FF\u4EE3\n');
|
|
1192
|
-
const { runOnboarding } = await import('./chunks/onboarding.mjs');
|
|
1193
|
-
await runOnboarding();
|
|
1194
|
-
});
|
|
1195
|
-
cli.command("sync", '[DEPRECATED] Use "ccjk system sync"').action(async () => {
|
|
1196
|
-
console.warn('\n\u26A0\uFE0F sync \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528 "ccjk system sync" \u66FF\u4EE3\n');
|
|
1197
|
-
const { quickSync } = await import('./chunks/onboarding.mjs');
|
|
1198
|
-
await quickSync();
|
|
1199
|
-
});
|
|
1200
|
-
cli.command("versions", '[DEPRECATED] Use "ccjk system versions"').action(async () => {
|
|
1201
|
-
console.warn('\n\u26A0\uFE0F versions \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528 "ccjk system versions" \u66FF\u4EE3\n');
|
|
1202
|
-
const { checkAllVersions } = await import('./chunks/upgrade-manager.mjs');
|
|
1203
|
-
await checkAllVersions();
|
|
1204
|
-
});
|
|
1205
|
-
cli.command("upgrade", '[DEPRECATED] Use "ccjk system upgrade"').action(async () => {
|
|
1206
|
-
console.warn('\n\u26A0\uFE0F upgrade \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528 "ccjk system upgrade" \u66FF\u4EE3\n');
|
|
1207
|
-
const { upgradeAll } = await import('./chunks/upgrade-manager.mjs');
|
|
1208
|
-
await upgradeAll();
|
|
1209
|
-
});
|
|
1210
|
-
cli.command("permissions", '[DEPRECATED] Use "ccjk system permissions"').action(async () => {
|
|
1211
|
-
console.warn('\n\u26A0\uFE0F permissions \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528 "ccjk system permissions" \u66FF\u4EE3\n');
|
|
1212
|
-
const { displayPermissions } = await import('./chunks/permission-manager.mjs');
|
|
1213
|
-
displayPermissions();
|
|
1214
|
-
});
|
|
1215
|
-
cli.command("config-scan", '[DEPRECATED] Use "ccjk system config"').action(async () => {
|
|
1216
|
-
console.warn('\n\u26A0\uFE0F config-scan \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528 "ccjk system config" \u66FF\u4EE3\n');
|
|
1217
|
-
const { detectAllConfigs, displayConfigScan } = await import('./chunks/config-consolidator.mjs');
|
|
1218
|
-
const configs = detectAllConfigs();
|
|
1219
|
-
displayConfigScan(configs);
|
|
1220
|
-
});
|
|
1221
|
-
cli.command("workspace [dir]", '[DEPRECATED] Use "ccjk system workspace"').action(async (dir) => {
|
|
1222
|
-
console.warn('\n\u26A0\uFE0F workspace \u5DF2\u5E9F\u5F03\uFF0C\u8BF7\u4F7F\u7528 "ccjk system workspace" \u66FF\u4EE3\n');
|
|
1223
|
-
const { workspaceDiagnostics } = await import('./chunks/doctor.mjs');
|
|
1224
|
-
await workspaceDiagnostics(dir);
|
|
1225
|
-
});
|
|
1226
1169
|
}
|
|
1227
1170
|
function customizeHelpLazy(_sections, version) {
|
|
1228
1171
|
const cyan = (s) => `\x1B[36m${s}\x1B[0m`;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ccjk",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "6.0.1",
|
|
5
5
|
"packageManager": "pnpm@10.17.1",
|
|
6
6
|
"description": "Claude Code JinKu - Advanced AI-powered development assistant with skills, agents, and LLM-driven audit",
|
|
7
7
|
"author": {
|
|
@@ -168,21 +168,21 @@
|
|
|
168
168
|
"@types/express": "^4.17.21",
|
|
169
169
|
"@types/fs-extra": "^11.0.4",
|
|
170
170
|
"@types/inquirer": "^9.0.9",
|
|
171
|
-
"@types/node": "^22.
|
|
171
|
+
"@types/node": "^22.10.6",
|
|
172
172
|
"@types/node-telegram-bot-api": "^0.64.7",
|
|
173
173
|
"@types/nodemailer": "^6.4.14",
|
|
174
174
|
"@types/react": "^19.2.8",
|
|
175
|
-
"@vitest/coverage-v8": "^3.
|
|
175
|
+
"@vitest/coverage-v8": "^3.1.1",
|
|
176
176
|
"@vitest/ui": "^3.2.4",
|
|
177
177
|
"eslint": "^9.36.0",
|
|
178
178
|
"eslint-plugin-format": "^1.0.2",
|
|
179
179
|
"glob": "^11.0.3",
|
|
180
180
|
"husky": "^9.1.7",
|
|
181
181
|
"lint-staged": "^16.2.0",
|
|
182
|
-
"tsx": "^4.
|
|
183
|
-
"typescript": "^5.
|
|
184
|
-
"unbuild": "^3.
|
|
185
|
-
"vitest": "^3.
|
|
182
|
+
"tsx": "^4.19.2",
|
|
183
|
+
"typescript": "^5.7.2",
|
|
184
|
+
"unbuild": "^3.3.1",
|
|
185
|
+
"vitest": "^3.1.1"
|
|
186
186
|
},
|
|
187
187
|
"lint-staged": {
|
|
188
188
|
"*": [
|