cost-katana-cli 2.0.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 (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +343 -0
  3. package/bin/cost-katana.js +20 -0
  4. package/dist/commands/agent-inspect.d.ts +3 -0
  5. package/dist/commands/agent-inspect.d.ts.map +1 -0
  6. package/dist/commands/agent-inspect.js +630 -0
  7. package/dist/commands/agent-inspect.js.map +1 -0
  8. package/dist/commands/analytics.d.ts +3 -0
  9. package/dist/commands/analytics.d.ts.map +1 -0
  10. package/dist/commands/analytics.js +375 -0
  11. package/dist/commands/analytics.js.map +1 -0
  12. package/dist/commands/analyze.d.ts +3 -0
  13. package/dist/commands/analyze.d.ts.map +1 -0
  14. package/dist/commands/analyze.js +286 -0
  15. package/dist/commands/analyze.js.map +1 -0
  16. package/dist/commands/ask.d.ts +3 -0
  17. package/dist/commands/ask.d.ts.map +1 -0
  18. package/dist/commands/ask.js +137 -0
  19. package/dist/commands/ask.js.map +1 -0
  20. package/dist/commands/audit-firewall.d.ts +3 -0
  21. package/dist/commands/audit-firewall.d.ts.map +1 -0
  22. package/dist/commands/audit-firewall.js +737 -0
  23. package/dist/commands/audit-firewall.js.map +1 -0
  24. package/dist/commands/budget.d.ts +3 -0
  25. package/dist/commands/budget.d.ts.map +1 -0
  26. package/dist/commands/budget.js +283 -0
  27. package/dist/commands/budget.js.map +1 -0
  28. package/dist/commands/bulk-optimize.d.ts +3 -0
  29. package/dist/commands/bulk-optimize.d.ts.map +1 -0
  30. package/dist/commands/bulk-optimize.js +863 -0
  31. package/dist/commands/bulk-optimize.js.map +1 -0
  32. package/dist/commands/chat.d.ts +3 -0
  33. package/dist/commands/chat.d.ts.map +1 -0
  34. package/dist/commands/chat.js +292 -0
  35. package/dist/commands/chat.js.map +1 -0
  36. package/dist/commands/check-cache.d.ts +3 -0
  37. package/dist/commands/check-cache.d.ts.map +1 -0
  38. package/dist/commands/check-cache.js +267 -0
  39. package/dist/commands/check-cache.js.map +1 -0
  40. package/dist/commands/compare.d.ts +3 -0
  41. package/dist/commands/compare.d.ts.map +1 -0
  42. package/dist/commands/compare.js +131 -0
  43. package/dist/commands/compare.js.map +1 -0
  44. package/dist/commands/config.d.ts +3 -0
  45. package/dist/commands/config.d.ts.map +1 -0
  46. package/dist/commands/config.js +421 -0
  47. package/dist/commands/config.js.map +1 -0
  48. package/dist/commands/craft-workflow.d.ts +3 -0
  49. package/dist/commands/craft-workflow.d.ts.map +1 -0
  50. package/dist/commands/craft-workflow.js +844 -0
  51. package/dist/commands/craft-workflow.js.map +1 -0
  52. package/dist/commands/debug-prompt.d.ts +3 -0
  53. package/dist/commands/debug-prompt.d.ts.map +1 -0
  54. package/dist/commands/debug-prompt.js +614 -0
  55. package/dist/commands/debug-prompt.js.map +1 -0
  56. package/dist/commands/diff-prompts.d.ts +3 -0
  57. package/dist/commands/diff-prompts.d.ts.map +1 -0
  58. package/dist/commands/diff-prompts.js +553 -0
  59. package/dist/commands/diff-prompts.js.map +1 -0
  60. package/dist/commands/high-cost-prompts.d.ts +3 -0
  61. package/dist/commands/high-cost-prompts.d.ts.map +1 -0
  62. package/dist/commands/high-cost-prompts.js +719 -0
  63. package/dist/commands/high-cost-prompts.js.map +1 -0
  64. package/dist/commands/init.d.ts +3 -0
  65. package/dist/commands/init.d.ts.map +1 -0
  66. package/dist/commands/init.js +325 -0
  67. package/dist/commands/init.js.map +1 -0
  68. package/dist/commands/key.d.ts +3 -0
  69. package/dist/commands/key.d.ts.map +1 -0
  70. package/dist/commands/key.js +574 -0
  71. package/dist/commands/key.js.map +1 -0
  72. package/dist/commands/list-models.d.ts +3 -0
  73. package/dist/commands/list-models.d.ts.map +1 -0
  74. package/dist/commands/list-models.js +154 -0
  75. package/dist/commands/list-models.js.map +1 -0
  76. package/dist/commands/models.d.ts +3 -0
  77. package/dist/commands/models.d.ts.map +1 -0
  78. package/dist/commands/models.js +107 -0
  79. package/dist/commands/models.js.map +1 -0
  80. package/dist/commands/optimize.d.ts +3 -0
  81. package/dist/commands/optimize.d.ts.map +1 -0
  82. package/dist/commands/optimize.js +345 -0
  83. package/dist/commands/optimize.js.map +1 -0
  84. package/dist/commands/project.d.ts +3 -0
  85. package/dist/commands/project.d.ts.map +1 -0
  86. package/dist/commands/project.js +475 -0
  87. package/dist/commands/project.js.map +1 -0
  88. package/dist/commands/prompt-metrics.d.ts +3 -0
  89. package/dist/commands/prompt-metrics.d.ts.map +1 -0
  90. package/dist/commands/prompt-metrics.js +665 -0
  91. package/dist/commands/prompt-metrics.js.map +1 -0
  92. package/dist/commands/replay-session.d.ts +3 -0
  93. package/dist/commands/replay-session.d.ts.map +1 -0
  94. package/dist/commands/replay-session.js +615 -0
  95. package/dist/commands/replay-session.js.map +1 -0
  96. package/dist/commands/retry-log.d.ts +3 -0
  97. package/dist/commands/retry-log.d.ts.map +1 -0
  98. package/dist/commands/retry-log.js +686 -0
  99. package/dist/commands/retry-log.js.map +1 -0
  100. package/dist/commands/rewrite-prompt.d.ts +3 -0
  101. package/dist/commands/rewrite-prompt.d.ts.map +1 -0
  102. package/dist/commands/rewrite-prompt.js +802 -0
  103. package/dist/commands/rewrite-prompt.js.map +1 -0
  104. package/dist/commands/set-budget.d.ts +3 -0
  105. package/dist/commands/set-budget.d.ts.map +1 -0
  106. package/dist/commands/set-budget.js +909 -0
  107. package/dist/commands/set-budget.js.map +1 -0
  108. package/dist/commands/simulate-cost.d.ts +3 -0
  109. package/dist/commands/simulate-cost.d.ts.map +1 -0
  110. package/dist/commands/simulate-cost.js +873 -0
  111. package/dist/commands/simulate-cost.js.map +1 -0
  112. package/dist/commands/suggest-models.d.ts +3 -0
  113. package/dist/commands/suggest-models.d.ts.map +1 -0
  114. package/dist/commands/suggest-models.js +674 -0
  115. package/dist/commands/suggest-models.js.map +1 -0
  116. package/dist/commands/test.d.ts +3 -0
  117. package/dist/commands/test.d.ts.map +1 -0
  118. package/dist/commands/test.js +187 -0
  119. package/dist/commands/test.js.map +1 -0
  120. package/dist/commands/trace-workflow.d.ts +3 -0
  121. package/dist/commands/trace-workflow.d.ts.map +1 -0
  122. package/dist/commands/trace-workflow.js +651 -0
  123. package/dist/commands/trace-workflow.js.map +1 -0
  124. package/dist/commands/trace.d.ts +3 -0
  125. package/dist/commands/trace.d.ts.map +1 -0
  126. package/dist/commands/trace.js +468 -0
  127. package/dist/commands/trace.js.map +1 -0
  128. package/dist/commands/track.d.ts +3 -0
  129. package/dist/commands/track.d.ts.map +1 -0
  130. package/dist/commands/track.js +404 -0
  131. package/dist/commands/track.js.map +1 -0
  132. package/dist/index.d.ts +4 -0
  133. package/dist/index.d.ts.map +1 -0
  134. package/dist/index.js +169 -0
  135. package/dist/index.js.map +1 -0
  136. package/dist/utils/config.d.ts +46 -0
  137. package/dist/utils/config.d.ts.map +1 -0
  138. package/dist/utils/config.js +321 -0
  139. package/dist/utils/config.js.map +1 -0
  140. package/dist/utils/logger.d.ts +21 -0
  141. package/dist/utils/logger.d.ts.map +1 -0
  142. package/dist/utils/logger.js +101 -0
  143. package/dist/utils/logger.js.map +1 -0
  144. package/dist/utils/models.d.ts +22 -0
  145. package/dist/utils/models.d.ts.map +1 -0
  146. package/dist/utils/models.js +2251 -0
  147. package/dist/utils/models.js.map +1 -0
  148. package/package.json +107 -0
@@ -0,0 +1,651 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.traceWorkflowCommand = traceWorkflowCommand;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const logger_1 = require("../utils/logger");
9
+ const config_1 = require("../utils/config");
10
+ const axios_1 = __importDefault(require("axios"));
11
+ function traceWorkflowCommand(program) {
12
+ const workflowGroup = program
13
+ .command('trace-workflow')
14
+ .description('šŸ” Trace workflow lifecycles and multi-agent tasks');
15
+ // Main trace-workflow command
16
+ workflowGroup
17
+ .option('--format <format>', 'Output format (table, json, csv)', 'table')
18
+ .option('--export <path>', 'Export workflow data to file')
19
+ .option('-v, --verbose', 'Show detailed workflow information')
20
+ .action(async (options) => {
21
+ try {
22
+ await handleTraceWorkflow(options);
23
+ }
24
+ catch (error) {
25
+ logger_1.logger.error('Trace workflow command failed:', error);
26
+ process.exit(1);
27
+ }
28
+ });
29
+ // Trace workflow by ID
30
+ workflowGroup
31
+ .command('id <workflowId>')
32
+ .description('šŸ” Trace a specific workflow by ID')
33
+ .option('--format <format>', 'Output format (table, json, csv)', 'table')
34
+ .option('--export <path>', 'Export workflow data to file')
35
+ .option('-v, --verbose', 'Show detailed workflow information')
36
+ .option('--include-session', 'Include session/conversation tree')
37
+ .option('--include-cache', 'Include cache usage details')
38
+ .option('--include-fallbacks', 'Include fallback usage details')
39
+ .action(async (workflowId, options) => {
40
+ try {
41
+ await handleTraceWorkflowById(workflowId, options);
42
+ }
43
+ catch (error) {
44
+ logger_1.logger.error('Trace workflow by ID failed:', error);
45
+ process.exit(1);
46
+ }
47
+ });
48
+ // Trace recent workflows
49
+ workflowGroup
50
+ .command('recent')
51
+ .description('šŸ“‹ Show recent workflow traces')
52
+ .option('-n, --number <count>', 'Number of recent workflows to show', '10')
53
+ .option('--format <format>', 'Output format (table, json, csv)', 'table')
54
+ .option('--export <path>', 'Export workflow data to file')
55
+ .option('-v, --verbose', 'Show detailed workflow information')
56
+ .action(async (options) => {
57
+ try {
58
+ await handleTraceWorkflowRecent(options);
59
+ }
60
+ catch (error) {
61
+ logger_1.logger.error('Trace workflow recent failed:', error);
62
+ process.exit(1);
63
+ }
64
+ });
65
+ // Trace workflows by project
66
+ workflowGroup
67
+ .command('project <projectName>')
68
+ .description('šŸ“ Trace workflows for a specific project')
69
+ .option('-d, --days <days>', 'Number of days to look back', '7')
70
+ .option('--format <format>', 'Output format (table, json, csv)', 'table')
71
+ .option('--export <path>', 'Export workflow data to file')
72
+ .option('-v, --verbose', 'Show detailed workflow information')
73
+ .action(async (projectName, options) => {
74
+ try {
75
+ await handleTraceWorkflowByProject(projectName, options);
76
+ }
77
+ catch (error) {
78
+ logger_1.logger.error('Trace workflow by project failed:', error);
79
+ process.exit(1);
80
+ }
81
+ });
82
+ // Trace workflows by agent
83
+ workflowGroup
84
+ .command('agent <agentName>')
85
+ .description('šŸ¤– Trace workflows involving a specific agent')
86
+ .option('-d, --days <days>', 'Number of days to look back', '7')
87
+ .option('--format <format>', 'Output format (table, json, csv)', 'table')
88
+ .option('--export <path>', 'Export workflow data to file')
89
+ .option('-v, --verbose', 'Show detailed workflow information')
90
+ .action(async (agentName, options) => {
91
+ try {
92
+ await handleTraceWorkflowByAgent(agentName, options);
93
+ }
94
+ catch (error) {
95
+ logger_1.logger.error('Trace workflow by agent failed:', error);
96
+ process.exit(1);
97
+ }
98
+ });
99
+ }
100
+ async function handleTraceWorkflow(options) {
101
+ console.log(chalk_1.default.cyan.bold('\nšŸ” Workflow Tracing & Lifecycle Analysis'));
102
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
103
+ console.log(chalk_1.default.yellow('Available commands:'));
104
+ console.log(chalk_1.default.white(' costkatana trace-workflow id <workflowId> Trace a specific workflow'));
105
+ console.log(chalk_1.default.white(' costkatana trace-workflow recent Show recent workflow traces'));
106
+ console.log(chalk_1.default.white(' costkatana trace-workflow project <name> Trace workflows for a project'));
107
+ console.log(chalk_1.default.white(' costkatana trace-workflow agent <name> Trace workflows by agent'));
108
+ console.log(chalk_1.default.gray('\nExamples:'));
109
+ console.log(chalk_1.default.white(' costkatana trace-workflow id workflow-98765'));
110
+ console.log(chalk_1.default.white(' costkatana trace-workflow recent --number 5'));
111
+ console.log(chalk_1.default.white(' costkatana trace-workflow project my-project --days 30'));
112
+ console.log(chalk_1.default.white(' costkatana trace-workflow agent assistant --verbose'));
113
+ console.log(chalk_1.default.gray('\nWorkflow Information:'));
114
+ console.log(chalk_1.default.white(' • Sequential call log (step-by-step)'));
115
+ console.log(chalk_1.default.white(' • Agents involved in the workflow'));
116
+ console.log(chalk_1.default.white(' • Prompt and response per step'));
117
+ console.log(chalk_1.default.white(' • Token and cost per step'));
118
+ console.log(chalk_1.default.white(' • Retry/fallback/cache usage per step'));
119
+ console.log(chalk_1.default.white(' • Session or conversation tree'));
120
+ console.log(chalk_1.default.white(' • Workflow completion status'));
121
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
122
+ }
123
+ async function handleTraceWorkflowById(workflowId, options) {
124
+ logger_1.logger.info(`šŸ” Tracing workflow: ${workflowId}`);
125
+ try {
126
+ const workflowData = await getWorkflowById(workflowId, options);
127
+ displayWorkflowResult(workflowData, options);
128
+ }
129
+ catch (error) {
130
+ logger_1.logger.error('Failed to trace workflow:', error);
131
+ process.exit(1);
132
+ }
133
+ }
134
+ async function getWorkflowById(workflowId, options) {
135
+ const baseUrl = config_1.configManager.get('baseUrl');
136
+ const apiKey = config_1.configManager.get('apiKey');
137
+ if (!baseUrl || !apiKey) {
138
+ console.log(chalk_1.default.red.bold('\nāŒ Configuration Missing'));
139
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
140
+ if (!apiKey) {
141
+ console.log(chalk_1.default.yellow('• API Key is not set'));
142
+ }
143
+ if (!baseUrl) {
144
+ console.log(chalk_1.default.yellow('• Base URL is not set'));
145
+ }
146
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
147
+ console.log(chalk_1.default.cyan('To set up your configuration, run:'));
148
+ console.log(chalk_1.default.white(' cost-katana init'));
149
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
150
+ throw new Error('Configuration incomplete. Please run "cost-katana init" to set up your API key and base URL.');
151
+ }
152
+ try {
153
+ const params = new URLSearchParams();
154
+ if (options.includeSession)
155
+ params.append('includeSession', 'true');
156
+ if (options.includeCache)
157
+ params.append('includeCache', 'true');
158
+ if (options.includeFallbacks)
159
+ params.append('includeFallbacks', 'true');
160
+ const response = await axios_1.default.get(`${baseUrl}/api/workflow/trace/${workflowId}?${params}`, {
161
+ headers: {
162
+ 'Authorization': `Bearer ${apiKey}`,
163
+ 'Content-Type': 'application/json',
164
+ },
165
+ timeout: 30000,
166
+ });
167
+ if (response.status !== 200) {
168
+ throw new Error(`API returned status ${response.status}`);
169
+ }
170
+ if (response.data.success && response.data.data) {
171
+ return response.data.data;
172
+ }
173
+ else {
174
+ throw new Error(response.data.message || 'Invalid response format');
175
+ }
176
+ }
177
+ catch (error) {
178
+ if (error.response) {
179
+ throw new Error(`API Error: ${error.response.status} - ${error.response.data?.message || 'Unknown error'}`);
180
+ }
181
+ else if (error.request) {
182
+ throw new Error('No response received from API');
183
+ }
184
+ else {
185
+ throw new Error(`Request failed: ${error.message}`);
186
+ }
187
+ }
188
+ }
189
+ function displayWorkflowResult(workflow, options) {
190
+ const format = options.format || 'table';
191
+ if (format === 'json') {
192
+ console.log(JSON.stringify(workflow, null, 2));
193
+ return;
194
+ }
195
+ else if (format === 'csv') {
196
+ console.log('Workflow ID,Status,Total Steps,Total Cost,Total Tokens,Duration,Agents');
197
+ console.log(`"${workflow.workflowId}","${workflow.status}","${workflow.steps?.length || 0}","${workflow.totalCost}","${workflow.totalTokens}","${workflow.duration}","${workflow.agents?.join(',')}"`);
198
+ return;
199
+ }
200
+ console.log(chalk_1.default.cyan.bold('\nšŸ” Workflow Trace'));
201
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
202
+ // Basic Workflow Information
203
+ console.log(chalk_1.default.yellow.bold('\nšŸ“‹ Workflow Information'));
204
+ console.log(chalk_1.default.gray('─'.repeat(50)));
205
+ console.log(chalk_1.default.white('šŸ†” Workflow ID:'), chalk_1.default.cyan(workflow.workflowId));
206
+ console.log(chalk_1.default.white('šŸ“… Started:'), chalk_1.default.cyan(new Date(workflow.startedAt).toLocaleString()));
207
+ console.log(chalk_1.default.white('ā±ļø Duration:'), chalk_1.default.cyan(`${workflow.duration}ms`));
208
+ console.log(chalk_1.default.white('šŸ“Š Status:'), workflow.status === 'completed' ? chalk_1.default.green(workflow.status) : chalk_1.default.red(workflow.status));
209
+ console.log(chalk_1.default.white('šŸŽÆ Type:'), chalk_1.default.cyan(workflow.workflowType || 'Multi-agent Task'));
210
+ // Agents Involved
211
+ if (workflow.agents && workflow.agents.length > 0) {
212
+ console.log(chalk_1.default.yellow.bold('\nšŸ¤– Agents Involved'));
213
+ console.log(chalk_1.default.gray('─'.repeat(50)));
214
+ workflow.agents.forEach((agent, index) => {
215
+ console.log(chalk_1.default.white(`${index + 1}. ${agent.name}`));
216
+ console.log(chalk_1.default.gray(` Role: ${agent.role}`));
217
+ console.log(chalk_1.default.gray(` Model: ${agent.model}`));
218
+ console.log(chalk_1.default.gray(` Provider: ${agent.provider}`));
219
+ if (agent.description) {
220
+ console.log(chalk_1.default.gray(` Description: ${agent.description}`));
221
+ }
222
+ });
223
+ }
224
+ // Sequential Call Log
225
+ if (workflow.steps && workflow.steps.length > 0) {
226
+ console.log(chalk_1.default.yellow.bold('\nšŸ“ Sequential Call Log'));
227
+ console.log(chalk_1.default.gray('─'.repeat(50)));
228
+ workflow.steps.forEach((step, index) => {
229
+ const stepNumber = index + 1;
230
+ const statusColor = step.status === 'success' ? chalk_1.default.green : chalk_1.default.red;
231
+ const statusIcon = step.status === 'success' ? 'āœ…' : 'āŒ';
232
+ console.log(chalk_1.default.white(`\n${stepNumber}. ${statusIcon} Step ${stepNumber}: ${step.name}`));
233
+ console.log(chalk_1.default.gray(' ─'.repeat(40)));
234
+ console.log(chalk_1.default.white(' šŸ¤– Agent:'), chalk_1.default.cyan(step.agent));
235
+ console.log(chalk_1.default.white(' šŸ“Š Status:'), statusColor(step.status));
236
+ console.log(chalk_1.default.white(' ā±ļø Duration:'), chalk_1.default.cyan(`${step.duration}ms`));
237
+ console.log(chalk_1.default.white(' šŸ’° Cost:'), chalk_1.default.green(`$${step.cost.toFixed(4)}`));
238
+ console.log(chalk_1.default.white(' šŸ”¢ Tokens:'), chalk_1.default.cyan(`${step.inputTokens} input + ${step.outputTokens} output = ${step.totalTokens} total`));
239
+ if (step.model) {
240
+ console.log(chalk_1.default.white(' 🧠 Model:'), chalk_1.default.cyan(step.model));
241
+ }
242
+ if (step.provider) {
243
+ console.log(chalk_1.default.white(' šŸ¢ Provider:'), chalk_1.default.cyan(step.provider));
244
+ }
245
+ // Prompt and Response (if verbose)
246
+ if (options.verbose && step.prompt) {
247
+ console.log(chalk_1.default.white(' šŸ“ Prompt:'));
248
+ console.log(chalk_1.default.gray(` ${step.prompt.substring(0, 200)}${step.prompt.length > 200 ? '...' : ''}`));
249
+ }
250
+ if (options.verbose && step.response) {
251
+ console.log(chalk_1.default.white(' šŸ¤– Response:'));
252
+ console.log(chalk_1.default.gray(` ${step.response.substring(0, 200)}${step.response.length > 200 ? '...' : ''}`));
253
+ }
254
+ // Retry/Fallback/Cache Information
255
+ if (step.retryCount > 0) {
256
+ console.log(chalk_1.default.white(' šŸ”„ Retries:'), chalk_1.default.yellow(step.retryCount));
257
+ }
258
+ if (step.fallbackUsed) {
259
+ console.log(chalk_1.default.white(' šŸ”„ Fallback:'), chalk_1.default.yellow('Used'));
260
+ }
261
+ if (step.cacheHit) {
262
+ console.log(chalk_1.default.white(' šŸ’¾ Cache:'), chalk_1.default.green('HIT'));
263
+ }
264
+ else if (step.cacheMiss) {
265
+ console.log(chalk_1.default.white(' šŸ’¾ Cache:'), chalk_1.default.red('MISS'));
266
+ }
267
+ if (step.error) {
268
+ console.log(chalk_1.default.white(' āŒ Error:'), chalk_1.default.red(step.error));
269
+ }
270
+ });
271
+ }
272
+ // Cost and Token Summary
273
+ console.log(chalk_1.default.yellow.bold('\nšŸ’° Cost & Token Summary'));
274
+ console.log(chalk_1.default.gray('─'.repeat(50)));
275
+ console.log(chalk_1.default.white('Total Cost:'), chalk_1.default.green(`$${workflow.totalCost.toFixed(4)}`));
276
+ console.log(chalk_1.default.white('Total Tokens:'), chalk_1.default.cyan(workflow.totalTokens.toLocaleString()));
277
+ console.log(chalk_1.default.white('Average Cost per Step:'), chalk_1.default.cyan(`$${(workflow.totalCost / (workflow.steps?.length || 1)).toFixed(4)}`));
278
+ console.log(chalk_1.default.white('Average Tokens per Step:'), chalk_1.default.cyan(Math.round(workflow.totalTokens / (workflow.steps?.length || 1)).toLocaleString()));
279
+ // Session/Conversation Tree
280
+ if (options.includeSession && workflow.sessionTree) {
281
+ console.log(chalk_1.default.yellow.bold('\n🌳 Session/Conversation Tree'));
282
+ console.log(chalk_1.default.gray('─'.repeat(50)));
283
+ displaySessionTree(workflow.sessionTree);
284
+ }
285
+ // Performance Metrics
286
+ console.log(chalk_1.default.yellow.bold('\nšŸ“ˆ Performance Metrics'));
287
+ console.log(chalk_1.default.gray('─'.repeat(50)));
288
+ console.log(chalk_1.default.white('Total Steps:'), chalk_1.default.cyan(workflow.steps?.length || 0));
289
+ console.log(chalk_1.default.white('Successful Steps:'), chalk_1.default.green(workflow.steps?.filter((s) => s.status === 'success').length || 0));
290
+ console.log(chalk_1.default.white('Failed Steps:'), chalk_1.default.red(workflow.steps?.filter((s) => s.status !== 'success').length || 0));
291
+ console.log(chalk_1.default.white('Average Step Duration:'), chalk_1.default.cyan(`${Math.round(workflow.duration / (workflow.steps?.length || 1))}ms`));
292
+ console.log(chalk_1.default.white('Throughput:'), chalk_1.default.cyan(`${((workflow.steps?.length || 0) / (workflow.duration / 1000)).toFixed(2)} steps/second`));
293
+ // Error Summary
294
+ const failedSteps = workflow.steps?.filter((s) => s.status !== 'success') || [];
295
+ if (failedSteps.length > 0) {
296
+ console.log(chalk_1.default.yellow.bold('\nāŒ Error Summary'));
297
+ console.log(chalk_1.default.gray('─'.repeat(50)));
298
+ failedSteps.forEach((step, index) => {
299
+ console.log(chalk_1.default.white(`${index + 1}. Step ${step.stepNumber}: ${step.error}`));
300
+ });
301
+ }
302
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
303
+ }
304
+ function displaySessionTree(sessionTree, level = 0) {
305
+ const indent = ' '.repeat(level);
306
+ console.log(chalk_1.default.white(`${indent}• ${sessionTree.name}`));
307
+ console.log(chalk_1.default.gray(`${indent} Agent: ${sessionTree.agent}`));
308
+ console.log(chalk_1.default.gray(`${indent} Status: ${sessionTree.status}`));
309
+ if (sessionTree.children && sessionTree.children.length > 0) {
310
+ sessionTree.children.forEach((child) => {
311
+ displaySessionTree(child, level + 1);
312
+ });
313
+ }
314
+ }
315
+ async function handleTraceWorkflowRecent(options) {
316
+ logger_1.logger.info('šŸ“‹ Fetching recent workflow traces...');
317
+ try {
318
+ const count = parseInt(options.number) || 10;
319
+ const workflows = await getRecentWorkflows(count);
320
+ displayRecentWorkflows(workflows, options);
321
+ }
322
+ catch (error) {
323
+ logger_1.logger.error('Failed to fetch recent workflows:', error);
324
+ process.exit(1);
325
+ }
326
+ }
327
+ async function getRecentWorkflows(count) {
328
+ const baseUrl = config_1.configManager.get('baseUrl');
329
+ const apiKey = config_1.configManager.get('apiKey');
330
+ if (!baseUrl || !apiKey) {
331
+ console.log(chalk_1.default.red.bold('\nāŒ Configuration Missing'));
332
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
333
+ if (!apiKey) {
334
+ console.log(chalk_1.default.yellow('• API Key is not set'));
335
+ }
336
+ if (!baseUrl) {
337
+ console.log(chalk_1.default.yellow('• Base URL is not set'));
338
+ }
339
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
340
+ console.log(chalk_1.default.cyan('To set up your configuration, run:'));
341
+ console.log(chalk_1.default.white(' cost-katana init'));
342
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
343
+ throw new Error('Configuration incomplete. Please run "cost-katana init" to set up your API key and base URL.');
344
+ }
345
+ try {
346
+ const response = await axios_1.default.get(`${baseUrl}/api/workflow/trace/recent?count=${count}`, {
347
+ headers: {
348
+ 'Authorization': `Bearer ${apiKey}`,
349
+ 'Content-Type': 'application/json',
350
+ },
351
+ timeout: 30000,
352
+ });
353
+ if (response.status !== 200) {
354
+ throw new Error(`API returned status ${response.status}`);
355
+ }
356
+ if (response.data.success && response.data.data) {
357
+ return response.data.data;
358
+ }
359
+ else {
360
+ throw new Error(response.data.message || 'Invalid response format');
361
+ }
362
+ }
363
+ catch (error) {
364
+ if (error.response) {
365
+ throw new Error(`API Error: ${error.response.status} - ${error.response.data?.message || 'Unknown error'}`);
366
+ }
367
+ else if (error.request) {
368
+ throw new Error('No response received from API');
369
+ }
370
+ else {
371
+ throw new Error(`Request failed: ${error.message}`);
372
+ }
373
+ }
374
+ }
375
+ function displayRecentWorkflows(workflows, options) {
376
+ const format = options.format || 'table';
377
+ if (format === 'json') {
378
+ console.log(JSON.stringify(workflows, null, 2));
379
+ return;
380
+ }
381
+ else if (format === 'csv') {
382
+ console.log('Workflow ID,Status,Steps,Cost,Tokens,Duration,Agents,Started');
383
+ workflows.forEach(workflow => {
384
+ console.log(`"${workflow.workflowId}","${workflow.status}","${workflow.steps?.length || 0}","${workflow.totalCost}","${workflow.totalTokens}","${workflow.duration}","${workflow.agents?.join(',')}","${workflow.startedAt}"`);
385
+ });
386
+ return;
387
+ }
388
+ console.log(chalk_1.default.cyan.bold('\nšŸ“‹ Recent Workflow Traces'));
389
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
390
+ if (workflows.length === 0) {
391
+ console.log(chalk_1.default.yellow('No recent workflows found.'));
392
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
393
+ return;
394
+ }
395
+ workflows.forEach((workflow, index) => {
396
+ const statusColor = workflow.status === 'completed' ? chalk_1.default.green : chalk_1.default.red;
397
+ const statusIcon = workflow.status === 'completed' ? 'āœ…' : 'āŒ';
398
+ console.log(chalk_1.default.white(`\n${index + 1}. ${statusIcon} ${workflow.workflowId}`));
399
+ console.log(chalk_1.default.gray(' ─'.repeat(40)));
400
+ console.log(chalk_1.default.white(' šŸ“Š Status:'), statusColor(workflow.status));
401
+ console.log(chalk_1.default.white(' šŸ“ Steps:'), chalk_1.default.cyan(workflow.steps?.length || 0));
402
+ console.log(chalk_1.default.white(' šŸ’° Cost:'), chalk_1.default.green(`$${workflow.totalCost.toFixed(4)}`));
403
+ console.log(chalk_1.default.white(' šŸ”¢ Tokens:'), chalk_1.default.cyan(workflow.totalTokens.toLocaleString()));
404
+ console.log(chalk_1.default.white(' ā±ļø Duration:'), chalk_1.default.cyan(`${workflow.duration}ms`));
405
+ console.log(chalk_1.default.white(' šŸ¤– Agents:'), chalk_1.default.cyan(workflow.agents?.join(', ') || 'N/A'));
406
+ console.log(chalk_1.default.white(' šŸ“… Started:'), chalk_1.default.cyan(new Date(workflow.startedAt).toLocaleString()));
407
+ if (workflow.workflowType) {
408
+ console.log(chalk_1.default.white(' šŸŽÆ Type:'), chalk_1.default.cyan(workflow.workflowType));
409
+ }
410
+ });
411
+ console.log(chalk_1.default.gray('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
412
+ console.log(chalk_1.default.yellow('šŸ’” Commands:'));
413
+ console.log(chalk_1.default.white(' • Trace specific workflow: costkatana trace-workflow id <workflowId>'));
414
+ console.log(chalk_1.default.white(' • Trace by project: costkatana trace-workflow project <name>'));
415
+ console.log(chalk_1.default.white(' • Trace by agent: costkatana trace-workflow agent <name>'));
416
+ }
417
+ async function handleTraceWorkflowByProject(projectName, options) {
418
+ logger_1.logger.info(`šŸ“ Tracing workflows for project: ${projectName}`);
419
+ try {
420
+ const days = parseInt(options.days) || 7;
421
+ const workflows = await getWorkflowsByProject(projectName, days);
422
+ displayProjectWorkflows(workflows, projectName, options);
423
+ }
424
+ catch (error) {
425
+ logger_1.logger.error('Failed to trace project workflows:', error);
426
+ process.exit(1);
427
+ }
428
+ }
429
+ async function getWorkflowsByProject(projectName, days) {
430
+ const baseUrl = config_1.configManager.get('baseUrl');
431
+ const apiKey = config_1.configManager.get('apiKey');
432
+ if (!baseUrl || !apiKey) {
433
+ console.log(chalk_1.default.red.bold('\nāŒ Configuration Missing'));
434
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
435
+ if (!apiKey) {
436
+ console.log(chalk_1.default.yellow('• API Key is not set'));
437
+ }
438
+ if (!baseUrl) {
439
+ console.log(chalk_1.default.yellow('• Base URL is not set'));
440
+ }
441
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
442
+ console.log(chalk_1.default.cyan('To set up your configuration, run:'));
443
+ console.log(chalk_1.default.white(' cost-katana init'));
444
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
445
+ throw new Error('Configuration incomplete. Please run "cost-katana init" to set up your API key and base URL.');
446
+ }
447
+ try {
448
+ const response = await axios_1.default.get(`${baseUrl}/api/workflow/trace/project/${projectName}?days=${days}`, {
449
+ headers: {
450
+ 'Authorization': `Bearer ${apiKey}`,
451
+ 'Content-Type': 'application/json',
452
+ },
453
+ timeout: 30000,
454
+ });
455
+ if (response.status !== 200) {
456
+ throw new Error(`API returned status ${response.status}`);
457
+ }
458
+ if (response.data.success && response.data.data) {
459
+ return response.data.data;
460
+ }
461
+ else {
462
+ throw new Error(response.data.message || 'Invalid response format');
463
+ }
464
+ }
465
+ catch (error) {
466
+ if (error.response) {
467
+ throw new Error(`API Error: ${error.response.status} - ${error.response.data?.message || 'Unknown error'}`);
468
+ }
469
+ else if (error.request) {
470
+ throw new Error('No response received from API');
471
+ }
472
+ else {
473
+ throw new Error(`Request failed: ${error.message}`);
474
+ }
475
+ }
476
+ }
477
+ function displayProjectWorkflows(workflows, projectName, options) {
478
+ const format = options.format || 'table';
479
+ if (format === 'json') {
480
+ console.log(JSON.stringify(workflows, null, 2));
481
+ return;
482
+ }
483
+ else if (format === 'csv') {
484
+ console.log('Workflow ID,Status,Steps,Cost,Tokens,Duration,Agents,Started');
485
+ workflows.forEach(workflow => {
486
+ console.log(`"${workflow.workflowId}","${workflow.status}","${workflow.steps?.length || 0}","${workflow.totalCost}","${workflow.totalTokens}","${workflow.duration}","${workflow.agents?.join(',')}","${workflow.startedAt}"`);
487
+ });
488
+ return;
489
+ }
490
+ console.log(chalk_1.default.cyan.bold(`\nšŸ“ Project Workflows: ${projectName}`));
491
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
492
+ if (workflows.length === 0) {
493
+ console.log(chalk_1.default.yellow(`No workflows found for project "${projectName}" in the last ${options.days} days.`));
494
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
495
+ return;
496
+ }
497
+ // Summary statistics
498
+ const totalCost = workflows.reduce((sum, workflow) => sum + workflow.totalCost, 0);
499
+ const totalTokens = workflows.reduce((sum, workflow) => sum + workflow.totalTokens, 0);
500
+ const completedCount = workflows.filter(workflow => workflow.status === 'completed').length;
501
+ const failedCount = workflows.length - completedCount;
502
+ console.log(chalk_1.default.yellow.bold('\nšŸ“Š Summary Statistics'));
503
+ console.log(chalk_1.default.gray('─'.repeat(50)));
504
+ console.log(chalk_1.default.white('Total Workflows:'), chalk_1.default.cyan(workflows.length));
505
+ console.log(chalk_1.default.white('Completed:'), chalk_1.default.green(completedCount));
506
+ console.log(chalk_1.default.white('Failed:'), chalk_1.default.red(failedCount));
507
+ console.log(chalk_1.default.white('Total Cost:'), chalk_1.default.green(`$${totalCost.toFixed(4)}`));
508
+ console.log(chalk_1.default.white('Total Tokens:'), chalk_1.default.cyan(totalTokens.toLocaleString()));
509
+ // Detailed workflows
510
+ console.log(chalk_1.default.yellow.bold('\nšŸ“‹ Workflow Details'));
511
+ console.log(chalk_1.default.gray('─'.repeat(50)));
512
+ workflows.forEach((workflow, index) => {
513
+ const statusColor = workflow.status === 'completed' ? chalk_1.default.green : chalk_1.default.red;
514
+ const statusIcon = workflow.status === 'completed' ? 'āœ…' : 'āŒ';
515
+ console.log(chalk_1.default.white(`\n${index + 1}. ${statusIcon} ${workflow.workflowId}`));
516
+ console.log(chalk_1.default.gray(' ─'.repeat(40)));
517
+ console.log(chalk_1.default.white(' šŸ“Š Status:'), statusColor(workflow.status));
518
+ console.log(chalk_1.default.white(' šŸ“ Steps:'), chalk_1.default.cyan(workflow.steps?.length || 0));
519
+ console.log(chalk_1.default.white(' šŸ’° Cost:'), chalk_1.default.green(`$${workflow.totalCost.toFixed(4)}`));
520
+ console.log(chalk_1.default.white(' šŸ”¢ Tokens:'), chalk_1.default.cyan(workflow.totalTokens.toLocaleString()));
521
+ console.log(chalk_1.default.white(' ā±ļø Duration:'), chalk_1.default.cyan(`${workflow.duration}ms`));
522
+ console.log(chalk_1.default.white(' šŸ¤– Agents:'), chalk_1.default.cyan(workflow.agents?.join(', ') || 'N/A'));
523
+ console.log(chalk_1.default.white(' šŸ“… Started:'), chalk_1.default.cyan(new Date(workflow.startedAt).toLocaleString()));
524
+ if (workflow.workflowType) {
525
+ console.log(chalk_1.default.white(' šŸŽÆ Type:'), chalk_1.default.cyan(workflow.workflowType));
526
+ }
527
+ });
528
+ console.log(chalk_1.default.gray('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
529
+ console.log(chalk_1.default.yellow('šŸ’” Commands:'));
530
+ console.log(chalk_1.default.white(` • Trace specific workflow: costkatana trace-workflow id <workflowId>`));
531
+ console.log(chalk_1.default.white(` • View recent workflows: costkatana trace-workflow recent`));
532
+ console.log(chalk_1.default.white(` • Trace by agent: costkatana trace-workflow agent <name>`));
533
+ }
534
+ async function handleTraceWorkflowByAgent(agentName, options) {
535
+ logger_1.logger.info(`šŸ¤– Tracing workflows for agent: ${agentName}`);
536
+ try {
537
+ const days = parseInt(options.days) || 7;
538
+ const workflows = await getWorkflowsByAgent(agentName, days);
539
+ displayAgentWorkflows(workflows, agentName, options);
540
+ }
541
+ catch (error) {
542
+ logger_1.logger.error('Failed to trace agent workflows:', error);
543
+ process.exit(1);
544
+ }
545
+ }
546
+ async function getWorkflowsByAgent(agentName, days) {
547
+ const baseUrl = config_1.configManager.get('baseUrl');
548
+ const apiKey = config_1.configManager.get('apiKey');
549
+ if (!baseUrl || !apiKey) {
550
+ console.log(chalk_1.default.red.bold('\nāŒ Configuration Missing'));
551
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
552
+ if (!apiKey) {
553
+ console.log(chalk_1.default.yellow('• API Key is not set'));
554
+ }
555
+ if (!baseUrl) {
556
+ console.log(chalk_1.default.yellow('• Base URL is not set'));
557
+ }
558
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
559
+ console.log(chalk_1.default.cyan('To set up your configuration, run:'));
560
+ console.log(chalk_1.default.white(' cost-katana init'));
561
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
562
+ throw new Error('Configuration incomplete. Please run "cost-katana init" to set up your API key and base URL.');
563
+ }
564
+ try {
565
+ const response = await axios_1.default.get(`${baseUrl}/api/workflow/trace/agent/${agentName}?days=${days}`, {
566
+ headers: {
567
+ 'Authorization': `Bearer ${apiKey}`,
568
+ 'Content-Type': 'application/json',
569
+ },
570
+ timeout: 30000,
571
+ });
572
+ if (response.status !== 200) {
573
+ throw new Error(`API returned status ${response.status}`);
574
+ }
575
+ if (response.data.success && response.data.data) {
576
+ return response.data.data;
577
+ }
578
+ else {
579
+ throw new Error(response.data.message || 'Invalid response format');
580
+ }
581
+ }
582
+ catch (error) {
583
+ if (error.response) {
584
+ throw new Error(`API Error: ${error.response.status} - ${error.response.data?.message || 'Unknown error'}`);
585
+ }
586
+ else if (error.request) {
587
+ throw new Error('No response received from API');
588
+ }
589
+ else {
590
+ throw new Error(`Request failed: ${error.message}`);
591
+ }
592
+ }
593
+ }
594
+ function displayAgentWorkflows(workflows, agentName, options) {
595
+ const format = options.format || 'table';
596
+ if (format === 'json') {
597
+ console.log(JSON.stringify(workflows, null, 2));
598
+ return;
599
+ }
600
+ else if (format === 'csv') {
601
+ console.log('Workflow ID,Status,Steps,Cost,Tokens,Duration,Agents,Started');
602
+ workflows.forEach(workflow => {
603
+ console.log(`"${workflow.workflowId}","${workflow.status}","${workflow.steps?.length || 0}","${workflow.totalCost}","${workflow.totalTokens}","${workflow.duration}","${workflow.agents?.join(',')}","${workflow.startedAt}"`);
604
+ });
605
+ return;
606
+ }
607
+ console.log(chalk_1.default.cyan.bold(`\nšŸ¤– Agent Workflows: ${agentName}`));
608
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
609
+ if (workflows.length === 0) {
610
+ console.log(chalk_1.default.yellow(`No workflows found for agent "${agentName}" in the last ${options.days} days.`));
611
+ console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
612
+ return;
613
+ }
614
+ // Summary statistics
615
+ const totalCost = workflows.reduce((sum, workflow) => sum + workflow.totalCost, 0);
616
+ const totalTokens = workflows.reduce((sum, workflow) => sum + workflow.totalTokens, 0);
617
+ const completedCount = workflows.filter(workflow => workflow.status === 'completed').length;
618
+ const failedCount = workflows.length - completedCount;
619
+ console.log(chalk_1.default.yellow.bold('\nšŸ“Š Summary Statistics'));
620
+ console.log(chalk_1.default.gray('─'.repeat(50)));
621
+ console.log(chalk_1.default.white('Total Workflows:'), chalk_1.default.cyan(workflows.length));
622
+ console.log(chalk_1.default.white('Completed:'), chalk_1.default.green(completedCount));
623
+ console.log(chalk_1.default.white('Failed:'), chalk_1.default.red(failedCount));
624
+ console.log(chalk_1.default.white('Total Cost:'), chalk_1.default.green(`$${totalCost.toFixed(4)}`));
625
+ console.log(chalk_1.default.white('Total Tokens:'), chalk_1.default.cyan(totalTokens.toLocaleString()));
626
+ // Detailed workflows
627
+ console.log(chalk_1.default.yellow.bold('\nšŸ“‹ Workflow Details'));
628
+ console.log(chalk_1.default.gray('─'.repeat(50)));
629
+ workflows.forEach((workflow, index) => {
630
+ const statusColor = workflow.status === 'completed' ? chalk_1.default.green : chalk_1.default.red;
631
+ const statusIcon = workflow.status === 'completed' ? 'āœ…' : 'āŒ';
632
+ console.log(chalk_1.default.white(`\n${index + 1}. ${statusIcon} ${workflow.workflowId}`));
633
+ console.log(chalk_1.default.gray(' ─'.repeat(40)));
634
+ console.log(chalk_1.default.white(' šŸ“Š Status:'), statusColor(workflow.status));
635
+ console.log(chalk_1.default.white(' šŸ“ Steps:'), chalk_1.default.cyan(workflow.steps?.length || 0));
636
+ console.log(chalk_1.default.white(' šŸ’° Cost:'), chalk_1.default.green(`$${workflow.totalCost.toFixed(4)}`));
637
+ console.log(chalk_1.default.white(' šŸ”¢ Tokens:'), chalk_1.default.cyan(workflow.totalTokens.toLocaleString()));
638
+ console.log(chalk_1.default.white(' ā±ļø Duration:'), chalk_1.default.cyan(`${workflow.duration}ms`));
639
+ console.log(chalk_1.default.white(' šŸ¤– Agents:'), chalk_1.default.cyan(workflow.agents?.join(', ') || 'N/A'));
640
+ console.log(chalk_1.default.white(' šŸ“… Started:'), chalk_1.default.cyan(new Date(workflow.startedAt).toLocaleString()));
641
+ if (workflow.workflowType) {
642
+ console.log(chalk_1.default.white(' šŸŽÆ Type:'), chalk_1.default.cyan(workflow.workflowType));
643
+ }
644
+ });
645
+ console.log(chalk_1.default.gray('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
646
+ console.log(chalk_1.default.yellow('šŸ’” Commands:'));
647
+ console.log(chalk_1.default.white(` • Trace specific workflow: costkatana trace-workflow id <workflowId>`));
648
+ console.log(chalk_1.default.white(` • View recent workflows: costkatana trace-workflow recent`));
649
+ console.log(chalk_1.default.white(` • Trace by project: costkatana trace-workflow project <name>`));
650
+ }
651
+ //# sourceMappingURL=trace-workflow.js.map