chainlesschain 0.51.0 → 0.66.0
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/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AppLayout-Rvi759IS.js → AppLayout-6SPt_8Y_.js} +1 -1
- package/src/assets/web-panel/assets/{Dashboard-DBhFxXYQ.js → Dashboard-Br7kCwKJ.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-CKeMmCoT.css +1 -0
- package/src/assets/web-panel/assets/{index-uL0cZ8N_.js → index-tN-8TosE.js} +2 -2
- package/src/assets/web-panel/index.html +2 -2
- package/src/commands/agent-network.js +785 -0
- package/src/commands/automation.js +654 -0
- package/src/commands/dao.js +565 -0
- package/src/commands/did-v2.js +620 -0
- package/src/commands/economy.js +578 -0
- package/src/commands/evolution.js +391 -0
- package/src/commands/hmemory.js +442 -0
- package/src/commands/perf.js +433 -0
- package/src/commands/pipeline.js +449 -0
- package/src/commands/plugin-ecosystem.js +517 -0
- package/src/commands/sandbox.js +401 -0
- package/src/commands/social.js +311 -0
- package/src/commands/sso.js +798 -0
- package/src/commands/workflow.js +320 -0
- package/src/commands/zkp.js +227 -1
- package/src/index.js +21 -0
- package/src/lib/agent-economy.js +479 -0
- package/src/lib/agent-network.js +1121 -0
- package/src/lib/automation-engine.js +948 -0
- package/src/lib/dao-governance.js +569 -0
- package/src/lib/did-v2-manager.js +1127 -0
- package/src/lib/evolution-system.js +453 -0
- package/src/lib/hierarchical-memory.js +481 -0
- package/src/lib/perf-tuning.js +734 -0
- package/src/lib/pipeline-orchestrator.js +928 -0
- package/src/lib/plugin-ecosystem.js +1109 -0
- package/src/lib/sandbox-v2.js +306 -0
- package/src/lib/social-graph-analytics.js +707 -0
- package/src/lib/sso-manager.js +841 -0
- package/src/lib/workflow-engine.js +454 -1
- package/src/lib/zkp-engine.js +249 -20
- package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +0 -1
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cc perf` — CLI surface for Phase 22 性能自动调优.
|
|
3
|
+
*
|
|
4
|
+
* Real os.cpus/freemem + process.memoryUsage sampling → SQLite ring buffer.
|
|
5
|
+
* 5 built-in rules, hysteresis + cooldown tracking. CLI reports
|
|
6
|
+
* recommendations but NEVER auto-applies actions.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Command } from "commander";
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
ALERT_LEVELS,
|
|
13
|
+
RECOMMENDATION_STATUS,
|
|
14
|
+
BUILTIN_RULES,
|
|
15
|
+
ensurePerfTables,
|
|
16
|
+
getPerfConfig,
|
|
17
|
+
setPerfConfig,
|
|
18
|
+
collectSample,
|
|
19
|
+
listSamples,
|
|
20
|
+
getLatestSample,
|
|
21
|
+
clearHistory,
|
|
22
|
+
listRules,
|
|
23
|
+
getRule,
|
|
24
|
+
setRuleEnabled,
|
|
25
|
+
evaluateRules,
|
|
26
|
+
listRecommendations,
|
|
27
|
+
applyRecommendation,
|
|
28
|
+
dismissRecommendation,
|
|
29
|
+
listHistory,
|
|
30
|
+
getAlerts,
|
|
31
|
+
getPerfStats,
|
|
32
|
+
getPerformanceReport,
|
|
33
|
+
} from "../lib/perf-tuning.js";
|
|
34
|
+
|
|
35
|
+
function _dbFromCtx(cmd) {
|
|
36
|
+
const root = cmd?.parent?.parent ?? cmd?.parent;
|
|
37
|
+
return root?._db;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function _json(v) {
|
|
41
|
+
console.log(JSON.stringify(v, null, 2));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function _fmtTs(ts) {
|
|
45
|
+
if (!ts) return "—";
|
|
46
|
+
return new Date(ts).toISOString();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function registerPerfCommand(program) {
|
|
50
|
+
const perf = new Command("perf")
|
|
51
|
+
.description("Performance monitoring & auto-tuning (Phase 22)")
|
|
52
|
+
.hook("preAction", (thisCmd) => {
|
|
53
|
+
const db = _dbFromCtx(thisCmd);
|
|
54
|
+
if (db) ensurePerfTables(db);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/* ── Catalogs ─────────────────────────────────────── */
|
|
58
|
+
|
|
59
|
+
perf
|
|
60
|
+
.command("levels")
|
|
61
|
+
.description("List alert levels")
|
|
62
|
+
.option("--json", "JSON output")
|
|
63
|
+
.action((opts) => {
|
|
64
|
+
const rows = Object.values(ALERT_LEVELS);
|
|
65
|
+
if (opts.json) return _json(rows);
|
|
66
|
+
for (const r of rows) console.log(` ${r}`);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
perf
|
|
70
|
+
.command("rule-statuses")
|
|
71
|
+
.description("List recommendation statuses")
|
|
72
|
+
.option("--json", "JSON output")
|
|
73
|
+
.action((opts) => {
|
|
74
|
+
const rows = Object.values(RECOMMENDATION_STATUS);
|
|
75
|
+
if (opts.json) return _json(rows);
|
|
76
|
+
for (const r of rows) console.log(` ${r}`);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
perf
|
|
80
|
+
.command("rules")
|
|
81
|
+
.description("List 5 built-in tuning rules")
|
|
82
|
+
.option("--json", "JSON output")
|
|
83
|
+
.action((opts) => {
|
|
84
|
+
const db = _dbFromCtx(perf);
|
|
85
|
+
const rules = db ? listRules(db) : BUILTIN_RULES.map((r) => ({ ...r }));
|
|
86
|
+
if (opts.json) return _json(rules);
|
|
87
|
+
for (const r of rules) {
|
|
88
|
+
const flag = r.enabled === false ? "[off] " : " ";
|
|
89
|
+
console.log(
|
|
90
|
+
`${flag}${r.id.padEnd(20)} ${r.severity.padEnd(8)} ${r.name}`,
|
|
91
|
+
);
|
|
92
|
+
console.log(
|
|
93
|
+
` cond=${r.condition.metric} ${r.condition.op} ${r.condition.value}` +
|
|
94
|
+
` hyst=${r.consecutiveRequired}x cooldown=${Math.round(r.cooldownMs / 1000)}s`,
|
|
95
|
+
);
|
|
96
|
+
console.log(` action=${r.action}`);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
perf
|
|
101
|
+
.command("rule-show")
|
|
102
|
+
.argument("<ruleId>", "Rule id")
|
|
103
|
+
.description("Show a rule with live state")
|
|
104
|
+
.option("--json", "JSON output")
|
|
105
|
+
.action((ruleId, opts) => {
|
|
106
|
+
const db = _dbFromCtx(perf);
|
|
107
|
+
const r = getRule(db, ruleId);
|
|
108
|
+
if (!r) {
|
|
109
|
+
console.error(`Unknown rule: ${ruleId}`);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
if (opts.json) return _json(r);
|
|
113
|
+
console.log(`Rule: ${r.id} — ${r.name}`);
|
|
114
|
+
console.log(` enabled: ${r.enabled}`);
|
|
115
|
+
console.log(` severity: ${r.severity}`);
|
|
116
|
+
console.log(
|
|
117
|
+
` condition: ${r.condition.metric} ${r.condition.op} ${r.condition.value}`,
|
|
118
|
+
);
|
|
119
|
+
console.log(` action: ${r.action}`);
|
|
120
|
+
console.log(
|
|
121
|
+
` hysteresis: ${r.consecutiveRequired}x cooldown: ${r.cooldownMs}ms`,
|
|
122
|
+
);
|
|
123
|
+
console.log(` consecutive: ${r.consecutiveCount}`);
|
|
124
|
+
console.log(` totalTriggered: ${r.totalTriggered}`);
|
|
125
|
+
console.log(` lastTriggeredAt: ${_fmtTs(r.lastTriggeredAt)}`);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
perf
|
|
129
|
+
.command("rule-enable")
|
|
130
|
+
.argument("<ruleId>", "Rule id")
|
|
131
|
+
.description("Enable a rule")
|
|
132
|
+
.option("--json", "JSON output")
|
|
133
|
+
.action((ruleId, opts) => {
|
|
134
|
+
const db = _dbFromCtx(perf);
|
|
135
|
+
const r = setRuleEnabled(db, ruleId, true);
|
|
136
|
+
if (opts.json) return _json(r);
|
|
137
|
+
if (!r.updated) {
|
|
138
|
+
console.error(`Failed: ${r.reason}`);
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
console.log(`Enabled ${ruleId}`);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
perf
|
|
145
|
+
.command("rule-disable")
|
|
146
|
+
.argument("<ruleId>", "Rule id")
|
|
147
|
+
.description("Disable a rule")
|
|
148
|
+
.option("--json", "JSON output")
|
|
149
|
+
.action((ruleId, opts) => {
|
|
150
|
+
const db = _dbFromCtx(perf);
|
|
151
|
+
const r = setRuleEnabled(db, ruleId, false);
|
|
152
|
+
if (opts.json) return _json(r);
|
|
153
|
+
if (!r.updated) {
|
|
154
|
+
console.error(`Failed: ${r.reason}`);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
console.log(`Disabled ${ruleId}`);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
/* ── Sampling ─────────────────────────────────────── */
|
|
161
|
+
|
|
162
|
+
perf
|
|
163
|
+
.command("collect")
|
|
164
|
+
.description("Collect one performance sample now")
|
|
165
|
+
.option("--slow-queries <n>", "Feed slowQueries counter (int)", (v) =>
|
|
166
|
+
parseInt(v, 10),
|
|
167
|
+
)
|
|
168
|
+
.option("--json", "JSON output")
|
|
169
|
+
.action((opts) => {
|
|
170
|
+
const db = _dbFromCtx(perf);
|
|
171
|
+
const s = collectSample(db, { slowQueries: opts.slowQueries });
|
|
172
|
+
if (opts.json) return _json(s);
|
|
173
|
+
console.log(`Sample @ ${_fmtTs(s.ts)}`);
|
|
174
|
+
console.log(` cpu: ${s.cpuPercent}% mem: ${s.memoryPercent}%`);
|
|
175
|
+
console.log(
|
|
176
|
+
` heap: ${s.heapPercent}% (${s.heapUsed}/${s.heapTotal}) rss: ${s.rss}`,
|
|
177
|
+
);
|
|
178
|
+
console.log(` load1: ${s.load1} loadPerCore: ${s.loadPerCore}`);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
perf
|
|
182
|
+
.command("metrics")
|
|
183
|
+
.description("Show the latest sample (collect one if none exists)")
|
|
184
|
+
.option("--json", "JSON output")
|
|
185
|
+
.action((opts) => {
|
|
186
|
+
const db = _dbFromCtx(perf);
|
|
187
|
+
let s = getLatestSample(db);
|
|
188
|
+
if (!s) s = collectSample(db);
|
|
189
|
+
if (opts.json) return _json(s);
|
|
190
|
+
console.log(`Latest @ ${_fmtTs(s.ts)}`);
|
|
191
|
+
console.log(
|
|
192
|
+
` cpu=${s.cpuPercent}% mem=${s.memoryPercent}% heap=${s.heapPercent}%`,
|
|
193
|
+
);
|
|
194
|
+
console.log(` load1=${s.load1} loadPerCore=${s.loadPerCore}`);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
perf
|
|
198
|
+
.command("samples")
|
|
199
|
+
.description("List recent samples (ring buffer)")
|
|
200
|
+
.option("--limit <n>", "Max rows", (v) => parseInt(v, 10), 20)
|
|
201
|
+
.option("--since-ms <ms>", "Only samples newer than N ms ago", (v) =>
|
|
202
|
+
parseInt(v, 10),
|
|
203
|
+
)
|
|
204
|
+
.option("--json", "JSON output")
|
|
205
|
+
.action((opts) => {
|
|
206
|
+
const db = _dbFromCtx(perf);
|
|
207
|
+
const rows = listSamples(db, {
|
|
208
|
+
limit: opts.limit,
|
|
209
|
+
sinceMs: opts.sinceMs,
|
|
210
|
+
});
|
|
211
|
+
if (opts.json) return _json(rows);
|
|
212
|
+
for (const r of rows)
|
|
213
|
+
console.log(
|
|
214
|
+
` ${_fmtTs(r.ts)} cpu=${r.cpuPercent}% mem=${r.memoryPercent}% heap=${r.heapPercent}% load/c=${r.loadPerCore}`,
|
|
215
|
+
);
|
|
216
|
+
console.log(`(${rows.length} rows)`);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
perf
|
|
220
|
+
.command("clear-history")
|
|
221
|
+
.description("Wipe the ring buffer")
|
|
222
|
+
.option("--json", "JSON output")
|
|
223
|
+
.action((opts) => {
|
|
224
|
+
const db = _dbFromCtx(perf);
|
|
225
|
+
const r = clearHistory(db);
|
|
226
|
+
if (opts.json) return _json(r);
|
|
227
|
+
console.log(`Cleared ${r.cleared} samples`);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
/* ── Evaluation ───────────────────────────────────── */
|
|
231
|
+
|
|
232
|
+
perf
|
|
233
|
+
.command("evaluate")
|
|
234
|
+
.description("Run the rule engine against the latest sample")
|
|
235
|
+
.option("--collect", "Collect a fresh sample before evaluating")
|
|
236
|
+
.option("--slow-queries <n>", "Feed slowQueries counter (int)", (v) =>
|
|
237
|
+
parseInt(v, 10),
|
|
238
|
+
)
|
|
239
|
+
.option("--json", "JSON output")
|
|
240
|
+
.action((opts) => {
|
|
241
|
+
const db = _dbFromCtx(perf);
|
|
242
|
+
if (opts.collect) collectSample(db, { slowQueries: opts.slowQueries });
|
|
243
|
+
const r = evaluateRules(db);
|
|
244
|
+
if (opts.json) return _json(r);
|
|
245
|
+
console.log(`Evaluated @ ${_fmtTs(r.evaluatedAt)}`);
|
|
246
|
+
console.log(
|
|
247
|
+
`Sample: cpu=${r.sample.cpuPercent}% mem=${r.sample.memoryPercent}% heap=${r.sample.heapPercent}% load/c=${r.sample.loadPerCore}`,
|
|
248
|
+
);
|
|
249
|
+
console.log(`Triggered: ${r.triggered.length}`);
|
|
250
|
+
for (const t of r.triggered)
|
|
251
|
+
console.log(
|
|
252
|
+
` ✱ ${t.ruleId} [${t.severity}] ${t.metric}=${t.value} (> ${t.threshold}) → ${t.recommendationId}`,
|
|
253
|
+
);
|
|
254
|
+
console.log(`Skipped: ${r.skipped.length}`);
|
|
255
|
+
for (const s of r.skipped) console.log(` · ${s.ruleId} — ${s.reason}`);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
perf
|
|
259
|
+
.command("recommendations")
|
|
260
|
+
.description("List recommendations")
|
|
261
|
+
.option("--status <s>", "Filter: pending|applied|dismissed")
|
|
262
|
+
.option("--limit <n>", "Max rows", (v) => parseInt(v, 10), 50)
|
|
263
|
+
.option("--json", "JSON output")
|
|
264
|
+
.action((opts) => {
|
|
265
|
+
const db = _dbFromCtx(perf);
|
|
266
|
+
const rows = listRecommendations(db, {
|
|
267
|
+
status: opts.status,
|
|
268
|
+
limit: opts.limit,
|
|
269
|
+
});
|
|
270
|
+
if (opts.json) return _json(rows);
|
|
271
|
+
for (const r of rows)
|
|
272
|
+
console.log(
|
|
273
|
+
` [${r.status.padEnd(10)}] ${r.id} ${r.ruleId} ${r.metric}=${r.metricValue} (> ${r.threshold})`,
|
|
274
|
+
);
|
|
275
|
+
console.log(`(${rows.length} rows)`);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
perf
|
|
279
|
+
.command("apply")
|
|
280
|
+
.argument("<id>", "Recommendation id")
|
|
281
|
+
.description("Mark a recommendation as applied")
|
|
282
|
+
.option("-n, --note <note>", "Optional note")
|
|
283
|
+
.option("--json", "JSON output")
|
|
284
|
+
.action((id, opts) => {
|
|
285
|
+
const db = _dbFromCtx(perf);
|
|
286
|
+
const r = applyRecommendation(db, id, { note: opts.note });
|
|
287
|
+
if (opts.json) return _json(r);
|
|
288
|
+
if (!r.applied) {
|
|
289
|
+
console.error(`Failed: ${r.reason}`);
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
console.log(`Applied ${id} @ ${_fmtTs(r.appliedAt)}`);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
perf
|
|
296
|
+
.command("dismiss")
|
|
297
|
+
.argument("<id>", "Recommendation id")
|
|
298
|
+
.description("Dismiss a pending recommendation")
|
|
299
|
+
.option("-n, --note <note>", "Optional note")
|
|
300
|
+
.option("--json", "JSON output")
|
|
301
|
+
.action((id, opts) => {
|
|
302
|
+
const db = _dbFromCtx(perf);
|
|
303
|
+
const r = dismissRecommendation(db, id, { note: opts.note });
|
|
304
|
+
if (opts.json) return _json(r);
|
|
305
|
+
if (!r.dismissed) {
|
|
306
|
+
console.error(`Failed: ${r.reason}`);
|
|
307
|
+
process.exit(1);
|
|
308
|
+
}
|
|
309
|
+
console.log(`Dismissed ${id}`);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
/* ── History / alerts / stats ─────────────────────── */
|
|
313
|
+
|
|
314
|
+
perf
|
|
315
|
+
.command("history")
|
|
316
|
+
.description("Tuning action history")
|
|
317
|
+
.option("--rule-id <id>", "Filter by rule id")
|
|
318
|
+
.option("--limit <n>", "Max rows", (v) => parseInt(v, 10), 50)
|
|
319
|
+
.option("--json", "JSON output")
|
|
320
|
+
.action((opts) => {
|
|
321
|
+
const db = _dbFromCtx(perf);
|
|
322
|
+
const rows = listHistory(db, { ruleId: opts.ruleId, limit: opts.limit });
|
|
323
|
+
if (opts.json) return _json(rows);
|
|
324
|
+
for (const r of rows)
|
|
325
|
+
console.log(
|
|
326
|
+
` ${_fmtTs(r.createdAt)} ${r.ruleId.padEnd(20)} ${r.action}`,
|
|
327
|
+
);
|
|
328
|
+
console.log(`(${rows.length} rows)`);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
perf
|
|
332
|
+
.command("alerts")
|
|
333
|
+
.description("Current threshold violations against latest sample")
|
|
334
|
+
.option("--json", "JSON output")
|
|
335
|
+
.action((opts) => {
|
|
336
|
+
const db = _dbFromCtx(perf);
|
|
337
|
+
const rows = getAlerts(db);
|
|
338
|
+
if (opts.json) return _json(rows);
|
|
339
|
+
if (rows.length === 0) {
|
|
340
|
+
console.log("No alerts.");
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
for (const a of rows)
|
|
344
|
+
console.log(` [${a.level}] ${a.metric}=${a.value} > ${a.threshold}`);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
perf
|
|
348
|
+
.command("config")
|
|
349
|
+
.description("Show or update performance config")
|
|
350
|
+
.option("--max-samples <n>", "Ring buffer size", (v) => parseInt(v, 10))
|
|
351
|
+
.option(
|
|
352
|
+
"--interval-ms <n>",
|
|
353
|
+
"Intended sample interval (informational)",
|
|
354
|
+
(v) => parseInt(v, 10),
|
|
355
|
+
)
|
|
356
|
+
.option(
|
|
357
|
+
"--threshold <metric=value>",
|
|
358
|
+
"Override threshold (repeatable)",
|
|
359
|
+
(val, prev = {}) => {
|
|
360
|
+
const [k, v] = val.split("=");
|
|
361
|
+
prev[k] = parseFloat(v);
|
|
362
|
+
return prev;
|
|
363
|
+
},
|
|
364
|
+
)
|
|
365
|
+
.option("--json", "JSON output")
|
|
366
|
+
.action((opts) => {
|
|
367
|
+
const db = _dbFromCtx(perf);
|
|
368
|
+
const patch = {};
|
|
369
|
+
if (opts.maxSamples != null) patch.maxSamples = opts.maxSamples;
|
|
370
|
+
if (opts.intervalMs != null) patch.sampleIntervalMs = opts.intervalMs;
|
|
371
|
+
if (opts.threshold) patch.thresholds = opts.threshold;
|
|
372
|
+
const cfg =
|
|
373
|
+
Object.keys(patch).length > 0
|
|
374
|
+
? setPerfConfig(db, patch)
|
|
375
|
+
: getPerfConfig(db);
|
|
376
|
+
if (opts.json) return _json(cfg);
|
|
377
|
+
console.log(`maxSamples: ${cfg.maxSamples}`);
|
|
378
|
+
console.log(`sampleIntervalMs: ${cfg.sampleIntervalMs}`);
|
|
379
|
+
console.log("thresholds:");
|
|
380
|
+
for (const [k, v] of Object.entries(cfg.thresholds))
|
|
381
|
+
console.log(` ${k.padEnd(16)} ${v}`);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
perf
|
|
385
|
+
.command("stats")
|
|
386
|
+
.description("Aggregate perf stats")
|
|
387
|
+
.option("--json", "JSON output")
|
|
388
|
+
.action((opts) => {
|
|
389
|
+
const db = _dbFromCtx(perf);
|
|
390
|
+
const s = getPerfStats(db);
|
|
391
|
+
if (opts.json) return _json(s);
|
|
392
|
+
console.log(`Samples: ${s.samples}`);
|
|
393
|
+
console.log(
|
|
394
|
+
`Rules: ${s.rules.enabled}/${s.rules.total} enabled, triggered ${s.rules.triggered}x`,
|
|
395
|
+
);
|
|
396
|
+
console.log(
|
|
397
|
+
`Recommendations: pending=${s.recommendations.pending} applied=${s.recommendations.applied} dismissed=${s.recommendations.dismissed} total=${s.recommendations.total}`,
|
|
398
|
+
);
|
|
399
|
+
console.log(`History: ${s.historyEntries}`);
|
|
400
|
+
console.log(
|
|
401
|
+
`Averages: cpu=${s.averages.cpuPercent ?? "—"}% mem=${s.averages.memoryPercent ?? "—"}% heap=${s.averages.heapPercent ?? "—"}%`,
|
|
402
|
+
);
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
perf
|
|
406
|
+
.command("report")
|
|
407
|
+
.description("Full performance report (sample + alerts + stats + pending)")
|
|
408
|
+
.option("--json", "JSON output")
|
|
409
|
+
.action((opts) => {
|
|
410
|
+
const db = _dbFromCtx(perf);
|
|
411
|
+
const r = getPerformanceReport(db);
|
|
412
|
+
if (opts.json) return _json(r);
|
|
413
|
+
console.log(`Report @ ${_fmtTs(r.generatedAt)}`);
|
|
414
|
+
if (r.sample) {
|
|
415
|
+
console.log(
|
|
416
|
+
`Sample: cpu=${r.sample.cpuPercent}% mem=${r.sample.memoryPercent}% heap=${r.sample.heapPercent}% load/c=${r.sample.loadPerCore}`,
|
|
417
|
+
);
|
|
418
|
+
} else {
|
|
419
|
+
console.log("Sample: (none — run `cc perf collect`)");
|
|
420
|
+
}
|
|
421
|
+
console.log(`Alerts: ${r.alerts.length}`);
|
|
422
|
+
for (const a of r.alerts)
|
|
423
|
+
console.log(` [${a.level}] ${a.metric}=${a.value} > ${a.threshold}`);
|
|
424
|
+
console.log(
|
|
425
|
+
`Pending recommendations: ${r.pendingRecommendations.length}`,
|
|
426
|
+
);
|
|
427
|
+
for (const p of r.pendingRecommendations)
|
|
428
|
+
console.log(` ${p.id} ${p.ruleId} ${p.description}`);
|
|
429
|
+
console.log(`Recent history: ${r.recentHistory.length}`);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
program.addCommand(perf);
|
|
433
|
+
}
|