feat: Add CLIReporterPlugin for real-time progress reporting#252
feat: Add CLIReporterPlugin for real-time progress reporting#252thalesraymond wants to merge 1 commit intomainfrom
Conversation
- Implement CLIReporterPlugin for real-time workflow observability - Hook into EventBus lifecycle events to print task states - Print total execution time, successful, failed, and skipped metrics on workflow end - Export plugin from index.ts - Add documentation to README.md - Add comprehensive unit tests achieving 100% coverage - Archive OpenSpec change proposal Co-authored-by: thalesraymond <32554150+thalesraymond@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Code Review
This pull request introduces the CLIReporterPlugin, which provides real-time CLI observability for workflow progress, including documentation, specifications, and unit tests. The review feedback identifies a concurrency issue where maintaining state as instance properties makes the plugin unsafe for simultaneous workflow executions. It is recommended to derive summary statistics from the results Map in the workflowEnd event to ensure reliability. Additionally, the reviewer noted overlapping logic between the taskEnd and taskSkipped listeners that could result in duplicate logging and incorrect task counts.
| private startTime = 0; | ||
| private successful = 0; | ||
| private failed = 0; | ||
| private skipped = 0; |
There was a problem hiding this comment.
The plugin maintains execution state (counters and start time) as instance properties. This makes the plugin unsafe for concurrent workflow executions on the same runner instance (or if the plugin instance is shared across multiple runners). If two workflows run concurrently, their counters will be interleaved and the startTime will be overwritten, leading to corrupted summaries.
To improve robustness, consider calculating the final summary statistics directly from the results Map provided in the workflowEnd event payload, which ensures the summary reflects the actual final state of that specific execution.
References
- When implementing an initialize or reset method in a stateful class, ensure all state-holding members are cleared to prevent stale data across multiple initializations.
| } else if (result.status === "cancelled") { | ||
| // According to the spec we track skipped, but cancelled is another status. | ||
| // Will just increment failed for now or leave it. We'll track it as skipped. | ||
| this.skipped++; | ||
| console.log(`[CANCELLED] Task ${step.name}`); | ||
| } else { | ||
| this.skipped++; | ||
| console.log(`[SKIPPED] Task ${step.name}`); | ||
| } |
There was a problem hiding this comment.
The logic in taskEnd for handling cancelled and other statuses overlaps with the taskSkipped listener. Specifically, both the else block here and the taskSkipped listener (lines 48-51) increment the skipped counter and log a [SKIPPED] message. If the runner emits both events for a single task (e.g., a task that is skipped but still triggers a terminal event), it will result in duplicate logs and double-counting in the summary.
Additionally, the else block acts as a catch-all that logs [SKIPPED] for any unknown status, which might mask future status types (like timeout).
| context.events.on("workflowEnd", () => { | ||
| const endTime = performance.now(); | ||
| const totalTime = endTime - this.startTime; | ||
|
|
||
| console.log("--- Workflow Execution Summary ---"); | ||
| console.log(`Total Time: ${Math.round(totalTime)}ms`); | ||
| console.log(`Successful: ${this.successful}`); | ||
| console.log(`Failed: ${this.failed}`); | ||
| console.log(`Skipped: ${this.skipped}`); | ||
| console.log("----------------------------------"); | ||
| }); |
There was a problem hiding this comment.
Instead of relying on manually incremented counters which are prone to concurrency issues, leverage the results Map passed in the workflowEnd event payload to generate the summary. This ensures the counts are derived from the source of truth for the workflow's completion state. While this involves creating an array from the map values, the performance impact is negligible for a reporter compared to the gain in reliability.
context.events.on("workflowEnd", ({ results }) => {
const endTime = performance.now();
const totalTime = endTime - this.startTime;
const counts = Array.from(results.values()).reduce(
(acc, res) => {
if (res.status === "success") acc.successful++;
else if (res.status === "failure") acc.failed++;
else acc.skipped++;
return acc;
},
{ successful: 0, failed: 0, skipped: 0 }
);
console.log("--- Workflow Execution Summary ---");
console.log("Total Time: " + Math.round(totalTime) + "ms");
console.log("Successful: " + counts.successful);
console.log("Failed: " + counts.failed);
console.log("Skipped: " + counts.skipped);
console.log("----------------------------------");
});References
- Before merging loops or removing duplicate checks for code simplification, consider the performance impact. Retaining separate logic can be justified if it avoids expensive operations (like JSON.stringify or heavy string manipulation) and provides significant, benchmarked performance gains.



Implemented the
add-cli-reporterproposal to introduce real-time CLI observability of workflow progress. The newCLIReporterPluginhooks into lifecycle events (taskStart,taskEnd, etc.) and displays task states and a final summary. Documentation was updated, unit tests added, and the OpenSpec change proposal archived.PR created automatically by Jules for task 16322371157142790787 started by @thalesraymond