Skip to content

feat: workflow to polish CLI output with listr2 + chalk#585

Merged
khaliqgant merged 23 commits into
mainfrom
feature/polish-workflow-output
Mar 19, 2026
Merged

feat: workflow to polish CLI output with listr2 + chalk#585
khaliqgant merged 23 commits into
mainfrom
feature/polish-workflow-output

Conversation

@khaliqgant

@khaliqgant khaliqgant commented Mar 18, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds workflows/polish-workflow-output.ts — a DAG workflow that integrates listr2 and chalk into the agent-relay workflow output system
  • Claude lead plans the integration; two parallel Codex workers implement cli.ts (listr2 step rendering) and runner.ts (chalk color on log/broker/summary)
  • Verified with --dry-run (0 errors, 0 warnings)

Test plan

  • Run agent-relay run workflows/polish-workflow-output.ts and verify the workflow executes end-to-end
  • Confirm cli.ts renders steps with spinners / ✓ / ✗ via listr2
  • Confirm runner.ts log output has chalk color on [workflow HH:MM], [broker], and summary table
  • Confirm packages/sdk still compiles cleanly after changes

🤖 Generated with Claude Code


Open with Devin

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@khaliqgant khaliqgant force-pushed the feature/polish-workflow-output branch from c668b92 to 4e77bdb Compare March 18, 2026 12:22
khaliqgant and others added 2 commits March 18, 2026 13:26
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… types

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
devin-ai-integration[bot]

This comment was marked as resolved.

khaliqgant and others added 2 commits March 18, 2026 13:53
…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>
Comment thread packages/sdk/src/workflows/runner.ts Fixed
khaliqgant and others added 2 commits March 18, 2026 13:59
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…flows

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
devin-ai-integration[bot]

This comment was marked as resolved.

khaliqgant and others added 2 commits March 18, 2026 14:12
…steps

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dering

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
devin-ai-integration[bot]

This comment was marked as resolved.

… 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>
devin-ai-integration[bot]

This comment was marked as resolved.

- 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
devin-ai-integration[bot]

This comment was marked as resolved.

- 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
devin-ai-integration[bot]

This comment was marked as resolved.

khaliqgant and others added 7 commits March 19, 2026 13:13
* 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.
devin-ai-integration[bot]

This comment was marked as resolved.

- 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.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 21 additional findings in Devin Review.

Open in Devin Review

Comment on lines +6 to +8
try {
execSync('npx trail start "Polish workflow output with listr2 + chalk"', { stdio: 'ignore' });
} catch {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@khaliqgant khaliqgant merged commit cd54fce into main Mar 19, 2026
40 of 41 checks passed
@khaliqgant khaliqgant deleted the feature/polish-workflow-output branch March 19, 2026 21:22
khaliqgant added a commit that referenced this pull request Mar 25, 2026
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants