@kb-labs/agent-cli 0.5.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.
Files changed (136) hide show
  1. package/README.md +56 -0
  2. package/dist/cli/commands/diff.d.ts +17 -0
  3. package/dist/cli/commands/diff.js +182 -0
  4. package/dist/cli/commands/diff.js.map +1 -0
  5. package/dist/cli/commands/history.d.ts +16 -0
  6. package/dist/cli/commands/history.js +216 -0
  7. package/dist/cli/commands/history.js.map +1 -0
  8. package/dist/cli/commands/quality-report.d.ts +21 -0
  9. package/dist/cli/commands/quality-report.js +457 -0
  10. package/dist/cli/commands/quality-report.js.map +1 -0
  11. package/dist/cli/commands/rollback.d.ts +27 -0
  12. package/dist/cli/commands/rollback.js +109 -0
  13. package/dist/cli/commands/rollback.js.map +1 -0
  14. package/dist/cli/commands/run.d.ts +42 -0
  15. package/dist/cli/commands/run.js +923 -0
  16. package/dist/cli/commands/run.js.map +1 -0
  17. package/dist/cli/commands/trace-context.d.ts +22 -0
  18. package/dist/cli/commands/trace-context.js +131 -0
  19. package/dist/cli/commands/trace-context.js.map +1 -0
  20. package/dist/cli/commands/trace-diagnose.d.ts +20 -0
  21. package/dist/cli/commands/trace-diagnose.js +434 -0
  22. package/dist/cli/commands/trace-diagnose.js.map +1 -0
  23. package/dist/cli/commands/trace-event-normalizer.d.ts +13 -0
  24. package/dist/cli/commands/trace-event-normalizer.js +39 -0
  25. package/dist/cli/commands/trace-event-normalizer.js.map +1 -0
  26. package/dist/cli/commands/trace-filter.d.ts +19 -0
  27. package/dist/cli/commands/trace-filter.js +153 -0
  28. package/dist/cli/commands/trace-filter.js.map +1 -0
  29. package/dist/cli/commands/trace-iteration.d.ts +18 -0
  30. package/dist/cli/commands/trace-iteration.js +192 -0
  31. package/dist/cli/commands/trace-iteration.js.map +1 -0
  32. package/dist/cli/commands/trace-stats.d.ts +17 -0
  33. package/dist/cli/commands/trace-stats.js +247 -0
  34. package/dist/cli/commands/trace-stats.js.map +1 -0
  35. package/dist/index.d.ts +2 -0
  36. package/dist/index.js +473 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/manifest.d.ts +184 -0
  39. package/dist/manifest.js +473 -0
  40. package/dist/manifest.js.map +1 -0
  41. package/dist/rest/handlers/approve-handler.d.ts +15 -0
  42. package/dist/rest/handlers/approve-handler.js +60 -0
  43. package/dist/rest/handlers/approve-handler.js.map +1 -0
  44. package/dist/rest/handlers/approve-session-plan-handler.d.ts +10 -0
  45. package/dist/rest/handlers/approve-session-plan-handler.js +52 -0
  46. package/dist/rest/handlers/approve-session-plan-handler.js.map +1 -0
  47. package/dist/rest/handlers/correct-handler.d.ts +7 -0
  48. package/dist/rest/handlers/correct-handler.js +326 -0
  49. package/dist/rest/handlers/correct-handler.js.map +1 -0
  50. package/dist/rest/handlers/create-session-handler.d.ts +7 -0
  51. package/dist/rest/handlers/create-session-handler.js +25 -0
  52. package/dist/rest/handlers/create-session-handler.js.map +1 -0
  53. package/dist/rest/handlers/execute-session-plan-handler.d.ts +10 -0
  54. package/dist/rest/handlers/execute-session-plan-handler.js +635 -0
  55. package/dist/rest/handlers/execute-session-plan-handler.js.map +1 -0
  56. package/dist/rest/handlers/generate-spec-handler.d.ts +10 -0
  57. package/dist/rest/handlers/generate-spec-handler.js +389 -0
  58. package/dist/rest/handlers/generate-spec-handler.js.map +1 -0
  59. package/dist/rest/handlers/get-file-diff-handler.d.ts +24 -0
  60. package/dist/rest/handlers/get-file-diff-handler.js +44 -0
  61. package/dist/rest/handlers/get-file-diff-handler.js.map +1 -0
  62. package/dist/rest/handlers/get-session-handler.d.ts +10 -0
  63. package/dist/rest/handlers/get-session-handler.js +23 -0
  64. package/dist/rest/handlers/get-session-handler.js.map +1 -0
  65. package/dist/rest/handlers/get-session-plan-handler.d.ts +10 -0
  66. package/dist/rest/handlers/get-session-plan-handler.js +53 -0
  67. package/dist/rest/handlers/get-session-plan-handler.js.map +1 -0
  68. package/dist/rest/handlers/get-session-turns-handler.d.ts +16 -0
  69. package/dist/rest/handlers/get-session-turns-handler.js +35 -0
  70. package/dist/rest/handlers/get-session-turns-handler.js.map +1 -0
  71. package/dist/rest/handlers/get-spec-handler.d.ts +10 -0
  72. package/dist/rest/handlers/get-spec-handler.js +39 -0
  73. package/dist/rest/handlers/get-spec-handler.js.map +1 -0
  74. package/dist/rest/handlers/list-file-changes-handler.d.ts +13 -0
  75. package/dist/rest/handlers/list-file-changes-handler.js +34 -0
  76. package/dist/rest/handlers/list-file-changes-handler.js.map +1 -0
  77. package/dist/rest/handlers/list-sessions-handler.d.ts +7 -0
  78. package/dist/rest/handlers/list-sessions-handler.js +23 -0
  79. package/dist/rest/handlers/list-sessions-handler.js.map +1 -0
  80. package/dist/rest/handlers/rollback-handler.d.ts +22 -0
  81. package/dist/rest/handlers/rollback-handler.js +91 -0
  82. package/dist/rest/handlers/rollback-handler.js.map +1 -0
  83. package/dist/rest/handlers/run-handler.d.ts +7 -0
  84. package/dist/rest/handlers/run-handler.js +516 -0
  85. package/dist/rest/handlers/run-handler.js.map +1 -0
  86. package/dist/rest/handlers/sessions-handler.d.ts +18 -0
  87. package/dist/rest/handlers/sessions-handler.js +56 -0
  88. package/dist/rest/handlers/sessions-handler.js.map +1 -0
  89. package/dist/rest/handlers/status-handler.d.ts +7 -0
  90. package/dist/rest/handlers/status-handler.js +313 -0
  91. package/dist/rest/handlers/status-handler.js.map +1 -0
  92. package/dist/rest/handlers/stop-handler.d.ts +7 -0
  93. package/dist/rest/handlers/stop-handler.js +317 -0
  94. package/dist/rest/handlers/stop-handler.js.map +1 -0
  95. package/dist/widgets/220.js +446 -0
  96. package/dist/widgets/220.js.map +1 -0
  97. package/dist/widgets/331.js +2 -0
  98. package/dist/widgets/331.js.map +1 -0
  99. package/dist/widgets/403.js +2 -0
  100. package/dist/widgets/403.js.map +1 -0
  101. package/dist/widgets/406.js +35 -0
  102. package/dist/widgets/406.js.map +1 -0
  103. package/dist/widgets/455.js +2 -0
  104. package/dist/widgets/455.js.map +1 -0
  105. package/dist/widgets/482.js +2 -0
  106. package/dist/widgets/482.js.map +1 -0
  107. package/dist/widgets/485.js +2 -0
  108. package/dist/widgets/485.js.map +1 -0
  109. package/dist/widgets/527.js +2 -0
  110. package/dist/widgets/527.js.map +1 -0
  111. package/dist/widgets/628.js +2 -0
  112. package/dist/widgets/628.js.map +1 -0
  113. package/dist/widgets/694.js +2 -0
  114. package/dist/widgets/694.js.map +1 -0
  115. package/dist/widgets/712.js +2 -0
  116. package/dist/widgets/712.js.map +1 -0
  117. package/dist/widgets/866.js +2 -0
  118. package/dist/widgets/866.js.map +1 -0
  119. package/dist/widgets/915.js +39 -0
  120. package/dist/widgets/915.js.map +1 -0
  121. package/dist/widgets/957.js +10 -0
  122. package/dist/widgets/957.js.map +1 -0
  123. package/dist/widgets/983.js +2 -0
  124. package/dist/widgets/983.js.map +1 -0
  125. package/dist/widgets/@mf-types.d.ts +3 -0
  126. package/dist/widgets/@mf-types.zip +0 -0
  127. package/dist/widgets/__federation_expose_AgentsPage.js +2 -0
  128. package/dist/widgets/__federation_expose_AgentsPage.js.map +1 -0
  129. package/dist/widgets/mf-manifest.json +260 -0
  130. package/dist/widgets/mf-stats.json +305 -0
  131. package/dist/widgets/remoteEntry.js +7 -0
  132. package/dist/widgets/remoteEntry.js.map +1 -0
  133. package/dist/ws/session-stream-handler.d.ts +8 -0
  134. package/dist/ws/session-stream-handler.js +409 -0
  135. package/dist/ws/session-stream-handler.js.map +1 -0
  136. package/package.json +83 -0
@@ -0,0 +1,457 @@
1
+ import { defineCommand } from '@kb-labs/sdk';
2
+ import { promises } from 'fs';
3
+ import path from 'path';
4
+ import { execFile as execFile$1 } from 'child_process';
5
+ import { promisify } from 'util';
6
+
7
+ // src/cli/commands/quality-report.ts
8
+ var execFile = promisify(execFile$1);
9
+ function deriveQualityStatus(payload) {
10
+ if (payload?.qualityGate?.status === "pass" || payload?.qualityGate?.status === "partial") {
11
+ return payload.qualityGate.status;
12
+ }
13
+ if (payload?.qualityGateStatus === "pass" || payload?.qualityGateStatus === "partial") {
14
+ return payload.qualityGateStatus;
15
+ }
16
+ return payload?.success ? "pass" : "partial";
17
+ }
18
+ var quality_report_default = defineCommand({
19
+ id: "quality:report",
20
+ description: "Show quality control report for agent runs (quality, tokens, tools, drift, regressions)",
21
+ handler: {
22
+ async execute(ctx, input) {
23
+ const flags = input.flags ?? input;
24
+ const days = Number(flags.days ?? 1);
25
+ const limit = Number(flags.limit ?? 200);
26
+ const rawSessionId = flags["session-id"] ?? flags.sessionId;
27
+ const sessionIdFilter = typeof rawSessionId === "string" ? rawSessionId : void 0;
28
+ const json = Boolean(flags.json);
29
+ if (!Number.isFinite(days) || days <= 0) {
30
+ const err = { success: false, error: "--days must be a positive number" };
31
+ ctx.ui.write(JSON.stringify(err, null, 2) + "\n");
32
+ return { exitCode: 1, response: err };
33
+ }
34
+ const analyticsDir = path.join(process.cwd(), ".kb", "analytics", "buffer");
35
+ const files = await listEventFiles(analyticsDir, days);
36
+ if (files.length === 0) {
37
+ const out = { success: true, message: "No analytics files found for selected period", runs: 0 };
38
+ ctx.ui.write(JSON.stringify(out, null, 2) + "\n");
39
+ return { exitCode: 0, response: out };
40
+ }
41
+ const since = Date.now() - days * 24 * 60 * 60 * 1e3;
42
+ let { runs, regressions } = await readEvents(files, since, sessionIdFilter, limit);
43
+ if (runs.length === 0) {
44
+ const sqlitePath = path.join(process.cwd(), ".kb", "analytics", "analytics.sqlite");
45
+ const sqliteEvents = await readEventsFromSqlite(sqlitePath, since, sessionIdFilter, limit);
46
+ runs = sqliteEvents.runs;
47
+ regressions = sqliteEvents.regressions;
48
+ }
49
+ const report = buildReport(runs, regressions, { days, sessionIdFilter });
50
+ if (json) {
51
+ ctx.ui.write(JSON.stringify({ success: true, report }, null, 2) + "\n");
52
+ } else {
53
+ printReport(ctx, report);
54
+ }
55
+ return { exitCode: 0, response: report };
56
+ }
57
+ }
58
+ });
59
+ async function listEventFiles(dir, days) {
60
+ try {
61
+ const entries = await promises.readdir(dir);
62
+ const candidates = entries.filter((name) => /^events-\d{8}\.jsonl$/.test(name)).sort();
63
+ const keep = Math.max(1, Math.min(candidates.length, days + 2));
64
+ return candidates.slice(-keep).map((name) => path.join(dir, name));
65
+ } catch {
66
+ return [];
67
+ }
68
+ }
69
+ async function readEvents(files, sinceMs, sessionIdFilter, limit) {
70
+ const runs = [];
71
+ const regressions = [];
72
+ for (const file of files) {
73
+ const content = await promises.readFile(file, "utf-8");
74
+ const lines = content.split("\n").filter(Boolean);
75
+ for (const line of lines) {
76
+ let raw;
77
+ try {
78
+ raw = JSON.parse(line);
79
+ } catch {
80
+ continue;
81
+ }
82
+ const ts = typeof raw.ts === "string" ? Date.parse(raw.ts) : NaN;
83
+ if (!Number.isFinite(ts) || ts < sinceMs) {
84
+ continue;
85
+ }
86
+ if (raw.type === "agent.kpi.run_completed") {
87
+ const event = raw;
88
+ const p = event.payload || {};
89
+ const sessionId = p.sessionId || "unknown";
90
+ if (sessionIdFilter && sessionId !== sessionIdFilter) {
91
+ continue;
92
+ }
93
+ runs.push({
94
+ ts: event.ts || new Date(ts).toISOString(),
95
+ sessionId,
96
+ success: Boolean(p.success),
97
+ task: p.task || "",
98
+ summaryPreview: p.summaryPreview || "",
99
+ tokensUsed: Number(p.tokensUsed || 0),
100
+ durationMs: Number(p.durationMs || 0),
101
+ iterationsUsed: Number(p.iterationsUsed || 0),
102
+ iterationBudget: Number(p.iterationBudget || 0),
103
+ iterationUtilization: Number(p.iterationUtilization || 0),
104
+ toolCallsTotal: Number(p.toolCallsTotal || 0),
105
+ toolErrorRate: Number(p.toolErrorRate || 0),
106
+ todoUsed: Boolean(p.todoUsed),
107
+ evidenceDensity: Number(p.evidenceDensity || 0),
108
+ driftRate: Number(p.driftRate || 0),
109
+ qualityStatus: deriveQualityStatus(p),
110
+ qualityScore: Number(p.qualityGate?.score ?? (p.success ? 1 : 0)),
111
+ qualityReasons: Array.isArray(p.qualityGate?.reasons) ? p.qualityGate.reasons : [],
112
+ startTier: p.startTier === "small" || p.startTier === "large" ? p.startTier : "medium",
113
+ finalTier: p.finalTier === "small" || p.finalTier === "large" ? p.finalTier : "medium",
114
+ escalated: Boolean(p.escalated),
115
+ escalationCount: Number(p.escalationCount || 0),
116
+ escalationReasons: Array.isArray(p.escalationReasons) ? p.escalationReasons.filter((v) => typeof v === "string") : [],
117
+ escalationPath: Array.isArray(p.escalationPath) ? p.escalationPath.filter((v) => typeof v === "string") : []
118
+ });
119
+ } else if (raw.type === "agent.kpi.quality_regression") {
120
+ const event = raw;
121
+ const sessionId = event.payload?.sessionId;
122
+ if (sessionIdFilter && sessionId !== sessionIdFilter) {
123
+ continue;
124
+ }
125
+ regressions.push(event);
126
+ }
127
+ }
128
+ }
129
+ runs.sort((a, b) => Date.parse(b.ts) - Date.parse(a.ts));
130
+ const trimmedRuns = runs.slice(0, Math.max(1, limit));
131
+ return { runs: trimmedRuns, regressions };
132
+ }
133
+ async function readEventsFromSqlite(sqlitePath, sinceMs, sessionIdFilter, limit) {
134
+ try {
135
+ await promises.access(sqlitePath);
136
+ } catch {
137
+ return { runs: [], regressions: [] };
138
+ }
139
+ const sinceIso = new Date(sinceMs).toISOString();
140
+ const sql = [
141
+ "SELECT type, ts, payload",
142
+ "FROM events",
143
+ `WHERE ts >= '${sinceIso}'`,
144
+ " AND type IN ('agent.kpi.run_completed', 'agent.kpi.quality_regression')",
145
+ "ORDER BY ts DESC",
146
+ `LIMIT ${Math.max(limit * 5, 500)};`
147
+ ].join(" ");
148
+ try {
149
+ const { stdout } = await execFile("sqlite3", ["-json", sqlitePath, sql], {
150
+ maxBuffer: 20 * 1024 * 1024
151
+ });
152
+ const rows = JSON.parse(stdout || "[]");
153
+ const pseudoFileEvents = rows.map((row) => ({
154
+ type: row.type ?? "",
155
+ ts: row.ts,
156
+ payload: parseJsonSafe(row.payload)
157
+ }));
158
+ return readInMemoryEvents(pseudoFileEvents, sinceMs, sessionIdFilter, limit);
159
+ } catch {
160
+ return { runs: [], regressions: [] };
161
+ }
162
+ }
163
+ function parseJsonSafe(value) {
164
+ if (value && typeof value === "object") {
165
+ return value;
166
+ }
167
+ if (typeof value !== "string") {
168
+ return {};
169
+ }
170
+ try {
171
+ const parsed = JSON.parse(value);
172
+ return parsed && typeof parsed === "object" ? parsed : {};
173
+ } catch {
174
+ return {};
175
+ }
176
+ }
177
+ function readInMemoryEvents(rows, sinceMs, sessionIdFilter, limit) {
178
+ const runs = [];
179
+ const regressions = [];
180
+ for (const raw of rows) {
181
+ const ts = typeof raw.ts === "string" ? Date.parse(raw.ts) : NaN;
182
+ if (!Number.isFinite(ts) || ts < sinceMs) {
183
+ continue;
184
+ }
185
+ if (raw.type === "agent.kpi.run_completed") {
186
+ const p = raw.payload || {};
187
+ const sessionId = p?.sessionId || "unknown";
188
+ if (sessionIdFilter && sessionId !== sessionIdFilter) {
189
+ continue;
190
+ }
191
+ runs.push({
192
+ ts: raw.ts || new Date(ts).toISOString(),
193
+ sessionId,
194
+ success: Boolean(p?.success),
195
+ task: p?.task || "",
196
+ summaryPreview: p?.summaryPreview || "",
197
+ tokensUsed: Number(p?.tokensUsed || 0),
198
+ durationMs: Number(p?.durationMs || 0),
199
+ iterationsUsed: Number(p?.iterationsUsed || 0),
200
+ iterationBudget: Number(p?.iterationBudget || 0),
201
+ iterationUtilization: Number(p?.iterationUtilization || 0),
202
+ toolCallsTotal: Number(p?.toolCallsTotal || 0),
203
+ toolErrorRate: Number(p?.toolErrorRate || 0),
204
+ todoUsed: Boolean(p?.todoUsed),
205
+ evidenceDensity: Number(p?.evidenceDensity || 0),
206
+ driftRate: Number(p?.driftRate || 0),
207
+ qualityStatus: deriveQualityStatus(p),
208
+ qualityScore: Number(p?.qualityGate?.score ?? (p?.success ? 1 : 0)),
209
+ qualityReasons: Array.isArray(p?.qualityGate?.reasons) ? p?.qualityGate.reasons : [],
210
+ startTier: p?.startTier === "small" || p?.startTier === "large" ? p.startTier : "medium",
211
+ finalTier: p?.finalTier === "small" || p?.finalTier === "large" ? p.finalTier : "medium",
212
+ escalated: Boolean(p?.escalated),
213
+ escalationCount: Number(p?.escalationCount || 0),
214
+ escalationReasons: Array.isArray(p?.escalationReasons) ? p.escalationReasons.filter((v) => typeof v === "string") : [],
215
+ escalationPath: Array.isArray(p?.escalationPath) ? p.escalationPath.filter((v) => typeof v === "string") : []
216
+ });
217
+ continue;
218
+ }
219
+ if (raw.type === "agent.kpi.quality_regression") {
220
+ const event = {
221
+ type: raw.type,
222
+ ts: raw.ts,
223
+ payload: raw.payload
224
+ };
225
+ const sessionId = event.payload?.sessionId;
226
+ if (sessionIdFilter && sessionId !== sessionIdFilter) {
227
+ continue;
228
+ }
229
+ regressions.push(event);
230
+ }
231
+ }
232
+ runs.sort((a, b) => Date.parse(b.ts) - Date.parse(a.ts));
233
+ return { runs: runs.slice(0, Math.max(1, limit)), regressions };
234
+ }
235
+ function buildReport(runs, regressions, meta) {
236
+ const count = runs.length;
237
+ if (count === 0) {
238
+ return {
239
+ periodDays: meta.days,
240
+ sessionId: meta.sessionIdFilter,
241
+ runs: 0,
242
+ message: "No agent.kpi.run_completed events in selected period"
243
+ };
244
+ }
245
+ const scorecard = scorecardOf(runs);
246
+ const topTokenRuns = [...runs].sort((a, b) => b.tokensUsed - a.tokensUsed).slice(0, 5);
247
+ const worstQualityRuns = [...runs].sort((a, b) => a.qualityScore - b.qualityScore || b.tokensUsed - a.tokensUsed).slice(0, 5);
248
+ const alerts = [];
249
+ if (scorecard.successRate < 0.85) {
250
+ alerts.push(`Low success rate: ${(scorecard.successRate * 100).toFixed(1)}%`);
251
+ }
252
+ if (scorecard.qualityPassRate < 0.9) {
253
+ alerts.push(`Quality pass rate below target: ${(scorecard.qualityPassRate * 100).toFixed(1)}%`);
254
+ }
255
+ if (scorecard.avgToolErrorRate > 0.05) {
256
+ alerts.push(`High tool error rate: ${(scorecard.avgToolErrorRate * 100).toFixed(1)}%`);
257
+ }
258
+ if (scorecard.avgDriftRate > 0.08) {
259
+ alerts.push(`Scope drift is elevated: ${(scorecard.avgDriftRate * 100).toFixed(1)}%`);
260
+ }
261
+ if (scorecard.nearBudgetRate > 0.35) {
262
+ alerts.push(`Too many runs near iteration budget: ${(scorecard.nearBudgetRate * 100).toFixed(1)}%`);
263
+ }
264
+ if (scorecard.escalationRate > 0.55) {
265
+ alerts.push(`Escalation rate too high: ${(scorecard.escalationRate * 100).toFixed(1)}%`);
266
+ }
267
+ if (scorecard.escalationRate > 0.2 && scorecard.escalationSuccessRate < 0.7) {
268
+ alerts.push(`Escalation effectiveness is low: ${(scorecard.escalationSuccessRate * 100).toFixed(1)}%`);
269
+ }
270
+ if (regressions.length > 0) {
271
+ alerts.push(`Quality regression events observed: ${regressions.length}`);
272
+ }
273
+ const sliceSize = Math.max(3, Math.min(10, Math.floor(runs.length / 2)));
274
+ const latestSlice = runs.slice(0, sliceSize);
275
+ const previousSlice = runs.slice(sliceSize, sliceSize * 2);
276
+ const latestScorecard = scorecardOf(latestSlice);
277
+ const previousScorecard = scorecardOf(previousSlice);
278
+ const slices = previousSlice.length > 0 ? {
279
+ sliceSize,
280
+ latest: latestScorecard,
281
+ previous: previousScorecard,
282
+ delta: {
283
+ successRate: latestScorecard.successRate - previousScorecard.successRate,
284
+ qualityPassRate: latestScorecard.qualityPassRate - previousScorecard.qualityPassRate,
285
+ avgQualityScore: latestScorecard.avgQualityScore - previousScorecard.avgQualityScore,
286
+ avgTokens: latestScorecard.avgTokens - previousScorecard.avgTokens,
287
+ p95Tokens: latestScorecard.p95Tokens - previousScorecard.p95Tokens,
288
+ avgDurationMs: latestScorecard.avgDurationMs - previousScorecard.avgDurationMs,
289
+ avgToolCalls: latestScorecard.avgToolCalls - previousScorecard.avgToolCalls,
290
+ avgToolErrorRate: latestScorecard.avgToolErrorRate - previousScorecard.avgToolErrorRate,
291
+ avgDriftRate: latestScorecard.avgDriftRate - previousScorecard.avgDriftRate,
292
+ avgEvidenceDensity: latestScorecard.avgEvidenceDensity - previousScorecard.avgEvidenceDensity,
293
+ nearBudgetRate: latestScorecard.nearBudgetRate - previousScorecard.nearBudgetRate,
294
+ escalationRate: latestScorecard.escalationRate - previousScorecard.escalationRate,
295
+ escalationSuccessRate: latestScorecard.escalationSuccessRate - previousScorecard.escalationSuccessRate,
296
+ avgEscalationCount: latestScorecard.avgEscalationCount - previousScorecard.avgEscalationCount
297
+ }
298
+ } : null;
299
+ return {
300
+ periodDays: meta.days,
301
+ sessionId: meta.sessionIdFilter,
302
+ runs: count,
303
+ regressions: regressions.length,
304
+ scorecard,
305
+ slices,
306
+ alerts,
307
+ topTokenRuns: topTokenRuns.map(toRunBrief),
308
+ worstQualityRuns: worstQualityRuns.map(toRunBrief)
309
+ };
310
+ }
311
+ function toRunBrief(run) {
312
+ return {
313
+ ts: run.ts,
314
+ sessionId: run.sessionId,
315
+ task: run.task.slice(0, 120),
316
+ tokensUsed: run.tokensUsed,
317
+ durationMs: run.durationMs,
318
+ toolCallsTotal: run.toolCallsTotal,
319
+ qualityStatus: run.qualityStatus,
320
+ qualityScore: run.qualityScore,
321
+ qualityReasons: run.qualityReasons,
322
+ startTier: run.startTier,
323
+ finalTier: run.finalTier,
324
+ escalated: run.escalated,
325
+ escalationCount: run.escalationCount,
326
+ escalationReasons: run.escalationReasons
327
+ };
328
+ }
329
+ function avg(values) {
330
+ if (values.length === 0) {
331
+ return 0;
332
+ }
333
+ return values.reduce((sum, value) => sum + value, 0) / values.length;
334
+ }
335
+ function p95(values) {
336
+ if (values.length === 0) {
337
+ return 0;
338
+ }
339
+ const sorted = [...values].sort((a, b) => a - b);
340
+ const index = Math.max(0, Math.min(sorted.length - 1, Math.ceil(sorted.length * 0.95) - 1));
341
+ return sorted[index] || 0;
342
+ }
343
+ function scorecardOf(runs) {
344
+ const escalatedRuns = runs.filter((r) => r.escalated);
345
+ const nonEscalatedRuns = runs.filter((r) => !r.escalated);
346
+ return {
347
+ successRate: avg(runs.map((r) => r.success ? 1 : 0)),
348
+ qualityPassRate: avg(runs.map((r) => r.qualityStatus === "pass" ? 1 : 0)),
349
+ avgQualityScore: avg(runs.map((r) => r.qualityScore)),
350
+ avgTokens: avg(runs.map((r) => r.tokensUsed)),
351
+ p95Tokens: p95(runs.map((r) => r.tokensUsed)),
352
+ avgDurationMs: avg(runs.map((r) => r.durationMs)),
353
+ avgToolCalls: avg(runs.map((r) => r.toolCallsTotal)),
354
+ avgToolErrorRate: avg(runs.map((r) => r.toolErrorRate)),
355
+ avgDriftRate: avg(runs.map((r) => r.driftRate)),
356
+ avgEvidenceDensity: avg(runs.map((r) => r.evidenceDensity)),
357
+ nearBudgetRate: avg(runs.map((r) => r.iterationUtilization >= 0.9 ? 1 : 0)),
358
+ escalationRate: avg(runs.map((r) => r.escalated ? 1 : 0)),
359
+ escalationSuccessRate: escalatedRuns.length > 0 ? avg(escalatedRuns.map((r) => r.success ? 1 : 0)) : 0,
360
+ avgEscalationCount: avg(runs.map((r) => r.escalationCount)),
361
+ avgTokensEscalated: escalatedRuns.length > 0 ? avg(escalatedRuns.map((r) => r.tokensUsed)) : 0,
362
+ avgTokensNonEscalated: nonEscalatedRuns.length > 0 ? avg(nonEscalatedRuns.map((r) => r.tokensUsed)) : 0,
363
+ avgQualityEscalated: escalatedRuns.length > 0 ? avg(escalatedRuns.map((r) => r.qualityScore)) : 0,
364
+ avgQualityNonEscalated: nonEscalatedRuns.length > 0 ? avg(nonEscalatedRuns.map((r) => r.qualityScore)) : 0
365
+ };
366
+ }
367
+ function printReport(ctx, report) {
368
+ if (report.runs === 0) {
369
+ ctx.ui.write(`No KPI runs for selected period (${report.periodDays}d)
370
+ `);
371
+ return;
372
+ }
373
+ const s = report.scorecard;
374
+ ctx.ui.write("\u250C\u2500\u2500 Agent Quality Control Report\n");
375
+ ctx.ui.write(`\u2502 Period: ${report.periodDays}d
376
+ `);
377
+ if (report.sessionId) {
378
+ ctx.ui.write(`\u2502 Session: ${report.sessionId}
379
+ `);
380
+ }
381
+ ctx.ui.write(`\u2502 Runs: ${report.runs} | Regressions: ${report.regressions}
382
+ `);
383
+ ctx.ui.write("\u2502\n");
384
+ ctx.ui.write(`\u2502 Success Rate: ${(s.successRate * 100).toFixed(1)}%
385
+ `);
386
+ ctx.ui.write(`\u2502 Quality Pass: ${(s.qualityPassRate * 100).toFixed(1)}% | Avg score: ${s.avgQualityScore.toFixed(2)}
387
+ `);
388
+ ctx.ui.write(`\u2502 Tokens: avg ${Math.round(s.avgTokens)} | p95 ${Math.round(s.p95Tokens)}
389
+ `);
390
+ ctx.ui.write(`\u2502 Duration: avg ${(s.avgDurationMs / 1e3).toFixed(1)}s
391
+ `);
392
+ ctx.ui.write(`\u2502 Tools: avg ${s.avgToolCalls.toFixed(1)} | error ${(s.avgToolErrorRate * 100).toFixed(2)}%
393
+ `);
394
+ ctx.ui.write(`\u2502 Drift: ${(s.avgDriftRate * 100).toFixed(2)}% | Evidence density: ${s.avgEvidenceDensity.toFixed(2)}
395
+ `);
396
+ ctx.ui.write(`\u2502 Near budget rate: ${(s.nearBudgetRate * 100).toFixed(1)}%
397
+ `);
398
+ ctx.ui.write(`\u2502 Escalation: ${(s.escalationRate * 100).toFixed(1)}% runs | success ${(s.escalationSuccessRate * 100).toFixed(1)}% | avg count ${s.avgEscalationCount.toFixed(2)}
399
+ `);
400
+ if (s.escalationRate > 0 && s.escalationRate < 1) {
401
+ const tokenDelta = s.avgTokensEscalated - s.avgTokensNonEscalated;
402
+ const qualityDelta = s.avgQualityEscalated - s.avgQualityNonEscalated;
403
+ ctx.ui.write(`\u2502 Escalated vs non-escalated: \u0394tokens ${tokenDelta >= 0 ? "+" : ""}${Math.round(tokenDelta)} | \u0394quality ${qualityDelta >= 0 ? "+" : ""}${qualityDelta.toFixed(2)}
404
+ `);
405
+ } else {
406
+ ctx.ui.write("\u2502 Escalated vs non-escalated: n/a (need both escalated and non-escalated runs)\n");
407
+ }
408
+ if (report.slices) {
409
+ const d = report.slices.delta;
410
+ ctx.ui.write("\u2502\n");
411
+ ctx.ui.write(`\u2502 Slices (${report.slices.sliceSize} latest vs previous):
412
+ `);
413
+ ctx.ui.write(`\u2502 \u0394 Quality score: ${d.avgQualityScore >= 0 ? "+" : ""}${d.avgQualityScore.toFixed(2)}
414
+ `);
415
+ ctx.ui.write(`\u2502 \u0394 Avg tokens: ${d.avgTokens >= 0 ? "+" : ""}${Math.round(d.avgTokens)}
416
+ `);
417
+ ctx.ui.write(`\u2502 \u0394 Avg duration: ${d.avgDurationMs >= 0 ? "+" : ""}${(d.avgDurationMs / 1e3).toFixed(1)}s
418
+ `);
419
+ ctx.ui.write(`\u2502 \u0394 Tool errors: ${d.avgToolErrorRate >= 0 ? "+" : ""}${(d.avgToolErrorRate * 100).toFixed(2)}%
420
+ `);
421
+ ctx.ui.write(`\u2502 \u0394 Drift: ${d.avgDriftRate >= 0 ? "+" : ""}${(d.avgDriftRate * 100).toFixed(2)}%
422
+ `);
423
+ ctx.ui.write(`\u2502 \u0394 Escalation rate: ${d.escalationRate >= 0 ? "+" : ""}${(d.escalationRate * 100).toFixed(1)}%
424
+ `);
425
+ ctx.ui.write(`\u2502 \u0394 Escalation success: ${d.escalationSuccessRate >= 0 ? "+" : ""}${(d.escalationSuccessRate * 100).toFixed(1)}%
426
+ `);
427
+ ctx.ui.write(`\u2502 \u0394 Escalation count: ${d.avgEscalationCount >= 0 ? "+" : ""}${d.avgEscalationCount.toFixed(2)}
428
+ `);
429
+ }
430
+ if (report.alerts.length > 0) {
431
+ ctx.ui.write("\u2502\n");
432
+ ctx.ui.write("\u2502 Alerts:\n");
433
+ for (const alert of report.alerts) {
434
+ ctx.ui.write(`\u2502 - ${alert}
435
+ `);
436
+ }
437
+ }
438
+ ctx.ui.write("\u2502\n");
439
+ ctx.ui.write("\u2502 Top expensive runs:\n");
440
+ for (const run of report.topTokenRuns) {
441
+ const esc = run.escalated ? ` | esc=${run.escalationCount}` : "";
442
+ ctx.ui.write(`\u2502 - ${run.ts} | tok=${run.tokensUsed} | q=${run.qualityScore.toFixed(2)}${esc} | ${run.task}
443
+ `);
444
+ }
445
+ ctx.ui.write("\u2502\n");
446
+ ctx.ui.write("\u2502 Worst quality runs:\n");
447
+ for (const run of report.worstQualityRuns) {
448
+ const reasons = (run.qualityReasons || []).join(", ");
449
+ ctx.ui.write(`\u2502 - ${run.ts} | q=${run.qualityScore.toFixed(2)} | tok=${run.tokensUsed} | reasons=${reasons || "n/a"}
450
+ `);
451
+ }
452
+ ctx.ui.write("\u2514\u2500\u2500\n");
453
+ }
454
+
455
+ export { quality_report_default as default };
456
+ //# sourceMappingURL=quality-report.js.map
457
+ //# sourceMappingURL=quality-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/quality-report.ts"],"names":["execFileCb","fs"],"mappings":"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","file":"quality-report.js","sourcesContent":["/**\n * agent:quality:report - Agent execution quality control report\n *\n * Usage:\n * pnpm kb agent quality report\n * pnpm kb agent quality report --days=3\n * pnpm kb agent quality report --session-id=session-123\n * pnpm kb agent quality report --json\n */\n\nimport { defineCommand, type PluginContextV3 } from '@kb-labs/sdk';\nimport { promises as fs } from 'fs';\nimport path from 'path';\nimport { execFile as execFileCb } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execFile = promisify(execFileCb);\n\ntype QualityReportInput = {\n days?: number;\n limit?: number;\n sessionId?: string;\n 'session-id'?: string;\n json?: boolean;\n};\n\ntype KpiRunEvent = {\n type: string;\n ts?: string;\n payload?: {\n sessionId?: string;\n success?: boolean;\n task?: string;\n summaryPreview?: string;\n tokensUsed?: number;\n durationMs?: number;\n iterationsUsed?: number;\n iterationBudget?: number;\n iterationUtilization?: number;\n toolCallsTotal?: number;\n toolErrorRate?: number;\n todoUsed?: boolean;\n evidenceDensity?: number;\n driftRate?: number;\n startTier?: 'small' | 'medium' | 'large';\n finalTier?: 'small' | 'medium' | 'large';\n escalated?: boolean;\n escalationCount?: number;\n escalationReasons?: string[];\n escalationPath?: string[];\n qualityGate?: {\n status?: 'pass' | 'partial';\n score?: number;\n reasons?: string[];\n };\n qualityGateStatus?: 'pass' | 'partial';\n };\n};\n\ntype RegressionEvent = {\n type: string;\n ts?: string;\n payload?: {\n sessionId?: string;\n reasons?: string[];\n metrics?: {\n driftRate?: number;\n evidenceDensity?: number;\n toolErrorRate?: number;\n iterationsUsed?: number;\n iterationBudget?: number;\n };\n };\n};\n\ntype RunSnapshot = {\n ts: string;\n sessionId: string;\n success: boolean;\n task: string;\n summaryPreview: string;\n tokensUsed: number;\n durationMs: number;\n iterationsUsed: number;\n iterationBudget: number;\n iterationUtilization: number;\n toolCallsTotal: number;\n toolErrorRate: number;\n todoUsed: boolean;\n evidenceDensity: number;\n driftRate: number;\n qualityStatus: 'pass' | 'partial';\n qualityScore: number;\n qualityReasons: string[];\n startTier: 'small' | 'medium' | 'large';\n finalTier: 'small' | 'medium' | 'large';\n escalated: boolean;\n escalationCount: number;\n escalationReasons: string[];\n escalationPath: string[];\n};\n\nfunction deriveQualityStatus(payload: KpiRunEvent['payload'] | undefined): 'pass' | 'partial' {\n if (payload?.qualityGate?.status === 'pass' || payload?.qualityGate?.status === 'partial') {\n return payload.qualityGate.status;\n }\n if (payload?.qualityGateStatus === 'pass' || payload?.qualityGateStatus === 'partial') {\n return payload.qualityGateStatus;\n }\n return payload?.success ? 'pass' : 'partial';\n}\n\nexport default defineCommand({\n id: 'quality:report',\n description: 'Show quality control report for agent runs (quality, tokens, tools, drift, regressions)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: QualityReportInput): Promise<{ exitCode: number; response?: unknown }> {\n const flags = (input as any).flags ?? input;\n const days = Number(flags.days ?? 1);\n const limit = Number(flags.limit ?? 200);\n const rawSessionId = flags['session-id'] ?? flags.sessionId;\n const sessionIdFilter = typeof rawSessionId === 'string' ? rawSessionId : undefined;\n const json = Boolean(flags.json);\n\n if (!Number.isFinite(days) || days <= 0) {\n const err = { success: false, error: '--days must be a positive number' };\n ctx.ui.write(JSON.stringify(err, null, 2) + '\\n');\n return { exitCode: 1, response: err };\n }\n\n const analyticsDir = path.join(process.cwd(), '.kb', 'analytics', 'buffer');\n const files = await listEventFiles(analyticsDir, days);\n if (files.length === 0) {\n const out = { success: true, message: 'No analytics files found for selected period', runs: 0 };\n ctx.ui.write(JSON.stringify(out, null, 2) + '\\n');\n return { exitCode: 0, response: out };\n }\n\n const since = Date.now() - days * 24 * 60 * 60 * 1000;\n let { runs, regressions } = await readEvents(files, since, sessionIdFilter, limit);\n if (runs.length === 0) {\n const sqlitePath = path.join(process.cwd(), '.kb', 'analytics', 'analytics.sqlite');\n const sqliteEvents = await readEventsFromSqlite(sqlitePath, since, sessionIdFilter, limit);\n runs = sqliteEvents.runs;\n regressions = sqliteEvents.regressions;\n }\n const report = buildReport(runs, regressions, { days, sessionIdFilter });\n\n if (json) {\n ctx.ui.write(JSON.stringify({ success: true, report }, null, 2) + '\\n');\n } else {\n printReport(ctx, report);\n }\n\n return { exitCode: 0, response: report };\n },\n },\n});\n\nasync function listEventFiles(dir: string, days: number): Promise<string[]> {\n try {\n const entries = await fs.readdir(dir);\n const candidates = entries\n .filter((name) => /^events-\\d{8}\\.jsonl$/.test(name))\n .sort();\n\n const keep = Math.max(1, Math.min(candidates.length, days + 2));\n return candidates.slice(-keep).map((name) => path.join(dir, name));\n } catch {\n return [];\n }\n}\n\nasync function readEvents(\n files: string[],\n sinceMs: number,\n sessionIdFilter: string | undefined,\n limit: number\n): Promise<{ runs: RunSnapshot[]; regressions: RegressionEvent[] }> {\n const runs: RunSnapshot[] = [];\n const regressions: RegressionEvent[] = [];\n\n for (const file of files) {\n const content = await fs.readFile(file, 'utf-8');\n const lines = content.split('\\n').filter(Boolean);\n\n for (const line of lines) {\n let raw: any;\n try {\n raw = JSON.parse(line);\n } catch {\n continue;\n }\n\n const ts = typeof raw.ts === 'string' ? Date.parse(raw.ts) : NaN;\n if (!Number.isFinite(ts) || ts < sinceMs) {\n continue;\n }\n\n if (raw.type === 'agent.kpi.run_completed') {\n const event = raw as KpiRunEvent;\n const p = event.payload || {};\n const sessionId = p.sessionId || 'unknown';\n if (sessionIdFilter && sessionId !== sessionIdFilter) {\n continue;\n }\n\n runs.push({\n ts: event.ts || new Date(ts).toISOString(),\n sessionId,\n success: Boolean(p.success),\n task: p.task || '',\n summaryPreview: p.summaryPreview || '',\n tokensUsed: Number(p.tokensUsed || 0),\n durationMs: Number(p.durationMs || 0),\n iterationsUsed: Number(p.iterationsUsed || 0),\n iterationBudget: Number(p.iterationBudget || 0),\n iterationUtilization: Number(p.iterationUtilization || 0),\n toolCallsTotal: Number(p.toolCallsTotal || 0),\n toolErrorRate: Number(p.toolErrorRate || 0),\n todoUsed: Boolean(p.todoUsed),\n evidenceDensity: Number(p.evidenceDensity || 0),\n driftRate: Number(p.driftRate || 0),\n qualityStatus: deriveQualityStatus(p),\n qualityScore: Number(p.qualityGate?.score ?? (p.success ? 1 : 0)),\n qualityReasons: Array.isArray(p.qualityGate?.reasons) ? p.qualityGate!.reasons! : [],\n startTier: (p.startTier === 'small' || p.startTier === 'large') ? p.startTier : 'medium',\n finalTier: (p.finalTier === 'small' || p.finalTier === 'large') ? p.finalTier : 'medium',\n escalated: Boolean(p.escalated),\n escalationCount: Number(p.escalationCount || 0),\n escalationReasons: Array.isArray(p.escalationReasons)\n ? p.escalationReasons.filter((v): v is string => typeof v === 'string')\n : [],\n escalationPath: Array.isArray(p.escalationPath)\n ? p.escalationPath.filter((v): v is string => typeof v === 'string')\n : [],\n });\n } else if (raw.type === 'agent.kpi.quality_regression') {\n const event = raw as RegressionEvent;\n const sessionId = event.payload?.sessionId;\n if (sessionIdFilter && sessionId !== sessionIdFilter) {\n continue;\n }\n regressions.push(event);\n }\n }\n }\n\n runs.sort((a, b) => Date.parse(b.ts) - Date.parse(a.ts));\n const trimmedRuns = runs.slice(0, Math.max(1, limit));\n return { runs: trimmedRuns, regressions };\n}\n\nasync function readEventsFromSqlite(\n sqlitePath: string,\n sinceMs: number,\n sessionIdFilter: string | undefined,\n limit: number,\n): Promise<{ runs: RunSnapshot[]; regressions: RegressionEvent[] }> {\n try {\n await fs.access(sqlitePath);\n } catch {\n return { runs: [], regressions: [] };\n }\n\n const sinceIso = new Date(sinceMs).toISOString();\n const sql = [\n 'SELECT type, ts, payload',\n 'FROM events',\n `WHERE ts >= '${sinceIso}'`,\n \" AND type IN ('agent.kpi.run_completed', 'agent.kpi.quality_regression')\",\n 'ORDER BY ts DESC',\n `LIMIT ${Math.max(limit * 5, 500)};`,\n ].join(' ');\n\n try {\n const { stdout } = await execFile('sqlite3', ['-json', sqlitePath, sql], {\n maxBuffer: 20 * 1024 * 1024,\n });\n const rows = JSON.parse(stdout || '[]') as Array<{\n type?: string;\n ts?: string;\n payload?: string;\n }>;\n const pseudoFileEvents = rows.map((row) => ({\n type: row.type ?? '',\n ts: row.ts,\n payload: parseJsonSafe(row.payload),\n }));\n return readInMemoryEvents(pseudoFileEvents, sinceMs, sessionIdFilter, limit);\n } catch {\n return { runs: [], regressions: [] };\n }\n}\n\nfunction parseJsonSafe(value: unknown): Record<string, unknown> {\n if (value && typeof value === 'object') {\n return value as Record<string, unknown>;\n }\n if (typeof value !== 'string') {\n return {};\n }\n try {\n const parsed = JSON.parse(value) as Record<string, unknown>;\n return parsed && typeof parsed === 'object' ? parsed : {};\n } catch {\n return {};\n }\n}\n\nfunction readInMemoryEvents(\n rows: Array<{ type: string; ts?: string; payload?: Record<string, unknown> }>,\n sinceMs: number,\n sessionIdFilter: string | undefined,\n limit: number\n): { runs: RunSnapshot[]; regressions: RegressionEvent[] } {\n const runs: RunSnapshot[] = [];\n const regressions: RegressionEvent[] = [];\n\n for (const raw of rows) {\n const ts = typeof raw.ts === 'string' ? Date.parse(raw.ts) : NaN;\n if (!Number.isFinite(ts) || ts < sinceMs) {\n continue;\n }\n\n if (raw.type === 'agent.kpi.run_completed') {\n const p = (raw.payload || {}) as KpiRunEvent['payload'];\n const sessionId = p?.sessionId || 'unknown';\n if (sessionIdFilter && sessionId !== sessionIdFilter) {\n continue;\n }\n runs.push({\n ts: raw.ts || new Date(ts).toISOString(),\n sessionId,\n success: Boolean(p?.success),\n task: p?.task || '',\n summaryPreview: p?.summaryPreview || '',\n tokensUsed: Number(p?.tokensUsed || 0),\n durationMs: Number(p?.durationMs || 0),\n iterationsUsed: Number(p?.iterationsUsed || 0),\n iterationBudget: Number(p?.iterationBudget || 0),\n iterationUtilization: Number(p?.iterationUtilization || 0),\n toolCallsTotal: Number(p?.toolCallsTotal || 0),\n toolErrorRate: Number(p?.toolErrorRate || 0),\n todoUsed: Boolean(p?.todoUsed),\n evidenceDensity: Number(p?.evidenceDensity || 0),\n driftRate: Number(p?.driftRate || 0),\n qualityStatus: deriveQualityStatus(p),\n qualityScore: Number(p?.qualityGate?.score ?? (p?.success ? 1 : 0)),\n qualityReasons: Array.isArray(p?.qualityGate?.reasons) ? p?.qualityGate.reasons : [],\n startTier: (p?.startTier === 'small' || p?.startTier === 'large') ? p.startTier : 'medium',\n finalTier: (p?.finalTier === 'small' || p?.finalTier === 'large') ? p.finalTier : 'medium',\n escalated: Boolean(p?.escalated),\n escalationCount: Number(p?.escalationCount || 0),\n escalationReasons: Array.isArray(p?.escalationReasons)\n ? p.escalationReasons.filter((v): v is string => typeof v === 'string')\n : [],\n escalationPath: Array.isArray(p?.escalationPath)\n ? p.escalationPath.filter((v): v is string => typeof v === 'string')\n : [],\n });\n continue;\n }\n\n if (raw.type === 'agent.kpi.quality_regression') {\n const event: RegressionEvent = {\n type: raw.type,\n ts: raw.ts,\n payload: raw.payload as RegressionEvent['payload'],\n };\n const sessionId = event.payload?.sessionId;\n if (sessionIdFilter && sessionId !== sessionIdFilter) {\n continue;\n }\n regressions.push(event);\n }\n }\n\n runs.sort((a, b) => Date.parse(b.ts) - Date.parse(a.ts));\n return { runs: runs.slice(0, Math.max(1, limit)), regressions };\n}\n\nfunction buildReport(\n runs: RunSnapshot[],\n regressions: RegressionEvent[],\n meta: { days: number; sessionIdFilter?: string }\n) {\n const count = runs.length;\n if (count === 0) {\n return {\n periodDays: meta.days,\n sessionId: meta.sessionIdFilter,\n runs: 0,\n message: 'No agent.kpi.run_completed events in selected period',\n };\n }\n\n const scorecard = scorecardOf(runs);\n\n const topTokenRuns = [...runs].sort((a, b) => b.tokensUsed - a.tokensUsed).slice(0, 5);\n const worstQualityRuns = [...runs]\n .sort((a, b) => a.qualityScore - b.qualityScore || b.tokensUsed - a.tokensUsed)\n .slice(0, 5);\n\n const alerts: string[] = [];\n if (scorecard.successRate < 0.85) {alerts.push(`Low success rate: ${(scorecard.successRate * 100).toFixed(1)}%`);}\n if (scorecard.qualityPassRate < 0.9) {alerts.push(`Quality pass rate below target: ${(scorecard.qualityPassRate * 100).toFixed(1)}%`);}\n if (scorecard.avgToolErrorRate > 0.05) {alerts.push(`High tool error rate: ${(scorecard.avgToolErrorRate * 100).toFixed(1)}%`);}\n if (scorecard.avgDriftRate > 0.08) {alerts.push(`Scope drift is elevated: ${(scorecard.avgDriftRate * 100).toFixed(1)}%`);}\n if (scorecard.nearBudgetRate > 0.35) {alerts.push(`Too many runs near iteration budget: ${(scorecard.nearBudgetRate * 100).toFixed(1)}%`);}\n if (scorecard.escalationRate > 0.55) {alerts.push(`Escalation rate too high: ${(scorecard.escalationRate * 100).toFixed(1)}%`);}\n if (scorecard.escalationRate > 0.2 && scorecard.escalationSuccessRate < 0.7) {\n alerts.push(`Escalation effectiveness is low: ${(scorecard.escalationSuccessRate * 100).toFixed(1)}%`);\n }\n if (regressions.length > 0) {alerts.push(`Quality regression events observed: ${regressions.length}`);}\n\n const sliceSize = Math.max(3, Math.min(10, Math.floor(runs.length / 2)));\n const latestSlice = runs.slice(0, sliceSize);\n const previousSlice = runs.slice(sliceSize, sliceSize * 2);\n const latestScorecard = scorecardOf(latestSlice);\n const previousScorecard = scorecardOf(previousSlice);\n\n const slices = previousSlice.length > 0\n ? {\n sliceSize,\n latest: latestScorecard,\n previous: previousScorecard,\n delta: {\n successRate: latestScorecard.successRate - previousScorecard.successRate,\n qualityPassRate: latestScorecard.qualityPassRate - previousScorecard.qualityPassRate,\n avgQualityScore: latestScorecard.avgQualityScore - previousScorecard.avgQualityScore,\n avgTokens: latestScorecard.avgTokens - previousScorecard.avgTokens,\n p95Tokens: latestScorecard.p95Tokens - previousScorecard.p95Tokens,\n avgDurationMs: latestScorecard.avgDurationMs - previousScorecard.avgDurationMs,\n avgToolCalls: latestScorecard.avgToolCalls - previousScorecard.avgToolCalls,\n avgToolErrorRate: latestScorecard.avgToolErrorRate - previousScorecard.avgToolErrorRate,\n avgDriftRate: latestScorecard.avgDriftRate - previousScorecard.avgDriftRate,\n avgEvidenceDensity: latestScorecard.avgEvidenceDensity - previousScorecard.avgEvidenceDensity,\n nearBudgetRate: latestScorecard.nearBudgetRate - previousScorecard.nearBudgetRate,\n escalationRate: latestScorecard.escalationRate - previousScorecard.escalationRate,\n escalationSuccessRate: latestScorecard.escalationSuccessRate - previousScorecard.escalationSuccessRate,\n avgEscalationCount: latestScorecard.avgEscalationCount - previousScorecard.avgEscalationCount,\n },\n }\n : null;\n\n return {\n periodDays: meta.days,\n sessionId: meta.sessionIdFilter,\n runs: count,\n regressions: regressions.length,\n scorecard,\n slices,\n alerts,\n topTokenRuns: topTokenRuns.map(toRunBrief),\n worstQualityRuns: worstQualityRuns.map(toRunBrief),\n };\n}\n\nfunction toRunBrief(run: RunSnapshot) {\n return {\n ts: run.ts,\n sessionId: run.sessionId,\n task: run.task.slice(0, 120),\n tokensUsed: run.tokensUsed,\n durationMs: run.durationMs,\n toolCallsTotal: run.toolCallsTotal,\n qualityStatus: run.qualityStatus,\n qualityScore: run.qualityScore,\n qualityReasons: run.qualityReasons,\n startTier: run.startTier,\n finalTier: run.finalTier,\n escalated: run.escalated,\n escalationCount: run.escalationCount,\n escalationReasons: run.escalationReasons,\n };\n}\n\nfunction avg(values: number[]): number {\n if (values.length === 0) {return 0;}\n return values.reduce((sum, value) => sum + value, 0) / values.length;\n}\n\nfunction p95(values: number[]): number {\n if (values.length === 0) {return 0;}\n const sorted = [...values].sort((a, b) => a - b);\n const index = Math.max(0, Math.min(sorted.length - 1, Math.ceil(sorted.length * 0.95) - 1));\n return sorted[index] || 0;\n}\n\nfunction scorecardOf(runs: RunSnapshot[]) {\n const escalatedRuns = runs.filter((r) => r.escalated);\n const nonEscalatedRuns = runs.filter((r) => !r.escalated);\n\n return {\n successRate: avg(runs.map((r) => (r.success ? 1 : 0))),\n qualityPassRate: avg(runs.map((r) => (r.qualityStatus === 'pass' ? 1 : 0))),\n avgQualityScore: avg(runs.map((r) => r.qualityScore)),\n avgTokens: avg(runs.map((r) => r.tokensUsed)),\n p95Tokens: p95(runs.map((r) => r.tokensUsed)),\n avgDurationMs: avg(runs.map((r) => r.durationMs)),\n avgToolCalls: avg(runs.map((r) => r.toolCallsTotal)),\n avgToolErrorRate: avg(runs.map((r) => r.toolErrorRate)),\n avgDriftRate: avg(runs.map((r) => r.driftRate)),\n avgEvidenceDensity: avg(runs.map((r) => r.evidenceDensity)),\n nearBudgetRate: avg(runs.map((r) => (r.iterationUtilization >= 0.9 ? 1 : 0))),\n escalationRate: avg(runs.map((r) => (r.escalated ? 1 : 0))),\n escalationSuccessRate: escalatedRuns.length > 0 ? avg(escalatedRuns.map((r) => (r.success ? 1 : 0))) : 0,\n avgEscalationCount: avg(runs.map((r) => r.escalationCount)),\n avgTokensEscalated: escalatedRuns.length > 0 ? avg(escalatedRuns.map((r) => r.tokensUsed)) : 0,\n avgTokensNonEscalated: nonEscalatedRuns.length > 0 ? avg(nonEscalatedRuns.map((r) => r.tokensUsed)) : 0,\n avgQualityEscalated: escalatedRuns.length > 0 ? avg(escalatedRuns.map((r) => r.qualityScore)) : 0,\n avgQualityNonEscalated: nonEscalatedRuns.length > 0 ? avg(nonEscalatedRuns.map((r) => r.qualityScore)) : 0,\n };\n}\n\nfunction printReport(ctx: PluginContextV3, report: any): void {\n if (report.runs === 0) {\n ctx.ui.write(`No KPI runs for selected period (${report.periodDays}d)\\n`);\n return;\n }\n\n const s = report.scorecard;\n ctx.ui.write('┌── Agent Quality Control Report\\n');\n ctx.ui.write(`│ Period: ${report.periodDays}d\\n`);\n if (report.sessionId) {\n ctx.ui.write(`│ Session: ${report.sessionId}\\n`);\n }\n ctx.ui.write(`│ Runs: ${report.runs} | Regressions: ${report.regressions}\\n`);\n ctx.ui.write('│\\n');\n ctx.ui.write(`│ Success Rate: ${(s.successRate * 100).toFixed(1)}%\\n`);\n ctx.ui.write(`│ Quality Pass: ${(s.qualityPassRate * 100).toFixed(1)}% | Avg score: ${s.avgQualityScore.toFixed(2)}\\n`);\n ctx.ui.write(`│ Tokens: avg ${Math.round(s.avgTokens)} | p95 ${Math.round(s.p95Tokens)}\\n`);\n ctx.ui.write(`│ Duration: avg ${(s.avgDurationMs / 1000).toFixed(1)}s\\n`);\n ctx.ui.write(`│ Tools: avg ${s.avgToolCalls.toFixed(1)} | error ${(s.avgToolErrorRate * 100).toFixed(2)}%\\n`);\n ctx.ui.write(`│ Drift: ${(s.avgDriftRate * 100).toFixed(2)}% | Evidence density: ${s.avgEvidenceDensity.toFixed(2)}\\n`);\n ctx.ui.write(`│ Near budget rate: ${(s.nearBudgetRate * 100).toFixed(1)}%\\n`);\n ctx.ui.write(`│ Escalation: ${(s.escalationRate * 100).toFixed(1)}% runs | success ${(s.escalationSuccessRate * 100).toFixed(1)}% | avg count ${s.avgEscalationCount.toFixed(2)}\\n`);\n if (s.escalationRate > 0 && s.escalationRate < 1) {\n const tokenDelta = s.avgTokensEscalated - s.avgTokensNonEscalated;\n const qualityDelta = s.avgQualityEscalated - s.avgQualityNonEscalated;\n ctx.ui.write(`│ Escalated vs non-escalated: Δtokens ${tokenDelta >= 0 ? '+' : ''}${Math.round(tokenDelta)} | Δquality ${qualityDelta >= 0 ? '+' : ''}${qualityDelta.toFixed(2)}\\n`);\n } else {\n ctx.ui.write('│ Escalated vs non-escalated: n/a (need both escalated and non-escalated runs)\\n');\n }\n\n if (report.slices) {\n const d = report.slices.delta;\n ctx.ui.write('│\\n');\n ctx.ui.write(`│ Slices (${report.slices.sliceSize} latest vs previous):\\n`);\n ctx.ui.write(`│ Δ Quality score: ${d.avgQualityScore >= 0 ? '+' : ''}${d.avgQualityScore.toFixed(2)}\\n`);\n ctx.ui.write(`│ Δ Avg tokens: ${d.avgTokens >= 0 ? '+' : ''}${Math.round(d.avgTokens)}\\n`);\n ctx.ui.write(`│ Δ Avg duration: ${d.avgDurationMs >= 0 ? '+' : ''}${(d.avgDurationMs / 1000).toFixed(1)}s\\n`);\n ctx.ui.write(`│ Δ Tool errors: ${d.avgToolErrorRate >= 0 ? '+' : ''}${(d.avgToolErrorRate * 100).toFixed(2)}%\\n`);\n ctx.ui.write(`│ Δ Drift: ${d.avgDriftRate >= 0 ? '+' : ''}${(d.avgDriftRate * 100).toFixed(2)}%\\n`);\n ctx.ui.write(`│ Δ Escalation rate: ${d.escalationRate >= 0 ? '+' : ''}${(d.escalationRate * 100).toFixed(1)}%\\n`);\n ctx.ui.write(`│ Δ Escalation success: ${d.escalationSuccessRate >= 0 ? '+' : ''}${(d.escalationSuccessRate * 100).toFixed(1)}%\\n`);\n ctx.ui.write(`│ Δ Escalation count: ${d.avgEscalationCount >= 0 ? '+' : ''}${d.avgEscalationCount.toFixed(2)}\\n`);\n }\n\n if (report.alerts.length > 0) {\n ctx.ui.write('│\\n');\n ctx.ui.write('│ Alerts:\\n');\n for (const alert of report.alerts) {\n ctx.ui.write(`│ - ${alert}\\n`);\n }\n }\n\n ctx.ui.write('│\\n');\n ctx.ui.write('│ Top expensive runs:\\n');\n for (const run of report.topTokenRuns) {\n const esc = run.escalated ? ` | esc=${run.escalationCount}` : '';\n ctx.ui.write(`│ - ${run.ts} | tok=${run.tokensUsed} | q=${run.qualityScore.toFixed(2)}${esc} | ${run.task}\\n`);\n }\n\n ctx.ui.write('│\\n');\n ctx.ui.write('│ Worst quality runs:\\n');\n for (const run of report.worstQualityRuns) {\n const reasons = (run.qualityReasons || []).join(', ');\n ctx.ui.write(`│ - ${run.ts} | q=${run.qualityScore.toFixed(2)} | tok=${run.tokensUsed} | reasons=${reasons || 'n/a'}\\n`);\n }\n ctx.ui.write('└──\\n');\n}\n"]}
@@ -0,0 +1,27 @@
1
+ import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
2
+
3
+ /**
4
+ * agent:rollback — Rollback file changes made by agents.
5
+ *
6
+ * Uses ChangeStore from @kb-labs/agent-history.
7
+ * All rollback logic is in ChangeTrackingMiddleware.rollbackRun() or handled here via ChangeStore.
8
+ *
9
+ * Usage:
10
+ * pnpm kb agent:rollback --run-id={id} --session-id={id}
11
+ * pnpm kb agent:rollback --file=src/index.ts --session-id={id}
12
+ * pnpm kb agent:rollback --session-id={id}
13
+ * pnpm kb agent:rollback --run-id={id} --session-id={id} --dry-run
14
+ */
15
+ type RollbackInput = {
16
+ 'run-id'?: string;
17
+ runId?: string;
18
+ 'session-id'?: string;
19
+ sessionId?: string;
20
+ file?: string;
21
+ 'dry-run'?: boolean;
22
+ dryRun?: boolean;
23
+ json?: boolean;
24
+ };
25
+ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, RollbackInput, unknown>;
26
+
27
+ export { _default as default };