@evantahler/mcpx 0.15.4 → 0.15.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/mcpx.md +115 -75
- package/package.json +1 -1
- package/src/client/http.ts +3 -22
- package/src/client/manager.ts +54 -66
- package/src/client/sse.ts +3 -14
- package/src/client/transport-options.ts +31 -0
- package/src/commands/exec.ts +2 -1
- package/src/commands/index.ts +15 -20
- package/src/commands/info.ts +47 -52
- package/src/commands/list.ts +49 -54
- package/src/commands/prompt.ts +16 -17
- package/src/commands/resource.ts +28 -32
- package/src/commands/search.ts +2 -1
- package/src/commands/servers.ts +6 -12
- package/src/commands/task.ts +48 -64
- package/src/commands/with-command.ts +59 -0
- package/src/config/env.ts +4 -2
- package/src/config/loader.ts +10 -4
- package/src/constants.ts +19 -0
- package/src/context.ts +7 -6
- package/src/output/format-output.ts +18 -0
- package/src/output/format-table.ts +63 -0
- package/src/output/formatter.ts +424 -570
- package/src/search/index.ts +2 -1
- package/src/search/keyword.ts +2 -5
- package/src/search/semantic.ts +4 -7
- package/src/search/types.ts +7 -0
- package/src/validation/schema.ts +18 -30
package/src/output/formatter.ts
CHANGED
|
@@ -3,6 +3,8 @@ import type { Tool, Resource, Prompt } from "../config/schemas.ts";
|
|
|
3
3
|
import type { ToolWithServer, ResourceWithServer, PromptWithServer } from "../client/manager.ts";
|
|
4
4
|
import type { ValidationError } from "../validation/schema.ts";
|
|
5
5
|
import type { SearchResult } from "../search/index.ts";
|
|
6
|
+
import { formatOutput } from "./format-output.ts";
|
|
7
|
+
import { formatTable } from "./format-table.ts";
|
|
6
8
|
|
|
7
9
|
export interface FormatOptions {
|
|
8
10
|
json?: boolean;
|
|
@@ -109,133 +111,104 @@ const KNOWN_CAPABILITIES = ["tools", "resources", "prompts", "logging", "complet
|
|
|
109
111
|
|
|
110
112
|
/** Format a full server overview (version, capabilities, tools, counts) */
|
|
111
113
|
export function formatServerOverview(overview: ServerOverview, options: FormatOptions): string {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
`${header} ${dim(`v${overview.version.version}`)} ${dim(`(${overview.version.name})`)}`,
|
|
135
|
-
);
|
|
136
|
-
} else {
|
|
137
|
-
lines.push(header);
|
|
138
|
-
}
|
|
114
|
+
return formatOutput(
|
|
115
|
+
{
|
|
116
|
+
server: overview.serverName,
|
|
117
|
+
version: overview.version ?? null,
|
|
118
|
+
capabilities: overview.capabilities ?? null,
|
|
119
|
+
instructions: overview.instructions ?? null,
|
|
120
|
+
tools: overview.tools.map((t) => ({ name: t.name, description: t.description ?? "" })),
|
|
121
|
+
resourceCount: overview.resourceCount,
|
|
122
|
+
promptCount: overview.promptCount,
|
|
123
|
+
},
|
|
124
|
+
() => {
|
|
125
|
+
const lines: string[] = [];
|
|
126
|
+
|
|
127
|
+
// Header: server name + version
|
|
128
|
+
const header = cyan.bold(overview.serverName);
|
|
129
|
+
if (overview.version) {
|
|
130
|
+
lines.push(
|
|
131
|
+
`${header} ${dim(`v${overview.version.version}`)} ${dim(`(${overview.version.name})`)}`,
|
|
132
|
+
);
|
|
133
|
+
} else {
|
|
134
|
+
lines.push(header);
|
|
135
|
+
}
|
|
139
136
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
lines.push(...capLines);
|
|
151
|
-
}
|
|
137
|
+
// Capabilities
|
|
138
|
+
if (overview.capabilities) {
|
|
139
|
+
lines.push("");
|
|
140
|
+
lines.push(bold("Capabilities:"));
|
|
141
|
+
const caps = overview.capabilities;
|
|
142
|
+
const present = KNOWN_CAPABILITIES.filter((k) => k in caps);
|
|
143
|
+
const absent = KNOWN_CAPABILITIES.filter((k) => !(k in caps));
|
|
144
|
+
for (const k of present) lines.push(` ${green("✓")} ${k}`);
|
|
145
|
+
for (const k of absent) lines.push(` ${dim("✗")} ${dim(k)}`);
|
|
146
|
+
}
|
|
152
147
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
148
|
+
// Instructions
|
|
149
|
+
if (overview.instructions) {
|
|
150
|
+
lines.push("");
|
|
151
|
+
lines.push(bold("Instructions:"));
|
|
152
|
+
lines.push(` ${dim(overview.instructions)}`);
|
|
153
|
+
}
|
|
159
154
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
} else {
|
|
165
|
-
lines.push(bold(`Tools (${overview.tools.length}):`));
|
|
166
|
-
const maxName = Math.max(...overview.tools.map((t) => t.name.length));
|
|
167
|
-
const termWidth = getTerminalWidth();
|
|
168
|
-
for (let i = 0; i < overview.tools.length; i++) {
|
|
169
|
-
const t = overview.tools[i];
|
|
170
|
-
if (i > 0) lines.push("");
|
|
171
|
-
const name = ` ${bold(t.name.padEnd(maxName))}`;
|
|
172
|
-
if (t.description) {
|
|
173
|
-
const pw = visibleLength(name) + 2;
|
|
174
|
-
const desc =
|
|
175
|
-
termWidth != null ? wrapDescription(t.description, pw, termWidth) : dim(t.description);
|
|
176
|
-
lines.push(`${name} ${desc}`);
|
|
155
|
+
// Tools
|
|
156
|
+
lines.push("");
|
|
157
|
+
if (overview.tools.length === 0) {
|
|
158
|
+
lines.push(bold("Tools:") + " " + dim("none"));
|
|
177
159
|
} else {
|
|
178
|
-
lines.push(
|
|
160
|
+
lines.push(bold(`Tools (${overview.tools.length}):`));
|
|
161
|
+
const maxName = Math.max(...overview.tools.map((t) => t.name.length));
|
|
162
|
+
const termWidth = getTerminalWidth();
|
|
163
|
+
for (let i = 0; i < overview.tools.length; i++) {
|
|
164
|
+
const t = overview.tools[i];
|
|
165
|
+
if (i > 0) lines.push("");
|
|
166
|
+
const name = ` ${bold(t.name.padEnd(maxName))}`;
|
|
167
|
+
if (t.description) {
|
|
168
|
+
const pw = visibleLength(name) + 2;
|
|
169
|
+
const desc =
|
|
170
|
+
termWidth != null
|
|
171
|
+
? wrapDescription(t.description, pw, termWidth)
|
|
172
|
+
: dim(t.description);
|
|
173
|
+
lines.push(`${name} ${desc}`);
|
|
174
|
+
} else {
|
|
175
|
+
lines.push(name);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
179
178
|
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Resource/prompt counts
|
|
184
|
-
const counts: string[] = [];
|
|
185
|
-
counts.push(`Resources: ${overview.resourceCount}`);
|
|
186
|
-
counts.push(`Prompts: ${overview.promptCount}`);
|
|
187
|
-
lines.push("");
|
|
188
|
-
lines.push(dim(counts.join(" | ")));
|
|
189
179
|
|
|
190
|
-
|
|
180
|
+
// Resource/prompt counts
|
|
181
|
+
const counts: string[] = [];
|
|
182
|
+
counts.push(`Resources: ${overview.resourceCount}`);
|
|
183
|
+
counts.push(`Prompts: ${overview.promptCount}`);
|
|
184
|
+
lines.push("");
|
|
185
|
+
lines.push(dim(counts.join(" | ")));
|
|
186
|
+
|
|
187
|
+
return lines.join("\n");
|
|
188
|
+
},
|
|
189
|
+
options,
|
|
190
|
+
);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
/** Format a list of tools with server names */
|
|
194
194
|
export function formatToolList(tools: ToolWithServer[], options: FormatOptions): string {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (tools.length === 0) {
|
|
215
|
-
return dim("No tools found");
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Calculate column widths
|
|
219
|
-
const maxServer = Math.max(...tools.map((t) => t.server.length));
|
|
220
|
-
const maxTool = Math.max(...tools.map((t) => t.tool.name.length));
|
|
221
|
-
const termWidth = getTerminalWidth();
|
|
222
|
-
|
|
223
|
-
return tools
|
|
224
|
-
.map((t) => {
|
|
225
|
-
const server = cyan(t.server.padEnd(maxServer));
|
|
226
|
-
const tool = bold(t.tool.name.padEnd(maxTool));
|
|
227
|
-
if (options.withDescriptions && t.tool.description) {
|
|
228
|
-
const prefix = `${server} ${tool}`;
|
|
229
|
-
const pw = visibleLength(prefix) + 2;
|
|
230
|
-
const desc =
|
|
231
|
-
termWidth != null
|
|
232
|
-
? wrapDescription(t.tool.description, pw, termWidth)
|
|
233
|
-
: dim(t.tool.description);
|
|
234
|
-
return `${prefix} ${desc}`;
|
|
235
|
-
}
|
|
236
|
-
return `${server} ${tool}`;
|
|
237
|
-
})
|
|
238
|
-
.join("\n");
|
|
195
|
+
return formatOutput(
|
|
196
|
+
tools.map((t) => ({
|
|
197
|
+
server: t.server,
|
|
198
|
+
tool: t.tool.name,
|
|
199
|
+
...(options.withDescriptions ? { description: t.tool.description ?? "" } : {}),
|
|
200
|
+
})),
|
|
201
|
+
() =>
|
|
202
|
+
formatTable(tools, {
|
|
203
|
+
columns: [
|
|
204
|
+
{ value: (t) => t.server, style: cyan },
|
|
205
|
+
{ value: (t) => t.tool.name, style: bold },
|
|
206
|
+
],
|
|
207
|
+
description: options.withDescriptions ? (t) => t.tool.description : undefined,
|
|
208
|
+
emptyMessage: "No tools found",
|
|
209
|
+
}),
|
|
210
|
+
options,
|
|
211
|
+
);
|
|
239
212
|
}
|
|
240
213
|
|
|
241
214
|
/** Format tools for a single server */
|
|
@@ -244,66 +217,46 @@ export function formatServerTools(
|
|
|
244
217
|
tools: Tool[],
|
|
245
218
|
options: FormatOptions,
|
|
246
219
|
): string {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
const lines = tools.map((t) => {
|
|
267
|
-
const name = ` ${bold(t.name.padEnd(maxName))}`;
|
|
268
|
-
if (t.description) {
|
|
269
|
-
const pw = visibleLength(name) + 2;
|
|
270
|
-
const desc =
|
|
271
|
-
termWidth != null ? wrapDescription(t.description, pw, termWidth) : dim(t.description);
|
|
272
|
-
return `${name} ${desc}`;
|
|
273
|
-
}
|
|
274
|
-
return name;
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
return [header, ...lines].join("\n");
|
|
220
|
+
return formatOutput(
|
|
221
|
+
{
|
|
222
|
+
server: serverName,
|
|
223
|
+
tools: tools.map((t) => ({ name: t.name, description: t.description ?? "" })),
|
|
224
|
+
},
|
|
225
|
+
() => {
|
|
226
|
+
if (tools.length === 0) {
|
|
227
|
+
return dim(`No tools found for ${serverName}`);
|
|
228
|
+
}
|
|
229
|
+
const header = cyan.bold(serverName);
|
|
230
|
+
const body = formatTable(tools, {
|
|
231
|
+
columns: [{ value: (t) => ` ${t.name}`, style: bold }],
|
|
232
|
+
description: (t) => t.description,
|
|
233
|
+
});
|
|
234
|
+
return `${header}\n${body}`;
|
|
235
|
+
},
|
|
236
|
+
options,
|
|
237
|
+
);
|
|
278
238
|
}
|
|
279
239
|
|
|
280
240
|
/** Format a tool schema */
|
|
281
241
|
export function formatToolSchema(serverName: string, tool: Tool, options: FormatOptions): string {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
lines.push("");
|
|
303
|
-
lines.push(bold("Input Schema:"));
|
|
304
|
-
lines.push(formatSchema(tool.inputSchema, 2));
|
|
305
|
-
|
|
306
|
-
return lines.join("\n");
|
|
242
|
+
return formatOutput(
|
|
243
|
+
{
|
|
244
|
+
server: serverName,
|
|
245
|
+
tool: tool.name,
|
|
246
|
+
description: tool.description ?? "",
|
|
247
|
+
inputSchema: tool.inputSchema,
|
|
248
|
+
},
|
|
249
|
+
() => {
|
|
250
|
+
const lines: string[] = [];
|
|
251
|
+
lines.push(`${cyan(serverName)}/${bold(tool.name)}`);
|
|
252
|
+
if (tool.description) lines.push(dim(tool.description));
|
|
253
|
+
lines.push("");
|
|
254
|
+
lines.push(bold("Input Schema:"));
|
|
255
|
+
lines.push(formatSchema(tool.inputSchema, 2));
|
|
256
|
+
return lines.join("\n");
|
|
257
|
+
},
|
|
258
|
+
options,
|
|
259
|
+
);
|
|
307
260
|
}
|
|
308
261
|
|
|
309
262
|
/** Format a JSON schema as a readable parameter list */
|
|
@@ -329,37 +282,29 @@ function formatSchema(schema: Tool["inputSchema"], indent: number): string {
|
|
|
329
282
|
|
|
330
283
|
/** Format detailed tool help with example payload */
|
|
331
284
|
export function formatToolHelp(serverName: string, tool: Tool, options: FormatOptions): string {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
lines.push(formatSchema(tool.inputSchema, 2));
|
|
356
|
-
|
|
357
|
-
const example = generateExample(tool.inputSchema);
|
|
358
|
-
lines.push("");
|
|
359
|
-
lines.push(bold("Example:"));
|
|
360
|
-
lines.push(dim(` mcpx call ${serverName} ${tool.name} '${JSON.stringify(example)}'`));
|
|
361
|
-
|
|
362
|
-
return lines.join("\n");
|
|
285
|
+
return formatOutput(
|
|
286
|
+
{
|
|
287
|
+
server: serverName,
|
|
288
|
+
tool: tool.name,
|
|
289
|
+
description: tool.description ?? "",
|
|
290
|
+
inputSchema: tool.inputSchema,
|
|
291
|
+
example: generateExample(tool.inputSchema),
|
|
292
|
+
},
|
|
293
|
+
() => {
|
|
294
|
+
const lines: string[] = [];
|
|
295
|
+
lines.push(`${cyan(serverName)}/${bold(tool.name)}`);
|
|
296
|
+
if (tool.description) lines.push(dim(tool.description));
|
|
297
|
+
lines.push("");
|
|
298
|
+
lines.push(bold("Parameters:"));
|
|
299
|
+
lines.push(formatSchema(tool.inputSchema, 2));
|
|
300
|
+
const example = generateExample(tool.inputSchema);
|
|
301
|
+
lines.push("");
|
|
302
|
+
lines.push(bold("Example:"));
|
|
303
|
+
lines.push(dim(` mcpx call ${serverName} ${tool.name} '${JSON.stringify(example)}'`));
|
|
304
|
+
return lines.join("\n");
|
|
305
|
+
},
|
|
306
|
+
options,
|
|
307
|
+
);
|
|
363
308
|
}
|
|
364
309
|
|
|
365
310
|
/** Generate an example payload from a JSON schema */
|
|
@@ -370,7 +315,6 @@ function generateExample(schema: Tool["inputSchema"]): Record<string, unknown> {
|
|
|
370
315
|
|
|
371
316
|
for (const [name, prop] of Object.entries(properties)) {
|
|
372
317
|
const p = prop as Record<string, unknown>;
|
|
373
|
-
// Include required fields and first few optional fields
|
|
374
318
|
if (required.has(name) || Object.keys(example).length < 3) {
|
|
375
319
|
example[name] = exampleValue(name, p);
|
|
376
320
|
}
|
|
@@ -380,15 +324,8 @@ function generateExample(schema: Tool["inputSchema"]): Record<string, unknown> {
|
|
|
380
324
|
}
|
|
381
325
|
|
|
382
326
|
function exampleValue(name: string, prop: Record<string, unknown>): unknown {
|
|
383
|
-
|
|
384
|
-
if (
|
|
385
|
-
return prop.enum[0];
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// Use default if provided
|
|
389
|
-
if (prop.default !== undefined) {
|
|
390
|
-
return prop.default;
|
|
391
|
-
}
|
|
327
|
+
if (Array.isArray(prop.enum) && prop.enum.length > 0) return prop.enum[0];
|
|
328
|
+
if (prop.default !== undefined) return prop.default;
|
|
392
329
|
|
|
393
330
|
const type = prop.type as string | undefined;
|
|
394
331
|
switch (type) {
|
|
@@ -438,51 +375,46 @@ export function formatValidationErrors(
|
|
|
438
375
|
errors: ValidationError[],
|
|
439
376
|
options: FormatOptions,
|
|
440
377
|
): string {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
details
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
const header = `${red("error:")} invalid arguments for ${cyan(serverName)}/${bold(toolName)}`;
|
|
451
|
-
const details = errors.map((e) => ` ${yellow(e.path)}: ${e.message}`).join("\n");
|
|
452
|
-
return `${header}\n${details}`;
|
|
378
|
+
return formatOutput(
|
|
379
|
+
{ error: "validation", server: serverName, tool: toolName, details: errors },
|
|
380
|
+
() => {
|
|
381
|
+
const header = `${red("error:")} invalid arguments for ${cyan(serverName)}/${bold(toolName)}`;
|
|
382
|
+
const details = errors.map((e) => ` ${yellow(e.path)}: ${e.message}`).join("\n");
|
|
383
|
+
return `${header}\n${details}`;
|
|
384
|
+
},
|
|
385
|
+
options,
|
|
386
|
+
);
|
|
453
387
|
}
|
|
454
388
|
|
|
455
389
|
/** Format search results */
|
|
456
390
|
export function formatSearchResults(results: SearchResult[], options: FormatOptions): string {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
const termWidth = getTerminalWidth();
|
|
466
|
-
const descIndent = 2;
|
|
467
|
-
|
|
468
|
-
return results
|
|
469
|
-
.map((r) => {
|
|
470
|
-
const header = `${cyan(r.server)} ${bold(r.tool)} ${yellow(r.score.toFixed(2))}`;
|
|
471
|
-
|
|
472
|
-
// Join all description lines into a single string for wrapping
|
|
473
|
-
const fullDesc = r.description
|
|
474
|
-
.split("\n")
|
|
475
|
-
.map((l) => l.trim())
|
|
476
|
-
.filter((l) => l.length > 0)
|
|
477
|
-
.join(" ");
|
|
478
|
-
|
|
479
|
-
const indent = " ".repeat(descIndent);
|
|
480
|
-
const desc =
|
|
481
|
-
termWidth != null ? wrapDescription(fullDesc, descIndent, termWidth) : dim(fullDesc);
|
|
391
|
+
return formatOutput(
|
|
392
|
+
results,
|
|
393
|
+
() => {
|
|
394
|
+
if (results.length === 0) {
|
|
395
|
+
return dim("No matching tools found");
|
|
396
|
+
}
|
|
482
397
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
398
|
+
const termWidth = getTerminalWidth();
|
|
399
|
+
const descIndent = 2;
|
|
400
|
+
|
|
401
|
+
return results
|
|
402
|
+
.map((r) => {
|
|
403
|
+
const header = `${cyan(r.server)} ${bold(r.tool)} ${yellow(r.score.toFixed(2))}`;
|
|
404
|
+
const fullDesc = r.description
|
|
405
|
+
.split("\n")
|
|
406
|
+
.map((l) => l.trim())
|
|
407
|
+
.filter((l) => l.length > 0)
|
|
408
|
+
.join(" ");
|
|
409
|
+
const indent = " ".repeat(descIndent);
|
|
410
|
+
const desc =
|
|
411
|
+
termWidth != null ? wrapDescription(fullDesc, descIndent, termWidth) : dim(fullDesc);
|
|
412
|
+
return `${header}\n${indent}${desc}`;
|
|
413
|
+
})
|
|
414
|
+
.join("\n\n");
|
|
415
|
+
},
|
|
416
|
+
options,
|
|
417
|
+
);
|
|
486
418
|
}
|
|
487
419
|
|
|
488
420
|
/** Format a list of resources with server names */
|
|
@@ -490,43 +422,24 @@ export function formatResourceList(
|
|
|
490
422
|
resources: ResourceWithServer[],
|
|
491
423
|
options: FormatOptions,
|
|
492
424
|
): string {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
const maxUri = Math.max(...resources.map((r) => r.resource.uri.length));
|
|
512
|
-
const termWidth = getTerminalWidth();
|
|
513
|
-
|
|
514
|
-
return resources
|
|
515
|
-
.map((r) => {
|
|
516
|
-
const server = cyan(r.server.padEnd(maxServer));
|
|
517
|
-
const uri = bold(r.resource.uri.padEnd(maxUri));
|
|
518
|
-
if (options.withDescriptions && r.resource.description) {
|
|
519
|
-
const prefix = `${server} ${uri}`;
|
|
520
|
-
const pw = visibleLength(prefix) + 2;
|
|
521
|
-
const desc =
|
|
522
|
-
termWidth != null
|
|
523
|
-
? wrapDescription(r.resource.description, pw, termWidth)
|
|
524
|
-
: dim(r.resource.description);
|
|
525
|
-
return `${prefix} ${desc}`;
|
|
526
|
-
}
|
|
527
|
-
return `${server} ${uri}`;
|
|
528
|
-
})
|
|
529
|
-
.join("\n");
|
|
425
|
+
return formatOutput(
|
|
426
|
+
resources.map((r) => ({
|
|
427
|
+
server: r.server,
|
|
428
|
+
uri: r.resource.uri,
|
|
429
|
+
name: r.resource.name,
|
|
430
|
+
...(options.withDescriptions ? { description: r.resource.description ?? "" } : {}),
|
|
431
|
+
})),
|
|
432
|
+
() =>
|
|
433
|
+
formatTable(resources, {
|
|
434
|
+
columns: [
|
|
435
|
+
{ value: (r) => r.server, style: cyan },
|
|
436
|
+
{ value: (r) => r.resource.uri, style: bold },
|
|
437
|
+
],
|
|
438
|
+
description: options.withDescriptions ? (r) => r.resource.description : undefined,
|
|
439
|
+
emptyMessage: "No resources found",
|
|
440
|
+
}),
|
|
441
|
+
options,
|
|
442
|
+
);
|
|
530
443
|
}
|
|
531
444
|
|
|
532
445
|
/** Format resources for a single server */
|
|
@@ -535,42 +448,29 @@ export function formatServerResources(
|
|
|
535
448
|
resources: Resource[],
|
|
536
449
|
options: FormatOptions,
|
|
537
450
|
): string {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
const lines = resources.map((r) => {
|
|
563
|
-
const uri = ` ${bold(r.uri.padEnd(maxUri))}`;
|
|
564
|
-
if (r.description) {
|
|
565
|
-
const pw = visibleLength(uri) + 2;
|
|
566
|
-
const desc =
|
|
567
|
-
termWidth != null ? wrapDescription(r.description, pw, termWidth) : dim(r.description);
|
|
568
|
-
return `${uri} ${desc}`;
|
|
569
|
-
}
|
|
570
|
-
return uri;
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
return [header, ...lines].join("\n");
|
|
451
|
+
return formatOutput(
|
|
452
|
+
{
|
|
453
|
+
server: serverName,
|
|
454
|
+
resources: resources.map((r) => ({
|
|
455
|
+
uri: r.uri,
|
|
456
|
+
name: r.name,
|
|
457
|
+
description: r.description ?? "",
|
|
458
|
+
mimeType: r.mimeType ?? "",
|
|
459
|
+
})),
|
|
460
|
+
},
|
|
461
|
+
() => {
|
|
462
|
+
if (resources.length === 0) {
|
|
463
|
+
return dim(`No resources found for ${serverName}`);
|
|
464
|
+
}
|
|
465
|
+
const header = cyan.bold(serverName);
|
|
466
|
+
const body = formatTable(resources, {
|
|
467
|
+
columns: [{ value: (r) => ` ${r.uri}`, style: bold }],
|
|
468
|
+
description: (r) => r.description,
|
|
469
|
+
});
|
|
470
|
+
return `${header}\n${body}`;
|
|
471
|
+
},
|
|
472
|
+
options,
|
|
473
|
+
);
|
|
574
474
|
}
|
|
575
475
|
|
|
576
476
|
/** Format resource contents */
|
|
@@ -580,74 +480,53 @@ export function formatResourceContents(
|
|
|
580
480
|
result: unknown,
|
|
581
481
|
options: FormatOptions,
|
|
582
482
|
): string {
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
lines.push(item.text);
|
|
604
|
-
} else if (item.blob !== undefined) {
|
|
605
|
-
lines.push(dim(`<binary blob, ${item.blob.length} bytes base64>`));
|
|
483
|
+
return formatOutput(
|
|
484
|
+
{ server: serverName, uri, contents: (result as { contents: unknown })?.contents ?? result },
|
|
485
|
+
() => {
|
|
486
|
+
const contents =
|
|
487
|
+
(result as { contents?: Array<{ text?: string; blob?: string; mimeType?: string }> })
|
|
488
|
+
?.contents ?? [];
|
|
489
|
+
const lines: string[] = [];
|
|
490
|
+
lines.push(`${cyan(serverName)}/${bold(uri)}`);
|
|
491
|
+
lines.push("");
|
|
492
|
+
|
|
493
|
+
if (contents.length === 0) {
|
|
494
|
+
lines.push(dim("(empty)"));
|
|
495
|
+
} else {
|
|
496
|
+
for (const item of contents) {
|
|
497
|
+
if (item.text !== undefined) {
|
|
498
|
+
lines.push(item.text);
|
|
499
|
+
} else if (item.blob !== undefined) {
|
|
500
|
+
lines.push(dim(`<binary blob, ${item.blob.length} bytes base64>`));
|
|
501
|
+
}
|
|
502
|
+
}
|
|
606
503
|
}
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
504
|
|
|
610
|
-
|
|
505
|
+
return lines.join("\n");
|
|
506
|
+
},
|
|
507
|
+
options,
|
|
508
|
+
);
|
|
611
509
|
}
|
|
612
510
|
|
|
613
511
|
/** Format a list of prompts with server names */
|
|
614
512
|
export function formatPromptList(prompts: PromptWithServer[], options: FormatOptions): string {
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
const maxName = Math.max(...prompts.map((p) => p.prompt.name.length));
|
|
633
|
-
const termWidth = getTerminalWidth();
|
|
634
|
-
|
|
635
|
-
return prompts
|
|
636
|
-
.map((p) => {
|
|
637
|
-
const server = cyan(p.server.padEnd(maxServer));
|
|
638
|
-
const name = bold(p.prompt.name.padEnd(maxName));
|
|
639
|
-
if (options.withDescriptions && p.prompt.description) {
|
|
640
|
-
const prefix = `${server} ${name}`;
|
|
641
|
-
const pw = visibleLength(prefix) + 2;
|
|
642
|
-
const desc =
|
|
643
|
-
termWidth != null
|
|
644
|
-
? wrapDescription(p.prompt.description, pw, termWidth)
|
|
645
|
-
: dim(p.prompt.description);
|
|
646
|
-
return `${prefix} ${desc}`;
|
|
647
|
-
}
|
|
648
|
-
return `${server} ${name}`;
|
|
649
|
-
})
|
|
650
|
-
.join("\n");
|
|
513
|
+
return formatOutput(
|
|
514
|
+
prompts.map((p) => ({
|
|
515
|
+
server: p.server,
|
|
516
|
+
name: p.prompt.name,
|
|
517
|
+
...(options.withDescriptions ? { description: p.prompt.description ?? "" } : {}),
|
|
518
|
+
})),
|
|
519
|
+
() =>
|
|
520
|
+
formatTable(prompts, {
|
|
521
|
+
columns: [
|
|
522
|
+
{ value: (p) => p.server, style: cyan },
|
|
523
|
+
{ value: (p) => p.prompt.name, style: bold },
|
|
524
|
+
],
|
|
525
|
+
description: options.withDescriptions ? (p) => p.prompt.description : undefined,
|
|
526
|
+
emptyMessage: "No prompts found",
|
|
527
|
+
}),
|
|
528
|
+
options,
|
|
529
|
+
);
|
|
651
530
|
}
|
|
652
531
|
|
|
653
532
|
/** Format prompts for a single server */
|
|
@@ -656,47 +535,44 @@ export function formatServerPrompts(
|
|
|
656
535
|
prompts: Prompt[],
|
|
657
536
|
options: FormatOptions,
|
|
658
537
|
): string {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
if (prompts.length === 0) {
|
|
675
|
-
return dim(`No prompts found for ${serverName}`);
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
const header = cyan.bold(serverName);
|
|
679
|
-
const maxName = Math.max(...prompts.map((p) => p.name.length));
|
|
680
|
-
|
|
681
|
-
const termWidth = getTerminalWidth();
|
|
682
|
-
|
|
683
|
-
const lines = prompts.map((p) => {
|
|
684
|
-
const name = ` ${bold(p.name.padEnd(maxName))}`;
|
|
685
|
-
const args =
|
|
686
|
-
p.arguments && p.arguments.length > 0
|
|
687
|
-
? ` ${dim(`(${p.arguments.map((a) => (a.required ? a.name : `[${a.name}]`)).join(", ")})`)}`
|
|
688
|
-
: "";
|
|
689
|
-
if (p.description) {
|
|
690
|
-
const prefix = `${name}${args}`;
|
|
691
|
-
const pw = visibleLength(prefix) + 2;
|
|
692
|
-
const desc =
|
|
693
|
-
termWidth != null ? wrapDescription(p.description, pw, termWidth) : dim(p.description);
|
|
694
|
-
return `${prefix} ${desc}`;
|
|
695
|
-
}
|
|
696
|
-
return `${name}${args}`;
|
|
697
|
-
});
|
|
538
|
+
return formatOutput(
|
|
539
|
+
{
|
|
540
|
+
server: serverName,
|
|
541
|
+
prompts: prompts.map((p) => ({
|
|
542
|
+
name: p.name,
|
|
543
|
+
description: p.description ?? "",
|
|
544
|
+
arguments: p.arguments ?? [],
|
|
545
|
+
})),
|
|
546
|
+
},
|
|
547
|
+
() => {
|
|
548
|
+
if (prompts.length === 0) {
|
|
549
|
+
return dim(`No prompts found for ${serverName}`);
|
|
550
|
+
}
|
|
698
551
|
|
|
699
|
-
|
|
552
|
+
const header = cyan.bold(serverName);
|
|
553
|
+
const maxName = Math.max(...prompts.map((p) => p.name.length));
|
|
554
|
+
const termWidth = getTerminalWidth();
|
|
555
|
+
|
|
556
|
+
const lines = prompts.map((p) => {
|
|
557
|
+
const name = ` ${bold(p.name.padEnd(maxName))}`;
|
|
558
|
+
const args =
|
|
559
|
+
p.arguments && p.arguments.length > 0
|
|
560
|
+
? ` ${dim(`(${p.arguments.map((a) => (a.required ? a.name : `[${a.name}]`)).join(", ")})`)}`
|
|
561
|
+
: "";
|
|
562
|
+
if (p.description) {
|
|
563
|
+
const prefix = `${name}${args}`;
|
|
564
|
+
const pw = visibleLength(prefix) + 2;
|
|
565
|
+
const desc =
|
|
566
|
+
termWidth != null ? wrapDescription(p.description, pw, termWidth) : dim(p.description);
|
|
567
|
+
return `${prefix} ${desc}`;
|
|
568
|
+
}
|
|
569
|
+
return `${name}${args}`;
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
return [header, ...lines].join("\n");
|
|
573
|
+
},
|
|
574
|
+
options,
|
|
575
|
+
);
|
|
700
576
|
}
|
|
701
577
|
|
|
702
578
|
/** Format prompt messages */
|
|
@@ -706,80 +582,56 @@ export function formatPromptMessages(
|
|
|
706
582
|
result: unknown,
|
|
707
583
|
options: FormatOptions,
|
|
708
584
|
): string {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
return lines.join("\n");
|
|
585
|
+
return formatOutput(
|
|
586
|
+
{ server: serverName, prompt: name, ...(result as object) },
|
|
587
|
+
() => {
|
|
588
|
+
const r = result as {
|
|
589
|
+
description?: string;
|
|
590
|
+
messages?: Array<{ role: string; content: { type: string; text?: string } }>;
|
|
591
|
+
};
|
|
592
|
+
const lines: string[] = [];
|
|
593
|
+
lines.push(`${cyan(serverName)}/${bold(name)}`);
|
|
594
|
+
if (r.description) lines.push(dim(r.description));
|
|
595
|
+
lines.push("");
|
|
596
|
+
for (const msg of r.messages ?? []) {
|
|
597
|
+
lines.push(`${bold(msg.role)}:`);
|
|
598
|
+
if (msg.content.text !== undefined) {
|
|
599
|
+
lines.push(` ${msg.content.text}`);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return lines.join("\n");
|
|
603
|
+
},
|
|
604
|
+
options,
|
|
605
|
+
);
|
|
734
606
|
}
|
|
735
607
|
|
|
736
608
|
/** Format a unified list of tools, resources, and prompts across servers */
|
|
737
609
|
export function formatUnifiedList(items: UnifiedItem[], options: FormatOptions): string {
|
|
738
|
-
|
|
739
|
-
return
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
type: i.type,
|
|
743
|
-
name: i.name,
|
|
744
|
-
...(options.withDescriptions ? { description: i.description ?? "" } : {}),
|
|
745
|
-
})),
|
|
746
|
-
null,
|
|
747
|
-
2,
|
|
748
|
-
);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
if (items.length === 0) {
|
|
752
|
-
return dim("No tools, resources, or prompts found");
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
const maxServer = Math.max(...items.map((i) => i.server.length));
|
|
756
|
-
const maxType = 8; // "resource" is the longest at 8 chars
|
|
757
|
-
const maxName = Math.max(...items.map((i) => i.name.length));
|
|
758
|
-
|
|
759
|
-
const typeLabel = (t: UnifiedItem["type"]) => {
|
|
760
|
-
const padded = t.padEnd(maxType);
|
|
761
|
-
if (t === "tool") return green(padded);
|
|
762
|
-
if (t === "resource") return cyan(padded);
|
|
763
|
-
return yellow(padded);
|
|
610
|
+
const typeLabel = (t: string) => {
|
|
611
|
+
if (t === "tool") return green(t);
|
|
612
|
+
if (t === "resource") return cyan(t);
|
|
613
|
+
return yellow(t);
|
|
764
614
|
};
|
|
765
615
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
616
|
+
return formatOutput(
|
|
617
|
+
items.map((i) => ({
|
|
618
|
+
server: i.server,
|
|
619
|
+
type: i.type,
|
|
620
|
+
name: i.name,
|
|
621
|
+
...(options.withDescriptions ? { description: i.description ?? "" } : {}),
|
|
622
|
+
})),
|
|
623
|
+
() =>
|
|
624
|
+
formatTable(items, {
|
|
625
|
+
columns: [
|
|
626
|
+
{ value: (i) => i.server, style: cyan },
|
|
627
|
+
{ value: (i) => i.type, style: typeLabel },
|
|
628
|
+
{ value: (i) => i.name, style: bold },
|
|
629
|
+
],
|
|
630
|
+
description: options.withDescriptions ? (i) => i.description : undefined,
|
|
631
|
+
emptyMessage: "No tools, resources, or prompts found",
|
|
632
|
+
}),
|
|
633
|
+
options,
|
|
634
|
+
);
|
|
783
635
|
}
|
|
784
636
|
|
|
785
637
|
/** Format a single task status */
|
|
@@ -787,36 +639,38 @@ export function formatTaskStatus(
|
|
|
787
639
|
task: { taskId: string; status: string; [key: string]: unknown },
|
|
788
640
|
options: FormatOptions,
|
|
789
641
|
): string {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
642
|
+
return formatOutput(
|
|
643
|
+
task,
|
|
644
|
+
() => {
|
|
645
|
+
const statusColor = (s: string) => {
|
|
646
|
+
switch (s) {
|
|
647
|
+
case "completed":
|
|
648
|
+
return green(s);
|
|
649
|
+
case "working":
|
|
650
|
+
return yellow(s);
|
|
651
|
+
case "failed":
|
|
652
|
+
case "cancelled":
|
|
653
|
+
return red(s);
|
|
654
|
+
case "input_required":
|
|
655
|
+
return yellow(s);
|
|
656
|
+
default:
|
|
657
|
+
return s;
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
const lines: string[] = [];
|
|
662
|
+
lines.push(`${bold("Task:")} ${cyan(task.taskId)}`);
|
|
663
|
+
lines.push(`${bold("Status:")} ${statusColor(task.status)}`);
|
|
664
|
+
if (task.statusMessage) lines.push(`${bold("Message:")} ${dim(String(task.statusMessage))}`);
|
|
665
|
+
if (task.createdAt) lines.push(`${bold("Created:")} ${dim(String(task.createdAt))}`);
|
|
666
|
+
if (task.lastUpdatedAt) lines.push(`${bold("Updated:")} ${dim(String(task.lastUpdatedAt))}`);
|
|
667
|
+
if (task.ttl != null) lines.push(`${bold("TTL:")} ${dim(String(task.ttl) + "ms")}`);
|
|
668
|
+
if (task.pollInterval != null)
|
|
669
|
+
lines.push(`${bold("Poll interval:")} ${dim(String(task.pollInterval) + "ms")}`);
|
|
670
|
+
return lines.join("\n");
|
|
671
|
+
},
|
|
672
|
+
options,
|
|
673
|
+
);
|
|
820
674
|
}
|
|
821
675
|
|
|
822
676
|
/** Format a list of tasks */
|
|
@@ -825,43 +679,45 @@ export function formatTasksList(
|
|
|
825
679
|
nextCursor: string | undefined,
|
|
826
680
|
options: FormatOptions,
|
|
827
681
|
): string {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
const statusColor = (s: string) => {
|
|
837
|
-
switch (s) {
|
|
838
|
-
case "completed":
|
|
839
|
-
return green(s.padEnd(14));
|
|
840
|
-
case "working":
|
|
841
|
-
return yellow(s.padEnd(14));
|
|
842
|
-
case "failed":
|
|
843
|
-
case "cancelled":
|
|
844
|
-
return red(s.padEnd(14));
|
|
845
|
-
default:
|
|
846
|
-
return s.padEnd(14);
|
|
847
|
-
}
|
|
848
|
-
};
|
|
849
|
-
|
|
850
|
-
const maxId = Math.max(...tasks.map((t) => t.taskId.length));
|
|
851
|
-
|
|
852
|
-
const lines = tasks.map((t) => {
|
|
853
|
-
const id = cyan(t.taskId.padEnd(maxId));
|
|
854
|
-
const status = statusColor(t.status);
|
|
855
|
-
const updated = t.lastUpdatedAt ? dim(String(t.lastUpdatedAt)) : "";
|
|
856
|
-
return `${id} ${status} ${updated}`;
|
|
857
|
-
});
|
|
682
|
+
return formatOutput(
|
|
683
|
+
{ tasks, ...(nextCursor ? { nextCursor } : {}) },
|
|
684
|
+
() => {
|
|
685
|
+
if (tasks.length === 0) {
|
|
686
|
+
return dim("No tasks found");
|
|
687
|
+
}
|
|
858
688
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
689
|
+
const statusColor = (s: string) => {
|
|
690
|
+
switch (s) {
|
|
691
|
+
case "completed":
|
|
692
|
+
return green(s.padEnd(14));
|
|
693
|
+
case "working":
|
|
694
|
+
return yellow(s.padEnd(14));
|
|
695
|
+
case "failed":
|
|
696
|
+
case "cancelled":
|
|
697
|
+
return red(s.padEnd(14));
|
|
698
|
+
default:
|
|
699
|
+
return s.padEnd(14);
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
const maxId = Math.max(...tasks.map((t) => t.taskId.length));
|
|
704
|
+
|
|
705
|
+
const lines = tasks.map((t) => {
|
|
706
|
+
const id = cyan(t.taskId.padEnd(maxId));
|
|
707
|
+
const status = statusColor(t.status);
|
|
708
|
+
const updated = t.lastUpdatedAt ? dim(String(t.lastUpdatedAt)) : "";
|
|
709
|
+
return `${id} ${status} ${updated}`;
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
if (nextCursor) {
|
|
713
|
+
lines.push("");
|
|
714
|
+
lines.push(dim(`Next cursor: ${nextCursor}`));
|
|
715
|
+
}
|
|
863
716
|
|
|
864
|
-
|
|
717
|
+
return lines.join("\n");
|
|
718
|
+
},
|
|
719
|
+
options,
|
|
720
|
+
);
|
|
865
721
|
}
|
|
866
722
|
|
|
867
723
|
/** Format task creation output (for --no-wait) */
|
|
@@ -869,16 +725,14 @@ export function formatTaskCreated(
|
|
|
869
725
|
task: { taskId: string; status: string; [key: string]: unknown },
|
|
870
726
|
options: FormatOptions,
|
|
871
727
|
): string {
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
728
|
+
return formatOutput(
|
|
729
|
+
{ task },
|
|
730
|
+
() => `${green("Task created:")} ${cyan(task.taskId)} ${dim(`(status: ${task.status})`)}`,
|
|
731
|
+
options,
|
|
732
|
+
);
|
|
876
733
|
}
|
|
877
734
|
|
|
878
735
|
/** Format an error message */
|
|
879
736
|
export function formatError(message: string, options: FormatOptions): string {
|
|
880
|
-
|
|
881
|
-
return JSON.stringify({ error: message });
|
|
882
|
-
}
|
|
883
|
-
return `${red("error:")} ${message}`;
|
|
737
|
+
return formatOutput({ error: message }, () => `${red("error:")} ${message}`, options);
|
|
884
738
|
}
|