feat: workflow to polish CLI output with listr2 + chalk#585
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
c668b92 to
4e77bdb
Compare
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… types Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…colors - Replace plain console.log progress in cli.ts with listr2 task list - Per-step spinners show owner, retry, nudge, force-release, and review events - chalk colors: cyan for timestamps, green/red/yellow for status, dim for metadata - logRunSummary() and broker stderr use chalk for visual hierarchy Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…flows Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…steps Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dering Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… path - cli.ts: installOutputFilter() in runWithListr so YAML workflows also suppress [broker]/[workflow HH:MM] noise during listr rendering - cli.ts: done.catch()/workflowDone.catch() guards for fast-failing steps - listr-renderer.ts: workflowDone.catch() guard for instant run:failed - listr-renderer.ts: add renderer.unmount() to JSDoc example Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Output filter: use regex .test() instead of startsWith/^ anchor so
chalk-colored [broker] and [workflow HH:MM] lines are properly suppressed
- Resume mode: add event listener for step progress reporting
- GHA workflow: fix grep exit code with || true, use env var instead of
raw ${{ }} interpolation (script injection), use npx tsx instead of
non-existent 'run' subcommand, only validate/dry-run YAML files
- Workflow: fix incorrect CJS assumption (SDK is ESM), add final
type-check gate after review step
- Add chalk and listr2 to root package.json (Build & Validate requires them) - Dynamic import listr2 so SDK loads on Node 18 (styleText not available) - Show steps skipped without prior start event in listr output - Remove unused ListrType import
* fix: detect claude CLI with inline args for MCP injection * fix: extract executable from cli string in gemini/droid mcp setup When cli contains inline args (e.g. 'gemini --model foo'), Command::new(cli) fails because it treats the entire string as an executable path. Now extract just the binary via shlex::split before passing to Command::new and manual_cmd.
* bump versions * fix: refresh lockfile for relaycast sdk 1.0.0 bump * fix: bump gemini relay extension to relaycast mcp 1.0.0
…colors - Replace plain console.log progress in cli.ts with listr2 task list - Per-step spinners show owner, retry, nudge, force-release, and review events - chalk colors: cyan for timestamps, green/red/yellow for status, dim for metadata - logRunSummary() and broker stderr use chalk for visual hierarchy Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolve package manifest conflicts by keeping main's version bumps and preserving the PR's chalk/listr2 additions. Regenerate package-lock.json from the merged manifests.
- pass yaml path before --validate in workflow validation CI - add trail start/complete/abandon to polish workflow script - fix remaining ESM wording/install command in planning prompt - queue listr tasks before lazy renderer initialization completes
Resolve lockfile/workflow conflicts and keep the newer workflow output polish script variant.
| try { | ||
| execSync('npx trail start "Polish workflow output with listr2 + chalk"', { stdio: 'ignore' }); | ||
| } catch {} |
There was a problem hiding this comment.
🟡 Trail left permanently in "active" state when workflow throws
trail start is called unconditionally at line 7, but trail complete/trail abandon at lines 255-261 are only reached if Promise.all on line 10 resolves successfully. The execute() method in packages/sdk/src/workflows/runner.ts:1793-1814 can throw before entering its internal try/catch (e.g., config validation failures, missing workflow name, path validation errors), which would cause Promise.all to reject. Since there is no try/catch around the await Promise.all(...) call, the rejection propagates as an unhandled error, skipping the trail finalization block entirely. The trajectory is left in "active" state indefinitely, polluting the trajectory index.
The fix is to wrap the Promise.all and subsequent logic in a try/catch/finally that ensures trail abandon is called when an exception occurs.
Prompt for agents
In workflows/polish-workflow-output.ts, the trail start at lines 6-8 and the trail complete/abandon at lines 254-261 are not connected by a try/finally, so if Promise.all on line 10 throws, the trail is never closed. Wrap the entire workflow execution (lines 10-262) in a try/catch/finally block so that trail abandon is always called on error. For example:
let result;
try {
[result] = await Promise.all([
workflow(...)
...run({ onEvent: renderer.onEvent }),
renderer.start(),
]);
renderer.unmount();
} catch (err) {
renderer.unmount();
try {
execSync('npx trail abandon --reason "Workflow threw an unexpected error"', { stdio: 'ignore' });
} catch {}
throw err;
}
try {
if (result.status === 'completed') {
execSync('npx trail complete --summary "Polished workflow output with listr2 + chalk" --confidence 0.88', { stdio: 'ignore' });
} else {
execSync(`npx trail abandon --reason "Workflow ended with status: ${result.status}"`, { stdio: 'ignore' });
}
} catch {}
console.log('Result:', result.status);
This ensures the trail is properly abandoned if Promise.all rejects.
Was this helpful? React with 👍 or 👎 to provide feedback.
* feat: add workflow to polish CLI output with listr2 + chalk
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ci: add workflow validation and dry-run check on PR
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ci): fetch full history for git diff, run dry-run on all workflow types
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(sdk): polish workflow CLI output with listr2 spinners and chalk colors
- Replace plain console.log progress in cli.ts with listr2 task list
- Per-step spinners show owner, retry, nudge, force-release, and review events
- chalk colors: cyan for timestamps, green/red/yellow for status, dim for metadata
- logRunSummary() and broker stderr use chalk for visual hierarchy
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test: add smoke test workflow for listr2 output rendering
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: use ESM-compatible import for check-sdk step
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(sdk): export createWorkflowRenderer for listr2 output in TS workflows
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: pre-attach catch to prevent unhandled rejection on fast-failing steps
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: use worker preset for verify step, mute console during listr rendering
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: filter [broker]/[workflow] noise, show observer URL, add unmount()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: add missing unhandled-rejection guards and output filter to YAML path
- cli.ts: installOutputFilter() in runWithListr so YAML workflows also
suppress [broker]/[workflow HH:MM] noise during listr rendering
- cli.ts: done.catch()/workflowDone.catch() guards for fast-failing steps
- listr-renderer.ts: workflowDone.catch() guard for instant run:failed
- listr-renderer.ts: add renderer.unmount() to JSDoc example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: address PR review feedback for workflow output polish
- Output filter: use regex .test() instead of startsWith/^ anchor so
chalk-colored [broker] and [workflow HH:MM] lines are properly suppressed
- Resume mode: add event listener for step progress reporting
- GHA workflow: fix grep exit code with || true, use env var instead of
raw ${{ }} interpolation (script injection), use npx tsx instead of
non-existent 'run' subcommand, only validate/dry-run YAML files
- Workflow: fix incorrect CJS assumption (SDK is ESM), add final
type-check gate after review step
* fix: CI failures and skipped-step visibility
- Add chalk and listr2 to root package.json (Build & Validate requires them)
- Dynamic import listr2 so SDK loads on Node 18 (styleText not available)
- Show steps skipped without prior start event in listr output
- Remove unused ListrType import
* fix: detect claude CLI with inline args for MCP injection (#584)
* fix: detect claude CLI with inline args for MCP injection
* fix: extract executable from cli string in gemini/droid mcp setup
When cli contains inline args (e.g. 'gemini --model foo'),
Command::new(cli) fails because it treats the entire string as
an executable path. Now extract just the binary via shlex::split
before passing to Command::new and manual_cmd.
* chore(release): v3.2.8
* bump versions (#590)
* bump versions
* fix: refresh lockfile for relaycast sdk 1.0.0 bump
* fix: bump gemini relay extension to relaycast mcp 1.0.0
* chore(release): v3.2.9
* feat(sdk): polish workflow CLI output with listr2 spinners and chalk colors
- Replace plain console.log progress in cli.ts with listr2 task list
- Per-step spinners show owner, retry, nudge, force-release, and review events
- chalk colors: cyan for timestamps, green/red/yellow for status, dim for metadata
- logRunSummary() and broker stderr use chalk for visual hierarchy
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: regenerate lockfile with npm 11 for Node 24 ci compatibility
* fix: address remaining workflow review feedback
- pass yaml path before --validate in workflow validation CI
- add trail start/complete/abandon to polish workflow script
- fix remaining ESM wording/install command in planning prompt
- queue listr tasks before lazy renderer initialization completes
* fix: mark test-only MCP merge helpers as dead-code allowed
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: GitHub Actions <actions@github.com>
Summary
workflows/polish-workflow-output.ts— a DAG workflow that integrateslistr2andchalkinto the agent-relay workflow output systemcli.ts(listr2 step rendering) andrunner.ts(chalk color on log/broker/summary)--dry-run(0 errors, 0 warnings)Test plan
agent-relay run workflows/polish-workflow-output.tsand verify the workflow executes end-to-endcli.tsrenders steps with spinners / ✓ / ✗ via listr2runner.tslog output has chalk color on[workflow HH:MM],[broker], and summary tablepackages/sdkstill compiles cleanly after changes🤖 Generated with Claude Code