Skip to content

Commit 078a8ab

Browse files
committed
feat: enhance output display for workflow run status with truncation and error handling
1 parent ae9a37e commit 078a8ab

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

src/commands/handler.test.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,107 @@ describe("handleWorkflowCommand", () => {
295295
expect(result.message).toContain("npm error");
296296
});
297297

298+
it("should display step outputs in status", async () => {
299+
const mockRun: WorkflowRun = {
300+
runId: "run-789",
301+
workflowId: "build",
302+
status: "completed",
303+
startedAt: new Date("2024-01-01T00:00:00Z"),
304+
completedAt: new Date("2024-01-01T00:05:00Z"),
305+
stepResults: {
306+
compile: {
307+
stepId: "compile",
308+
status: "success",
309+
duration: 2000,
310+
startedAt: new Date(),
311+
output: { stdout: "Build successful", stderr: "", exitCode: 0 },
312+
},
313+
test: {
314+
stepId: "test",
315+
status: "success",
316+
duration: 3000,
317+
startedAt: new Date(),
318+
output: { stdout: "All tests passed", stderr: "", exitCode: 0 },
319+
},
320+
},
321+
inputs: {},
322+
};
323+
vi.mocked(mockRunner.getStatus).mockReturnValue(mockRun);
324+
325+
const result = await handleWorkflowCommand("status run-789", mockCtx);
326+
327+
expect(result.success).toBe(true);
328+
expect(result.message).toContain("compile");
329+
expect(result.message).toContain("test");
330+
// Check that outputs are displayed
331+
expect(result.message).toContain("Build successful");
332+
expect(result.message).toContain("All tests passed");
333+
expect(result.message).toContain("Output:");
334+
});
335+
336+
it("should truncate large step outputs", async () => {
337+
const largeOutput = "x".repeat(600); // Longer than 500 char limit
338+
const mockRun: WorkflowRun = {
339+
runId: "run-999",
340+
workflowId: "large",
341+
status: "completed",
342+
startedAt: new Date("2024-01-01T00:00:00Z"),
343+
completedAt: new Date("2024-01-01T00:05:00Z"),
344+
stepResults: {
345+
large: {
346+
stepId: "large",
347+
status: "success",
348+
duration: 1000,
349+
startedAt: new Date(),
350+
output: { result: largeOutput },
351+
},
352+
},
353+
inputs: {},
354+
};
355+
vi.mocked(mockRunner.getStatus).mockReturnValue(mockRun);
356+
357+
const result = await handleWorkflowCommand("status run-999", mockCtx);
358+
359+
expect(result.success).toBe(true);
360+
expect(result.message).toContain("Output:");
361+
expect(result.message).toContain("(truncated)");
362+
// Should not contain the full output
363+
expect(result.message).not.toContain("x".repeat(600));
364+
});
365+
366+
it("should handle step outputs that cannot be serialized as JSON", async () => {
367+
const mockRun: WorkflowRun = {
368+
runId: "run-888",
369+
workflowId: "circular",
370+
status: "completed",
371+
startedAt: new Date("2024-01-01T00:00:00Z"),
372+
completedAt: new Date("2024-01-01T00:05:00Z"),
373+
stepResults: {
374+
step1: {
375+
stepId: "step1",
376+
status: "success",
377+
duration: 1000,
378+
startedAt: new Date(),
379+
// Create a circular reference that can't be JSON.stringify'd
380+
output: (() => {
381+
const obj: Record<string, unknown> = { foo: "bar" };
382+
obj.self = obj;
383+
return obj as never;
384+
})(),
385+
},
386+
},
387+
inputs: {},
388+
};
389+
vi.mocked(mockRunner.getStatus).mockReturnValue(mockRun);
390+
391+
const result = await handleWorkflowCommand("status run-888", mockCtx);
392+
393+
expect(result.success).toBe(true);
394+
expect(result.message).toContain("Output:");
395+
// Should fall back to String() conversion
396+
expect(result.message).toContain("[object Object]");
397+
});
398+
298399
it("should return error for missing run id", async () => {
299400
const result = await handleWorkflowCommand("status", mockCtx);
300401

src/commands/handler.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,21 @@ function formatRunStatus(run: WorkflowRun): string {
186186
if (result.error) {
187187
lines.push(` Error: ${result.error}`);
188188
}
189+
// Display step output (if available and not too large)
190+
if (result.output) {
191+
try {
192+
const outputStr = JSON.stringify(result.output, null, 2);
193+
// Limit output display to avoid overwhelming the UI
194+
const maxLength = 500;
195+
if (outputStr.length > maxLength) {
196+
lines.push(` Output: ${outputStr.slice(0, maxLength)}... (truncated)`);
197+
} else {
198+
lines.push(` Output: \`\`\`json\n${outputStr}\n \`\`\``);
199+
}
200+
} catch {
201+
lines.push(` Output: ${String(result.output)}`);
202+
}
203+
}
189204
}
190205

191206
return lines.join("\n");

0 commit comments

Comments
 (0)