Conversation
- Created `CLIReporterPlugin` to hook into EventBus lifecycle events and output task progress to the CLI. - Integrated `performance.now()` to measure workflow duration. - Exported plugin from `src/index.ts`. - Updated README.md with configuration instructions. - Added test coverage via `vitest`. - Marked all task items as complete and archived the specification using the OpenSpec workflow. 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 reporting for task execution progress and a final summary of results. The plugin is integrated into the main package exports and includes comprehensive unit tests. Feedback focuses on improving state management within the plugin to prevent stale data during concurrent or repeated executions by moving state variables into the method scope. Additionally, it is recommended to replace process.nextTick with Promise.resolve() in tests to improve portability and consistency with the microtask queue.
| private startTime = 0; | ||
| private successCount = 0; | ||
| private failureCount = 0; | ||
| private skippedCount = 0; | ||
|
|
||
| public install(context: PluginContext<TContext>): void { | ||
| context.events.on("workflowStart", () => { | ||
| this.startTime = performance.now(); | ||
| this.successCount = 0; | ||
| this.failureCount = 0; | ||
| this.skippedCount = 0; | ||
| console.log("\n🚀 Starting TaskRunner workflow..."); | ||
| }); | ||
|
|
||
| context.events.on("taskStart", ({ step }) => { | ||
| console.log(`⏳ Starting: ${step.name}`); | ||
| }); | ||
|
|
||
| context.events.on("taskEnd", ({ step, result }) => { | ||
| if (result.status === "success") { | ||
| this.successCount++; | ||
| console.log(`✅ Success: ${step.name}`); | ||
| } else { | ||
| this.failureCount++; | ||
| console.log(`❌ Failed: ${step.name}${result.error ? ` - ${result.error}` : ""}`); | ||
| } | ||
| }); | ||
|
|
||
| context.events.on("taskSkipped", ({ step, result }) => { | ||
| this.skippedCount++; | ||
| const reason = result.error ? ` - ${result.error}` : ""; | ||
| console.log(`⏭️ Skipped: ${step.name}${reason}`); | ||
| }); | ||
|
|
||
| context.events.on("workflowEnd", () => { | ||
| const duration = performance.now() - this.startTime; | ||
| console.log(`\n🏁 Workflow Completed in ${duration.toFixed(2)}ms`); | ||
| console.log("📊 Summary:"); | ||
| console.log(` ✅ Success: ${this.successCount}`); | ||
| console.log(` ❌ Failed: ${this.failureCount}`); | ||
| console.log(` ⏭️ Skipped: ${this.skippedCount}\n`); | ||
| }); | ||
| } |
There was a problem hiding this comment.
The plugin currently stores execution state as class members. To prevent stale data across multiple initializations or concurrent executions, ensure all state-holding members are cleared or move state into the method scope. This aligns with the repository rule regarding stateful class initialization.
public install(context: PluginContext<TContext>): void {
let startTime = 0;
context.events.on("workflowStart", () => {
startTime = performance.now();
console.log("\n🚀 Starting TaskRunner workflow...");
});
context.events.on("taskStart", ({ step }) => {
console.log(`⏳ Starting: ${step.name}`);
});
context.events.on("taskEnd", ({ step, result }) => {
if (result.status === "success") {
console.log(`✅ Success: ${step.name}`);
} else {
console.log(`❌ Failed: ${step.name}${result.error ? ` - ${result.error}` : ""}`);
}
});
context.events.on("taskSkipped", ({ step, result }) => {
const reason = result.error ? ` - ${result.error}` : "";
console.log(`⏭️ Skipped: ${step.name}${reason}`);
});
context.events.on("workflowEnd", ({ results }) => {
const duration = performance.now() - startTime;
let successCount = 0;
let failureCount = 0;
let skippedCount = 0;
for (const result of results.values()) {
if (result.status === "success") successCount++;
else if (result.status === "failure") failureCount++;
else if (result.status === "skipped") skippedCount++;
}
console.log(`\n🏁 Workflow Completed in ${duration.toFixed(2)}ms`);
console.log("📊 Summary:");
console.log(` ✅ Success: ${successCount}`);
console.log(` ❌ Failed: ${failureCount}`);
console.log(` ⏭️ Skipped: ${skippedCount}\n`);
});
}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.
| plugin.install(context); | ||
| events.emit("workflowStart", { context: {}, steps: [] }); | ||
| // events are processed asynchronously | ||
| await new Promise(process.nextTick); |
There was a problem hiding this comment.
Using process.nextTick in tests makes them dependent on the Node.js environment. Since the EventBus uses queueMicrotask, it is better to use await Promise.resolve() to wait for the microtask queue to flush. This improves test portability.
| await new Promise(process.nextTick); | |
| await Promise.resolve(); |



Implemented the
add-cli-reporterchange to introduce a real-time, structured CLI reporting utility as an installable TaskRunner plugin. Includes fully passing vitest coverage and satisfies all original proposal specifications.PR created automatically by Jules for task 18189689605612180723 started by @thalesraymond