@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,247 @@
1
+ import { defineCommand, useLogger } from '@kb-labs/sdk';
2
+ import { loadTrace, formatTraceLoadError } from '@kb-labs/agent-tracing';
3
+
4
+ // src/cli/commands/trace-stats.ts
5
+
6
+ // src/cli/commands/trace-event-normalizer.ts
7
+ function normalizeTraceEvents(events) {
8
+ const out = [];
9
+ let currentIteration = 0;
10
+ for (const raw of events) {
11
+ const type = String(raw.type ?? "");
12
+ const data = getEventData(raw);
13
+ const explicitIteration = asNumber(raw.iteration) ?? asNumber(data.iteration);
14
+ if (type === "iteration:start") {
15
+ currentIteration = explicitIteration ?? Math.max(1, currentIteration + 1);
16
+ }
17
+ const iteration = explicitIteration ?? currentIteration;
18
+ out.push({ raw, type, data, iteration });
19
+ }
20
+ return out;
21
+ }
22
+ function getEventData(event) {
23
+ const data = event.data;
24
+ if (data && typeof data === "object") {
25
+ return data;
26
+ }
27
+ return {};
28
+ }
29
+ function asNumber(value) {
30
+ if (typeof value === "number" && Number.isFinite(value)) {
31
+ return value;
32
+ }
33
+ if (typeof value === "string") {
34
+ const n = Number(value);
35
+ if (Number.isFinite(n)) {
36
+ return n;
37
+ }
38
+ }
39
+ return void 0;
40
+ }
41
+
42
+ // src/cli/commands/trace-stats.ts
43
+ var trace_stats_default = defineCommand({
44
+ id: "trace:stats",
45
+ description: "Show trace statistics with cost and performance metrics",
46
+ handler: {
47
+ async execute(ctx, input) {
48
+ const logger = useLogger();
49
+ const flags = input.flags ?? input;
50
+ const taskId = flags["task-id"] ?? flags.taskId;
51
+ try {
52
+ const loaded = await loadTrace(taskId);
53
+ if (!loaded.ok) {
54
+ const code = loaded.error.kind === "invalid_task_id" ? "INVALID_TASK_ID" : loaded.error.kind === "not_found" ? "TRACE_NOT_FOUND" : loaded.error.kind === "too_large" ? "FILE_TOO_LARGE" : "CORRUPTED_TRACE";
55
+ const err = error(code, formatTraceLoadError(loaded.error));
56
+ ctx.ui.write(JSON.stringify(err, null, 2) + "\n");
57
+ return { exitCode: 1, response: err };
58
+ }
59
+ const { events } = loaded;
60
+ const stats = calculateStats(events, taskId);
61
+ const response = {
62
+ success: true,
63
+ command: "trace:stats",
64
+ taskId: taskId ?? "",
65
+ data: stats,
66
+ summary: {
67
+ message: `${stats.iterations.total} iterations, ${stats.llm.calls} LLM calls, $${stats.cost.total.toFixed(4)} cost`,
68
+ severity: stats.errors > 0 ? "warning" : "info",
69
+ actionable: stats.errors > 5
70
+ }
71
+ };
72
+ if (flags.json) {
73
+ ctx.ui.write(JSON.stringify(response, null, 2) + "\n");
74
+ } else {
75
+ printHumanReadable(ctx, stats);
76
+ }
77
+ return { exitCode: 0, response };
78
+ } catch (err) {
79
+ logger.error("trace:stats error:", err instanceof Error ? err : void 0);
80
+ const errResponse = error("IO_ERROR", err instanceof Error ? err.message : String(err));
81
+ ctx.ui.write(JSON.stringify(errResponse, null, 2) + "\n");
82
+ return { exitCode: 1, response: errResponse };
83
+ }
84
+ }
85
+ }
86
+ });
87
+ function calculateStats(events, taskId) {
88
+ const normalized = normalizeTraceEvents(events);
89
+ const iterationSet = /* @__PURE__ */ new Set();
90
+ for (const e of normalized) {
91
+ if (e.iteration > 0) {
92
+ iterationSet.add(e.iteration);
93
+ }
94
+ }
95
+ const llmStartEvents = normalized.filter((e) => e.type === "llm:start" || e.type === "llm:call" || e.type === "llm_call");
96
+ const llmEndEvents = normalized.filter((e) => e.type === "llm:end" || e.type === "llm:call");
97
+ const toolEndEvents = normalized.filter((e) => e.type === "tool:end" || e.type === "tool:execution" || e.type === "tool_result");
98
+ const errorEvents = normalized.filter((e) => e.type === "error:captured" || e.type === "agent:error" || e.type === "tool:error");
99
+ const inputTokens = llmEndEvents.reduce((sum, e) => {
100
+ const tokens = e.raw.response?.usage?.inputTokens || 0;
101
+ return sum + tokens;
102
+ }, 0);
103
+ const outputTokens = llmEndEvents.reduce((sum, e) => {
104
+ const tokens = e.raw.response?.usage?.outputTokens || 0;
105
+ return sum + tokens;
106
+ }, 0);
107
+ const legacyTotalTokens = llmEndEvents.reduce((sum, e) => {
108
+ const tokens = e.data.tokensUsed || 0;
109
+ return sum + tokens;
110
+ }, 0);
111
+ const totalCost = llmEndEvents.reduce((sum, e) => {
112
+ const cost = e.raw.cost?.totalCost || 0;
113
+ return sum + cost;
114
+ }, 0);
115
+ const toolCounts = {};
116
+ let successfulTools = 0;
117
+ let failedTools = 0;
118
+ for (const tool of toolEndEvents) {
119
+ const toolName = tool.raw.tool?.name || tool.data.toolName || "unknown";
120
+ toolCounts[toolName] = (toolCounts[toolName] || 0) + 1;
121
+ const success = tool.raw.output?.success ?? tool.data.success ?? true;
122
+ if (success) {
123
+ successfulTools++;
124
+ } else {
125
+ failedTools++;
126
+ }
127
+ }
128
+ const firstEvent = events[0];
129
+ const lastEvent = events[events.length - 1];
130
+ const startedAt = firstEvent?.timestamp || (/* @__PURE__ */ new Date()).toISOString();
131
+ const completedAt = lastEvent?.timestamp || (/* @__PURE__ */ new Date()).toISOString();
132
+ const totalDurationMs = new Date(completedAt).getTime() - new Date(startedAt).getTime();
133
+ return {
134
+ taskId: taskId || "unknown",
135
+ status: errorEvents.length > 0 ? "failed" : "success",
136
+ iterations: {
137
+ total: iterationSet.size,
138
+ completed: iterationSet.size
139
+ },
140
+ llm: {
141
+ calls: llmStartEvents.length,
142
+ inputTokens,
143
+ outputTokens,
144
+ // Use explicit tokens if available, otherwise fall back to legacy total
145
+ totalTokens: inputTokens + outputTokens || legacyTotalTokens
146
+ },
147
+ tools: {
148
+ totalCalls: toolEndEvents.length,
149
+ byTool: toolCounts,
150
+ successful: successfulTools,
151
+ failed: failedTools
152
+ },
153
+ timing: {
154
+ startedAt,
155
+ completedAt,
156
+ totalDurationMs,
157
+ durationFormatted: formatDuration(totalDurationMs)
158
+ },
159
+ cost: {
160
+ total: totalCost,
161
+ currency: "USD"
162
+ },
163
+ errors: errorEvents.length
164
+ };
165
+ }
166
+ function formatDuration(ms) {
167
+ const seconds = Math.floor(ms / 1e3);
168
+ const minutes = Math.floor(seconds / 60);
169
+ const hours = Math.floor(minutes / 60);
170
+ if (hours > 0) {
171
+ return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
172
+ }
173
+ if (minutes > 0) {
174
+ return `${minutes}m ${seconds % 60}s`;
175
+ }
176
+ return `${seconds}s`;
177
+ }
178
+ function printHumanReadable(ctx, stats) {
179
+ ctx.ui.write("\n");
180
+ ctx.ui.write("\u{1F4CA} Trace Statistics\n");
181
+ ctx.ui.write("\n");
182
+ ctx.ui.write(`Status: ${stats.status === "success" ? "\u2705 Success" : "\u274C Failed"}
183
+ `);
184
+ ctx.ui.write(`Iterations: ${stats.iterations.total}
185
+ `);
186
+ ctx.ui.write("\n");
187
+ ctx.ui.write("\u{1F916} LLM Usage:\n");
188
+ ctx.ui.write(` Calls: ${stats.llm.calls}
189
+ `);
190
+ ctx.ui.write(` Input tokens: ${stats.llm.inputTokens.toLocaleString()}
191
+ `);
192
+ ctx.ui.write(` Output tokens: ${stats.llm.outputTokens.toLocaleString()}
193
+ `);
194
+ ctx.ui.write(` Total tokens: ${stats.llm.totalTokens.toLocaleString()}
195
+ `);
196
+ ctx.ui.write("\n");
197
+ ctx.ui.write("\u{1F527} Tool Usage:\n");
198
+ ctx.ui.write(` Total calls: ${stats.tools.totalCalls}
199
+ `);
200
+ ctx.ui.write(` Successful: ${stats.tools.successful}
201
+ `);
202
+ ctx.ui.write(` Failed: ${stats.tools.failed}
203
+ `);
204
+ ctx.ui.write(" By tool:\n");
205
+ for (const [tool, count] of Object.entries(stats.tools.byTool)) {
206
+ ctx.ui.write(` ${tool}: ${count}
207
+ `);
208
+ }
209
+ ctx.ui.write("\n");
210
+ ctx.ui.write("\u23F1\uFE0F Timing:\n");
211
+ ctx.ui.write(` Started: ${stats.timing.startedAt}
212
+ `);
213
+ ctx.ui.write(` Completed: ${stats.timing.completedAt}
214
+ `);
215
+ ctx.ui.write(` Duration: ${stats.timing.durationFormatted}
216
+ `);
217
+ ctx.ui.write("\n");
218
+ ctx.ui.write("\u{1F4B0} Cost:\n");
219
+ ctx.ui.write(` Total: $${stats.cost.total.toFixed(4)} ${stats.cost.currency}
220
+ `);
221
+ ctx.ui.write("\n");
222
+ if (stats.errors > 0) {
223
+ ctx.ui.write(`\u26A0\uFE0F Errors: ${stats.errors}
224
+ `);
225
+ ctx.ui.write("\n");
226
+ }
227
+ }
228
+ function error(code, message) {
229
+ return {
230
+ success: false,
231
+ command: "trace:stats",
232
+ taskId: "",
233
+ error: {
234
+ code,
235
+ message
236
+ },
237
+ summary: {
238
+ message,
239
+ severity: "error",
240
+ actionable: true
241
+ }
242
+ };
243
+ }
244
+
245
+ export { trace_stats_default as default };
246
+ //# sourceMappingURL=trace-stats.js.map
247
+ //# sourceMappingURL=trace-stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/trace-event-normalizer.ts","../../../src/cli/commands/trace-stats.ts"],"names":[],"mappings":"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","file":"trace-stats.js","sourcesContent":["import type { DetailedTraceEntry } from '@kb-labs/agent-contracts';\n\nexport type NormalizedTraceEvent = {\n raw: DetailedTraceEntry;\n type: string;\n data: Record<string, unknown>;\n iteration: number;\n};\n\nexport function normalizeTraceEvents(events: DetailedTraceEntry[]): NormalizedTraceEvent[] {\n const out: NormalizedTraceEvent[] = [];\n let currentIteration = 0;\n\n for (const raw of events) {\n const type = String((raw as any).type ?? '');\n const data = getEventData(raw);\n\n const explicitIteration = asNumber((raw as any).iteration) ?? asNumber(data.iteration);\n if (type === 'iteration:start') {\n currentIteration = explicitIteration ?? Math.max(1, currentIteration + 1);\n }\n\n const iteration = explicitIteration ?? currentIteration;\n out.push({ raw, type, data, iteration });\n }\n\n return out;\n}\n\nexport function getEventData(event: DetailedTraceEntry): Record<string, unknown> {\n const data = (event as any).data;\n if (data && typeof data === 'object') {\n return data as Record<string, unknown>;\n }\n return {};\n}\n\nexport function asNumber(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n if (typeof value === 'string') {\n const n = Number(value);\n if (Number.isFinite(n)) {\n return n;\n }\n }\n return undefined;\n}\n","/**\n * agent:trace:stats - Show trace statistics (AI-friendly)\n *\n * Usage:\n * pnpm kb agent:trace:stats <taskId>\n * pnpm kb agent:trace:stats <taskId> --json\n */\n\nimport { defineCommand, useLogger } from '@kb-labs/sdk';\nimport type { PluginContextV3 } from '@kb-labs/sdk';\nimport type {\n TraceCommandResponse,\n StatsResponse,\n TraceErrorCode,\n DetailedTraceEntry,\n} from '@kb-labs/agent-contracts';\nimport { loadTrace, formatTraceLoadError } from '@kb-labs/agent-tracing';\nimport { normalizeTraceEvents } from './trace-event-normalizer.js';\n\ntype TraceStatsInput = {\n taskId?: string;\n 'task-id'?: string;\n json?: boolean;\n};\n\ntype TraceStatsResult = { exitCode: number; response?: TraceCommandResponse };\n\nexport default defineCommand({\n id: 'trace:stats',\n description: 'Show trace statistics with cost and performance metrics',\n\n handler: {\n async execute(ctx: PluginContextV3, input: TraceStatsInput): Promise<TraceStatsResult> {\n const logger = useLogger();\n const flags = (input as any).flags ?? input;\n const taskId = (flags['task-id'] ?? flags.taskId) as string | undefined;\n\n try {\n const loaded = await loadTrace(taskId);\n if (!loaded.ok) {\n const code: TraceErrorCode =\n loaded.error.kind === 'invalid_task_id' ? 'INVALID_TASK_ID' :\n loaded.error.kind === 'not_found' ? 'TRACE_NOT_FOUND' :\n loaded.error.kind === 'too_large' ? 'FILE_TOO_LARGE' :\n 'CORRUPTED_TRACE';\n const err = error(code, formatTraceLoadError(loaded.error));\n ctx.ui.write(JSON.stringify(err, null, 2) + '\\n');\n return { exitCode: 1, response: err };\n }\n\n const { events } = loaded;\n\n // Calculate stats\n const stats = calculateStats(events, taskId);\n\n // Build response\n const response: TraceCommandResponse<StatsResponse> = {\n success: true,\n command: 'trace:stats',\n taskId: taskId ?? '',\n data: stats,\n summary: {\n message: `${stats.iterations.total} iterations, ${stats.llm.calls} LLM calls, $${stats.cost.total.toFixed(4)} cost`,\n severity: stats.errors > 0 ? 'warning' : 'info',\n actionable: stats.errors > 5,\n },\n };\n\n // Output\n if (flags.json) {\n ctx.ui.write(JSON.stringify(response, null, 2) + '\\n');\n } else {\n printHumanReadable(ctx, stats);\n }\n\n return { exitCode: 0, response };\n } catch (err) {\n logger.error('trace:stats error:', err instanceof Error ? err : undefined);\n const errResponse = error('IO_ERROR', err instanceof Error ? err.message : String(err));\n ctx.ui.write(JSON.stringify(errResponse, null, 2) + '\\n');\n return { exitCode: 1, response: errResponse };\n }\n },\n },\n});\n\n/**\n * Calculate statistics from trace events\n */\nfunction calculateStats(events: DetailedTraceEntry[], taskId?: string): StatsResponse {\n const normalized = normalizeTraceEvents(events);\n const iterationSet = new Set<number>();\n for (const e of normalized) {\n if (e.iteration > 0) {\n iterationSet.add(e.iteration);\n }\n }\n\n const llmStartEvents = normalized.filter((e) => e.type === 'llm:start' || e.type === 'llm:call' || e.type === 'llm_call');\n const llmEndEvents = normalized.filter((e) => e.type === 'llm:end' || e.type === 'llm:call');\n const toolEndEvents = normalized.filter((e) => e.type === 'tool:end' || e.type === 'tool:execution' || e.type === 'tool_result');\n const errorEvents = normalized.filter((e) => e.type === 'error:captured' || e.type === 'agent:error' || e.type === 'tool:error');\n\n // Calculate LLM stats (handle both new and legacy data structures)\n const inputTokens = llmEndEvents.reduce((sum, e) => {\n const tokens = (e.raw as any).response?.usage?.inputTokens || 0;\n return sum + tokens;\n }, 0);\n\n const outputTokens = llmEndEvents.reduce((sum, e) => {\n const tokens = (e.raw as any).response?.usage?.outputTokens || 0;\n return sum + tokens;\n }, 0);\n\n const legacyTotalTokens = llmEndEvents.reduce((sum, e) => {\n const tokens = (e.data.tokensUsed as number | undefined) || 0;\n return sum + tokens;\n }, 0);\n\n const totalCost = llmEndEvents.reduce((sum, e) => {\n const cost = (e.raw as any).cost?.totalCost || 0;\n return sum + cost;\n }, 0);\n\n // Calculate tool stats (handle both new and legacy formats)\n const toolCounts: Record<string, number> = {};\n let successfulTools = 0;\n let failedTools = 0;\n\n for (const tool of toolEndEvents) {\n const toolName = (tool.raw as any).tool?.name || (tool.data.toolName as string | undefined) || 'unknown';\n toolCounts[toolName] = (toolCounts[toolName] || 0) + 1;\n\n const success = (tool.raw as any).output?.success ?? tool.data.success ?? true;\n if (success) {\n successfulTools++;\n } else {\n failedTools++;\n }\n }\n\n // Calculate timing\n const firstEvent = events[0];\n const lastEvent = events[events.length - 1];\n const startedAt = firstEvent?.timestamp || new Date().toISOString();\n const completedAt = lastEvent?.timestamp || new Date().toISOString();\n const totalDurationMs = new Date(completedAt).getTime() - new Date(startedAt).getTime();\n\n return {\n taskId: taskId || 'unknown',\n status: errorEvents.length > 0 ? 'failed' : 'success',\n\n iterations: {\n total: iterationSet.size,\n completed: iterationSet.size,\n },\n\n llm: {\n calls: llmStartEvents.length,\n inputTokens,\n outputTokens,\n // Use explicit tokens if available, otherwise fall back to legacy total\n totalTokens: (inputTokens + outputTokens) || legacyTotalTokens,\n },\n\n tools: {\n totalCalls: toolEndEvents.length,\n byTool: toolCounts,\n successful: successfulTools,\n failed: failedTools,\n },\n\n timing: {\n startedAt,\n completedAt,\n totalDurationMs,\n durationFormatted: formatDuration(totalDurationMs),\n },\n\n cost: {\n total: totalCost,\n currency: 'USD',\n },\n\n errors: errorEvents.length,\n };\n}\n\n/**\n * Format duration in human-readable format\n */\nfunction formatDuration(ms: number): string {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n\n if (hours > 0) {\n return `${hours}h ${minutes % 60}m ${seconds % 60}s`;\n }\n if (minutes > 0) {\n return `${minutes}m ${seconds % 60}s`;\n }\n return `${seconds}s`;\n}\n\n/**\n * Print human-readable output\n */\nfunction printHumanReadable(ctx: PluginContextV3, stats: StatsResponse): void {\n ctx.ui.write('\\n');\n ctx.ui.write('📊 Trace Statistics\\n');\n ctx.ui.write('\\n');\n\n ctx.ui.write(`Status: ${stats.status === 'success' ? '✅ Success' : '❌ Failed'}\\n`);\n ctx.ui.write(`Iterations: ${stats.iterations.total}\\n`);\n ctx.ui.write('\\n');\n\n ctx.ui.write('🤖 LLM Usage:\\n');\n ctx.ui.write(` Calls: ${stats.llm.calls}\\n`);\n ctx.ui.write(` Input tokens: ${stats.llm.inputTokens.toLocaleString()}\\n`);\n ctx.ui.write(` Output tokens: ${stats.llm.outputTokens.toLocaleString()}\\n`);\n ctx.ui.write(` Total tokens: ${stats.llm.totalTokens.toLocaleString()}\\n`);\n ctx.ui.write('\\n');\n\n ctx.ui.write('🔧 Tool Usage:\\n');\n ctx.ui.write(` Total calls: ${stats.tools.totalCalls}\\n`);\n ctx.ui.write(` Successful: ${stats.tools.successful}\\n`);\n ctx.ui.write(` Failed: ${stats.tools.failed}\\n`);\n ctx.ui.write(' By tool:\\n');\n for (const [tool, count] of Object.entries(stats.tools.byTool)) {\n ctx.ui.write(` ${tool}: ${count}\\n`);\n }\n ctx.ui.write('\\n');\n\n ctx.ui.write('⏱️ Timing:\\n');\n ctx.ui.write(` Started: ${stats.timing.startedAt}\\n`);\n ctx.ui.write(` Completed: ${stats.timing.completedAt}\\n`);\n ctx.ui.write(` Duration: ${stats.timing.durationFormatted}\\n`);\n ctx.ui.write('\\n');\n\n ctx.ui.write('💰 Cost:\\n');\n ctx.ui.write(` Total: $${stats.cost.total.toFixed(4)} ${stats.cost.currency}\\n`);\n ctx.ui.write('\\n');\n\n if (stats.errors > 0) {\n ctx.ui.write(`⚠️ Errors: ${stats.errors}\\n`);\n ctx.ui.write('\\n');\n }\n}\n\n/**\n * Create error response\n */\nfunction error(code: TraceErrorCode, message: string): TraceCommandResponse {\n return {\n success: false,\n command: 'trace:stats',\n taskId: '',\n error: {\n code,\n message,\n },\n summary: {\n message,\n severity: 'error',\n actionable: true,\n },\n };\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export { manifest } from './manifest.js';
2
+ import '@kb-labs/perm-presets';