@sentio/cli 3.4.2-rc.1 → 3.5.0-rc.1
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/lib/index.js +126 -2
- package/package.json +1 -1
- package/src/commands/processor.ts +178 -3
package/lib/index.js
CHANGED
|
@@ -151941,6 +151941,7 @@ function createProcessorCommand() {
|
|
|
151941
151941
|
processorCommand.addCommand(createProcessorPauseCommand());
|
|
151942
151942
|
processorCommand.addCommand(createProcessorResumeCommand());
|
|
151943
151943
|
processorCommand.addCommand(createProcessorStopCommand());
|
|
151944
|
+
processorCommand.addCommand(createProcessorLogsCommand());
|
|
151944
151945
|
return processorCommand;
|
|
151945
151946
|
}
|
|
151946
151947
|
function createProcessorStatusCommand() {
|
|
@@ -152011,6 +152012,17 @@ function createProcessorStopCommand() {
|
|
|
152011
152012
|
}
|
|
152012
152013
|
});
|
|
152013
152014
|
}
|
|
152015
|
+
function createProcessorLogsCommand() {
|
|
152016
|
+
return withOutputOptions3(
|
|
152017
|
+
withSharedProjectOptions3(withAuthOptions3(new Command("logs").description("View processor logs")))
|
|
152018
|
+
).showHelpAfterError().argument("[processorId]", "ID of the processor (defaults to active processor)").option("--limit <count>", "Maximum number of log entries to fetch", parseInteger2, 100).option("-f, --follow", "Poll for new log entries continuously").option("--log-type <type>", "Filter by log type (e.g. execution, system)").option("--level <level>", "Filter by log level: DEBUG, INFO, WARNING, ERROR").option("--query <query>", "Free-text filter query").action(async (processorId, options, command) => {
|
|
152019
|
+
try {
|
|
152020
|
+
await runProcessorLogs(processorId, options);
|
|
152021
|
+
} catch (error) {
|
|
152022
|
+
handleProcessorCommandError(error, command);
|
|
152023
|
+
}
|
|
152024
|
+
});
|
|
152025
|
+
}
|
|
152014
152026
|
async function runProcessorStatus(options) {
|
|
152015
152027
|
const context = createApiContext(options);
|
|
152016
152028
|
const project = await resolveProjectRef(options, context, { ownerSlug: true });
|
|
@@ -152164,6 +152176,101 @@ async function runProcessorStop(processorId, options) {
|
|
|
152164
152176
|
...response
|
|
152165
152177
|
});
|
|
152166
152178
|
}
|
|
152179
|
+
async function resolveProcessorId(processorId, options) {
|
|
152180
|
+
if (processorId) return processorId;
|
|
152181
|
+
const context = createApiContext(options);
|
|
152182
|
+
const project = await resolveProjectRef(options, context, { ownerSlug: true });
|
|
152183
|
+
const statusResponse = await import_api5.ProcessorService.getProcessorStatusV2({
|
|
152184
|
+
path: { owner: project.owner, slug: project.slug },
|
|
152185
|
+
query: { version: "ACTIVE" },
|
|
152186
|
+
headers: context.headers
|
|
152187
|
+
});
|
|
152188
|
+
const data = unwrapApiResult(statusResponse);
|
|
152189
|
+
const processors = Array.isArray(data.processors) ? data.processors : [];
|
|
152190
|
+
const activeProcessor = processors.find((p7) => asString3(p7.versionState) === "ACTIVE");
|
|
152191
|
+
if (!activeProcessor || !activeProcessor.processorId) {
|
|
152192
|
+
throw new CliError(
|
|
152193
|
+
`No active processor found for project ${project.owner}/${project.slug}. Please specify a processorId.`
|
|
152194
|
+
);
|
|
152195
|
+
}
|
|
152196
|
+
return asString3(activeProcessor.processorId);
|
|
152197
|
+
}
|
|
152198
|
+
async function runProcessorLogs(processorId, options) {
|
|
152199
|
+
const resolvedProcessorId = await resolveProcessorId(processorId, options);
|
|
152200
|
+
const context = createApiContext(options);
|
|
152201
|
+
if (options.follow && !options.json && !options.yaml) {
|
|
152202
|
+
await followProcessorLogs(resolvedProcessorId, context, options);
|
|
152203
|
+
return;
|
|
152204
|
+
}
|
|
152205
|
+
const response = await postApiJson(
|
|
152206
|
+
`/api/v1/processors/${resolvedProcessorId}/logs`,
|
|
152207
|
+
context,
|
|
152208
|
+
buildLogsRequestBody(resolvedProcessorId, options)
|
|
152209
|
+
);
|
|
152210
|
+
printOutput3(options, response);
|
|
152211
|
+
}
|
|
152212
|
+
async function followProcessorLogs(processorId, context, options) {
|
|
152213
|
+
let until;
|
|
152214
|
+
let running = true;
|
|
152215
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
152216
|
+
process19.on("SIGINT", () => {
|
|
152217
|
+
running = false;
|
|
152218
|
+
});
|
|
152219
|
+
while (running) {
|
|
152220
|
+
try {
|
|
152221
|
+
const body = { ...buildLogsRequestBody(processorId, options), until };
|
|
152222
|
+
const response = await postApiJson(`/api/v1/processors/${processorId}/logs`, context, body);
|
|
152223
|
+
const entries2 = Array.isArray(response.logs) ? response.logs : [];
|
|
152224
|
+
for (const entry of entries2) {
|
|
152225
|
+
const e10 = entry;
|
|
152226
|
+
const id = e10.id ?? "";
|
|
152227
|
+
if (id && seenIds.has(id)) continue;
|
|
152228
|
+
if (id) seenIds.add(id);
|
|
152229
|
+
process19.stdout.write(formatLogEntry(e10) + "\n");
|
|
152230
|
+
}
|
|
152231
|
+
if (response.until) {
|
|
152232
|
+
until = response.until;
|
|
152233
|
+
}
|
|
152234
|
+
} catch {
|
|
152235
|
+
}
|
|
152236
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
152237
|
+
}
|
|
152238
|
+
}
|
|
152239
|
+
function buildLogsRequestBody(processorId, options) {
|
|
152240
|
+
const body = { processorId, limit: options.limit };
|
|
152241
|
+
if (options.logType) {
|
|
152242
|
+
body.logTypeFilters = [options.logType];
|
|
152243
|
+
}
|
|
152244
|
+
if (options.level || options.query) {
|
|
152245
|
+
const parts = [];
|
|
152246
|
+
if (options.level) parts.push(options.level.toUpperCase());
|
|
152247
|
+
if (options.query) parts.push(options.query);
|
|
152248
|
+
body.query = parts.join(" ");
|
|
152249
|
+
}
|
|
152250
|
+
return body;
|
|
152251
|
+
}
|
|
152252
|
+
function formatLogEntry(entry) {
|
|
152253
|
+
const formattedTime = entry.timestamp ? source_default.gray(entry.timestamp.replace("T", " ").replace("Z", "")) : "";
|
|
152254
|
+
const level = (entry.level ?? "INFO").toUpperCase();
|
|
152255
|
+
const logType = entry.logType ? source_default.gray(`[${entry.logType}]`) : "";
|
|
152256
|
+
const coloredLevel = colorSeverity(level);
|
|
152257
|
+
const message = entry.message ?? "";
|
|
152258
|
+
const chain4 = entry.chainId ? source_default.gray(`(chain=${entry.chainId})`) : "";
|
|
152259
|
+
return [formattedTime, coloredLevel, logType, message, chain4].filter(Boolean).join(" ");
|
|
152260
|
+
}
|
|
152261
|
+
function colorSeverity(severity) {
|
|
152262
|
+
switch (severity) {
|
|
152263
|
+
case "ERROR":
|
|
152264
|
+
return source_default.red(`[${severity}]`);
|
|
152265
|
+
case "WARNING":
|
|
152266
|
+
case "WARN":
|
|
152267
|
+
return source_default.yellow(`[${severity}]`);
|
|
152268
|
+
case "DEBUG":
|
|
152269
|
+
return source_default.gray(`[${severity}]`);
|
|
152270
|
+
default:
|
|
152271
|
+
return source_default.cyan(`[${severity}]`);
|
|
152272
|
+
}
|
|
152273
|
+
}
|
|
152167
152274
|
function withAuthOptions3(command) {
|
|
152168
152275
|
return command.option("--host <host>", "Override Sentio host").option("--api-key <key>", "Use an explicit API key instead of saved credentials").option("--token <token>", "Use an explicit bearer token instead of saved credentials");
|
|
152169
152276
|
}
|
|
@@ -152207,7 +152314,8 @@ function formatOutput2(data) {
|
|
|
152207
152314
|
lines.push(`${group.versionState} (${group.processors.length})`);
|
|
152208
152315
|
for (const processor of group.processors) {
|
|
152209
152316
|
const version2 = asNumber(processor.version);
|
|
152210
|
-
const
|
|
152317
|
+
const processorStatus = processor.processorStatus;
|
|
152318
|
+
const statusState = asString3(processorStatus?.state) ?? "UNKNOWN";
|
|
152211
152319
|
const uploadedAt = asString3(processor.uploadedAt);
|
|
152212
152320
|
lines.push(`- v${version2 ?? "?"} status=${statusState}${uploadedAt ? ` uploaded=${uploadedAt}` : ""}`);
|
|
152213
152321
|
if (asString3(processor.processorId)) {
|
|
@@ -152217,9 +152325,17 @@ function formatOutput2(data) {
|
|
|
152217
152325
|
for (const stateEntry of states.slice(0, 5)) {
|
|
152218
152326
|
const state = stateEntry;
|
|
152219
152327
|
const chainId = asString3(state.chainId) ?? "?";
|
|
152220
|
-
const
|
|
152328
|
+
const stateStatus = state.status;
|
|
152329
|
+
const chainState = asString3(stateStatus?.state) ?? "UNKNOWN";
|
|
152221
152330
|
const block = asString3(state.processedBlockNumber) ?? "?";
|
|
152222
152331
|
lines.push(` chain ${chainId}: ${chainState} block=${block}`);
|
|
152332
|
+
const errorRecord = stateStatus?.errorRecord;
|
|
152333
|
+
const chainError = asString3(errorRecord?.message);
|
|
152334
|
+
if (chainError) {
|
|
152335
|
+
const createdAt = asString3(errorRecord?.createdAt);
|
|
152336
|
+
const prefix = createdAt ? `[${createdAt}] ` : "";
|
|
152337
|
+
lines.push(` error: ${prefix}${chainError}`);
|
|
152338
|
+
}
|
|
152223
152339
|
}
|
|
152224
152340
|
if (states.length > 5) {
|
|
152225
152341
|
lines.push(` ... ${states.length - 5} more chains`);
|
|
@@ -152248,6 +152364,14 @@ function formatOutput2(data) {
|
|
|
152248
152364
|
const objectData = data;
|
|
152249
152365
|
return `Processor ${asString3(objectData.processorId)} successfully ${asString3(objectData.action)}.`;
|
|
152250
152366
|
}
|
|
152367
|
+
if (data && typeof data === "object" && "logs" in data) {
|
|
152368
|
+
const logsData = data;
|
|
152369
|
+
const entries2 = Array.isArray(logsData.logs) ? logsData.logs : [];
|
|
152370
|
+
if (entries2.length === 0) {
|
|
152371
|
+
return "No logs found.";
|
|
152372
|
+
}
|
|
152373
|
+
return entries2.map((entry) => formatLogEntry(entry)).join("\n");
|
|
152374
|
+
}
|
|
152251
152375
|
return JSON.stringify(data, null, 2);
|
|
152252
152376
|
}
|
|
152253
152377
|
function normalizeVersionSelector(value) {
|
package/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ProcessorExtService, ProcessorService } from '@sentio/api'
|
|
2
2
|
import { Command, InvalidArgumentError } from '@commander-js/extra-typings'
|
|
3
|
+
import chalk from 'chalk'
|
|
3
4
|
import process from 'process'
|
|
4
5
|
import yaml from 'yaml'
|
|
5
6
|
import {
|
|
@@ -34,6 +35,14 @@ interface ProcessorSourceOptions extends ProcessorOptions {
|
|
|
34
35
|
path?: string
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
interface ProcessorLogsOptions extends ProcessorOptions {
|
|
39
|
+
limit?: number
|
|
40
|
+
follow?: boolean
|
|
41
|
+
logType?: string
|
|
42
|
+
level?: string
|
|
43
|
+
query?: string
|
|
44
|
+
}
|
|
45
|
+
|
|
37
46
|
export function createProcessorCommand() {
|
|
38
47
|
const processorCommand = new Command('processor').description('Manage Sentio processor versions')
|
|
39
48
|
processorCommand.addCommand(createProcessorStatusCommand())
|
|
@@ -42,6 +51,7 @@ export function createProcessorCommand() {
|
|
|
42
51
|
processorCommand.addCommand(createProcessorPauseCommand())
|
|
43
52
|
processorCommand.addCommand(createProcessorResumeCommand())
|
|
44
53
|
processorCommand.addCommand(createProcessorStopCommand())
|
|
54
|
+
processorCommand.addCommand(createProcessorLogsCommand())
|
|
45
55
|
return processorCommand
|
|
46
56
|
}
|
|
47
57
|
|
|
@@ -142,6 +152,26 @@ function createProcessorStopCommand() {
|
|
|
142
152
|
})
|
|
143
153
|
}
|
|
144
154
|
|
|
155
|
+
function createProcessorLogsCommand() {
|
|
156
|
+
return withOutputOptions(
|
|
157
|
+
withSharedProjectOptions(withAuthOptions(new Command('logs').description('View processor logs')))
|
|
158
|
+
)
|
|
159
|
+
.showHelpAfterError()
|
|
160
|
+
.argument('[processorId]', 'ID of the processor (defaults to active processor)')
|
|
161
|
+
.option('--limit <count>', 'Maximum number of log entries to fetch', parseInteger, 100)
|
|
162
|
+
.option('-f, --follow', 'Poll for new log entries continuously')
|
|
163
|
+
.option('--log-type <type>', 'Filter by log type (e.g. execution, system)')
|
|
164
|
+
.option('--level <level>', 'Filter by log level: DEBUG, INFO, WARNING, ERROR')
|
|
165
|
+
.option('--query <query>', 'Free-text filter query')
|
|
166
|
+
.action(async (processorId, options, command) => {
|
|
167
|
+
try {
|
|
168
|
+
await runProcessorLogs(processorId, options)
|
|
169
|
+
} catch (error) {
|
|
170
|
+
handleProcessorCommandError(error, command)
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
|
|
145
175
|
async function runProcessorStatus(options: ProcessorStatusOptions) {
|
|
146
176
|
const context = createApiContext(options)
|
|
147
177
|
const project = await resolveProjectRef(options, context, { ownerSlug: true })
|
|
@@ -319,6 +349,134 @@ async function runProcessorStop(processorId: string | undefined, options: Proces
|
|
|
319
349
|
})
|
|
320
350
|
}
|
|
321
351
|
|
|
352
|
+
async function resolveProcessorId(processorId: string | undefined, options: ProcessorOptions): Promise<string> {
|
|
353
|
+
if (processorId) return processorId
|
|
354
|
+
const context = createApiContext(options)
|
|
355
|
+
const project = await resolveProjectRef(options, context, { ownerSlug: true })
|
|
356
|
+
const statusResponse = await ProcessorService.getProcessorStatusV2({
|
|
357
|
+
path: { owner: project.owner, slug: project.slug },
|
|
358
|
+
query: { version: 'ACTIVE' },
|
|
359
|
+
headers: context.headers
|
|
360
|
+
})
|
|
361
|
+
const data = unwrapApiResult(statusResponse)
|
|
362
|
+
const processors = Array.isArray(data.processors) ? data.processors : []
|
|
363
|
+
const activeProcessor = processors.find((p) => asString(p.versionState) === 'ACTIVE')
|
|
364
|
+
if (!activeProcessor || !activeProcessor.processorId) {
|
|
365
|
+
throw new CliError(
|
|
366
|
+
`No active processor found for project ${project.owner}/${project.slug}. Please specify a processorId.`
|
|
367
|
+
)
|
|
368
|
+
}
|
|
369
|
+
return asString(activeProcessor.processorId)!
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async function runProcessorLogs(processorId: string | undefined, options: ProcessorLogsOptions) {
|
|
373
|
+
const resolvedProcessorId = await resolveProcessorId(processorId, options)
|
|
374
|
+
const context = createApiContext(options)
|
|
375
|
+
|
|
376
|
+
if (options.follow && !options.json && !options.yaml) {
|
|
377
|
+
await followProcessorLogs(resolvedProcessorId, context, options)
|
|
378
|
+
return
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const response = await postApiJson<ProcessorLogsResponse>(
|
|
382
|
+
`/api/v1/processors/${resolvedProcessorId}/logs`,
|
|
383
|
+
context,
|
|
384
|
+
buildLogsRequestBody(resolvedProcessorId, options)
|
|
385
|
+
)
|
|
386
|
+
printOutput(options, response)
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async function followProcessorLogs(
|
|
390
|
+
processorId: string,
|
|
391
|
+
context: ReturnType<typeof createApiContext>,
|
|
392
|
+
options: ProcessorLogsOptions
|
|
393
|
+
) {
|
|
394
|
+
let until: unknown[] | undefined
|
|
395
|
+
let running = true
|
|
396
|
+
const seenIds = new Set<string>()
|
|
397
|
+
|
|
398
|
+
process.on('SIGINT', () => {
|
|
399
|
+
running = false
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
while (running) {
|
|
403
|
+
try {
|
|
404
|
+
const body = { ...buildLogsRequestBody(processorId, options), until }
|
|
405
|
+
const response = await postApiJson<ProcessorLogsResponse>(`/api/v1/processors/${processorId}/logs`, context, body)
|
|
406
|
+
const entries = Array.isArray(response.logs) ? response.logs : []
|
|
407
|
+
for (const entry of entries) {
|
|
408
|
+
const e = entry as ProcessorLog
|
|
409
|
+
const id = e.id ?? ''
|
|
410
|
+
if (id && seenIds.has(id)) continue
|
|
411
|
+
if (id) seenIds.add(id)
|
|
412
|
+
process.stdout.write(formatLogEntry(e) + '\n')
|
|
413
|
+
}
|
|
414
|
+
if (response.until) {
|
|
415
|
+
until = response.until
|
|
416
|
+
}
|
|
417
|
+
} catch {
|
|
418
|
+
// Ignore transient fetch errors during follow mode
|
|
419
|
+
}
|
|
420
|
+
await new Promise((resolve) => setTimeout(resolve, 2000))
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function buildLogsRequestBody(processorId: string, options: ProcessorLogsOptions): Record<string, unknown> {
|
|
425
|
+
const body: Record<string, unknown> = { processorId, limit: options.limit }
|
|
426
|
+
if (options.logType) {
|
|
427
|
+
body.logTypeFilters = [options.logType]
|
|
428
|
+
}
|
|
429
|
+
if (options.level || options.query) {
|
|
430
|
+
const parts: string[] = []
|
|
431
|
+
if (options.level) parts.push(options.level.toUpperCase())
|
|
432
|
+
if (options.query) parts.push(options.query)
|
|
433
|
+
body.query = parts.join(' ')
|
|
434
|
+
}
|
|
435
|
+
return body
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
interface ProcessorLog {
|
|
439
|
+
id?: string
|
|
440
|
+
message?: string
|
|
441
|
+
timestamp?: string
|
|
442
|
+
attributes?: Record<string, unknown>
|
|
443
|
+
logType?: string
|
|
444
|
+
level?: string
|
|
445
|
+
highlightedMessage?: string
|
|
446
|
+
chainId?: string
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
interface ProcessorLogsResponse {
|
|
450
|
+
logs?: ProcessorLog[]
|
|
451
|
+
until?: unknown[]
|
|
452
|
+
total?: string
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function formatLogEntry(entry: ProcessorLog): string {
|
|
456
|
+
const formattedTime = entry.timestamp ? chalk.gray(entry.timestamp.replace('T', ' ').replace('Z', '')) : ''
|
|
457
|
+
const level = (entry.level ?? 'INFO').toUpperCase()
|
|
458
|
+
const logType = entry.logType ? chalk.gray(`[${entry.logType}]`) : ''
|
|
459
|
+
const coloredLevel = colorSeverity(level)
|
|
460
|
+
const message = entry.message ?? ''
|
|
461
|
+
const chain = entry.chainId ? chalk.gray(`(chain=${entry.chainId})`) : ''
|
|
462
|
+
|
|
463
|
+
return [formattedTime, coloredLevel, logType, message, chain].filter(Boolean).join(' ')
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function colorSeverity(severity: string): string {
|
|
467
|
+
switch (severity) {
|
|
468
|
+
case 'ERROR':
|
|
469
|
+
return chalk.red(`[${severity}]`)
|
|
470
|
+
case 'WARNING':
|
|
471
|
+
case 'WARN':
|
|
472
|
+
return chalk.yellow(`[${severity}]`)
|
|
473
|
+
case 'DEBUG':
|
|
474
|
+
return chalk.gray(`[${severity}]`)
|
|
475
|
+
default:
|
|
476
|
+
return chalk.cyan(`[${severity}]`)
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
322
480
|
function withAuthOptions<T extends Command<any, any, any>>(command: T) {
|
|
323
481
|
return command
|
|
324
482
|
.option('--host <host>', 'Override Sentio host')
|
|
@@ -380,8 +538,8 @@ function formatOutput(data: unknown) {
|
|
|
380
538
|
lines.push(`${group.versionState} (${group.processors.length})`)
|
|
381
539
|
for (const processor of group.processors) {
|
|
382
540
|
const version = asNumber(processor.version)
|
|
383
|
-
const
|
|
384
|
-
|
|
541
|
+
const processorStatus = processor.processorStatus as Record<string, unknown> | undefined
|
|
542
|
+
const statusState = asString(processorStatus?.state) ?? 'UNKNOWN'
|
|
385
543
|
const uploadedAt = asString(processor.uploadedAt)
|
|
386
544
|
lines.push(`- v${version ?? '?'} status=${statusState}${uploadedAt ? ` uploaded=${uploadedAt}` : ''}`)
|
|
387
545
|
if (asString(processor.processorId)) {
|
|
@@ -391,9 +549,17 @@ function formatOutput(data: unknown) {
|
|
|
391
549
|
for (const stateEntry of states.slice(0, 5)) {
|
|
392
550
|
const state = stateEntry as Record<string, unknown>
|
|
393
551
|
const chainId = asString(state.chainId) ?? '?'
|
|
394
|
-
const
|
|
552
|
+
const stateStatus = state.status as Record<string, unknown> | undefined
|
|
553
|
+
const chainState = asString(stateStatus?.state) ?? 'UNKNOWN'
|
|
395
554
|
const block = asString(state.processedBlockNumber) ?? '?'
|
|
396
555
|
lines.push(` chain ${chainId}: ${chainState} block=${block}`)
|
|
556
|
+
const errorRecord = stateStatus?.errorRecord as Record<string, unknown> | undefined
|
|
557
|
+
const chainError = asString(errorRecord?.message)
|
|
558
|
+
if (chainError) {
|
|
559
|
+
const createdAt = asString(errorRecord?.createdAt)
|
|
560
|
+
const prefix = createdAt ? `[${createdAt}] ` : ''
|
|
561
|
+
lines.push(` error: ${prefix}${chainError}`)
|
|
562
|
+
}
|
|
397
563
|
}
|
|
398
564
|
if (states.length > 5) {
|
|
399
565
|
lines.push(` ... ${states.length - 5} more chains`)
|
|
@@ -432,6 +598,15 @@ function formatOutput(data: unknown) {
|
|
|
432
598
|
return `Processor ${asString(objectData.processorId)} successfully ${asString(objectData.action)}.`
|
|
433
599
|
}
|
|
434
600
|
|
|
601
|
+
if (data && typeof data === 'object' && 'logs' in (data as Record<string, unknown>)) {
|
|
602
|
+
const logsData = data as ProcessorLogsResponse
|
|
603
|
+
const entries = Array.isArray(logsData.logs) ? logsData.logs : []
|
|
604
|
+
if (entries.length === 0) {
|
|
605
|
+
return 'No logs found.'
|
|
606
|
+
}
|
|
607
|
+
return entries.map((entry) => formatLogEntry(entry)).join('\n')
|
|
608
|
+
}
|
|
609
|
+
|
|
435
610
|
return JSON.stringify(data, null, 2)
|
|
436
611
|
}
|
|
437
612
|
|