ccjk 12.0.7 → 12.0.8
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/package.json +1 -1
- package/dist/chunks/agent-teams.mjs +0 -136
- package/dist/chunks/agent.mjs +0 -1439
- package/dist/chunks/agents.mjs +0 -3778
- package/dist/chunks/api-cli.mjs +0 -132
- package/dist/chunks/api-providers.mjs +0 -129
- package/dist/chunks/api.mjs +0 -112
- package/dist/chunks/auto-bootstrap.mjs +0 -358
- package/dist/chunks/auto-init.mjs +0 -7584
- package/dist/chunks/auto-updater.mjs +0 -410
- package/dist/chunks/banner.mjs +0 -188
- package/dist/chunks/bash.mjs +0 -187
- package/dist/chunks/boost.mjs +0 -397
- package/dist/chunks/ccjk-agents.mjs +0 -414
- package/dist/chunks/ccjk-all.mjs +0 -1028
- package/dist/chunks/ccjk-config.mjs +0 -261
- package/dist/chunks/ccjk-hooks.mjs +0 -1074
- package/dist/chunks/ccjk-mcp.mjs +0 -761
- package/dist/chunks/ccjk-setup.mjs +0 -763
- package/dist/chunks/ccjk-skills.mjs +0 -514
- package/dist/chunks/ccr.mjs +0 -98
- package/dist/chunks/ccu.mjs +0 -40
- package/dist/chunks/check-updates.mjs +0 -108
- package/dist/chunks/claude-code-config-manager.mjs +0 -750
- package/dist/chunks/claude-code-incremental-manager.mjs +0 -623
- package/dist/chunks/claude-config.mjs +0 -236
- package/dist/chunks/claude-wrapper.mjs +0 -85
- package/dist/chunks/cleanup-migration.mjs +0 -20
- package/dist/chunks/cli-hook.mjs +0 -2285
- package/dist/chunks/cloud-sync.mjs +0 -29
- package/dist/chunks/codex-config-switch.mjs +0 -451
- package/dist/chunks/codex-provider-manager.mjs +0 -236
- package/dist/chunks/codex-uninstaller.mjs +0 -404
- package/dist/chunks/codex.mjs +0 -2077
- package/dist/chunks/commands.mjs +0 -108
- package/dist/chunks/commands2.mjs +0 -413
- package/dist/chunks/commit.mjs +0 -138
- package/dist/chunks/completion.mjs +0 -515
- package/dist/chunks/config-consolidator.mjs +0 -172
- package/dist/chunks/config-switch.mjs +0 -317
- package/dist/chunks/config.mjs +0 -379
- package/dist/chunks/config2.mjs +0 -477
- package/dist/chunks/config3.mjs +0 -470
- package/dist/chunks/constants.mjs +0 -133
- package/dist/chunks/context-loader.mjs +0 -343
- package/dist/chunks/context.mjs +0 -372
- package/dist/chunks/convoy-manager.mjs +0 -880
- package/dist/chunks/dashboard.mjs +0 -476
- package/dist/chunks/doctor.mjs +0 -964
- package/dist/chunks/evolution.mjs +0 -382
- package/dist/chunks/features.mjs +0 -698
- package/dist/chunks/fish.mjs +0 -181
- package/dist/chunks/fs-operations.mjs +0 -192
- package/dist/chunks/health-alerts.mjs +0 -304
- package/dist/chunks/health-check.mjs +0 -532
- package/dist/chunks/help.mjs +0 -340
- package/dist/chunks/hook-installer.mjs +0 -45
- package/dist/chunks/index.mjs +0 -24
- package/dist/chunks/index10.mjs +0 -1171
- package/dist/chunks/index11.mjs +0 -1008
- package/dist/chunks/index12.mjs +0 -193
- package/dist/chunks/index13.mjs +0 -218
- package/dist/chunks/index14.mjs +0 -663
- package/dist/chunks/index2.mjs +0 -19
- package/dist/chunks/index3.mjs +0 -19092
- package/dist/chunks/index4.mjs +0 -8
- package/dist/chunks/index5.mjs +0 -7600
- package/dist/chunks/index6.mjs +0 -171
- package/dist/chunks/index7.mjs +0 -3583
- package/dist/chunks/index8.mjs +0 -19
- package/dist/chunks/index9.mjs +0 -616
- package/dist/chunks/init.mjs +0 -1606
- package/dist/chunks/installer.mjs +0 -690
- package/dist/chunks/installer2.mjs +0 -179
- package/dist/chunks/interview.mjs +0 -2927
- package/dist/chunks/json-config.mjs +0 -60
- package/dist/chunks/linux.mjs +0 -3863
- package/dist/chunks/macos.mjs +0 -69
- package/dist/chunks/main.mjs +0 -635
- package/dist/chunks/manager.mjs +0 -1048
- package/dist/chunks/marketplace.mjs +0 -949
- package/dist/chunks/mcp-cli.mjs +0 -204
- package/dist/chunks/mcp-performance.mjs +0 -187
- package/dist/chunks/mcp.mjs +0 -1231
- package/dist/chunks/menu.mjs +0 -652
- package/dist/chunks/metrics-display.mjs +0 -153
- package/dist/chunks/migrator.mjs +0 -178
- package/dist/chunks/monitor.mjs +0 -1856
- package/dist/chunks/notification.mjs +0 -1864
- package/dist/chunks/onboarding.mjs +0 -385
- package/dist/chunks/package.mjs +0 -3
- package/dist/chunks/paradigm.mjs +0 -74
- package/dist/chunks/permission-manager.mjs +0 -132
- package/dist/chunks/permissions.mjs +0 -265
- package/dist/chunks/persistence-manager.mjs +0 -794
- package/dist/chunks/persistence.mjs +0 -667
- package/dist/chunks/platform.mjs +0 -391
- package/dist/chunks/plugin.mjs +0 -1936
- package/dist/chunks/powershell.mjs +0 -213
- package/dist/chunks/prompts.mjs +0 -241
- package/dist/chunks/providers.mjs +0 -260
- package/dist/chunks/quick-actions.mjs +0 -320
- package/dist/chunks/quick-provider.mjs +0 -682
- package/dist/chunks/quick-setup.mjs +0 -412
- package/dist/chunks/remote.mjs +0 -497
- package/dist/chunks/session.mjs +0 -878
- package/dist/chunks/sessions.mjs +0 -106
- package/dist/chunks/silent-updater.mjs +0 -396
- package/dist/chunks/simple-config.mjs +0 -98
- package/dist/chunks/skill.mjs +0 -117
- package/dist/chunks/skill2.mjs +0 -9003
- package/dist/chunks/skills-sync.mjs +0 -6460
- package/dist/chunks/skills.mjs +0 -567
- package/dist/chunks/slash-commands.mjs +0 -207
- package/dist/chunks/smart-defaults.mjs +0 -412
- package/dist/chunks/smart-guide.mjs +0 -194
- package/dist/chunks/startup.mjs +0 -487
- package/dist/chunks/stats.mjs +0 -410
- package/dist/chunks/status.mjs +0 -289
- package/dist/chunks/team.mjs +0 -63
- package/dist/chunks/thinking.mjs +0 -626
- package/dist/chunks/trace.mjs +0 -57
- package/dist/chunks/uninstall.mjs +0 -849
- package/dist/chunks/update.mjs +0 -167
- package/dist/chunks/upgrade-manager.mjs +0 -204
- package/dist/chunks/version-checker.mjs +0 -881
- package/dist/chunks/vim.mjs +0 -903
- package/dist/chunks/windows.mjs +0 -14
- package/dist/chunks/workflows.mjs +0 -633
- package/dist/chunks/wsl.mjs +0 -129
- package/dist/chunks/zero-config.mjs +0 -374
- package/dist/chunks/zsh.mjs +0 -182
- package/dist/cli.d.mts +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.mjs +0 -2199
- package/dist/i18n/locales/en/agent-teams.json +0 -18
- package/dist/i18n/locales/en/agentBrowser.json +0 -79
- package/dist/i18n/locales/en/agents.json +0 -135
- package/dist/i18n/locales/en/api.json +0 -63
- package/dist/i18n/locales/en/ccjk-agents.json +0 -33
- package/dist/i18n/locales/en/ccjk-all.json +0 -23
- package/dist/i18n/locales/en/ccjk-skills.json +0 -22
- package/dist/i18n/locales/en/ccjk.json +0 -276
- package/dist/i18n/locales/en/ccr.json +0 -65
- package/dist/i18n/locales/en/claude-md.json +0 -73
- package/dist/i18n/locales/en/cli.json +0 -152
- package/dist/i18n/locales/en/cloud-setup.json +0 -31
- package/dist/i18n/locales/en/cloud-sync.json +0 -147
- package/dist/i18n/locales/en/cloud.json +0 -40
- package/dist/i18n/locales/en/cloudPlugins.json +0 -118
- package/dist/i18n/locales/en/codex.json +0 -127
- package/dist/i18n/locales/en/cometix.json +0 -29
- package/dist/i18n/locales/en/common.json +0 -68
- package/dist/i18n/locales/en/config.json +0 -108
- package/dist/i18n/locales/en/configuration.json +0 -226
- package/dist/i18n/locales/en/context.json +0 -85
- package/dist/i18n/locales/en/dashboard.json +0 -78
- package/dist/i18n/locales/en/errors.json +0 -26
- package/dist/i18n/locales/en/evolution.json +0 -54
- package/dist/i18n/locales/en/hooks.json +0 -74
- package/dist/i18n/locales/en/hooksSync.json +0 -133
- package/dist/i18n/locales/en/installation.json +0 -83
- package/dist/i18n/locales/en/interview.json +0 -104
- package/dist/i18n/locales/en/language.json +0 -19
- package/dist/i18n/locales/en/lsp.json +0 -78
- package/dist/i18n/locales/en/marketplace.json +0 -116
- package/dist/i18n/locales/en/mcp.json +0 -178
- package/dist/i18n/locales/en/memory.json +0 -92
- package/dist/i18n/locales/en/menu.json +0 -143
- package/dist/i18n/locales/en/multi-config.json +0 -79
- package/dist/i18n/locales/en/notification.json +0 -307
- package/dist/i18n/locales/en/permissions.json +0 -95
- package/dist/i18n/locales/en/persistence.json +0 -127
- package/dist/i18n/locales/en/plugins.json +0 -146
- package/dist/i18n/locales/en/quick-actions.json +0 -78
- package/dist/i18n/locales/en/registry.json +0 -54
- package/dist/i18n/locales/en/remote.json +0 -93
- package/dist/i18n/locales/en/sandbox.json +0 -44
- package/dist/i18n/locales/en/setup.json +0 -44
- package/dist/i18n/locales/en/shencha.json +0 -14
- package/dist/i18n/locales/en/skills.json +0 -100
- package/dist/i18n/locales/en/skillsSync.json +0 -74
- package/dist/i18n/locales/en/smartGuide.json +0 -49
- package/dist/i18n/locales/en/stats.json +0 -20
- package/dist/i18n/locales/en/subagent.json +0 -69
- package/dist/i18n/locales/en/superpowers.json +0 -117
- package/dist/i18n/locales/en/team.json +0 -7
- package/dist/i18n/locales/en/thinking.json +0 -65
- package/dist/i18n/locales/en/tools.json +0 -42
- package/dist/i18n/locales/en/uninstall.json +0 -56
- package/dist/i18n/locales/en/updater.json +0 -29
- package/dist/i18n/locales/en/vim.json +0 -169
- package/dist/i18n/locales/en/workflow.json +0 -55
- package/dist/i18n/locales/en/workspace.json +0 -108
- package/dist/i18n/locales/zh-CN/agent-teams.json +0 -18
- package/dist/i18n/locales/zh-CN/agentBrowser.json +0 -79
- package/dist/i18n/locales/zh-CN/agents.json +0 -135
- package/dist/i18n/locales/zh-CN/api.json +0 -63
- package/dist/i18n/locales/zh-CN/ccjk-agents.json +0 -33
- package/dist/i18n/locales/zh-CN/ccjk-all.json +0 -23
- package/dist/i18n/locales/zh-CN/ccjk-skills.json +0 -22
- package/dist/i18n/locales/zh-CN/ccjk.json +0 -276
- package/dist/i18n/locales/zh-CN/ccr.json +0 -65
- package/dist/i18n/locales/zh-CN/claude-md.json +0 -73
- package/dist/i18n/locales/zh-CN/cli.json +0 -152
- package/dist/i18n/locales/zh-CN/cloud-setup.json +0 -31
- package/dist/i18n/locales/zh-CN/cloud-sync.json +0 -147
- package/dist/i18n/locales/zh-CN/cloud.json +0 -40
- package/dist/i18n/locales/zh-CN/cloudPlugins.json +0 -118
- package/dist/i18n/locales/zh-CN/codex.json +0 -127
- package/dist/i18n/locales/zh-CN/cometix.json +0 -29
- package/dist/i18n/locales/zh-CN/common.json +0 -68
- package/dist/i18n/locales/zh-CN/config.json +0 -108
- package/dist/i18n/locales/zh-CN/configuration.json +0 -224
- package/dist/i18n/locales/zh-CN/context.json +0 -85
- package/dist/i18n/locales/zh-CN/dashboard.json +0 -78
- package/dist/i18n/locales/zh-CN/errors.json +0 -26
- package/dist/i18n/locales/zh-CN/evolution.json +0 -54
- package/dist/i18n/locales/zh-CN/hooks.json +0 -74
- package/dist/i18n/locales/zh-CN/hooksSync.json +0 -133
- package/dist/i18n/locales/zh-CN/installation.json +0 -83
- package/dist/i18n/locales/zh-CN/interview.json +0 -104
- package/dist/i18n/locales/zh-CN/language.json +0 -19
- package/dist/i18n/locales/zh-CN/lsp.json +0 -78
- package/dist/i18n/locales/zh-CN/marketplace.json +0 -116
- package/dist/i18n/locales/zh-CN/mcp.json +0 -178
- package/dist/i18n/locales/zh-CN/memory.json +0 -92
- package/dist/i18n/locales/zh-CN/menu.json +0 -143
- package/dist/i18n/locales/zh-CN/multi-config.json +0 -79
- package/dist/i18n/locales/zh-CN/notification.json +0 -307
- package/dist/i18n/locales/zh-CN/permissions.json +0 -95
- package/dist/i18n/locales/zh-CN/persistence.json +0 -127
- package/dist/i18n/locales/zh-CN/plugins.json +0 -146
- package/dist/i18n/locales/zh-CN/quick-actions.json +0 -78
- package/dist/i18n/locales/zh-CN/registry.json +0 -54
- package/dist/i18n/locales/zh-CN/remote.json +0 -93
- package/dist/i18n/locales/zh-CN/sandbox.json +0 -44
- package/dist/i18n/locales/zh-CN/setup.json +0 -44
- package/dist/i18n/locales/zh-CN/shencha.json +0 -14
- package/dist/i18n/locales/zh-CN/skills.json +0 -100
- package/dist/i18n/locales/zh-CN/skillsSync.json +0 -74
- package/dist/i18n/locales/zh-CN/smartGuide.json +0 -49
- package/dist/i18n/locales/zh-CN/stats.json +0 -20
- package/dist/i18n/locales/zh-CN/subagent.json +0 -69
- package/dist/i18n/locales/zh-CN/superpowers.json +0 -117
- package/dist/i18n/locales/zh-CN/team.json +0 -7
- package/dist/i18n/locales/zh-CN/thinking.json +0 -65
- package/dist/i18n/locales/zh-CN/tools.json +0 -42
- package/dist/i18n/locales/zh-CN/uninstall.json +0 -56
- package/dist/i18n/locales/zh-CN/updater.json +0 -29
- package/dist/i18n/locales/zh-CN/vim.json +0 -169
- package/dist/i18n/locales/zh-CN/workflow.json +0 -55
- package/dist/i18n/locales/zh-CN/workspace.json +0 -108
- package/dist/index.d.mts +0 -5295
- package/dist/index.d.ts +0 -5295
- package/dist/index.mjs +0 -4941
- package/dist/shared/ccjk.B364Fu0N.mjs +0 -1819
- package/dist/shared/ccjk.BAGoDD49.mjs +0 -36
- package/dist/shared/ccjk.BBtCGd_g.mjs +0 -899
- package/dist/shared/ccjk.BFQ7yr5S.mjs +0 -16
- package/dist/shared/ccjk.BFxsJM0k.mjs +0 -599
- package/dist/shared/ccjk.BIxuVL3_.mjs +0 -25
- package/dist/shared/ccjk.BRZ9ww8S.mjs +0 -142
- package/dist/shared/ccjk.BoApaI4j.mjs +0 -28
- package/dist/shared/ccjk.BrPUmTqm.mjs +0 -266
- package/dist/shared/ccjk.BtB1e5jm.mjs +0 -171
- package/dist/shared/ccjk.BwfbSKN2.mjs +0 -1051
- package/dist/shared/ccjk.BxSmJ8B7.mjs +0 -243
- package/dist/shared/ccjk.Bx_rmYfN.mjs +0 -69
- package/dist/shared/ccjk.C2jHOZVP.mjs +0 -52
- package/dist/shared/ccjk.CL4Yat0G.mjs +0 -303
- package/dist/shared/ccjk.COweQ1RR.mjs +0 -5
- package/dist/shared/ccjk.CePkJq2S.mjs +0 -223
- package/dist/shared/ccjk.CfKKcvWy.mjs +0 -126
- package/dist/shared/ccjk.Cjgrln_h.mjs +0 -297
- package/dist/shared/ccjk.Cjj8SVrn.mjs +0 -54
- package/dist/shared/ccjk.CxpGa6MC.mjs +0 -2724
- package/dist/shared/ccjk.D5MFQT7w.mjs +0 -400
- package/dist/shared/ccjk.D6ycHbak.mjs +0 -270
- package/dist/shared/ccjk.D8ZLYSZZ.mjs +0 -299
- package/dist/shared/ccjk.DG_o24cZ.mjs +0 -88
- package/dist/shared/ccjk.DLLw-h4Y.mjs +0 -460
- package/dist/shared/ccjk.DOwtZMk8.mjs +0 -4019
- package/dist/shared/ccjk.DS7UESmF.mjs +0 -2451
- package/dist/shared/ccjk.DTdjs-qK.mjs +0 -1447
- package/dist/shared/ccjk.DXRAZcix.mjs +0 -66
- package/dist/shared/ccjk.DsYaCCx4.mjs +0 -317
- package/dist/shared/ccjk.J8YiPsOw.mjs +0 -259
- package/dist/shared/ccjk.KfSWcGlE.mjs +0 -38
- package/dist/shared/ccjk.RyizuzOI.mjs +0 -21
- package/dist/shared/ccjk.SPoXMvZD.mjs +0 -1242
- package/dist/shared/ccjk.T_cX87dY.mjs +0 -15
- package/dist/shared/ccjk.UIvifqNE.mjs +0 -1486
- package/dist/shared/ccjk._dESH4Rk.mjs +0 -111
- package/dist/shared/ccjk.bQ7Dh1g4.mjs +0 -249
- package/dist/shared/ccjk.c-ETfBZ_.mjs +0 -617
- package/dist/shared/ccjk.gDEDGD_t.mjs +0 -38
- package/dist/shared/ccjk.hoqrwWdN.mjs +0 -333
- package/dist/shared/ccjk.waa2ikKJ.mjs +0 -351
package/dist/chunks/monitor.mjs
DELETED
|
@@ -1,1856 +0,0 @@
|
|
|
1
|
-
import a from './index2.mjs';
|
|
2
|
-
import { i18n } from './index5.mjs';
|
|
3
|
-
import { displayBannerWithInfo } from './banner.mjs';
|
|
4
|
-
import process__default from 'node:process';
|
|
5
|
-
import { n as nanoid } from '../shared/ccjk.BoApaI4j.mjs';
|
|
6
|
-
import '../shared/ccjk.BAGoDD49.mjs';
|
|
7
|
-
import 'node:fs';
|
|
8
|
-
import 'node:url';
|
|
9
|
-
import '../shared/ccjk.bQ7Dh1g4.mjs';
|
|
10
|
-
import '../shared/ccjk.gDEDGD_t.mjs';
|
|
11
|
-
import 'node:crypto';
|
|
12
|
-
|
|
13
|
-
const DEFAULT_STORAGE_CONFIG = {
|
|
14
|
-
maxRecords: 1e4,
|
|
15
|
-
retentionPeriod: 7 * 24 * 60 * 60 * 1e3,
|
|
16
|
-
// 7 days
|
|
17
|
-
enablePersistence: false,
|
|
18
|
-
compressOldData: true
|
|
19
|
-
};
|
|
20
|
-
class MetricsCollector {
|
|
21
|
-
commands = /* @__PURE__ */ new Map();
|
|
22
|
-
commandHistory = [];
|
|
23
|
-
apiCalls = /* @__PURE__ */ new Map();
|
|
24
|
-
apiHistory = [];
|
|
25
|
-
cacheOperations = [];
|
|
26
|
-
errors = [];
|
|
27
|
-
agentTasks = /* @__PURE__ */ new Map();
|
|
28
|
-
agentHistory = [];
|
|
29
|
-
memorySnapshots = [];
|
|
30
|
-
eventListeners = /* @__PURE__ */ new Map();
|
|
31
|
-
thresholds = [];
|
|
32
|
-
config;
|
|
33
|
-
startTime;
|
|
34
|
-
constructor(config = {}) {
|
|
35
|
-
this.config = { ...DEFAULT_STORAGE_CONFIG, ...config };
|
|
36
|
-
this.startTime = Date.now();
|
|
37
|
-
}
|
|
38
|
-
// ==========================================================================
|
|
39
|
-
// Command Metrics
|
|
40
|
-
// ==========================================================================
|
|
41
|
-
/**
|
|
42
|
-
* Start tracking a command execution
|
|
43
|
-
*/
|
|
44
|
-
startCommand(command, args = []) {
|
|
45
|
-
const id = nanoid();
|
|
46
|
-
const execution = {
|
|
47
|
-
id,
|
|
48
|
-
command,
|
|
49
|
-
args,
|
|
50
|
-
startTime: Date.now(),
|
|
51
|
-
status: "running"
|
|
52
|
-
};
|
|
53
|
-
this.commands.set(id, execution);
|
|
54
|
-
this.emit("command:start", execution);
|
|
55
|
-
return id;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* End tracking a command execution
|
|
59
|
-
*/
|
|
60
|
-
endCommand(id, status, error) {
|
|
61
|
-
const execution = this.commands.get(id);
|
|
62
|
-
if (!execution)
|
|
63
|
-
return;
|
|
64
|
-
execution.endTime = Date.now();
|
|
65
|
-
execution.duration = execution.endTime - execution.startTime;
|
|
66
|
-
execution.status = status;
|
|
67
|
-
execution.error = error;
|
|
68
|
-
execution.memoryUsed = process.memoryUsage().heapUsed;
|
|
69
|
-
this.commandHistory.push(execution);
|
|
70
|
-
this.commands.delete(id);
|
|
71
|
-
this.trimHistory(this.commandHistory);
|
|
72
|
-
this.emit("command:end", execution);
|
|
73
|
-
this.checkThresholds("command.duration", execution.duration);
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Get command statistics
|
|
77
|
-
*/
|
|
78
|
-
getCommandStats() {
|
|
79
|
-
const statsMap = /* @__PURE__ */ new Map();
|
|
80
|
-
for (const exec of this.commandHistory) {
|
|
81
|
-
let stats = statsMap.get(exec.command);
|
|
82
|
-
if (!stats) {
|
|
83
|
-
stats = {
|
|
84
|
-
command: exec.command,
|
|
85
|
-
totalExecutions: 0,
|
|
86
|
-
successCount: 0,
|
|
87
|
-
failureCount: 0,
|
|
88
|
-
avgDuration: 0,
|
|
89
|
-
minDuration: Infinity,
|
|
90
|
-
maxDuration: 0,
|
|
91
|
-
p95Duration: 0
|
|
92
|
-
};
|
|
93
|
-
statsMap.set(exec.command, stats);
|
|
94
|
-
}
|
|
95
|
-
stats.totalExecutions++;
|
|
96
|
-
if (exec.status === "success")
|
|
97
|
-
stats.successCount++;
|
|
98
|
-
else if (exec.status === "failed" || exec.status === "timeout")
|
|
99
|
-
stats.failureCount++;
|
|
100
|
-
if (exec.duration !== void 0) {
|
|
101
|
-
stats.minDuration = Math.min(stats.minDuration, exec.duration);
|
|
102
|
-
stats.maxDuration = Math.max(stats.maxDuration, exec.duration);
|
|
103
|
-
}
|
|
104
|
-
stats.lastExecution = exec.endTime || exec.startTime;
|
|
105
|
-
}
|
|
106
|
-
for (const [command, stats] of statsMap) {
|
|
107
|
-
const durations = this.commandHistory.filter((e) => e.command === command && e.duration !== void 0).map((e) => e.duration).sort((a, b) => a - b);
|
|
108
|
-
if (durations.length > 0) {
|
|
109
|
-
stats.avgDuration = durations.reduce((a, b) => a + b, 0) / durations.length;
|
|
110
|
-
stats.p95Duration = this.calculatePercentile(durations, 95);
|
|
111
|
-
}
|
|
112
|
-
if (stats.minDuration === Infinity)
|
|
113
|
-
stats.minDuration = 0;
|
|
114
|
-
}
|
|
115
|
-
return Array.from(statsMap.values());
|
|
116
|
-
}
|
|
117
|
-
// ==========================================================================
|
|
118
|
-
// API Call Metrics
|
|
119
|
-
// ==========================================================================
|
|
120
|
-
/**
|
|
121
|
-
* Start tracking an API call
|
|
122
|
-
*/
|
|
123
|
-
startApiCall(provider, endpoint, method = "POST") {
|
|
124
|
-
const id = nanoid();
|
|
125
|
-
const record = {
|
|
126
|
-
id,
|
|
127
|
-
provider,
|
|
128
|
-
endpoint,
|
|
129
|
-
method,
|
|
130
|
-
startTime: Date.now(),
|
|
131
|
-
status: "pending"
|
|
132
|
-
};
|
|
133
|
-
this.apiCalls.set(id, record);
|
|
134
|
-
this.emit("api:start", record);
|
|
135
|
-
return id;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* End tracking an API call
|
|
139
|
-
*/
|
|
140
|
-
endApiCall(id, status, options = {}) {
|
|
141
|
-
const record = this.apiCalls.get(id);
|
|
142
|
-
if (!record)
|
|
143
|
-
return;
|
|
144
|
-
record.endTime = Date.now();
|
|
145
|
-
record.latency = record.endTime - record.startTime;
|
|
146
|
-
record.status = status;
|
|
147
|
-
record.statusCode = options.statusCode;
|
|
148
|
-
record.error = options.error;
|
|
149
|
-
record.requestSize = options.requestSize;
|
|
150
|
-
record.responseSize = options.responseSize;
|
|
151
|
-
record.tokensUsed = options.tokensUsed;
|
|
152
|
-
record.cached = options.cached;
|
|
153
|
-
this.apiHistory.push(record);
|
|
154
|
-
this.apiCalls.delete(id);
|
|
155
|
-
this.trimHistory(this.apiHistory);
|
|
156
|
-
this.emit("api:end", record);
|
|
157
|
-
this.checkThresholds("api.latency", record.latency);
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Get API statistics by provider
|
|
161
|
-
*/
|
|
162
|
-
getApiStats() {
|
|
163
|
-
const statsMap = /* @__PURE__ */ new Map();
|
|
164
|
-
for (const call of this.apiHistory) {
|
|
165
|
-
let stats = statsMap.get(call.provider);
|
|
166
|
-
if (!stats) {
|
|
167
|
-
stats = {
|
|
168
|
-
provider: call.provider,
|
|
169
|
-
totalCalls: 0,
|
|
170
|
-
successCount: 0,
|
|
171
|
-
failureCount: 0,
|
|
172
|
-
avgLatency: 0,
|
|
173
|
-
minLatency: Infinity,
|
|
174
|
-
maxLatency: 0,
|
|
175
|
-
p95Latency: 0,
|
|
176
|
-
totalTokens: 0,
|
|
177
|
-
cacheHits: 0,
|
|
178
|
-
cacheMisses: 0,
|
|
179
|
-
errorRate: 0
|
|
180
|
-
};
|
|
181
|
-
statsMap.set(call.provider, stats);
|
|
182
|
-
}
|
|
183
|
-
stats.totalCalls++;
|
|
184
|
-
if (call.status === "success")
|
|
185
|
-
stats.successCount++;
|
|
186
|
-
else stats.failureCount++;
|
|
187
|
-
if (call.latency !== void 0) {
|
|
188
|
-
stats.minLatency = Math.min(stats.minLatency, call.latency);
|
|
189
|
-
stats.maxLatency = Math.max(stats.maxLatency, call.latency);
|
|
190
|
-
}
|
|
191
|
-
if (call.tokensUsed)
|
|
192
|
-
stats.totalTokens += call.tokensUsed;
|
|
193
|
-
if (call.cached)
|
|
194
|
-
stats.cacheHits++;
|
|
195
|
-
else stats.cacheMisses++;
|
|
196
|
-
}
|
|
197
|
-
for (const [provider, stats] of statsMap) {
|
|
198
|
-
const latencies = this.apiHistory.filter((c) => c.provider === provider && c.latency !== void 0).map((c) => c.latency).sort((a, b) => a - b);
|
|
199
|
-
if (latencies.length > 0) {
|
|
200
|
-
stats.avgLatency = latencies.reduce((a, b) => a + b, 0) / latencies.length;
|
|
201
|
-
stats.p95Latency = this.calculatePercentile(latencies, 95);
|
|
202
|
-
}
|
|
203
|
-
if (stats.minLatency === Infinity)
|
|
204
|
-
stats.minLatency = 0;
|
|
205
|
-
stats.errorRate = stats.totalCalls > 0 ? stats.failureCount / stats.totalCalls : 0;
|
|
206
|
-
}
|
|
207
|
-
return Array.from(statsMap.values());
|
|
208
|
-
}
|
|
209
|
-
// ==========================================================================
|
|
210
|
-
// Cache Metrics
|
|
211
|
-
// ==========================================================================
|
|
212
|
-
/**
|
|
213
|
-
* Record a cache operation
|
|
214
|
-
*/
|
|
215
|
-
recordCacheOperation(operation, key, hit, latency, size) {
|
|
216
|
-
const record = {
|
|
217
|
-
timestamp: Date.now(),
|
|
218
|
-
operation,
|
|
219
|
-
key,
|
|
220
|
-
hit,
|
|
221
|
-
latency,
|
|
222
|
-
size
|
|
223
|
-
};
|
|
224
|
-
this.cacheOperations.push(record);
|
|
225
|
-
this.trimHistory(this.cacheOperations);
|
|
226
|
-
this.emit("cache:operation", record);
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Get cache statistics
|
|
230
|
-
*/
|
|
231
|
-
getCacheStats() {
|
|
232
|
-
const getOps = this.cacheOperations.filter((op) => op.operation === "get");
|
|
233
|
-
const hits = getOps.filter((op) => op.hit).length;
|
|
234
|
-
const misses = getOps.filter((op) => !op.hit).length;
|
|
235
|
-
const totalSize = this.cacheOperations.filter((op) => op.size !== void 0).reduce((sum, op) => sum + (op.size || 0), 0);
|
|
236
|
-
const latencies = this.cacheOperations.map((op) => op.latency);
|
|
237
|
-
const avgLatency = latencies.length > 0 ? latencies.reduce((a, b) => a + b, 0) / latencies.length : 0;
|
|
238
|
-
return {
|
|
239
|
-
totalOperations: this.cacheOperations.length,
|
|
240
|
-
hits,
|
|
241
|
-
misses,
|
|
242
|
-
hitRate: getOps.length > 0 ? hits / getOps.length : 0,
|
|
243
|
-
avgLatency,
|
|
244
|
-
totalSize,
|
|
245
|
-
itemCount: new Set(this.cacheOperations.map((op) => op.key)).size,
|
|
246
|
-
evictions: this.cacheOperations.filter((op) => op.operation === "delete").length
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
// ==========================================================================
|
|
250
|
-
// Error Metrics
|
|
251
|
-
// ==========================================================================
|
|
252
|
-
/**
|
|
253
|
-
* Record an error
|
|
254
|
-
*/
|
|
255
|
-
recordError(type, message, options = {}) {
|
|
256
|
-
const id = nanoid();
|
|
257
|
-
const record = {
|
|
258
|
-
id,
|
|
259
|
-
timestamp: Date.now(),
|
|
260
|
-
type,
|
|
261
|
-
message,
|
|
262
|
-
stack: options.stack,
|
|
263
|
-
context: options.context,
|
|
264
|
-
severity: options.severity || "medium",
|
|
265
|
-
resolved: false
|
|
266
|
-
};
|
|
267
|
-
this.errors.push(record);
|
|
268
|
-
this.trimHistory(this.errors);
|
|
269
|
-
this.emit("error:recorded", record);
|
|
270
|
-
this.checkThresholds("error.count", this.errors.length);
|
|
271
|
-
return id;
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* Mark an error as resolved
|
|
275
|
-
*/
|
|
276
|
-
resolveError(id) {
|
|
277
|
-
const error = this.errors.find((e) => e.id === id);
|
|
278
|
-
if (error) {
|
|
279
|
-
error.resolved = true;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Get error statistics
|
|
284
|
-
*/
|
|
285
|
-
getErrorStats() {
|
|
286
|
-
const errorsByType = {};
|
|
287
|
-
const errorsBySeverity = { low: 0, medium: 0, high: 0, critical: 0 };
|
|
288
|
-
for (const error of this.errors) {
|
|
289
|
-
errorsByType[error.type] = (errorsByType[error.type] || 0) + 1;
|
|
290
|
-
errorsBySeverity[error.severity]++;
|
|
291
|
-
}
|
|
292
|
-
const recentErrors = this.errors.slice(-10).reverse();
|
|
293
|
-
const oneHourAgo = Date.now() - 60 * 60 * 1e3;
|
|
294
|
-
const recentErrorCount = this.errors.filter((e) => e.timestamp > oneHourAgo).length;
|
|
295
|
-
const errorRate = recentErrorCount / 60;
|
|
296
|
-
return {
|
|
297
|
-
totalErrors: this.errors.length,
|
|
298
|
-
errorsByType,
|
|
299
|
-
errorsBySeverity,
|
|
300
|
-
errorRate,
|
|
301
|
-
recentErrors
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
// ==========================================================================
|
|
305
|
-
// Agent Task Metrics
|
|
306
|
-
// ==========================================================================
|
|
307
|
-
/**
|
|
308
|
-
* Start tracking an agent task
|
|
309
|
-
*/
|
|
310
|
-
startAgentTask(agentId, agentName, taskType) {
|
|
311
|
-
const id = nanoid();
|
|
312
|
-
const record = {
|
|
313
|
-
id,
|
|
314
|
-
agentId,
|
|
315
|
-
agentName,
|
|
316
|
-
taskType,
|
|
317
|
-
startTime: Date.now(),
|
|
318
|
-
status: "running"
|
|
319
|
-
};
|
|
320
|
-
this.agentTasks.set(id, record);
|
|
321
|
-
this.emit("agent:task:start", record);
|
|
322
|
-
return id;
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* End tracking an agent task
|
|
326
|
-
*/
|
|
327
|
-
endAgentTask(id, status, options = {}) {
|
|
328
|
-
const record = this.agentTasks.get(id);
|
|
329
|
-
if (!record)
|
|
330
|
-
return;
|
|
331
|
-
record.endTime = Date.now();
|
|
332
|
-
record.duration = record.endTime - record.startTime;
|
|
333
|
-
record.status = status;
|
|
334
|
-
record.tokensUsed = options.tokensUsed;
|
|
335
|
-
record.error = options.error;
|
|
336
|
-
record.metadata = options.metadata;
|
|
337
|
-
this.agentHistory.push(record);
|
|
338
|
-
this.agentTasks.delete(id);
|
|
339
|
-
this.trimHistory(this.agentHistory);
|
|
340
|
-
this.emit("agent:task:end", record);
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Get agent statistics
|
|
344
|
-
*/
|
|
345
|
-
getAgentStats() {
|
|
346
|
-
const statsMap = /* @__PURE__ */ new Map();
|
|
347
|
-
for (const task of this.agentHistory) {
|
|
348
|
-
let stats = statsMap.get(task.agentId);
|
|
349
|
-
if (!stats) {
|
|
350
|
-
stats = {
|
|
351
|
-
agentId: task.agentId,
|
|
352
|
-
agentName: task.agentName,
|
|
353
|
-
totalTasks: 0,
|
|
354
|
-
successCount: 0,
|
|
355
|
-
failureCount: 0,
|
|
356
|
-
avgDuration: 0,
|
|
357
|
-
totalTokens: 0,
|
|
358
|
-
successRate: 0
|
|
359
|
-
};
|
|
360
|
-
statsMap.set(task.agentId, stats);
|
|
361
|
-
}
|
|
362
|
-
stats.totalTasks++;
|
|
363
|
-
if (task.status === "success")
|
|
364
|
-
stats.successCount++;
|
|
365
|
-
else if (task.status === "failed")
|
|
366
|
-
stats.failureCount++;
|
|
367
|
-
if (task.tokensUsed)
|
|
368
|
-
stats.totalTokens += task.tokensUsed;
|
|
369
|
-
stats.lastActive = task.endTime || task.startTime;
|
|
370
|
-
}
|
|
371
|
-
for (const [agentId, stats] of statsMap) {
|
|
372
|
-
const durations = this.agentHistory.filter((t) => t.agentId === agentId && t.duration !== void 0).map((t) => t.duration);
|
|
373
|
-
if (durations.length > 0) {
|
|
374
|
-
stats.avgDuration = durations.reduce((a, b) => a + b, 0) / durations.length;
|
|
375
|
-
}
|
|
376
|
-
stats.successRate = stats.totalTasks > 0 ? stats.successCount / stats.totalTasks : 0;
|
|
377
|
-
}
|
|
378
|
-
return Array.from(statsMap.values());
|
|
379
|
-
}
|
|
380
|
-
// ==========================================================================
|
|
381
|
-
// Memory Metrics
|
|
382
|
-
// ==========================================================================
|
|
383
|
-
/**
|
|
384
|
-
* Take a memory snapshot
|
|
385
|
-
*/
|
|
386
|
-
takeMemorySnapshot() {
|
|
387
|
-
const mem = process.memoryUsage();
|
|
388
|
-
const snapshot = {
|
|
389
|
-
timestamp: Date.now(),
|
|
390
|
-
heapUsed: mem.heapUsed,
|
|
391
|
-
heapTotal: mem.heapTotal,
|
|
392
|
-
external: mem.external,
|
|
393
|
-
arrayBuffers: mem.arrayBuffers,
|
|
394
|
-
rss: mem.rss,
|
|
395
|
-
heapUsedPercent: mem.heapUsed / mem.heapTotal
|
|
396
|
-
};
|
|
397
|
-
this.memorySnapshots.push(snapshot);
|
|
398
|
-
this.trimHistory(this.memorySnapshots);
|
|
399
|
-
this.emit("memory:snapshot", snapshot);
|
|
400
|
-
this.checkThresholds("memory.heapUsedPercent", snapshot.heapUsedPercent);
|
|
401
|
-
return snapshot;
|
|
402
|
-
}
|
|
403
|
-
/**
|
|
404
|
-
* Get memory statistics
|
|
405
|
-
*/
|
|
406
|
-
getMemoryStats() {
|
|
407
|
-
const current = this.takeMemorySnapshot();
|
|
408
|
-
if (this.memorySnapshots.length === 0) {
|
|
409
|
-
return {
|
|
410
|
-
current,
|
|
411
|
-
peak: current,
|
|
412
|
-
average: {
|
|
413
|
-
heapUsed: current.heapUsed,
|
|
414
|
-
heapTotal: current.heapTotal,
|
|
415
|
-
rss: current.rss
|
|
416
|
-
},
|
|
417
|
-
trend: "stable"
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
const peak = this.memorySnapshots.reduce(
|
|
421
|
-
(max, snap) => snap.heapUsed > max.heapUsed ? snap : max
|
|
422
|
-
);
|
|
423
|
-
const avgHeapUsed = this.memorySnapshots.reduce((sum, s) => sum + s.heapUsed, 0) / this.memorySnapshots.length;
|
|
424
|
-
const avgHeapTotal = this.memorySnapshots.reduce((sum, s) => sum + s.heapTotal, 0) / this.memorySnapshots.length;
|
|
425
|
-
const avgRss = this.memorySnapshots.reduce((sum, s) => sum + s.rss, 0) / this.memorySnapshots.length;
|
|
426
|
-
let trend = "stable";
|
|
427
|
-
if (this.memorySnapshots.length >= 5) {
|
|
428
|
-
const recent = this.memorySnapshots.slice(-5);
|
|
429
|
-
const first = recent[0].heapUsed;
|
|
430
|
-
const last = recent[recent.length - 1].heapUsed;
|
|
431
|
-
const change = (last - first) / first;
|
|
432
|
-
if (change > 0.1)
|
|
433
|
-
trend = "increasing";
|
|
434
|
-
else if (change < -0.1)
|
|
435
|
-
trend = "decreasing";
|
|
436
|
-
}
|
|
437
|
-
return {
|
|
438
|
-
current,
|
|
439
|
-
peak,
|
|
440
|
-
average: {
|
|
441
|
-
heapUsed: avgHeapUsed,
|
|
442
|
-
heapTotal: avgHeapTotal,
|
|
443
|
-
rss: avgRss
|
|
444
|
-
},
|
|
445
|
-
trend
|
|
446
|
-
};
|
|
447
|
-
}
|
|
448
|
-
// ==========================================================================
|
|
449
|
-
// Event System
|
|
450
|
-
// ==========================================================================
|
|
451
|
-
/**
|
|
452
|
-
* Subscribe to metric events
|
|
453
|
-
*/
|
|
454
|
-
on(type, listener) {
|
|
455
|
-
if (!this.eventListeners.has(type)) {
|
|
456
|
-
this.eventListeners.set(type, /* @__PURE__ */ new Set());
|
|
457
|
-
}
|
|
458
|
-
this.eventListeners.get(type).add(listener);
|
|
459
|
-
return () => {
|
|
460
|
-
this.eventListeners.get(type)?.delete(listener);
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
/**
|
|
464
|
-
* Emit a metric event
|
|
465
|
-
*/
|
|
466
|
-
emit(type, data) {
|
|
467
|
-
const event = { type, timestamp: Date.now(), data };
|
|
468
|
-
this.eventListeners.get(type)?.forEach((listener) => {
|
|
469
|
-
try {
|
|
470
|
-
listener(event);
|
|
471
|
-
} catch {
|
|
472
|
-
}
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
// ==========================================================================
|
|
476
|
-
// Threshold System
|
|
477
|
-
// ==========================================================================
|
|
478
|
-
/**
|
|
479
|
-
* Add a threshold configuration
|
|
480
|
-
*/
|
|
481
|
-
addThreshold(config) {
|
|
482
|
-
this.thresholds.push(config);
|
|
483
|
-
}
|
|
484
|
-
/**
|
|
485
|
-
* Remove a threshold configuration
|
|
486
|
-
*/
|
|
487
|
-
removeThreshold(metric) {
|
|
488
|
-
this.thresholds = this.thresholds.filter((t) => t.metric !== metric);
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* Check thresholds and emit alerts
|
|
492
|
-
*/
|
|
493
|
-
checkThresholds(metric, value) {
|
|
494
|
-
for (const threshold of this.thresholds) {
|
|
495
|
-
if (threshold.metric !== metric)
|
|
496
|
-
continue;
|
|
497
|
-
let exceeded = false;
|
|
498
|
-
let level = "warning";
|
|
499
|
-
const checkValue = (limit, comparison) => {
|
|
500
|
-
switch (comparison) {
|
|
501
|
-
case "gt":
|
|
502
|
-
return value > limit;
|
|
503
|
-
case "lt":
|
|
504
|
-
return value < limit;
|
|
505
|
-
case "gte":
|
|
506
|
-
return value >= limit;
|
|
507
|
-
case "lte":
|
|
508
|
-
return value <= limit;
|
|
509
|
-
case "eq":
|
|
510
|
-
return value === limit;
|
|
511
|
-
default:
|
|
512
|
-
return false;
|
|
513
|
-
}
|
|
514
|
-
};
|
|
515
|
-
if (checkValue(threshold.critical, threshold.comparison)) {
|
|
516
|
-
exceeded = true;
|
|
517
|
-
level = "critical";
|
|
518
|
-
} else if (checkValue(threshold.warning, threshold.comparison)) {
|
|
519
|
-
exceeded = true;
|
|
520
|
-
level = "warning";
|
|
521
|
-
}
|
|
522
|
-
if (exceeded) {
|
|
523
|
-
const alert = {
|
|
524
|
-
threshold,
|
|
525
|
-
currentValue: value,
|
|
526
|
-
level,
|
|
527
|
-
timestamp: Date.now(),
|
|
528
|
-
message: `${metric} ${level}: ${value} (threshold: ${level === "critical" ? threshold.critical : threshold.warning})`
|
|
529
|
-
};
|
|
530
|
-
this.emit("threshold:exceeded", alert);
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
// ==========================================================================
|
|
535
|
-
// Utility Methods
|
|
536
|
-
// ==========================================================================
|
|
537
|
-
/**
|
|
538
|
-
* Calculate percentile from sorted array
|
|
539
|
-
*/
|
|
540
|
-
calculatePercentile(sortedValues, percentile) {
|
|
541
|
-
if (sortedValues.length === 0)
|
|
542
|
-
return 0;
|
|
543
|
-
const index = Math.ceil(percentile / 100 * sortedValues.length) - 1;
|
|
544
|
-
return sortedValues[Math.max(0, index)];
|
|
545
|
-
}
|
|
546
|
-
/**
|
|
547
|
-
* Trim history arrays to max records
|
|
548
|
-
*/
|
|
549
|
-
trimHistory(array) {
|
|
550
|
-
const cutoff = Date.now() - this.config.retentionPeriod;
|
|
551
|
-
while (array.length > 0) {
|
|
552
|
-
const timestamp = array[0].timestamp || array[0].startTime || 0;
|
|
553
|
-
if (timestamp < cutoff) {
|
|
554
|
-
array.shift();
|
|
555
|
-
} else {
|
|
556
|
-
break;
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
while (array.length > this.config.maxRecords) {
|
|
560
|
-
array.shift();
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
/**
|
|
564
|
-
* Calculate aggregated statistics
|
|
565
|
-
*/
|
|
566
|
-
aggregate(values) {
|
|
567
|
-
if (values.length === 0) {
|
|
568
|
-
return {
|
|
569
|
-
min: 0,
|
|
570
|
-
max: 0,
|
|
571
|
-
avg: 0,
|
|
572
|
-
median: 0,
|
|
573
|
-
p95: 0,
|
|
574
|
-
p99: 0,
|
|
575
|
-
sum: 0,
|
|
576
|
-
count: 0,
|
|
577
|
-
stdDev: 0
|
|
578
|
-
};
|
|
579
|
-
}
|
|
580
|
-
const sorted = [...values].sort((a, b) => a - b);
|
|
581
|
-
const sum = values.reduce((a, b) => a + b, 0);
|
|
582
|
-
const avg = sum / values.length;
|
|
583
|
-
const squaredDiffs = values.map((v) => (v - avg) ** 2);
|
|
584
|
-
const avgSquaredDiff = squaredDiffs.reduce((a, b) => a + b, 0) / values.length;
|
|
585
|
-
const stdDev = Math.sqrt(avgSquaredDiff);
|
|
586
|
-
return {
|
|
587
|
-
min: sorted[0],
|
|
588
|
-
max: sorted[sorted.length - 1],
|
|
589
|
-
avg,
|
|
590
|
-
median: this.calculatePercentile(sorted, 50),
|
|
591
|
-
p95: this.calculatePercentile(sorted, 95),
|
|
592
|
-
p99: this.calculatePercentile(sorted, 99),
|
|
593
|
-
sum,
|
|
594
|
-
count: values.length,
|
|
595
|
-
stdDev
|
|
596
|
-
};
|
|
597
|
-
}
|
|
598
|
-
/**
|
|
599
|
-
* Get uptime in milliseconds
|
|
600
|
-
*/
|
|
601
|
-
getUptime() {
|
|
602
|
-
return Date.now() - this.startTime;
|
|
603
|
-
}
|
|
604
|
-
/**
|
|
605
|
-
* Export all metrics data
|
|
606
|
-
*/
|
|
607
|
-
exportData() {
|
|
608
|
-
return {
|
|
609
|
-
version: "1.0.0",
|
|
610
|
-
savedAt: Date.now(),
|
|
611
|
-
commands: this.commandHistory,
|
|
612
|
-
apiCalls: this.apiHistory,
|
|
613
|
-
cacheOps: this.cacheOperations,
|
|
614
|
-
errors: this.errors,
|
|
615
|
-
agentTasks: this.agentHistory,
|
|
616
|
-
memorySnapshots: this.memorySnapshots
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
|
-
/**
|
|
620
|
-
* Import metrics data
|
|
621
|
-
*/
|
|
622
|
-
importData(data) {
|
|
623
|
-
this.commandHistory = data.commands || [];
|
|
624
|
-
this.apiHistory = data.apiCalls || [];
|
|
625
|
-
this.cacheOperations = data.cacheOps || [];
|
|
626
|
-
this.errors = data.errors || [];
|
|
627
|
-
this.agentHistory = data.agentTasks || [];
|
|
628
|
-
this.memorySnapshots = data.memorySnapshots || [];
|
|
629
|
-
}
|
|
630
|
-
/**
|
|
631
|
-
* Clear all metrics
|
|
632
|
-
*/
|
|
633
|
-
clear() {
|
|
634
|
-
this.commands.clear();
|
|
635
|
-
this.commandHistory = [];
|
|
636
|
-
this.apiCalls.clear();
|
|
637
|
-
this.apiHistory = [];
|
|
638
|
-
this.cacheOperations = [];
|
|
639
|
-
this.errors = [];
|
|
640
|
-
this.agentTasks.clear();
|
|
641
|
-
this.agentHistory = [];
|
|
642
|
-
this.memorySnapshots = [];
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
let globalCollector;
|
|
646
|
-
function getMetricsCollector(config) {
|
|
647
|
-
if (!globalCollector) {
|
|
648
|
-
globalCollector = new MetricsCollector(config);
|
|
649
|
-
}
|
|
650
|
-
return globalCollector;
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
const DEFAULT_CONFIG = {
|
|
654
|
-
refreshInterval: 2e3,
|
|
655
|
-
showCommands: true,
|
|
656
|
-
showMemory: true,
|
|
657
|
-
showApi: true,
|
|
658
|
-
showCache: true,
|
|
659
|
-
showErrors: true,
|
|
660
|
-
showAgents: true,
|
|
661
|
-
chartWidth: 40,
|
|
662
|
-
chartHeight: 8,
|
|
663
|
-
colorScheme: "default"
|
|
664
|
-
};
|
|
665
|
-
function generateBarChart(data, options = {}) {
|
|
666
|
-
const { width = 30, showValues = true } = options;
|
|
667
|
-
const maxValue = options.maxValue || Math.max(...data.map((d) => d.value), 1);
|
|
668
|
-
const maxLabelLength = Math.max(...data.map((d) => d.label.length), 10);
|
|
669
|
-
const lines = [];
|
|
670
|
-
for (const item of data) {
|
|
671
|
-
const barLength = Math.round(item.value / maxValue * width);
|
|
672
|
-
const bar = a.green("\u2588".repeat(barLength)) + a.dim("\u2591".repeat(width - barLength));
|
|
673
|
-
const label = item.label.padEnd(maxLabelLength);
|
|
674
|
-
const value = showValues ? ` ${item.value.toFixed(0)}` : "";
|
|
675
|
-
lines.push(` ${a.cyan(label)} ${bar}${a.yellow(value)}`);
|
|
676
|
-
}
|
|
677
|
-
return lines;
|
|
678
|
-
}
|
|
679
|
-
function generateSparkline(values, width = 20) {
|
|
680
|
-
if (values.length === 0)
|
|
681
|
-
return a.dim("\u2500".repeat(width));
|
|
682
|
-
const chars = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
|
|
683
|
-
const min = Math.min(...values);
|
|
684
|
-
const max = Math.max(...values);
|
|
685
|
-
const range = max - min || 1;
|
|
686
|
-
const step = Math.max(1, Math.floor(values.length / width));
|
|
687
|
-
const sampled = values.filter((_, i) => i % step === 0).slice(-width);
|
|
688
|
-
return sampled.map((v) => {
|
|
689
|
-
const normalized = (v - min) / range;
|
|
690
|
-
const index = Math.min(Math.floor(normalized * chars.length), chars.length - 1);
|
|
691
|
-
return a.green(chars[index]);
|
|
692
|
-
}).join("");
|
|
693
|
-
}
|
|
694
|
-
function generateProgressBar(value, max, width = 20, options = {}) {
|
|
695
|
-
const { showPercent = true, colorThresholds } = options;
|
|
696
|
-
const percent = Math.min(value / max, 1);
|
|
697
|
-
const filled = Math.round(percent * width);
|
|
698
|
-
const empty = width - filled;
|
|
699
|
-
let color = a.green;
|
|
700
|
-
if (colorThresholds) {
|
|
701
|
-
if (percent >= colorThresholds.critical)
|
|
702
|
-
color = a.red;
|
|
703
|
-
else if (percent >= colorThresholds.warning)
|
|
704
|
-
color = a.yellow;
|
|
705
|
-
}
|
|
706
|
-
const bar = color("\u2588".repeat(filled)) + a.dim("\u2591".repeat(empty));
|
|
707
|
-
const percentStr = showPercent ? ` ${(percent * 100).toFixed(1)}%` : "";
|
|
708
|
-
return `[${bar}]${a.yellow(percentStr)}`;
|
|
709
|
-
}
|
|
710
|
-
function formatDuration(ms) {
|
|
711
|
-
if (ms < 1e3)
|
|
712
|
-
return `${ms.toFixed(0)}ms`;
|
|
713
|
-
if (ms < 6e4)
|
|
714
|
-
return `${(ms / 1e3).toFixed(1)}s`;
|
|
715
|
-
if (ms < 36e5)
|
|
716
|
-
return `${(ms / 6e4).toFixed(1)}m`;
|
|
717
|
-
return `${(ms / 36e5).toFixed(1)}h`;
|
|
718
|
-
}
|
|
719
|
-
function formatBytes(bytes) {
|
|
720
|
-
if (bytes < 1024)
|
|
721
|
-
return `${bytes}B`;
|
|
722
|
-
if (bytes < 1024 * 1024)
|
|
723
|
-
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
724
|
-
if (bytes < 1024 * 1024 * 1024)
|
|
725
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
726
|
-
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)}GB`;
|
|
727
|
-
}
|
|
728
|
-
function formatUptime(ms) {
|
|
729
|
-
const seconds = Math.floor(ms / 1e3);
|
|
730
|
-
const minutes = Math.floor(seconds / 60);
|
|
731
|
-
const hours = Math.floor(minutes / 60);
|
|
732
|
-
const days = Math.floor(hours / 24);
|
|
733
|
-
if (days > 0)
|
|
734
|
-
return `${days}d ${hours % 24}h ${minutes % 60}m`;
|
|
735
|
-
if (hours > 0)
|
|
736
|
-
return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
|
|
737
|
-
if (minutes > 0)
|
|
738
|
-
return `${minutes}m ${seconds % 60}s`;
|
|
739
|
-
return `${seconds}s`;
|
|
740
|
-
}
|
|
741
|
-
function getHealthColor(status) {
|
|
742
|
-
switch (status) {
|
|
743
|
-
case "healthy":
|
|
744
|
-
return a.green;
|
|
745
|
-
case "degraded":
|
|
746
|
-
return a.yellow;
|
|
747
|
-
case "unhealthy":
|
|
748
|
-
return a.red;
|
|
749
|
-
case "critical":
|
|
750
|
-
return a.red.bold;
|
|
751
|
-
default:
|
|
752
|
-
return a.gray;
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
function getHealthIcon(status) {
|
|
756
|
-
switch (status) {
|
|
757
|
-
case "healthy":
|
|
758
|
-
return a.green("\u25CF");
|
|
759
|
-
case "degraded":
|
|
760
|
-
return a.yellow("\u25D0");
|
|
761
|
-
case "unhealthy":
|
|
762
|
-
return a.red("\u25CB");
|
|
763
|
-
case "critical":
|
|
764
|
-
return a.red.bold("\u2716");
|
|
765
|
-
default:
|
|
766
|
-
return a.gray("?");
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
class DashboardRenderer {
|
|
770
|
-
config;
|
|
771
|
-
collector;
|
|
772
|
-
memoryHistory = [];
|
|
773
|
-
apiLatencyHistory = [];
|
|
774
|
-
constructor(config, collector) {
|
|
775
|
-
this.config = config;
|
|
776
|
-
this.collector = collector;
|
|
777
|
-
}
|
|
778
|
-
/**
|
|
779
|
-
* Render the complete dashboard
|
|
780
|
-
*/
|
|
781
|
-
render() {
|
|
782
|
-
const lines = [];
|
|
783
|
-
lines.push(...this.renderHeader());
|
|
784
|
-
lines.push("");
|
|
785
|
-
lines.push(...this.renderSystemOverview());
|
|
786
|
-
lines.push("");
|
|
787
|
-
const leftColumn = [];
|
|
788
|
-
const rightColumn = [];
|
|
789
|
-
if (this.config.showMemory) {
|
|
790
|
-
leftColumn.push(...this.renderMemorySection());
|
|
791
|
-
leftColumn.push("");
|
|
792
|
-
}
|
|
793
|
-
if (this.config.showApi) {
|
|
794
|
-
leftColumn.push(...this.renderApiSection());
|
|
795
|
-
leftColumn.push("");
|
|
796
|
-
}
|
|
797
|
-
if (this.config.showCommands) {
|
|
798
|
-
rightColumn.push(...this.renderCommandsSection());
|
|
799
|
-
rightColumn.push("");
|
|
800
|
-
}
|
|
801
|
-
if (this.config.showCache) {
|
|
802
|
-
rightColumn.push(...this.renderCacheSection());
|
|
803
|
-
rightColumn.push("");
|
|
804
|
-
}
|
|
805
|
-
const maxLines = Math.max(leftColumn.length, rightColumn.length);
|
|
806
|
-
for (let i = 0; i < maxLines; i++) {
|
|
807
|
-
const left = (leftColumn[i] || "").padEnd(50);
|
|
808
|
-
const right = rightColumn[i] || "";
|
|
809
|
-
lines.push(`${left} ${right}`);
|
|
810
|
-
}
|
|
811
|
-
if (this.config.showErrors) {
|
|
812
|
-
lines.push("");
|
|
813
|
-
lines.push(...this.renderErrorsSection());
|
|
814
|
-
}
|
|
815
|
-
if (this.config.showAgents) {
|
|
816
|
-
lines.push("");
|
|
817
|
-
lines.push(...this.renderAgentsSection());
|
|
818
|
-
}
|
|
819
|
-
lines.push("");
|
|
820
|
-
lines.push(...this.renderFooter());
|
|
821
|
-
return lines.join("\n");
|
|
822
|
-
}
|
|
823
|
-
/**
|
|
824
|
-
* Render dashboard header
|
|
825
|
-
*/
|
|
826
|
-
renderHeader() {
|
|
827
|
-
const title = a.bold.cyan("CCJK Performance Monitor");
|
|
828
|
-
const time = a.dim((/* @__PURE__ */ new Date()).toLocaleString());
|
|
829
|
-
const separator = a.dim("\u2550".repeat(80));
|
|
830
|
-
return [
|
|
831
|
-
separator,
|
|
832
|
-
` ${title}${" ".repeat(80 - 30 - time.length)}${time}`,
|
|
833
|
-
separator
|
|
834
|
-
];
|
|
835
|
-
}
|
|
836
|
-
/**
|
|
837
|
-
* Render system overview section
|
|
838
|
-
*/
|
|
839
|
-
renderSystemOverview() {
|
|
840
|
-
const memStats = this.collector.getMemoryStats();
|
|
841
|
-
const uptime = this.collector.getUptime();
|
|
842
|
-
const errorStats = this.collector.getErrorStats();
|
|
843
|
-
let health = "healthy";
|
|
844
|
-
if (errorStats.errorsBySeverity.critical > 0)
|
|
845
|
-
health = "critical";
|
|
846
|
-
else if (errorStats.errorsBySeverity.high > 0)
|
|
847
|
-
health = "unhealthy";
|
|
848
|
-
else if (memStats.current.heapUsedPercent > 0.9)
|
|
849
|
-
health = "degraded";
|
|
850
|
-
const healthColor = getHealthColor(health);
|
|
851
|
-
const healthIcon = getHealthIcon(health);
|
|
852
|
-
return [
|
|
853
|
-
a.bold.white(" System Overview"),
|
|
854
|
-
a.dim(` ${"\u2500".repeat(40)}`),
|
|
855
|
-
` ${healthIcon} Status: ${healthColor(health.toUpperCase())}`,
|
|
856
|
-
` ${a.cyan("\u23F1")} Uptime: ${a.yellow(formatUptime(uptime))}`,
|
|
857
|
-
` ${a.cyan("\u{1F4CA}")} Memory: ${formatBytes(memStats.current.heapUsed)} / ${formatBytes(memStats.current.heapTotal)}`,
|
|
858
|
-
` ${a.cyan("\u26A0")} Errors: ${errorStats.totalErrors > 0 ? a.red(errorStats.totalErrors.toString()) : a.green("0")}`
|
|
859
|
-
];
|
|
860
|
-
}
|
|
861
|
-
/**
|
|
862
|
-
* Render memory section
|
|
863
|
-
*/
|
|
864
|
-
renderMemorySection() {
|
|
865
|
-
const stats = this.collector.getMemoryStats();
|
|
866
|
-
this.memoryHistory.push(stats.current.heapUsedPercent * 100);
|
|
867
|
-
if (this.memoryHistory.length > 60)
|
|
868
|
-
this.memoryHistory.shift();
|
|
869
|
-
const lines = [
|
|
870
|
-
a.bold.white(" Memory Usage"),
|
|
871
|
-
a.dim(` ${"\u2500".repeat(40)}`)
|
|
872
|
-
];
|
|
873
|
-
const memBar = generateProgressBar(
|
|
874
|
-
stats.current.heapUsed,
|
|
875
|
-
stats.current.heapTotal,
|
|
876
|
-
30,
|
|
877
|
-
{ colorThresholds: { warning: 0.7, critical: 0.9 } }
|
|
878
|
-
);
|
|
879
|
-
lines.push(` Heap: ${memBar}`);
|
|
880
|
-
lines.push(` ${a.dim("Used:")} ${a.yellow(formatBytes(stats.current.heapUsed))}`);
|
|
881
|
-
lines.push(` ${a.dim("Total:")} ${a.yellow(formatBytes(stats.current.heapTotal))}`);
|
|
882
|
-
lines.push(` ${a.dim("RSS:")} ${a.yellow(formatBytes(stats.current.rss))}`);
|
|
883
|
-
const trendIcon = stats.trend === "increasing" ? a.red("\u2191") : stats.trend === "decreasing" ? a.green("\u2193") : a.gray("\u2192");
|
|
884
|
-
lines.push(` ${a.dim("Trend:")} ${trendIcon} ${stats.trend}`);
|
|
885
|
-
lines.push(` ${a.dim("History:")} ${generateSparkline(this.memoryHistory, 30)}`);
|
|
886
|
-
return lines;
|
|
887
|
-
}
|
|
888
|
-
/**
|
|
889
|
-
* Render API section
|
|
890
|
-
*/
|
|
891
|
-
renderApiSection() {
|
|
892
|
-
const stats = this.collector.getApiStats();
|
|
893
|
-
const lines = [
|
|
894
|
-
a.bold.white(" API Performance"),
|
|
895
|
-
a.dim(` ${"\u2500".repeat(40)}`)
|
|
896
|
-
];
|
|
897
|
-
if (stats.length === 0) {
|
|
898
|
-
lines.push(a.dim(" No API calls recorded"));
|
|
899
|
-
return lines;
|
|
900
|
-
}
|
|
901
|
-
const avgLatency = stats.reduce((sum, s) => sum + s.avgLatency, 0) / stats.length;
|
|
902
|
-
this.apiLatencyHistory.push(avgLatency);
|
|
903
|
-
if (this.apiLatencyHistory.length > 60)
|
|
904
|
-
this.apiLatencyHistory.shift();
|
|
905
|
-
for (const provider of stats.slice(0, 3)) {
|
|
906
|
-
const successRate = provider.totalCalls > 0 ? (provider.successCount / provider.totalCalls * 100).toFixed(1) : "0";
|
|
907
|
-
const rateColor = Number(successRate) >= 95 ? a.green : Number(successRate) >= 80 ? a.yellow : a.red;
|
|
908
|
-
lines.push(` ${a.cyan(provider.provider)}`);
|
|
909
|
-
lines.push(` ${a.dim("Calls:")} ${provider.totalCalls} | ${a.dim("Success:")} ${rateColor(`${successRate}%`)}`);
|
|
910
|
-
lines.push(` ${a.dim("Latency:")} ${a.yellow(formatDuration(provider.avgLatency))} (p95: ${formatDuration(provider.p95Latency)})`);
|
|
911
|
-
}
|
|
912
|
-
lines.push(` ${a.dim("Latency:")} ${generateSparkline(this.apiLatencyHistory, 30)}`);
|
|
913
|
-
return lines;
|
|
914
|
-
}
|
|
915
|
-
/**
|
|
916
|
-
* Render commands section
|
|
917
|
-
*/
|
|
918
|
-
renderCommandsSection() {
|
|
919
|
-
const stats = this.collector.getCommandStats();
|
|
920
|
-
const lines = [
|
|
921
|
-
a.bold.white(" Command Execution"),
|
|
922
|
-
a.dim(` ${"\u2500".repeat(40)}`)
|
|
923
|
-
];
|
|
924
|
-
if (stats.length === 0) {
|
|
925
|
-
lines.push(a.dim(" No commands recorded"));
|
|
926
|
-
return lines;
|
|
927
|
-
}
|
|
928
|
-
const sorted = [...stats].sort((a, b) => b.totalExecutions - a.totalExecutions).slice(0, 5);
|
|
929
|
-
const chartData = sorted.map((s) => ({
|
|
930
|
-
label: s.command.slice(0, 15),
|
|
931
|
-
value: s.totalExecutions
|
|
932
|
-
}));
|
|
933
|
-
lines.push(...generateBarChart(chartData, { width: 20 }));
|
|
934
|
-
const totalExecs = stats.reduce((sum, s) => sum + s.totalExecutions, 0);
|
|
935
|
-
const totalSuccess = stats.reduce((sum, s) => sum + s.successCount, 0);
|
|
936
|
-
const successRate = totalExecs > 0 ? (totalSuccess / totalExecs * 100).toFixed(1) : "0";
|
|
937
|
-
lines.push("");
|
|
938
|
-
lines.push(` ${a.dim("Total:")} ${totalExecs} | ${a.dim("Success:")} ${a.green(`${successRate}%`)}`);
|
|
939
|
-
return lines;
|
|
940
|
-
}
|
|
941
|
-
/**
|
|
942
|
-
* Render cache section
|
|
943
|
-
*/
|
|
944
|
-
renderCacheSection() {
|
|
945
|
-
const stats = this.collector.getCacheStats();
|
|
946
|
-
const lines = [
|
|
947
|
-
a.bold.white(" Cache Performance"),
|
|
948
|
-
a.dim(` ${"\u2500".repeat(40)}`)
|
|
949
|
-
];
|
|
950
|
-
const hitRateBar = generateProgressBar(stats.hitRate, 1, 20, { showPercent: true });
|
|
951
|
-
lines.push(` Hit Rate: ${hitRateBar}`);
|
|
952
|
-
lines.push(` ${a.dim("Hits:")} ${a.green(stats.hits.toString())} | ${a.dim("Misses:")} ${a.red(stats.misses.toString())}`);
|
|
953
|
-
lines.push(` ${a.dim("Avg Latency:")} ${a.yellow(formatDuration(stats.avgLatency))}`);
|
|
954
|
-
lines.push(` ${a.dim("Items:")} ${stats.itemCount} | ${a.dim("Size:")} ${formatBytes(stats.totalSize)}`);
|
|
955
|
-
return lines;
|
|
956
|
-
}
|
|
957
|
-
/**
|
|
958
|
-
* Render errors section
|
|
959
|
-
*/
|
|
960
|
-
renderErrorsSection() {
|
|
961
|
-
const stats = this.collector.getErrorStats();
|
|
962
|
-
const lines = [
|
|
963
|
-
a.bold.white(" Recent Errors"),
|
|
964
|
-
a.dim(` ${"\u2500".repeat(76)}`)
|
|
965
|
-
];
|
|
966
|
-
if (stats.totalErrors === 0) {
|
|
967
|
-
lines.push(a.green(" No errors recorded"));
|
|
968
|
-
return lines;
|
|
969
|
-
}
|
|
970
|
-
const severityLine = [
|
|
971
|
-
`${a.red("Critical:")} ${stats.errorsBySeverity.critical}`,
|
|
972
|
-
`${a.red("High:")} ${stats.errorsBySeverity.high}`,
|
|
973
|
-
`${a.yellow("Medium:")} ${stats.errorsBySeverity.medium}`,
|
|
974
|
-
`${a.green("Low:")} ${stats.errorsBySeverity.low}`
|
|
975
|
-
].join(" | ");
|
|
976
|
-
lines.push(` ${severityLine}`);
|
|
977
|
-
lines.push("");
|
|
978
|
-
for (const error of stats.recentErrors.slice(0, 3)) {
|
|
979
|
-
const severityIcon = error.severity === "critical" ? a.red("\u25CF") : error.severity === "high" ? a.red("\u25CB") : error.severity === "medium" ? a.yellow("\u25CB") : a.green("\u25CB");
|
|
980
|
-
const time = new Date(error.timestamp).toLocaleTimeString();
|
|
981
|
-
lines.push(` ${severityIcon} ${a.dim(time)} ${a.cyan(error.type)}: ${error.message.slice(0, 50)}`);
|
|
982
|
-
}
|
|
983
|
-
return lines;
|
|
984
|
-
}
|
|
985
|
-
/**
|
|
986
|
-
* Render agents section
|
|
987
|
-
*/
|
|
988
|
-
renderAgentsSection() {
|
|
989
|
-
const stats = this.collector.getAgentStats();
|
|
990
|
-
const lines = [
|
|
991
|
-
a.bold.white(" Agent Tasks"),
|
|
992
|
-
a.dim(` ${"\u2500".repeat(76)}`)
|
|
993
|
-
];
|
|
994
|
-
if (stats.length === 0) {
|
|
995
|
-
lines.push(a.dim(" No agent tasks recorded"));
|
|
996
|
-
return lines;
|
|
997
|
-
}
|
|
998
|
-
lines.push(` ${a.dim("Agent".padEnd(30))} ${a.dim("Tasks".padEnd(8))} ${a.dim("Success".padEnd(10))} ${a.dim("Avg Time")}`);
|
|
999
|
-
for (const agent of stats.slice(0, 5)) {
|
|
1000
|
-
const successRate = `${(agent.successRate * 100).toFixed(0)}%`;
|
|
1001
|
-
const rateColor = agent.successRate >= 0.95 ? a.green : agent.successRate >= 0.8 ? a.yellow : a.red;
|
|
1002
|
-
lines.push(
|
|
1003
|
-
` ${a.cyan(agent.agentName.slice(0, 28).padEnd(30))} ${agent.totalTasks.toString().padEnd(8)} ${rateColor(successRate.padEnd(10))} ${a.yellow(formatDuration(agent.avgDuration))}`
|
|
1004
|
-
);
|
|
1005
|
-
}
|
|
1006
|
-
return lines;
|
|
1007
|
-
}
|
|
1008
|
-
/**
|
|
1009
|
-
* Render footer
|
|
1010
|
-
*/
|
|
1011
|
-
renderFooter() {
|
|
1012
|
-
return [
|
|
1013
|
-
a.dim("\u2550".repeat(80)),
|
|
1014
|
-
a.dim(` Press Ctrl+C to exit | Refresh: ${this.config.refreshInterval / 1e3}s | ${(/* @__PURE__ */ new Date()).toISOString()}`)
|
|
1015
|
-
];
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
class PerformanceDashboard {
|
|
1019
|
-
config;
|
|
1020
|
-
collector;
|
|
1021
|
-
renderer;
|
|
1022
|
-
refreshTimer;
|
|
1023
|
-
isRunning = false;
|
|
1024
|
-
constructor(config = {}, collector) {
|
|
1025
|
-
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
1026
|
-
this.collector = collector || getMetricsCollector();
|
|
1027
|
-
this.renderer = new DashboardRenderer(this.config, this.collector);
|
|
1028
|
-
}
|
|
1029
|
-
/**
|
|
1030
|
-
* Show the dashboard
|
|
1031
|
-
*/
|
|
1032
|
-
show() {
|
|
1033
|
-
if (this.isRunning)
|
|
1034
|
-
return;
|
|
1035
|
-
this.isRunning = true;
|
|
1036
|
-
this.render();
|
|
1037
|
-
this.refreshTimer = setInterval(() => {
|
|
1038
|
-
this.render();
|
|
1039
|
-
}, this.config.refreshInterval);
|
|
1040
|
-
process__default.on("SIGINT", () => {
|
|
1041
|
-
this.stop();
|
|
1042
|
-
process__default.exit(0);
|
|
1043
|
-
});
|
|
1044
|
-
}
|
|
1045
|
-
/**
|
|
1046
|
-
* Refresh the dashboard
|
|
1047
|
-
*/
|
|
1048
|
-
refresh() {
|
|
1049
|
-
this.render();
|
|
1050
|
-
}
|
|
1051
|
-
/**
|
|
1052
|
-
* Render the dashboard to terminal
|
|
1053
|
-
*/
|
|
1054
|
-
render() {
|
|
1055
|
-
process__default.stdout.write("\x1B[2J\x1B[0f");
|
|
1056
|
-
const output = this.renderer.render();
|
|
1057
|
-
console.log(output);
|
|
1058
|
-
}
|
|
1059
|
-
/**
|
|
1060
|
-
* Stop the dashboard
|
|
1061
|
-
*/
|
|
1062
|
-
stop() {
|
|
1063
|
-
this.isRunning = false;
|
|
1064
|
-
if (this.refreshTimer) {
|
|
1065
|
-
clearInterval(this.refreshTimer);
|
|
1066
|
-
this.refreshTimer = void 0;
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
/**
|
|
1070
|
-
* Export dashboard data
|
|
1071
|
-
*/
|
|
1072
|
-
export(format) {
|
|
1073
|
-
const data = this.collectData();
|
|
1074
|
-
switch (format) {
|
|
1075
|
-
case "json":
|
|
1076
|
-
return this.exportJson(data);
|
|
1077
|
-
case "csv":
|
|
1078
|
-
return this.exportCsv(data);
|
|
1079
|
-
case "html":
|
|
1080
|
-
return this.exportHtml(data);
|
|
1081
|
-
default:
|
|
1082
|
-
return this.exportJson(data);
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
/**
|
|
1086
|
-
* Collect current dashboard data
|
|
1087
|
-
*/
|
|
1088
|
-
collectData() {
|
|
1089
|
-
const memStats = this.collector.getMemoryStats();
|
|
1090
|
-
const errorStats = this.collector.getErrorStats();
|
|
1091
|
-
let health = "healthy";
|
|
1092
|
-
if (errorStats.errorsBySeverity.critical > 0)
|
|
1093
|
-
health = "critical";
|
|
1094
|
-
else if (errorStats.errorsBySeverity.high > 0)
|
|
1095
|
-
health = "unhealthy";
|
|
1096
|
-
else if (memStats.current.heapUsedPercent > 0.9)
|
|
1097
|
-
health = "degraded";
|
|
1098
|
-
const system = {
|
|
1099
|
-
status: health,
|
|
1100
|
-
uptime: this.collector.getUptime(),
|
|
1101
|
-
startTime: Date.now() - this.collector.getUptime(),
|
|
1102
|
-
version: "1.0.0",
|
|
1103
|
-
nodeVersion: process__default.version,
|
|
1104
|
-
platform: process__default.platform,
|
|
1105
|
-
healthChecks: []
|
|
1106
|
-
};
|
|
1107
|
-
return {
|
|
1108
|
-
timestamp: Date.now(),
|
|
1109
|
-
system,
|
|
1110
|
-
commands: this.collector.getCommandStats(),
|
|
1111
|
-
memory: memStats,
|
|
1112
|
-
api: this.collector.getApiStats(),
|
|
1113
|
-
cache: this.collector.getCacheStats(),
|
|
1114
|
-
errors: errorStats,
|
|
1115
|
-
agents: this.collector.getAgentStats()
|
|
1116
|
-
};
|
|
1117
|
-
}
|
|
1118
|
-
/**
|
|
1119
|
-
* Export as JSON
|
|
1120
|
-
*/
|
|
1121
|
-
exportJson(data) {
|
|
1122
|
-
return JSON.stringify(data, null, 2);
|
|
1123
|
-
}
|
|
1124
|
-
/**
|
|
1125
|
-
* Export as CSV
|
|
1126
|
-
*/
|
|
1127
|
-
exportCsv(data) {
|
|
1128
|
-
const lines = [];
|
|
1129
|
-
lines.push("# Commands");
|
|
1130
|
-
lines.push("command,total,success,failure,avg_duration,p95_duration");
|
|
1131
|
-
for (const cmd of data.commands) {
|
|
1132
|
-
lines.push(`${cmd.command},${cmd.totalExecutions},${cmd.successCount},${cmd.failureCount},${cmd.avgDuration},${cmd.p95Duration}`);
|
|
1133
|
-
}
|
|
1134
|
-
lines.push("");
|
|
1135
|
-
lines.push("# API Calls");
|
|
1136
|
-
lines.push("provider,total,success,failure,avg_latency,p95_latency,tokens");
|
|
1137
|
-
for (const api of data.api) {
|
|
1138
|
-
lines.push(`${api.provider},${api.totalCalls},${api.successCount},${api.failureCount},${api.avgLatency},${api.p95Latency},${api.totalTokens}`);
|
|
1139
|
-
}
|
|
1140
|
-
lines.push("");
|
|
1141
|
-
lines.push("# Memory");
|
|
1142
|
-
lines.push("heap_used,heap_total,rss,heap_percent");
|
|
1143
|
-
lines.push(`${data.memory.current.heapUsed},${data.memory.current.heapTotal},${data.memory.current.rss},${data.memory.current.heapUsedPercent}`);
|
|
1144
|
-
return lines.join("\n");
|
|
1145
|
-
}
|
|
1146
|
-
/**
|
|
1147
|
-
* Export as HTML
|
|
1148
|
-
*/
|
|
1149
|
-
exportHtml(data) {
|
|
1150
|
-
return `<!DOCTYPE html>
|
|
1151
|
-
<html>
|
|
1152
|
-
<head>
|
|
1153
|
-
<title>CCJK Performance Report</title>
|
|
1154
|
-
<style>
|
|
1155
|
-
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 20px; background: #1a1a2e; color: #eee; }
|
|
1156
|
-
h1 { color: #00d9ff; }
|
|
1157
|
-
h2 { color: #00ff88; border-bottom: 1px solid #333; padding-bottom: 10px; }
|
|
1158
|
-
.card { background: #16213e; border-radius: 8px; padding: 20px; margin: 20px 0; }
|
|
1159
|
-
.metric { display: inline-block; margin: 10px 20px; }
|
|
1160
|
-
.metric-value { font-size: 2em; color: #00d9ff; }
|
|
1161
|
-
.metric-label { color: #888; }
|
|
1162
|
-
table { width: 100%; border-collapse: collapse; }
|
|
1163
|
-
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #333; }
|
|
1164
|
-
th { color: #00ff88; }
|
|
1165
|
-
.status-healthy { color: #00ff88; }
|
|
1166
|
-
.status-degraded { color: #ffaa00; }
|
|
1167
|
-
.status-unhealthy { color: #ff4444; }
|
|
1168
|
-
</style>
|
|
1169
|
-
</head>
|
|
1170
|
-
<body>
|
|
1171
|
-
<h1>CCJK Performance Report</h1>
|
|
1172
|
-
<p>Generated: ${new Date(data.timestamp).toLocaleString()}</p>
|
|
1173
|
-
|
|
1174
|
-
<div class="card">
|
|
1175
|
-
<h2>System Overview</h2>
|
|
1176
|
-
<div class="metric">
|
|
1177
|
-
<div class="metric-value status-${data.system.status}">${data.system.status.toUpperCase()}</div>
|
|
1178
|
-
<div class="metric-label">Status</div>
|
|
1179
|
-
</div>
|
|
1180
|
-
<div class="metric">
|
|
1181
|
-
<div class="metric-value">${formatUptime(data.system.uptime)}</div>
|
|
1182
|
-
<div class="metric-label">Uptime</div>
|
|
1183
|
-
</div>
|
|
1184
|
-
<div class="metric">
|
|
1185
|
-
<div class="metric-value">${formatBytes(data.memory.current.heapUsed)}</div>
|
|
1186
|
-
<div class="metric-label">Memory Used</div>
|
|
1187
|
-
</div>
|
|
1188
|
-
<div class="metric">
|
|
1189
|
-
<div class="metric-value">${data.errors.totalErrors}</div>
|
|
1190
|
-
<div class="metric-label">Total Errors</div>
|
|
1191
|
-
</div>
|
|
1192
|
-
</div>
|
|
1193
|
-
|
|
1194
|
-
<div class="card">
|
|
1195
|
-
<h2>Command Statistics</h2>
|
|
1196
|
-
<table>
|
|
1197
|
-
<tr><th>Command</th><th>Total</th><th>Success</th><th>Failure</th><th>Avg Duration</th></tr>
|
|
1198
|
-
${data.commands.map((c) => `<tr><td>${c.command}</td><td>${c.totalExecutions}</td><td>${c.successCount}</td><td>${c.failureCount}</td><td>${formatDuration(c.avgDuration)}</td></tr>`).join("")}
|
|
1199
|
-
</table>
|
|
1200
|
-
</div>
|
|
1201
|
-
|
|
1202
|
-
<div class="card">
|
|
1203
|
-
<h2>API Performance</h2>
|
|
1204
|
-
<table>
|
|
1205
|
-
<tr><th>Provider</th><th>Calls</th><th>Success Rate</th><th>Avg Latency</th><th>Tokens</th></tr>
|
|
1206
|
-
${data.api.map((a) => `<tr><td>${a.provider}</td><td>${a.totalCalls}</td><td>${(a.successCount / a.totalCalls * 100).toFixed(1)}%</td><td>${formatDuration(a.avgLatency)}</td><td>${a.totalTokens}</td></tr>`).join("")}
|
|
1207
|
-
</table>
|
|
1208
|
-
</div>
|
|
1209
|
-
|
|
1210
|
-
<div class="card">
|
|
1211
|
-
<h2>Cache Statistics</h2>
|
|
1212
|
-
<div class="metric">
|
|
1213
|
-
<div class="metric-value">${(data.cache.hitRate * 100).toFixed(1)}%</div>
|
|
1214
|
-
<div class="metric-label">Hit Rate</div>
|
|
1215
|
-
</div>
|
|
1216
|
-
<div class="metric">
|
|
1217
|
-
<div class="metric-value">${data.cache.hits}</div>
|
|
1218
|
-
<div class="metric-label">Hits</div>
|
|
1219
|
-
</div>
|
|
1220
|
-
<div class="metric">
|
|
1221
|
-
<div class="metric-value">${data.cache.misses}</div>
|
|
1222
|
-
<div class="metric-label">Misses</div>
|
|
1223
|
-
</div>
|
|
1224
|
-
</div>
|
|
1225
|
-
</body>
|
|
1226
|
-
</html>`;
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
function createDashboard(config) {
|
|
1230
|
-
return new PerformanceDashboard(config);
|
|
1231
|
-
}
|
|
1232
|
-
|
|
1233
|
-
const DEFAULT_REPORT_CONFIG = {
|
|
1234
|
-
timeRange: "daily",
|
|
1235
|
-
includeCommands: true,
|
|
1236
|
-
includeMemory: true,
|
|
1237
|
-
includeApi: true,
|
|
1238
|
-
includeCache: true,
|
|
1239
|
-
includeErrors: true,
|
|
1240
|
-
includeAgents: true,
|
|
1241
|
-
includeTrends: true,
|
|
1242
|
-
includeAnomalies: true
|
|
1243
|
-
};
|
|
1244
|
-
function getTimeRangeBoundaries(range, custom) {
|
|
1245
|
-
const now = Date.now();
|
|
1246
|
-
const end = custom?.end || now;
|
|
1247
|
-
switch (range) {
|
|
1248
|
-
case "hourly":
|
|
1249
|
-
return { start: end - 60 * 60 * 1e3, end };
|
|
1250
|
-
case "daily":
|
|
1251
|
-
return { start: end - 24 * 60 * 60 * 1e3, end };
|
|
1252
|
-
case "weekly":
|
|
1253
|
-
return { start: end - 7 * 24 * 60 * 60 * 1e3, end };
|
|
1254
|
-
case "monthly":
|
|
1255
|
-
return { start: end - 30 * 24 * 60 * 60 * 1e3, end };
|
|
1256
|
-
case "custom":
|
|
1257
|
-
return {
|
|
1258
|
-
start: custom?.start || end - 24 * 60 * 60 * 1e3,
|
|
1259
|
-
end
|
|
1260
|
-
};
|
|
1261
|
-
default:
|
|
1262
|
-
return { start: end - 24 * 60 * 60 * 1e3, end };
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
function analyzeTrend(values, metricName) {
|
|
1266
|
-
if (values.length < 2) {
|
|
1267
|
-
return {
|
|
1268
|
-
metric: metricName,
|
|
1269
|
-
direction: "stable",
|
|
1270
|
-
changePercent: 0,
|
|
1271
|
-
significance: "low"
|
|
1272
|
-
};
|
|
1273
|
-
}
|
|
1274
|
-
const midpoint = Math.floor(values.length / 2);
|
|
1275
|
-
const firstHalf = values.slice(0, midpoint);
|
|
1276
|
-
const secondHalf = values.slice(midpoint);
|
|
1277
|
-
const firstAvg = firstHalf.reduce((a, b) => a + b, 0) / firstHalf.length;
|
|
1278
|
-
const secondAvg = secondHalf.reduce((a, b) => a + b, 0) / secondHalf.length;
|
|
1279
|
-
const changePercent = firstAvg !== 0 ? (secondAvg - firstAvg) / firstAvg * 100 : secondAvg > 0 ? 100 : 0;
|
|
1280
|
-
let direction = "stable";
|
|
1281
|
-
if (changePercent > 5)
|
|
1282
|
-
direction = "up";
|
|
1283
|
-
else if (changePercent < -5)
|
|
1284
|
-
direction = "down";
|
|
1285
|
-
let significance = "low";
|
|
1286
|
-
const absChange = Math.abs(changePercent);
|
|
1287
|
-
if (absChange > 50)
|
|
1288
|
-
significance = "high";
|
|
1289
|
-
else if (absChange > 20)
|
|
1290
|
-
significance = "medium";
|
|
1291
|
-
const slope = (secondAvg - firstAvg) / midpoint;
|
|
1292
|
-
const prediction = secondAvg + slope * midpoint;
|
|
1293
|
-
return {
|
|
1294
|
-
metric: metricName,
|
|
1295
|
-
direction,
|
|
1296
|
-
changePercent,
|
|
1297
|
-
significance,
|
|
1298
|
-
prediction: prediction > 0 ? prediction : void 0
|
|
1299
|
-
};
|
|
1300
|
-
}
|
|
1301
|
-
function generateRecommendations(commands, api, cache, errors, memory, agents) {
|
|
1302
|
-
const recommendations = [];
|
|
1303
|
-
const slowCommands = commands.filter((c) => c.avgDuration > 5e3);
|
|
1304
|
-
if (slowCommands.length > 0) {
|
|
1305
|
-
recommendations.push(
|
|
1306
|
-
`Consider optimizing slow commands: ${slowCommands.map((c) => c.command).join(", ")} (avg > 5s)`
|
|
1307
|
-
);
|
|
1308
|
-
}
|
|
1309
|
-
const failingCommands = commands.filter((c) => c.failureCount / c.totalExecutions > 0.1);
|
|
1310
|
-
if (failingCommands.length > 0) {
|
|
1311
|
-
recommendations.push(
|
|
1312
|
-
`Investigate high failure rate commands: ${failingCommands.map((c) => c.command).join(", ")} (>10% failure)`
|
|
1313
|
-
);
|
|
1314
|
-
}
|
|
1315
|
-
const slowApis = api.filter((a) => a.avgLatency > 3e3);
|
|
1316
|
-
if (slowApis.length > 0) {
|
|
1317
|
-
recommendations.push(
|
|
1318
|
-
`API latency is high for: ${slowApis.map((a) => a.provider).join(", ")} (avg > 3s). Consider caching or optimization.`
|
|
1319
|
-
);
|
|
1320
|
-
}
|
|
1321
|
-
const highErrorApis = api.filter((a) => a.errorRate > 0.05);
|
|
1322
|
-
if (highErrorApis.length > 0) {
|
|
1323
|
-
recommendations.push(
|
|
1324
|
-
`High API error rate for: ${highErrorApis.map((a) => a.provider).join(", ")} (>5%). Check API health and credentials.`
|
|
1325
|
-
);
|
|
1326
|
-
}
|
|
1327
|
-
if (cache.hitRate < 0.5 && cache.totalOperations > 100) {
|
|
1328
|
-
recommendations.push(
|
|
1329
|
-
`Cache hit rate is low (${(cache.hitRate * 100).toFixed(1)}%). Consider reviewing cache strategy and TTL settings.`
|
|
1330
|
-
);
|
|
1331
|
-
}
|
|
1332
|
-
if (cache.evictions > cache.totalOperations * 0.2) {
|
|
1333
|
-
recommendations.push(
|
|
1334
|
-
`High cache eviction rate. Consider increasing cache size or adjusting eviction policy.`
|
|
1335
|
-
);
|
|
1336
|
-
}
|
|
1337
|
-
if (errors.errorsBySeverity.critical > 0) {
|
|
1338
|
-
recommendations.push(
|
|
1339
|
-
`Critical errors detected (${errors.errorsBySeverity.critical}). Immediate investigation required.`
|
|
1340
|
-
);
|
|
1341
|
-
}
|
|
1342
|
-
if (errors.errorRate > 1) {
|
|
1343
|
-
recommendations.push(
|
|
1344
|
-
`Error rate is high (${errors.errorRate.toFixed(2)}/min). Review error logs and implement error handling.`
|
|
1345
|
-
);
|
|
1346
|
-
}
|
|
1347
|
-
if (memory.current.heapUsedPercent > 0.8) {
|
|
1348
|
-
recommendations.push(
|
|
1349
|
-
`Memory usage is high (${(memory.current.heapUsedPercent * 100).toFixed(1)}%). Consider memory optimization or increasing heap size.`
|
|
1350
|
-
);
|
|
1351
|
-
}
|
|
1352
|
-
if (memory.trend === "increasing") {
|
|
1353
|
-
recommendations.push(
|
|
1354
|
-
`Memory usage is trending upward. Monitor for potential memory leaks.`
|
|
1355
|
-
);
|
|
1356
|
-
}
|
|
1357
|
-
const lowSuccessAgents = agents.filter((a) => a.successRate < 0.8);
|
|
1358
|
-
if (lowSuccessAgents.length > 0) {
|
|
1359
|
-
recommendations.push(
|
|
1360
|
-
`Low success rate for agents: ${lowSuccessAgents.map((a) => a.agentName).join(", ")} (<80%). Review agent configurations.`
|
|
1361
|
-
);
|
|
1362
|
-
}
|
|
1363
|
-
if (recommendations.length === 0) {
|
|
1364
|
-
recommendations.push("System is performing well. No immediate optimizations needed.");
|
|
1365
|
-
}
|
|
1366
|
-
return recommendations;
|
|
1367
|
-
}
|
|
1368
|
-
class PerformanceReporter {
|
|
1369
|
-
collector;
|
|
1370
|
-
config;
|
|
1371
|
-
constructor(config = {}, collector) {
|
|
1372
|
-
this.config = { ...DEFAULT_REPORT_CONFIG, ...config };
|
|
1373
|
-
this.collector = collector || getMetricsCollector();
|
|
1374
|
-
}
|
|
1375
|
-
/**
|
|
1376
|
-
* Generate a performance report
|
|
1377
|
-
*/
|
|
1378
|
-
generateReport(config) {
|
|
1379
|
-
const reportConfig = { ...this.config, ...config };
|
|
1380
|
-
const { start, end } = getTimeRangeBoundaries(
|
|
1381
|
-
reportConfig.timeRange,
|
|
1382
|
-
{ start: reportConfig.startTime, end: reportConfig.endTime }
|
|
1383
|
-
);
|
|
1384
|
-
const commands = reportConfig.includeCommands ? this.collector.getCommandStats() : [];
|
|
1385
|
-
const api = reportConfig.includeApi ? this.collector.getApiStats() : [];
|
|
1386
|
-
const cache = reportConfig.includeCache ? this.collector.getCacheStats() : { totalOperations: 0, hits: 0, misses: 0, hitRate: 0, avgLatency: 0, totalSize: 0, itemCount: 0, evictions: 0 };
|
|
1387
|
-
const errors = reportConfig.includeErrors ? this.collector.getErrorStats() : { totalErrors: 0, errorsByType: {}, errorsBySeverity: { low: 0, medium: 0, high: 0, critical: 0 }, errorRate: 0, recentErrors: [] };
|
|
1388
|
-
const memory = reportConfig.includeMemory ? this.collector.getMemoryStats() : this.getEmptyMemoryStats();
|
|
1389
|
-
const agents = reportConfig.includeAgents ? this.collector.getAgentStats() : [];
|
|
1390
|
-
const totalCommands = commands.reduce((sum, c) => sum + c.totalExecutions, 0);
|
|
1391
|
-
const avgCommandDuration = commands.length > 0 ? commands.reduce((sum, c) => sum + c.avgDuration * c.totalExecutions, 0) / totalCommands : 0;
|
|
1392
|
-
const totalApiCalls = api.reduce((sum, a) => sum + a.totalCalls, 0);
|
|
1393
|
-
const avgApiLatency = api.length > 0 ? api.reduce((sum, a) => sum + a.avgLatency * a.totalCalls, 0) / totalApiCalls : 0;
|
|
1394
|
-
const trends = [];
|
|
1395
|
-
if (reportConfig.includeTrends) {
|
|
1396
|
-
if (commands.length > 0) {
|
|
1397
|
-
const durations = commands.map((c) => c.avgDuration);
|
|
1398
|
-
trends.push(analyzeTrend(durations, "command.avgDuration"));
|
|
1399
|
-
}
|
|
1400
|
-
if (api.length > 0) {
|
|
1401
|
-
const latencies = api.map((a) => a.avgLatency);
|
|
1402
|
-
trends.push(analyzeTrend(latencies, "api.avgLatency"));
|
|
1403
|
-
}
|
|
1404
|
-
trends.push(analyzeTrend([errors.errorRate], "error.rate"));
|
|
1405
|
-
trends.push({
|
|
1406
|
-
metric: "memory.heapUsed",
|
|
1407
|
-
direction: memory.trend === "increasing" ? "up" : memory.trend === "decreasing" ? "down" : "stable",
|
|
1408
|
-
changePercent: 0,
|
|
1409
|
-
significance: memory.trend === "increasing" ? "medium" : "low"
|
|
1410
|
-
});
|
|
1411
|
-
}
|
|
1412
|
-
const anomalies = [];
|
|
1413
|
-
if (reportConfig.includeAnomalies) {
|
|
1414
|
-
for (const cmd of commands) {
|
|
1415
|
-
if (cmd.avgDuration > cmd.p95Duration * 1.5) {
|
|
1416
|
-
anomalies.push({
|
|
1417
|
-
metric: `command.${cmd.command}.duration`,
|
|
1418
|
-
timestamp: cmd.lastExecution || Date.now(),
|
|
1419
|
-
value: cmd.avgDuration,
|
|
1420
|
-
expectedValue: cmd.p95Duration,
|
|
1421
|
-
deviation: (cmd.avgDuration - cmd.p95Duration) / cmd.p95Duration,
|
|
1422
|
-
severity: "medium",
|
|
1423
|
-
description: `Command ${cmd.command} average duration exceeds p95`
|
|
1424
|
-
});
|
|
1425
|
-
}
|
|
1426
|
-
}
|
|
1427
|
-
for (const a of api) {
|
|
1428
|
-
if (a.errorRate > 0.1) {
|
|
1429
|
-
anomalies.push({
|
|
1430
|
-
metric: `api.${a.provider}.errorRate`,
|
|
1431
|
-
timestamp: Date.now(),
|
|
1432
|
-
value: a.errorRate,
|
|
1433
|
-
expectedValue: 0.01,
|
|
1434
|
-
deviation: a.errorRate / 0.01,
|
|
1435
|
-
severity: a.errorRate > 0.5 ? "critical" : a.errorRate > 0.2 ? "high" : "medium",
|
|
1436
|
-
description: `API ${a.provider} has high error rate (${(a.errorRate * 100).toFixed(1)}%)`
|
|
1437
|
-
});
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
const recommendations = generateRecommendations(commands, api, cache, errors, memory, agents);
|
|
1442
|
-
return {
|
|
1443
|
-
id: `report_${Date.now()}`,
|
|
1444
|
-
generatedAt: Date.now(),
|
|
1445
|
-
timeRange: { start, end },
|
|
1446
|
-
summary: {
|
|
1447
|
-
totalCommands,
|
|
1448
|
-
avgCommandDuration,
|
|
1449
|
-
totalApiCalls,
|
|
1450
|
-
avgApiLatency,
|
|
1451
|
-
cacheHitRate: cache.hitRate,
|
|
1452
|
-
errorRate: errors.errorRate,
|
|
1453
|
-
memoryUsage: memory.current.heapUsedPercent
|
|
1454
|
-
},
|
|
1455
|
-
commands,
|
|
1456
|
-
api,
|
|
1457
|
-
cache,
|
|
1458
|
-
errors,
|
|
1459
|
-
agents,
|
|
1460
|
-
trends,
|
|
1461
|
-
anomalies,
|
|
1462
|
-
recommendations
|
|
1463
|
-
};
|
|
1464
|
-
}
|
|
1465
|
-
/**
|
|
1466
|
-
* Generate a daily report
|
|
1467
|
-
*/
|
|
1468
|
-
generateDailyReport() {
|
|
1469
|
-
return this.generateReport({ timeRange: "daily" });
|
|
1470
|
-
}
|
|
1471
|
-
/**
|
|
1472
|
-
* Generate a weekly report
|
|
1473
|
-
*/
|
|
1474
|
-
generateWeeklyReport() {
|
|
1475
|
-
return this.generateReport({ timeRange: "weekly" });
|
|
1476
|
-
}
|
|
1477
|
-
/**
|
|
1478
|
-
* Generate a monthly report
|
|
1479
|
-
*/
|
|
1480
|
-
generateMonthlyReport() {
|
|
1481
|
-
return this.generateReport({ timeRange: "monthly" });
|
|
1482
|
-
}
|
|
1483
|
-
/**
|
|
1484
|
-
* Format report as text
|
|
1485
|
-
*/
|
|
1486
|
-
formatReportAsText(report) {
|
|
1487
|
-
const lines = [];
|
|
1488
|
-
const separator = "\u2550".repeat(60);
|
|
1489
|
-
const thinSeparator = "\u2500".repeat(60);
|
|
1490
|
-
lines.push(separator);
|
|
1491
|
-
lines.push(" CCJK Performance Report");
|
|
1492
|
-
lines.push(` Generated: ${new Date(report.generatedAt).toLocaleString()}`);
|
|
1493
|
-
lines.push(` Period: ${new Date(report.timeRange.start).toLocaleDateString()} - ${new Date(report.timeRange.end).toLocaleDateString()}`);
|
|
1494
|
-
lines.push(separator);
|
|
1495
|
-
lines.push("");
|
|
1496
|
-
lines.push(" SUMMARY");
|
|
1497
|
-
lines.push(thinSeparator);
|
|
1498
|
-
lines.push(` Total Commands: ${report.summary.totalCommands}`);
|
|
1499
|
-
lines.push(` Avg Command Duration: ${report.summary.avgCommandDuration.toFixed(0)}ms`);
|
|
1500
|
-
lines.push(` Total API Calls: ${report.summary.totalApiCalls}`);
|
|
1501
|
-
lines.push(` Avg API Latency: ${report.summary.avgApiLatency.toFixed(0)}ms`);
|
|
1502
|
-
lines.push(` Cache Hit Rate: ${(report.summary.cacheHitRate * 100).toFixed(1)}%`);
|
|
1503
|
-
lines.push(` Error Rate: ${report.summary.errorRate.toFixed(2)}/min`);
|
|
1504
|
-
lines.push(` Memory Usage: ${(report.summary.memoryUsage * 100).toFixed(1)}%`);
|
|
1505
|
-
lines.push("");
|
|
1506
|
-
if (report.commands.length > 0) {
|
|
1507
|
-
lines.push(" COMMAND STATISTICS");
|
|
1508
|
-
lines.push(thinSeparator);
|
|
1509
|
-
for (const cmd of report.commands.slice(0, 10)) {
|
|
1510
|
-
const successRate = cmd.totalExecutions > 0 ? (cmd.successCount / cmd.totalExecutions * 100).toFixed(1) : "0";
|
|
1511
|
-
lines.push(` ${cmd.command}`);
|
|
1512
|
-
lines.push(` Executions: ${cmd.totalExecutions} | Success: ${successRate}% | Avg: ${cmd.avgDuration.toFixed(0)}ms`);
|
|
1513
|
-
}
|
|
1514
|
-
lines.push("");
|
|
1515
|
-
}
|
|
1516
|
-
if (report.api.length > 0) {
|
|
1517
|
-
lines.push(" API PERFORMANCE");
|
|
1518
|
-
lines.push(thinSeparator);
|
|
1519
|
-
for (const api of report.api) {
|
|
1520
|
-
lines.push(` ${api.provider}`);
|
|
1521
|
-
lines.push(` Calls: ${api.totalCalls} | Latency: ${api.avgLatency.toFixed(0)}ms | Errors: ${(api.errorRate * 100).toFixed(1)}%`);
|
|
1522
|
-
}
|
|
1523
|
-
lines.push("");
|
|
1524
|
-
}
|
|
1525
|
-
if (report.trends.length > 0) {
|
|
1526
|
-
lines.push(" TRENDS");
|
|
1527
|
-
lines.push(thinSeparator);
|
|
1528
|
-
for (const trend of report.trends) {
|
|
1529
|
-
const arrow = trend.direction === "up" ? "\u2191" : trend.direction === "down" ? "\u2193" : "\u2192";
|
|
1530
|
-
lines.push(` ${trend.metric}: ${arrow} ${trend.changePercent.toFixed(1)}% (${trend.significance})`);
|
|
1531
|
-
}
|
|
1532
|
-
lines.push("");
|
|
1533
|
-
}
|
|
1534
|
-
if (report.anomalies.length > 0) {
|
|
1535
|
-
lines.push(" ANOMALIES DETECTED");
|
|
1536
|
-
lines.push(thinSeparator);
|
|
1537
|
-
for (const anomaly of report.anomalies.slice(0, 5)) {
|
|
1538
|
-
lines.push(` [${anomaly.severity.toUpperCase()}] ${anomaly.description}`);
|
|
1539
|
-
}
|
|
1540
|
-
lines.push("");
|
|
1541
|
-
}
|
|
1542
|
-
if (report.recommendations.length > 0) {
|
|
1543
|
-
lines.push(" RECOMMENDATIONS");
|
|
1544
|
-
lines.push(thinSeparator);
|
|
1545
|
-
for (const rec of report.recommendations) {
|
|
1546
|
-
lines.push(` \u2022 ${rec}`);
|
|
1547
|
-
}
|
|
1548
|
-
lines.push("");
|
|
1549
|
-
}
|
|
1550
|
-
lines.push(separator);
|
|
1551
|
-
return lines.join("\n");
|
|
1552
|
-
}
|
|
1553
|
-
/**
|
|
1554
|
-
* Format report as JSON
|
|
1555
|
-
*/
|
|
1556
|
-
formatReportAsJson(report) {
|
|
1557
|
-
return JSON.stringify(report, null, 2);
|
|
1558
|
-
}
|
|
1559
|
-
/**
|
|
1560
|
-
* Format report as HTML
|
|
1561
|
-
*/
|
|
1562
|
-
formatReportAsHtml(report) {
|
|
1563
|
-
return `<!DOCTYPE html>
|
|
1564
|
-
<html>
|
|
1565
|
-
<head>
|
|
1566
|
-
<title>CCJK Performance Report - ${new Date(report.generatedAt).toLocaleDateString()}</title>
|
|
1567
|
-
<style>
|
|
1568
|
-
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 20px; background: #0d1117; color: #c9d1d9; }
|
|
1569
|
-
.container { max-width: 1200px; margin: 0 auto; }
|
|
1570
|
-
h1 { color: #58a6ff; border-bottom: 1px solid #30363d; padding-bottom: 10px; }
|
|
1571
|
-
h2 { color: #7ee787; margin-top: 30px; }
|
|
1572
|
-
.card { background: #161b22; border: 1px solid #30363d; border-radius: 6px; padding: 20px; margin: 15px 0; }
|
|
1573
|
-
.metric-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; }
|
|
1574
|
-
.metric { text-align: center; padding: 15px; background: #21262d; border-radius: 6px; }
|
|
1575
|
-
.metric-value { font-size: 2em; color: #58a6ff; font-weight: bold; }
|
|
1576
|
-
.metric-label { color: #8b949e; font-size: 0.9em; }
|
|
1577
|
-
table { width: 100%; border-collapse: collapse; margin: 10px 0; }
|
|
1578
|
-
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #30363d; }
|
|
1579
|
-
th { color: #7ee787; font-weight: 600; }
|
|
1580
|
-
.trend-up { color: #f85149; }
|
|
1581
|
-
.trend-down { color: #7ee787; }
|
|
1582
|
-
.trend-stable { color: #8b949e; }
|
|
1583
|
-
.severity-critical { color: #f85149; font-weight: bold; }
|
|
1584
|
-
.severity-high { color: #f85149; }
|
|
1585
|
-
.severity-medium { color: #d29922; }
|
|
1586
|
-
.severity-low { color: #7ee787; }
|
|
1587
|
-
.recommendation { padding: 10px 15px; background: #21262d; border-left: 3px solid #58a6ff; margin: 10px 0; }
|
|
1588
|
-
.footer { text-align: center; color: #8b949e; margin-top: 30px; padding-top: 20px; border-top: 1px solid #30363d; }
|
|
1589
|
-
</style>
|
|
1590
|
-
</head>
|
|
1591
|
-
<body>
|
|
1592
|
-
<div class="container">
|
|
1593
|
-
<h1>CCJK Performance Report</h1>
|
|
1594
|
-
<p>Generated: ${new Date(report.generatedAt).toLocaleString()}</p>
|
|
1595
|
-
<p>Period: ${new Date(report.timeRange.start).toLocaleDateString()} - ${new Date(report.timeRange.end).toLocaleDateString()}</p>
|
|
1596
|
-
|
|
1597
|
-
<h2>Summary</h2>
|
|
1598
|
-
<div class="card">
|
|
1599
|
-
<div class="metric-grid">
|
|
1600
|
-
<div class="metric">
|
|
1601
|
-
<div class="metric-value">${report.summary.totalCommands}</div>
|
|
1602
|
-
<div class="metric-label">Total Commands</div>
|
|
1603
|
-
</div>
|
|
1604
|
-
<div class="metric">
|
|
1605
|
-
<div class="metric-value">${report.summary.avgCommandDuration.toFixed(0)}ms</div>
|
|
1606
|
-
<div class="metric-label">Avg Command Duration</div>
|
|
1607
|
-
</div>
|
|
1608
|
-
<div class="metric">
|
|
1609
|
-
<div class="metric-value">${report.summary.totalApiCalls}</div>
|
|
1610
|
-
<div class="metric-label">API Calls</div>
|
|
1611
|
-
</div>
|
|
1612
|
-
<div class="metric">
|
|
1613
|
-
<div class="metric-value">${report.summary.avgApiLatency.toFixed(0)}ms</div>
|
|
1614
|
-
<div class="metric-label">Avg API Latency</div>
|
|
1615
|
-
</div>
|
|
1616
|
-
<div class="metric">
|
|
1617
|
-
<div class="metric-value">${(report.summary.cacheHitRate * 100).toFixed(1)}%</div>
|
|
1618
|
-
<div class="metric-label">Cache Hit Rate</div>
|
|
1619
|
-
</div>
|
|
1620
|
-
<div class="metric">
|
|
1621
|
-
<div class="metric-value">${(report.summary.memoryUsage * 100).toFixed(1)}%</div>
|
|
1622
|
-
<div class="metric-label">Memory Usage</div>
|
|
1623
|
-
</div>
|
|
1624
|
-
</div>
|
|
1625
|
-
</div>
|
|
1626
|
-
|
|
1627
|
-
${report.commands.length > 0 ? `
|
|
1628
|
-
<h2>Command Statistics</h2>
|
|
1629
|
-
<div class="card">
|
|
1630
|
-
<table>
|
|
1631
|
-
<tr><th>Command</th><th>Executions</th><th>Success Rate</th><th>Avg Duration</th><th>P95 Duration</th></tr>
|
|
1632
|
-
${report.commands.map((c) => `
|
|
1633
|
-
<tr>
|
|
1634
|
-
<td>${c.command}</td>
|
|
1635
|
-
<td>${c.totalExecutions}</td>
|
|
1636
|
-
<td>${(c.successCount / c.totalExecutions * 100).toFixed(1)}%</td>
|
|
1637
|
-
<td>${c.avgDuration.toFixed(0)}ms</td>
|
|
1638
|
-
<td>${c.p95Duration.toFixed(0)}ms</td>
|
|
1639
|
-
</tr>`).join("")}
|
|
1640
|
-
</table>
|
|
1641
|
-
</div>` : ""}
|
|
1642
|
-
|
|
1643
|
-
${report.api.length > 0 ? `
|
|
1644
|
-
<h2>API Performance</h2>
|
|
1645
|
-
<div class="card">
|
|
1646
|
-
<table>
|
|
1647
|
-
<tr><th>Provider</th><th>Calls</th><th>Success Rate</th><th>Avg Latency</th><th>P95 Latency</th><th>Tokens</th></tr>
|
|
1648
|
-
${report.api.map((a) => `
|
|
1649
|
-
<tr>
|
|
1650
|
-
<td>${a.provider}</td>
|
|
1651
|
-
<td>${a.totalCalls}</td>
|
|
1652
|
-
<td>${((1 - a.errorRate) * 100).toFixed(1)}%</td>
|
|
1653
|
-
<td>${a.avgLatency.toFixed(0)}ms</td>
|
|
1654
|
-
<td>${a.p95Latency.toFixed(0)}ms</td>
|
|
1655
|
-
<td>${a.totalTokens}</td>
|
|
1656
|
-
</tr>`).join("")}
|
|
1657
|
-
</table>
|
|
1658
|
-
</div>` : ""}
|
|
1659
|
-
|
|
1660
|
-
${report.trends.length > 0 ? `
|
|
1661
|
-
<h2>Trends</h2>
|
|
1662
|
-
<div class="card">
|
|
1663
|
-
<table>
|
|
1664
|
-
<tr><th>Metric</th><th>Direction</th><th>Change</th><th>Significance</th></tr>
|
|
1665
|
-
${report.trends.map((t) => `
|
|
1666
|
-
<tr>
|
|
1667
|
-
<td>${t.metric}</td>
|
|
1668
|
-
<td class="trend-${t.direction}">${t.direction === "up" ? "\u2191 Up" : t.direction === "down" ? "\u2193 Down" : "\u2192 Stable"}</td>
|
|
1669
|
-
<td>${t.changePercent.toFixed(1)}%</td>
|
|
1670
|
-
<td>${t.significance}</td>
|
|
1671
|
-
</tr>`).join("")}
|
|
1672
|
-
</table>
|
|
1673
|
-
</div>` : ""}
|
|
1674
|
-
|
|
1675
|
-
${report.anomalies.length > 0 ? `
|
|
1676
|
-
<h2>Anomalies Detected</h2>
|
|
1677
|
-
<div class="card">
|
|
1678
|
-
${report.anomalies.map((a) => `
|
|
1679
|
-
<div class="recommendation">
|
|
1680
|
-
<span class="severity-${a.severity}">[${a.severity.toUpperCase()}]</span> ${a.description}
|
|
1681
|
-
</div>`).join("")}
|
|
1682
|
-
</div>` : ""}
|
|
1683
|
-
|
|
1684
|
-
<h2>Recommendations</h2>
|
|
1685
|
-
<div class="card">
|
|
1686
|
-
${report.recommendations.map((r) => `<div class="recommendation">${r}</div>`).join("")}
|
|
1687
|
-
</div>
|
|
1688
|
-
|
|
1689
|
-
<div class="footer">
|
|
1690
|
-
<p>Generated by CCJK Performance Monitor</p>
|
|
1691
|
-
</div>
|
|
1692
|
-
</div>
|
|
1693
|
-
</body>
|
|
1694
|
-
</html>`;
|
|
1695
|
-
}
|
|
1696
|
-
/**
|
|
1697
|
-
* Get empty memory stats
|
|
1698
|
-
*/
|
|
1699
|
-
getEmptyMemoryStats() {
|
|
1700
|
-
const emptySnapshot = {
|
|
1701
|
-
timestamp: Date.now(),
|
|
1702
|
-
heapUsed: 0,
|
|
1703
|
-
heapTotal: 0,
|
|
1704
|
-
external: 0,
|
|
1705
|
-
arrayBuffers: 0,
|
|
1706
|
-
rss: 0,
|
|
1707
|
-
heapUsedPercent: 0
|
|
1708
|
-
};
|
|
1709
|
-
return {
|
|
1710
|
-
current: emptySnapshot,
|
|
1711
|
-
peak: emptySnapshot,
|
|
1712
|
-
average: { heapUsed: 0, heapTotal: 0, rss: 0 },
|
|
1713
|
-
trend: "stable"
|
|
1714
|
-
};
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
function createReporter(config) {
|
|
1718
|
-
return new PerformanceReporter(config);
|
|
1719
|
-
}
|
|
1720
|
-
|
|
1721
|
-
async function monitor(subcommand, options = {}) {
|
|
1722
|
-
const isZh = (options.lang || i18n.language) === "zh-CN";
|
|
1723
|
-
if (!options.noBanner) {
|
|
1724
|
-
displayBannerWithInfo();
|
|
1725
|
-
}
|
|
1726
|
-
switch (subcommand) {
|
|
1727
|
-
case "start":
|
|
1728
|
-
await monitorStart(options);
|
|
1729
|
-
break;
|
|
1730
|
-
case "stop":
|
|
1731
|
-
console.log(a.dim(isZh ? "\u63D0\u793A: \u6309 Ctrl+C \u9000\u51FA\u76D1\u63A7\u9762\u677F" : "Tip: Press Ctrl+C to exit the dashboard"));
|
|
1732
|
-
break;
|
|
1733
|
-
case "report":
|
|
1734
|
-
await monitorReport(options);
|
|
1735
|
-
break;
|
|
1736
|
-
case "export":
|
|
1737
|
-
await monitorExport(options);
|
|
1738
|
-
break;
|
|
1739
|
-
case "help":
|
|
1740
|
-
monitorHelp(options);
|
|
1741
|
-
break;
|
|
1742
|
-
default:
|
|
1743
|
-
await monitorStart(options);
|
|
1744
|
-
break;
|
|
1745
|
-
}
|
|
1746
|
-
}
|
|
1747
|
-
async function monitorStart(options) {
|
|
1748
|
-
const isZh = (options.lang || i18n.language) === "zh-CN";
|
|
1749
|
-
const refreshMs = options.refresh ? Number.parseInt(options.refresh, 10) * 1e3 : void 0;
|
|
1750
|
-
const config = {
|
|
1751
|
-
refreshInterval: refreshMs || 2e3,
|
|
1752
|
-
showCommands: true,
|
|
1753
|
-
showMemory: true,
|
|
1754
|
-
showApi: true,
|
|
1755
|
-
showCache: true,
|
|
1756
|
-
showErrors: true,
|
|
1757
|
-
showAgents: true
|
|
1758
|
-
};
|
|
1759
|
-
console.log("");
|
|
1760
|
-
console.log(a.bold.cyan(isZh ? "\u{1F4CA} \u542F\u52A8 CCJK \u6027\u80FD\u76D1\u63A7\u9762\u677F..." : "\u{1F4CA} Starting CCJK Performance Monitor..."));
|
|
1761
|
-
console.log("");
|
|
1762
|
-
console.log(a.dim(isZh ? "\u63D0\u793A: \u6309 Ctrl+C \u9000\u51FA\u76D1\u63A7" : "Tip: Press Ctrl+C to exit monitoring"));
|
|
1763
|
-
console.log("");
|
|
1764
|
-
const dashboard = createDashboard(config);
|
|
1765
|
-
dashboard.show();
|
|
1766
|
-
}
|
|
1767
|
-
async function monitorReport(options) {
|
|
1768
|
-
const isZh = (options.lang || i18n.language) === "zh-CN";
|
|
1769
|
-
const timeRange = options.range || "daily";
|
|
1770
|
-
console.log("");
|
|
1771
|
-
console.log(a.bold.cyan(isZh ? "\u{1F4C8} \u751F\u6210\u6027\u80FD\u62A5\u544A..." : "\u{1F4C8} Generating Performance Report..."));
|
|
1772
|
-
console.log("");
|
|
1773
|
-
const reporter = createReporter({ timeRange });
|
|
1774
|
-
const report = reporter.generateReport();
|
|
1775
|
-
const reportText = reporter.formatReportAsText(report);
|
|
1776
|
-
console.log(reportText);
|
|
1777
|
-
if (options.output) {
|
|
1778
|
-
const fs = await import('node:fs/promises');
|
|
1779
|
-
await fs.writeFile(options.output, reportText);
|
|
1780
|
-
console.log("");
|
|
1781
|
-
console.log(a.green(`${isZh ? "\u62A5\u544A\u5DF2\u4FDD\u5B58\u5230" : "Report saved to"} ${options.output}`));
|
|
1782
|
-
}
|
|
1783
|
-
if (options.json) {
|
|
1784
|
-
const jsonReport = reporter.formatReportAsJson(report);
|
|
1785
|
-
const jsonOutput = options.output ? options.output.replace(/\.[^.]+$/, ".json") : "ccjk-monitor-report.json";
|
|
1786
|
-
const fs = await import('node:fs/promises');
|
|
1787
|
-
await fs.writeFile(jsonOutput, jsonReport);
|
|
1788
|
-
console.log(a.green(`${isZh ? "JSON \u62A5\u544A\u5DF2\u4FDD\u5B58\u5230" : "JSON report saved to"} ${jsonOutput}`));
|
|
1789
|
-
}
|
|
1790
|
-
console.log("");
|
|
1791
|
-
}
|
|
1792
|
-
async function monitorExport(options = {}) {
|
|
1793
|
-
const isZh = (options.lang || i18n.language) === "zh-CN";
|
|
1794
|
-
const format = options.format || "json";
|
|
1795
|
-
console.log("");
|
|
1796
|
-
console.log(a.bold.cyan(isZh ? "\u{1F4BE} \u5BFC\u51FA\u76D1\u63A7\u6570\u636E..." : "\u{1F4BE} Exporting Monitoring Data..."));
|
|
1797
|
-
console.log("");
|
|
1798
|
-
const dashboard = createDashboard();
|
|
1799
|
-
const data = dashboard.export(format);
|
|
1800
|
-
let outputFile = options.output;
|
|
1801
|
-
if (!outputFile) {
|
|
1802
|
-
const ext = format === "csv" ? "csv" : format === "html" ? "html" : "json";
|
|
1803
|
-
outputFile = `ccjk-metrics-${Date.now()}.${ext}`;
|
|
1804
|
-
}
|
|
1805
|
-
const fs = await import('node:fs/promises');
|
|
1806
|
-
await fs.writeFile(outputFile, data);
|
|
1807
|
-
console.log(a.green(`${isZh ? "\u6570\u636E\u5DF2\u5BFC\u51FA\u5230" : "Data exported to"} ${outputFile}`));
|
|
1808
|
-
console.log("");
|
|
1809
|
-
}
|
|
1810
|
-
function monitorHelp(options = {}) {
|
|
1811
|
-
const isZh = (options.lang || i18n.language) === "zh-CN";
|
|
1812
|
-
console.log("");
|
|
1813
|
-
console.log(a.bold.cyan(isZh ? "\u{1F4CA} CCJK \u6027\u80FD\u76D1\u63A7\u547D\u4EE4" : "\u{1F4CA} CCJK Performance Monitor Commands"));
|
|
1814
|
-
console.log(a.dim("\u2500".repeat(60)));
|
|
1815
|
-
console.log("");
|
|
1816
|
-
const commands = [
|
|
1817
|
-
{
|
|
1818
|
-
cmd: "ccjk monitor",
|
|
1819
|
-
desc: isZh ? "\u542F\u52A8\u5B9E\u65F6\u76D1\u63A7\u9762\u677F" : "Start real-time monitoring dashboard"
|
|
1820
|
-
},
|
|
1821
|
-
{
|
|
1822
|
-
cmd: "ccjk monitor start",
|
|
1823
|
-
desc: isZh ? "\u542F\u52A8\u5B9E\u65F6\u76D1\u63A7\u9762\u677F" : "Start real-time monitoring dashboard"
|
|
1824
|
-
},
|
|
1825
|
-
{
|
|
1826
|
-
cmd: "ccjk monitor report",
|
|
1827
|
-
desc: isZh ? "\u751F\u6210\u6027\u80FD\u62A5\u544A" : "Generate performance report"
|
|
1828
|
-
},
|
|
1829
|
-
{
|
|
1830
|
-
cmd: "ccjk monitor export",
|
|
1831
|
-
desc: isZh ? "\u5BFC\u51FA\u76D1\u63A7\u6570\u636E" : "Export monitoring data"
|
|
1832
|
-
},
|
|
1833
|
-
{
|
|
1834
|
-
cmd: "ccjk monitor help",
|
|
1835
|
-
desc: isZh ? "\u663E\u793A\u5E2E\u52A9\u4FE1\u606F" : "Show help information"
|
|
1836
|
-
}
|
|
1837
|
-
];
|
|
1838
|
-
for (const { cmd, desc } of commands) {
|
|
1839
|
-
console.log(` ${a.green(cmd)}`);
|
|
1840
|
-
console.log(` ${a.dim(desc)}`);
|
|
1841
|
-
console.log("");
|
|
1842
|
-
}
|
|
1843
|
-
console.log(a.bold.yellow(isZh ? "\u9009\u9879:" : "Options:"));
|
|
1844
|
-
console.log("");
|
|
1845
|
-
console.log(` ${a.cyan("--refresh, -r <ms>")} ${isZh ? "\u5237\u65B0\u95F4\u9694 (\u6BEB\u79D2)" : "Refresh interval (milliseconds)"}`);
|
|
1846
|
-
console.log(` ${a.cyan("--range <timeRange>")} ${isZh ? "\u62A5\u544A\u65F6\u95F4\u8303\u56F4 (hourly|daily|weekly|monthly)" : "Report time range (hourly|daily|weekly|monthly)"}`);
|
|
1847
|
-
console.log(` ${a.cyan("--format, -f <format>")} ${isZh ? "\u5BFC\u51FA\u683C\u5F0F (json|csv|html)" : "Export format (json|csv|html)"}`);
|
|
1848
|
-
console.log(` ${a.cyan("--output, -o <file>")} ${isZh ? "\u8F93\u51FA\u6587\u4EF6\u8DEF\u5F84" : "Output file path"}`);
|
|
1849
|
-
console.log(` ${a.cyan("--json")} ${isZh ? "\u540C\u65F6\u8F93\u51FA JSON \u683C\u5F0F" : "Also output JSON format"}`);
|
|
1850
|
-
console.log(` ${a.cyan("--no-banner")} ${isZh ? "\u4E0D\u663E\u793A\u6A2A\u5E45" : "Do not display banner"}`);
|
|
1851
|
-
console.log("");
|
|
1852
|
-
console.log(a.dim(isZh ? "\u{1F4A1} \u63D0\u793A: \u4F7F\u7528 ccjk monitor \u542F\u52A8\u5B9E\u65F6\u76D1\u63A7\u9762\u677F\uFF0C\u6309 Ctrl+C \u9000\u51FA" : '\u{1F4A1} Tip: Run "ccjk monitor" to start the dashboard, press Ctrl+C to exit'));
|
|
1853
|
-
console.log("");
|
|
1854
|
-
}
|
|
1855
|
-
|
|
1856
|
-
export { monitor };
|