chainlesschain 0.47.9 → 0.49.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/bin/chainlesschain.js +0 -0
- package/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AppLayout-6SPt_8Y_.js → AppLayout-Rvi759IS.js} +1 -1
- package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +1 -0
- package/src/assets/web-panel/assets/{Dashboard-Br7kCwKJ.js → Dashboard-DBhFxXYQ.js} +2 -2
- package/src/assets/web-panel/assets/{index-tN-8TosE.js → index-uL0cZ8N_.js} +2 -2
- package/src/assets/web-panel/index.html +2 -2
- package/src/commands/codegen.js +303 -0
- package/src/commands/collab.js +482 -0
- package/src/commands/crosschain.js +382 -0
- package/src/commands/dbevo.js +388 -0
- package/src/commands/dev.js +411 -0
- package/src/commands/federation.js +427 -0
- package/src/commands/fusion.js +332 -0
- package/src/commands/governance.js +505 -0
- package/src/commands/hardening.js +110 -0
- package/src/commands/incentive.js +373 -0
- package/src/commands/inference.js +304 -0
- package/src/commands/infra.js +361 -0
- package/src/commands/kg.js +371 -0
- package/src/commands/marketplace.js +326 -0
- package/src/commands/mcp.js +97 -18
- package/src/commands/nlprog.js +329 -0
- package/src/commands/ops.js +408 -0
- package/src/commands/perception.js +385 -0
- package/src/commands/pqc.js +34 -0
- package/src/commands/privacy.js +345 -0
- package/src/commands/quantization.js +280 -0
- package/src/commands/recommend.js +336 -0
- package/src/commands/reputation.js +349 -0
- package/src/commands/runtime.js +500 -0
- package/src/commands/sla.js +352 -0
- package/src/commands/stress.js +252 -0
- package/src/commands/tech.js +268 -0
- package/src/commands/tenant.js +576 -0
- package/src/commands/trust.js +366 -0
- package/src/harness/mcp-client.js +330 -54
- package/src/index.js +112 -0
- package/src/lib/aiops.js +523 -0
- package/src/lib/autonomous-developer.js +524 -0
- package/src/lib/code-agent.js +442 -0
- package/src/lib/collaboration-governance.js +556 -0
- package/src/lib/community-governance.js +649 -0
- package/src/lib/content-recommendation.js +600 -0
- package/src/lib/cross-chain.js +669 -0
- package/src/lib/dbevo.js +669 -0
- package/src/lib/decentral-infra.js +445 -0
- package/src/lib/federation-hardening.js +587 -0
- package/src/lib/hardening-manager.js +409 -0
- package/src/lib/inference-network.js +407 -0
- package/src/lib/knowledge-graph.js +530 -0
- package/src/lib/mcp-client.js +3 -0
- package/src/lib/multimodal.js +698 -0
- package/src/lib/nl-programming.js +595 -0
- package/src/lib/perception.js +500 -0
- package/src/lib/pqc-manager.js +141 -9
- package/src/lib/privacy-computing.js +575 -0
- package/src/lib/protocol-fusion.js +535 -0
- package/src/lib/quantization.js +362 -0
- package/src/lib/reputation-optimizer.js +509 -0
- package/src/lib/skill-marketplace.js +397 -0
- package/src/lib/sla-manager.js +484 -0
- package/src/lib/stress-tester.js +383 -0
- package/src/lib/tech-learning-engine.js +651 -0
- package/src/lib/tenant-saas.js +831 -0
- package/src/lib/token-incentive.js +513 -0
- package/src/lib/trust-security.js +473 -0
- package/src/lib/universal-runtime.js +771 -0
- package/src/assets/web-panel/assets/Dashboard-CKeMmCoT.css +0 -1
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cc ops` — CLI surface for Autonomous Ops (AIOps).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
SEVERITY,
|
|
9
|
+
INCIDENT_STATUS,
|
|
10
|
+
DETECTION_ALGORITHM,
|
|
11
|
+
ROLLBACK_TYPE,
|
|
12
|
+
ensureAiOpsTables,
|
|
13
|
+
updateBaseline,
|
|
14
|
+
getBaseline,
|
|
15
|
+
listBaselines,
|
|
16
|
+
detectAnomaly,
|
|
17
|
+
createIncident,
|
|
18
|
+
getIncident,
|
|
19
|
+
acknowledgeIncident,
|
|
20
|
+
resolveIncident,
|
|
21
|
+
closeIncident,
|
|
22
|
+
listIncidents,
|
|
23
|
+
createPlaybook,
|
|
24
|
+
getPlaybook,
|
|
25
|
+
togglePlaybook,
|
|
26
|
+
recordPlaybookResult,
|
|
27
|
+
listPlaybooks,
|
|
28
|
+
generatePostmortem,
|
|
29
|
+
getOpsStats,
|
|
30
|
+
} from "../lib/aiops.js";
|
|
31
|
+
|
|
32
|
+
function _dbFromCtx(cmd) {
|
|
33
|
+
const root = cmd?.parent?.parent ?? cmd?.parent;
|
|
34
|
+
return root?._db;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function registerOpsCommand(program) {
|
|
38
|
+
const ops = new Command("ops")
|
|
39
|
+
.description("Autonomous operations / AIOps")
|
|
40
|
+
.hook("preAction", (thisCmd) => {
|
|
41
|
+
const db = _dbFromCtx(thisCmd);
|
|
42
|
+
if (db) ensureAiOpsTables(db);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
/* ── Catalogs ────────────────────────────────────── */
|
|
46
|
+
|
|
47
|
+
ops
|
|
48
|
+
.command("severities")
|
|
49
|
+
.description("List severity levels")
|
|
50
|
+
.option("--json", "JSON output")
|
|
51
|
+
.action((opts) => {
|
|
52
|
+
const sevs = Object.values(SEVERITY);
|
|
53
|
+
if (opts.json) return console.log(JSON.stringify(sevs, null, 2));
|
|
54
|
+
for (const s of sevs) console.log(` ${s}`);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
ops
|
|
58
|
+
.command("statuses")
|
|
59
|
+
.description("List incident statuses")
|
|
60
|
+
.option("--json", "JSON output")
|
|
61
|
+
.action((opts) => {
|
|
62
|
+
const sts = Object.values(INCIDENT_STATUS);
|
|
63
|
+
if (opts.json) return console.log(JSON.stringify(sts, null, 2));
|
|
64
|
+
for (const s of sts) console.log(` ${s}`);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
ops
|
|
68
|
+
.command("algorithms")
|
|
69
|
+
.description("List detection algorithms")
|
|
70
|
+
.option("--json", "JSON output")
|
|
71
|
+
.action((opts) => {
|
|
72
|
+
const algos = Object.values(DETECTION_ALGORITHM);
|
|
73
|
+
if (opts.json) return console.log(JSON.stringify(algos, null, 2));
|
|
74
|
+
for (const a of algos) console.log(` ${a}`);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
ops
|
|
78
|
+
.command("rollback-types")
|
|
79
|
+
.description("List rollback types")
|
|
80
|
+
.option("--json", "JSON output")
|
|
81
|
+
.action((opts) => {
|
|
82
|
+
const types = Object.values(ROLLBACK_TYPE);
|
|
83
|
+
if (opts.json) return console.log(JSON.stringify(types, null, 2));
|
|
84
|
+
for (const t of types) console.log(` ${t}`);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
/* ── Baselines ───────────────────────────────────── */
|
|
88
|
+
|
|
89
|
+
ops
|
|
90
|
+
.command("baseline-update <metric>")
|
|
91
|
+
.description("Update metric baseline from values")
|
|
92
|
+
.requiredOption("-v, --values <csv>", "Comma-separated values")
|
|
93
|
+
.option("--json", "JSON output")
|
|
94
|
+
.action((metric, opts) => {
|
|
95
|
+
const db = _dbFromCtx(ops);
|
|
96
|
+
const values = opts.values
|
|
97
|
+
.split(",")
|
|
98
|
+
.map(Number)
|
|
99
|
+
.filter((n) => !isNaN(n));
|
|
100
|
+
const result = updateBaseline(db, metric, values);
|
|
101
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
102
|
+
if (result.updated) {
|
|
103
|
+
const b = result.baseline;
|
|
104
|
+
console.log(`Baseline updated: ${metric}`);
|
|
105
|
+
console.log(
|
|
106
|
+
` mean=${b.mean} stddev=${b.std_dev} q1=${b.q1} q3=${b.q3} samples=${b.sample_count}`,
|
|
107
|
+
);
|
|
108
|
+
} else {
|
|
109
|
+
console.log(`Failed: ${result.reason}`);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
ops
|
|
114
|
+
.command("baseline-show <metric>")
|
|
115
|
+
.description("Show metric baseline")
|
|
116
|
+
.option("--json", "JSON output")
|
|
117
|
+
.action((metric, opts) => {
|
|
118
|
+
const db = _dbFromCtx(ops);
|
|
119
|
+
const b = getBaseline(db, metric);
|
|
120
|
+
if (!b) return console.log("Baseline not found.");
|
|
121
|
+
if (opts.json) return console.log(JSON.stringify(b, null, 2));
|
|
122
|
+
console.log(`Metric: ${b.metric_name}`);
|
|
123
|
+
console.log(`Mean: ${b.mean}`);
|
|
124
|
+
console.log(`StdDev: ${b.std_dev}`);
|
|
125
|
+
console.log(`Q1: ${b.q1}`);
|
|
126
|
+
console.log(`Q3: ${b.q3}`);
|
|
127
|
+
console.log(`Samples: ${b.sample_count}`);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
ops
|
|
131
|
+
.command("baselines")
|
|
132
|
+
.description("List metric baselines")
|
|
133
|
+
.option("--json", "JSON output")
|
|
134
|
+
.action((opts) => {
|
|
135
|
+
const db = _dbFromCtx(ops);
|
|
136
|
+
const bls = listBaselines(db);
|
|
137
|
+
if (opts.json) return console.log(JSON.stringify(bls, null, 2));
|
|
138
|
+
if (bls.length === 0) return console.log("No baselines.");
|
|
139
|
+
for (const b of bls) {
|
|
140
|
+
console.log(
|
|
141
|
+
` ${b.metric_name.padEnd(20)} mean=${String(b.mean).padEnd(8)} stddev=${String(b.std_dev).padEnd(8)} n=${b.sample_count}`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
/* ── Anomaly Detection ───────────────────────────── */
|
|
147
|
+
|
|
148
|
+
ops
|
|
149
|
+
.command("detect <metric> <value>")
|
|
150
|
+
.description("Detect anomaly for a metric value")
|
|
151
|
+
.option("-a, --algorithm <algo>", "Algorithm (z_score|iqr)", "z_score")
|
|
152
|
+
.option("--json", "JSON output")
|
|
153
|
+
.action((metric, value, opts) => {
|
|
154
|
+
const db = _dbFromCtx(ops);
|
|
155
|
+
const result = detectAnomaly(db, {
|
|
156
|
+
metricName: metric,
|
|
157
|
+
value: parseFloat(value),
|
|
158
|
+
algorithm: opts.algorithm,
|
|
159
|
+
});
|
|
160
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
161
|
+
if (result.reason) return console.log(`Cannot detect: ${result.reason}`);
|
|
162
|
+
if (result.anomaly) {
|
|
163
|
+
console.log(
|
|
164
|
+
`⚠ ANOMALY: ${metric}=${value} (${result.algorithm} score=${result.score})`,
|
|
165
|
+
);
|
|
166
|
+
if (result.incidentId)
|
|
167
|
+
console.log(` Incident: ${result.incidentId} [${result.severity}]`);
|
|
168
|
+
} else {
|
|
169
|
+
console.log(
|
|
170
|
+
`OK: ${metric}=${value} within normal range (score=${result.score})`,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
/* ── Incidents ───────────────────────────────────── */
|
|
176
|
+
|
|
177
|
+
ops
|
|
178
|
+
.command("incident-create")
|
|
179
|
+
.description("Create an incident manually")
|
|
180
|
+
.option("-m, --metric <name>", "Anomaly metric")
|
|
181
|
+
.option("-s, --severity <P0-P3>", "Severity", "P3")
|
|
182
|
+
.option("-d, --description <text>", "Description")
|
|
183
|
+
.option("--json", "JSON output")
|
|
184
|
+
.action((opts) => {
|
|
185
|
+
const db = _dbFromCtx(ops);
|
|
186
|
+
const result = createIncident(db, {
|
|
187
|
+
anomalyMetric: opts.metric,
|
|
188
|
+
severity: opts.severity,
|
|
189
|
+
description: opts.description,
|
|
190
|
+
});
|
|
191
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
192
|
+
console.log(`Incident created: ${result.incidentId}`);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
ops
|
|
196
|
+
.command("incident-show <id>")
|
|
197
|
+
.description("Show incident details")
|
|
198
|
+
.option("--json", "JSON output")
|
|
199
|
+
.action((id, opts) => {
|
|
200
|
+
const db = _dbFromCtx(ops);
|
|
201
|
+
const i = getIncident(db, id);
|
|
202
|
+
if (!i) return console.log("Incident not found.");
|
|
203
|
+
if (opts.json) return console.log(JSON.stringify(i, null, 2));
|
|
204
|
+
console.log(`ID: ${i.id}`);
|
|
205
|
+
console.log(`Severity: ${i.severity}`);
|
|
206
|
+
console.log(`Status: ${i.status}`);
|
|
207
|
+
if (i.anomaly_metric) console.log(`Metric: ${i.anomaly_metric}`);
|
|
208
|
+
if (i.description) console.log(`Desc: ${i.description.slice(0, 80)}`);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
ops
|
|
212
|
+
.command("incident-ack <id>")
|
|
213
|
+
.description("Acknowledge an incident")
|
|
214
|
+
.option("--json", "JSON output")
|
|
215
|
+
.action((id, opts) => {
|
|
216
|
+
const db = _dbFromCtx(ops);
|
|
217
|
+
const result = acknowledgeIncident(db, id);
|
|
218
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
219
|
+
console.log(
|
|
220
|
+
result.acknowledged
|
|
221
|
+
? "Incident acknowledged."
|
|
222
|
+
: `Failed: ${result.reason}`,
|
|
223
|
+
);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
ops
|
|
227
|
+
.command("incident-resolve <id>")
|
|
228
|
+
.description("Resolve an incident")
|
|
229
|
+
.option("--json", "JSON output")
|
|
230
|
+
.action((id, opts) => {
|
|
231
|
+
const db = _dbFromCtx(ops);
|
|
232
|
+
const result = resolveIncident(db, id);
|
|
233
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
234
|
+
console.log(
|
|
235
|
+
result.resolved ? "Incident resolved." : `Failed: ${result.reason}`,
|
|
236
|
+
);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
ops
|
|
240
|
+
.command("incident-close <id>")
|
|
241
|
+
.description("Close a resolved incident")
|
|
242
|
+
.option("--json", "JSON output")
|
|
243
|
+
.action((id, opts) => {
|
|
244
|
+
const db = _dbFromCtx(ops);
|
|
245
|
+
const result = closeIncident(db, id);
|
|
246
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
247
|
+
console.log(
|
|
248
|
+
result.closed ? "Incident closed." : `Failed: ${result.reason}`,
|
|
249
|
+
);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
ops
|
|
253
|
+
.command("incidents")
|
|
254
|
+
.description("List incidents")
|
|
255
|
+
.option("-s, --severity <P0-P3>", "Filter by severity")
|
|
256
|
+
.option("-S, --status <status>", "Filter by status")
|
|
257
|
+
.option("--limit <n>", "Max results", parseInt)
|
|
258
|
+
.option("--json", "JSON output")
|
|
259
|
+
.action((opts) => {
|
|
260
|
+
const db = _dbFromCtx(ops);
|
|
261
|
+
const incs = listIncidents(db, {
|
|
262
|
+
severity: opts.severity,
|
|
263
|
+
status: opts.status,
|
|
264
|
+
limit: opts.limit,
|
|
265
|
+
});
|
|
266
|
+
if (opts.json) return console.log(JSON.stringify(incs, null, 2));
|
|
267
|
+
if (incs.length === 0) return console.log("No incidents.");
|
|
268
|
+
for (const i of incs) {
|
|
269
|
+
console.log(
|
|
270
|
+
` [${i.severity}] ${i.status.padEnd(14)} ${(i.anomaly_metric || "").padEnd(20)} ${i.id.slice(0, 8)}`,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
/* ── Playbooks ───────────────────────────────────── */
|
|
276
|
+
|
|
277
|
+
ops
|
|
278
|
+
.command("playbook-create")
|
|
279
|
+
.description("Create remediation playbook")
|
|
280
|
+
.requiredOption("-n, --name <name>", "Playbook name")
|
|
281
|
+
.option("-t, --trigger <json>", "Trigger condition JSON")
|
|
282
|
+
.option("-s, --steps <json>", "Steps JSON")
|
|
283
|
+
.option("--json", "JSON output")
|
|
284
|
+
.action((opts) => {
|
|
285
|
+
const db = _dbFromCtx(ops);
|
|
286
|
+
const result = createPlaybook(db, {
|
|
287
|
+
name: opts.name,
|
|
288
|
+
triggerCondition: opts.trigger,
|
|
289
|
+
steps: opts.steps,
|
|
290
|
+
});
|
|
291
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
292
|
+
if (result.playbookId)
|
|
293
|
+
console.log(`Playbook created: ${result.playbookId}`);
|
|
294
|
+
else console.log(`Failed: ${result.reason}`);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
ops
|
|
298
|
+
.command("playbook-show <id>")
|
|
299
|
+
.description("Show playbook details")
|
|
300
|
+
.option("--json", "JSON output")
|
|
301
|
+
.action((id, opts) => {
|
|
302
|
+
const db = _dbFromCtx(ops);
|
|
303
|
+
const p = getPlaybook(db, id);
|
|
304
|
+
if (!p) return console.log("Playbook not found.");
|
|
305
|
+
if (opts.json) return console.log(JSON.stringify(p, null, 2));
|
|
306
|
+
console.log(`ID: ${p.id}`);
|
|
307
|
+
console.log(`Name: ${p.name}`);
|
|
308
|
+
console.log(`Enabled: ${p.enabled ? "YES" : "NO"}`);
|
|
309
|
+
console.log(`Success: ${p.success_count} Failure: ${p.failure_count}`);
|
|
310
|
+
if (p.trigger_condition) console.log(`Trigger: ${p.trigger_condition}`);
|
|
311
|
+
if (p.steps) console.log(`Steps: ${p.steps}`);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
ops
|
|
315
|
+
.command("playbook-toggle <id> <on|off>")
|
|
316
|
+
.description("Enable or disable a playbook")
|
|
317
|
+
.option("--json", "JSON output")
|
|
318
|
+
.action((id, state, opts) => {
|
|
319
|
+
const db = _dbFromCtx(ops);
|
|
320
|
+
const result = togglePlaybook(db, id, state === "on");
|
|
321
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
322
|
+
console.log(
|
|
323
|
+
result.toggled
|
|
324
|
+
? `Playbook ${result.enabled ? "enabled" : "disabled"}.`
|
|
325
|
+
: `Failed: ${result.reason}`,
|
|
326
|
+
);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
ops
|
|
330
|
+
.command("playbook-record <id> <success|failure>")
|
|
331
|
+
.description("Record playbook execution result")
|
|
332
|
+
.option("--json", "JSON output")
|
|
333
|
+
.action((id, outcome, opts) => {
|
|
334
|
+
const db = _dbFromCtx(ops);
|
|
335
|
+
const result = recordPlaybookResult(db, id, outcome === "success");
|
|
336
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
337
|
+
console.log(
|
|
338
|
+
result.recorded
|
|
339
|
+
? `Recorded. Success=${result.successCount} Failure=${result.failureCount}`
|
|
340
|
+
: `Failed: ${result.reason}`,
|
|
341
|
+
);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
ops
|
|
345
|
+
.command("playbooks")
|
|
346
|
+
.description("List playbooks")
|
|
347
|
+
.option("-e, --enabled", "Only enabled")
|
|
348
|
+
.option("-d, --disabled", "Only disabled")
|
|
349
|
+
.option("--limit <n>", "Max results", parseInt)
|
|
350
|
+
.option("--json", "JSON output")
|
|
351
|
+
.action((opts) => {
|
|
352
|
+
const db = _dbFromCtx(ops);
|
|
353
|
+
const enabled = opts.enabled ? true : opts.disabled ? false : undefined;
|
|
354
|
+
const pbs = listPlaybooks(db, { enabled, limit: opts.limit });
|
|
355
|
+
if (opts.json) return console.log(JSON.stringify(pbs, null, 2));
|
|
356
|
+
if (pbs.length === 0) return console.log("No playbooks.");
|
|
357
|
+
for (const p of pbs) {
|
|
358
|
+
console.log(
|
|
359
|
+
` ${p.enabled ? "ON " : "OFF"} ${p.name.padEnd(24)} ok:${String(p.success_count).padEnd(3)} fail:${String(p.failure_count).padEnd(3)} ${p.id.slice(0, 8)}`,
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
/* ── Postmortem ──────────────────────────────────── */
|
|
365
|
+
|
|
366
|
+
ops
|
|
367
|
+
.command("postmortem <id>")
|
|
368
|
+
.description("Generate postmortem for resolved incident")
|
|
369
|
+
.option("--json", "JSON output")
|
|
370
|
+
.action((id, opts) => {
|
|
371
|
+
const db = _dbFromCtx(ops);
|
|
372
|
+
const result = generatePostmortem(db, id);
|
|
373
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
374
|
+
if (!result.generated) return console.log(`Failed: ${result.reason}`);
|
|
375
|
+
const pm = result.postmortem;
|
|
376
|
+
console.log(`Postmortem for ${pm.incidentId} [${pm.severity}]`);
|
|
377
|
+
console.log(` Metric: ${pm.metric || "N/A"}`);
|
|
378
|
+
console.log(` Impact: ${pm.impact}`);
|
|
379
|
+
console.log(` Root Cause: ${pm.rootCause}`);
|
|
380
|
+
console.log(` TTR: ${pm.timeline.timeToResolveMs}ms`);
|
|
381
|
+
if (pm.timeline.timeToAcknowledgeMs != null)
|
|
382
|
+
console.log(` TTA: ${pm.timeline.timeToAcknowledgeMs}ms`);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
/* ── Stats ───────────────────────────────────────── */
|
|
386
|
+
|
|
387
|
+
ops
|
|
388
|
+
.command("stats")
|
|
389
|
+
.description("AIOps statistics")
|
|
390
|
+
.option("--json", "JSON output")
|
|
391
|
+
.action((opts) => {
|
|
392
|
+
const db = _dbFromCtx(ops);
|
|
393
|
+
const s = getOpsStats(db);
|
|
394
|
+
if (opts.json) return console.log(JSON.stringify(s, null, 2));
|
|
395
|
+
console.log(
|
|
396
|
+
`Incidents: ${s.incidents.total} (avg resolve ${s.incidents.avgResolveMs}ms)`,
|
|
397
|
+
);
|
|
398
|
+
for (const [sev, count] of Object.entries(s.incidents.bySeverity)) {
|
|
399
|
+
if (count > 0) console.log(` ${sev}: ${count}`);
|
|
400
|
+
}
|
|
401
|
+
console.log(
|
|
402
|
+
`Playbooks: ${s.playbooks.total} (${s.playbooks.enabled} enabled, ${s.playbooks.totalSuccess} ok / ${s.playbooks.totalFailure} fail)`,
|
|
403
|
+
);
|
|
404
|
+
console.log(`Baselines: ${s.baselines.total} metrics`);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
program.addCommand(ops);
|
|
408
|
+
}
|