@desplega.ai/agent-swarm 1.9.0 → 1.10.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.
@@ -71,149 +71,166 @@ function formatToolInput(input: Record<string, unknown>): string {
71
71
 
72
72
  /** Pretty print a single JSON line from Claude output */
73
73
  export function prettyPrintLine(line: string, role: string): void {
74
- if (!line.trim()) return;
75
-
76
- let json: Record<string, unknown>;
77
74
  try {
78
- json = JSON.parse(line.trim());
79
- } catch {
80
- // Raw output - just print it
81
- console.log(`${c.dim}[${role}]${c.reset} ${line.trim()}`);
82
- return;
83
- }
84
-
85
- const type = json.type as string;
86
- const prefix = `${c.dim}[${role}]${c.reset}`;
87
-
88
- switch (type) {
89
- case "system": {
90
- const subtype = json.subtype as string;
91
- if (subtype === "init") {
92
- const model = json.model as string;
93
- const tools = json.tools as string[];
94
- console.log(
95
- `${prefix} ${c.cyan}●${c.reset} ${c.bold}Session started${c.reset} ${c.dim}(${model}, ${tools?.length || 0} tools)${c.reset}`,
96
- );
97
- } else if (subtype === "hook_response") {
98
- const hookName = json.hook_name as string;
99
- const stdout = json.stdout as string;
100
- console.log(`${prefix} ${c.yellow}⚡${c.reset} Hook: ${c.yellow}${hookName}${c.reset}`);
101
- if (stdout) {
102
- const lines = stdout.split("\n").filter((l) => l.trim());
103
- for (const l of lines.slice(0, 3)) {
104
- console.log(`${prefix} ${c.dim}${truncate(l, 80)}${c.reset}`);
105
- }
106
- if (lines.length > 3) {
107
- console.log(`${prefix} ${c.dim}... (${lines.length - 3} more lines)${c.reset}`);
108
- }
109
- }
110
- } else {
111
- const msg = (json.message as string) || (json.content as string) || "";
112
- console.log(
113
- `${prefix} ${c.cyan}ℹ${c.reset} System${subtype ? ` (${subtype})` : ""}: ${truncate(msg, 100)}`,
114
- );
115
- }
116
- break;
75
+ if (!line.trim()) return;
76
+
77
+ let json: Record<string, unknown>;
78
+ try {
79
+ json = JSON.parse(line.trim());
80
+ } catch {
81
+ // Raw output - just print it
82
+ console.log(`${c.dim}[${role}]${c.reset} ${line.trim()}`);
83
+ return;
117
84
  }
118
85
 
119
- case "assistant": {
120
- const message = json.message as Record<string, unknown>;
121
- if (!message) break;
86
+ const type = json.type as string;
87
+ const prefix = `${c.dim}[${role}]${c.reset}`;
122
88
 
123
- const content = message.content as Array<Record<string, unknown>>;
124
- if (!content) break;
125
-
126
- for (const block of content) {
127
- if (block.type === "text") {
128
- const text = block.text as string;
129
- console.log(`${prefix} ${c.green}◆${c.reset} ${c.bold}Assistant:${c.reset}`);
130
- // Print text with nice indentation, truncate long lines
131
- const lines = text.split("\n");
132
- for (const l of lines.slice(0, 5)) {
133
- console.log(`${prefix} ${truncate(l, 100)}`);
134
- }
135
- if (lines.length > 5) {
136
- console.log(`${prefix} ${c.dim}... (${lines.length - 5} more lines)${c.reset}`);
137
- }
138
- } else if (block.type === "tool_use") {
139
- const toolName = formatToolName((block.name as string) || "unknown");
140
- const input = (block.input as Record<string, unknown>) || {};
89
+ switch (type) {
90
+ case "system": {
91
+ const subtype = json.subtype as string;
92
+ if (subtype === "init") {
93
+ const model = json.model as string;
94
+ const tools = json.tools as string[];
141
95
  console.log(
142
- `${prefix} ${c.magenta}▶${c.reset} Tool: ${c.magenta}${toolName}${c.reset}${formatToolInput(input)}`,
96
+ `${prefix} ${c.cyan}●${c.reset} ${c.bold}Session started${c.reset} ${c.dim}(${model}, ${tools?.length || 0} tools)${c.reset}`,
143
97
  );
144
- } else if (block.type === "thinking") {
145
- const thinking = block.thinking as string;
146
- console.log(`${prefix} ${c.blue}💭${c.reset} ${c.dim}Thinking...${c.reset}`);
147
- if (thinking) {
148
- console.log(`${prefix} ${c.dim}${truncate(thinking, 80)}${c.reset}`);
98
+ } else if (subtype === "hook_response") {
99
+ const hookName = json.hook_name as string;
100
+ const stdout = json.stdout as string;
101
+ console.log(`${prefix} ${c.yellow}⚡${c.reset} Hook: ${c.yellow}${hookName}${c.reset}`);
102
+ if (stdout) {
103
+ const lines = stdout.split("\n").filter((l) => l.trim());
104
+ for (const l of lines.slice(0, 3)) {
105
+ console.log(`${prefix} ${c.dim}${truncate(l, 80)}${c.reset}`);
106
+ }
107
+ if (lines.length > 3) {
108
+ console.log(`${prefix} ${c.dim}... (${lines.length - 3} more lines)${c.reset}`);
109
+ }
149
110
  }
111
+ } else {
112
+ const msg = (json.message as string) || (json.content as string) || "";
113
+ console.log(
114
+ `${prefix} ${c.cyan}ℹ${c.reset} System${subtype ? ` (${subtype})` : ""}: ${truncate(msg, 100)}`,
115
+ );
150
116
  }
117
+ break;
151
118
  }
152
- break;
153
- }
154
119
 
155
- case "user": {
156
- const message = json.message as Record<string, unknown>;
157
- const toolResult = json.tool_use_result as string;
120
+ case "assistant": {
121
+ const message = json.message as Record<string, unknown>;
122
+ if (!message) break;
158
123
 
159
- if (toolResult) {
160
- const isError = toolResult.includes("Error") || toolResult.includes("error");
161
- const icon = isError ? `${c.red}✗${c.reset}` : `${c.green}✓${c.reset}`;
162
- console.log(`${prefix} ${icon} Result: ${truncate(toolResult, 100)}`);
163
- } else if (message) {
164
124
  const content = message.content as Array<Record<string, unknown>>;
165
- if (content) {
166
- for (const block of content) {
167
- if (block.type === "tool_result") {
168
- const result = block.content as string;
169
- const isError = block.is_error as boolean;
170
- const icon = isError ? `${c.red}✗${c.reset}` : `${c.green}✓${c.reset}`;
171
- console.log(`${prefix} ${icon} Result: ${truncate(result || "", 100)}`);
125
+ if (!content) break;
126
+
127
+ for (const block of content) {
128
+ if (block.type === "text") {
129
+ const text = block.text as string;
130
+ console.log(`${prefix} ${c.green}◆${c.reset} ${c.bold}Assistant:${c.reset}`);
131
+ // Print text with nice indentation, truncate long lines
132
+ const lines = text.split("\n");
133
+ for (const l of lines.slice(0, 5)) {
134
+ console.log(`${prefix} ${truncate(l, 100)}`);
135
+ }
136
+ if (lines.length > 5) {
137
+ console.log(`${prefix} ${c.dim}... (${lines.length - 5} more lines)${c.reset}`);
138
+ }
139
+ } else if (block.type === "tool_use") {
140
+ const toolName = formatToolName((block.name as string) || "unknown");
141
+ const input = (block.input as Record<string, unknown>) || {};
142
+ console.log(
143
+ `${prefix} ${c.magenta}▶${c.reset} Tool: ${c.magenta}${toolName}${c.reset}${formatToolInput(input)}`,
144
+ );
145
+ } else if (block.type === "thinking") {
146
+ const thinking = block.thinking as string;
147
+ console.log(`${prefix} ${c.blue}💭${c.reset} ${c.dim}Thinking...${c.reset}`);
148
+ if (thinking) {
149
+ console.log(`${prefix} ${c.dim}${truncate(thinking, 80)}${c.reset}`);
172
150
  }
173
151
  }
174
152
  }
153
+ break;
175
154
  }
176
- break;
177
- }
178
155
 
179
- case "result": {
180
- const subtype = json.subtype as string;
181
- const isError = json.is_error as boolean;
182
- const duration = json.duration_ms as number;
183
- const cost = json.total_cost_usd as number;
184
- const numTurns = json.num_turns as number;
185
- const result = json.result as string;
186
-
187
- const icon = isError ? `${c.red}✗${c.reset}` : `${c.green}✓${c.reset}`;
188
- const durationStr = duration ? `${(duration / 1000).toFixed(1)}s` : "";
189
- const costStr = cost ? `$${cost.toFixed(4)}` : "";
190
-
191
- console.log(
192
- `${prefix} ${icon} ${c.bold}Done${c.reset} ${c.dim}(${subtype}, ${numTurns} turns, ${durationStr}, ${costStr})${c.reset}`,
193
- );
194
-
195
- if (result) {
196
- const lines = result.split("\n").filter((l) => l.trim());
197
- for (const l of lines.slice(0, 3)) {
198
- console.log(`${prefix} ${truncate(l, 100)}`);
156
+ case "user": {
157
+ const message = json.message as Record<string, unknown>;
158
+ const rawToolResult = json.tool_use_result;
159
+ const toolResult =
160
+ typeof rawToolResult === "string"
161
+ ? rawToolResult
162
+ : rawToolResult
163
+ ? JSON.stringify(rawToolResult)
164
+ : null;
165
+
166
+ if (toolResult) {
167
+ const isError = toolResult.includes("Error") || toolResult.includes("error");
168
+ const icon = isError ? `${c.red}✗${c.reset}` : `${c.green}✓${c.reset}`;
169
+ console.log(`${prefix} ${icon} Result: ${truncate(toolResult, 100)}`);
170
+ } else if (message) {
171
+ const content = message.content as Array<Record<string, unknown>>;
172
+ if (content) {
173
+ for (const block of content) {
174
+ if (block.type === "tool_result") {
175
+ const rawResult = block.content;
176
+ const result =
177
+ typeof rawResult === "string"
178
+ ? rawResult
179
+ : rawResult
180
+ ? JSON.stringify(rawResult)
181
+ : "";
182
+ const isError = block.is_error as boolean;
183
+ const icon = isError ? `${c.red}✗${c.reset}` : `${c.green}✓${c.reset}`;
184
+ console.log(`${prefix} ${icon} Result: ${truncate(result, 100)}`);
185
+ }
186
+ }
187
+ }
199
188
  }
200
- if (lines.length > 3) {
201
- console.log(`${prefix} ${c.dim}... (${lines.length - 3} more lines)${c.reset}`);
189
+ break;
190
+ }
191
+
192
+ case "result": {
193
+ const subtype = json.subtype as string;
194
+ const isError = json.is_error as boolean;
195
+ const duration = json.duration_ms as number;
196
+ const cost = json.total_cost_usd as number;
197
+ const numTurns = json.num_turns as number;
198
+ const result = json.result as string;
199
+
200
+ const icon = isError ? `${c.red}✗${c.reset}` : `${c.green}✓${c.reset}`;
201
+ const durationStr = duration ? `${(duration / 1000).toFixed(1)}s` : "";
202
+ const costStr = cost ? `$${cost.toFixed(4)}` : "";
203
+
204
+ console.log(
205
+ `${prefix} ${icon} ${c.bold}Done${c.reset} ${c.dim}(${subtype}, ${numTurns} turns, ${durationStr}, ${costStr})${c.reset}`,
206
+ );
207
+
208
+ if (result) {
209
+ const lines = result.split("\n").filter((l) => l.trim());
210
+ for (const l of lines.slice(0, 3)) {
211
+ console.log(`${prefix} ${truncate(l, 100)}`);
212
+ }
213
+ if (lines.length > 3) {
214
+ console.log(`${prefix} ${c.dim}... (${lines.length - 3} more lines)${c.reset}`);
215
+ }
202
216
  }
217
+ break;
203
218
  }
204
- break;
205
- }
206
219
 
207
- case "error": {
208
- const error = (json.error as string) || (json.message as string) || JSON.stringify(json);
209
- console.log(`${prefix} ${c.red}✗ Error:${c.reset} ${truncate(error, 100)}`);
210
- break;
211
- }
220
+ case "error": {
221
+ const error = (json.error as string) || (json.message as string) || JSON.stringify(json);
222
+ console.log(`${prefix} ${c.red}✗ Error:${c.reset} ${truncate(error, 100)}`);
223
+ break;
224
+ }
212
225
 
213
- default: {
214
- // Unknown type - print a summary
215
- console.log(`${prefix} ${c.dim}[${type}]${c.reset} ${truncate(JSON.stringify(json), 100)}`);
226
+ default: {
227
+ // Unknown type - print a summary
228
+ console.log(`${prefix} ${c.dim}[${type}]${c.reset} ${truncate(JSON.stringify(json), 100)}`);
229
+ }
216
230
  }
231
+ } catch (_err) {
232
+ // Never let pretty-print crash the runner - just log raw line
233
+ console.log(`${c.dim}[${role}]${c.reset} ${line}`);
217
234
  }
218
235
  }
219
236