Skip to content

refactor: unify all command functions as async generators#413

Closed
BYK wants to merge 1 commit intomainfrom
feat/streaming-command
Closed

refactor: unify all command functions as async generators#413
BYK wants to merge 1 commit intomainfrom
feat/streaming-command

Conversation

@BYK
Copy link
Member

@BYK BYK commented Mar 12, 2026

Summary

All command functions now use async generator signatures (async *func). The framework iterates each yielded value through the existing OutputConfig rendering pipeline.

Key insight

Every command function becomes an async generator. No detection, no branching, no special cases. The framework always does for await (const value of generator):

  • Non-streaming commands: yield once and return
  • Streaming commands (log list --follow): yield multiple times
  • Void commands (help, auth/token): return without yielding

Changes

Framework (command.ts)

  • SentryCommandFunction → returns AsyncGenerator<unknown, void, undefined>
  • Wrapper uses for await...of to iterate and render each yielded value
  • Removed sync/async/Promise branching — one code path

Output rendering (output.ts)

  • Extracted applyJsonExclude() and writeTransformedJson() helpers (reduced complexity)
  • jsonTransform returning undefined now suppresses the chunk (streaming text-only chunks)
  • human() returning empty string suppresses output (streaming data-only chunks in human mode)

All ~27 command files

  • async funcasync *func
  • return { data, hint }yield { data, hint }
  • Commands without output config get biome-ignore for useYield

log/list follow mode

  • drainStreamingOutput replaced by yield* delegation to yieldStreamChunks() generator
  • Human mode: yields chunks as-is for the unified OutputConfig
  • JSON mode: expands data chunks into one yield per log entry (JSONL)

Deleted: streaming-command.ts (151 lines)

  • drainStreamingOutput() and StreamingOutputConfig — no longer needed

Stats

  • 34 files changed, +259/-390 (net -131 lines)
  • Typecheck: 0 errors
  • Lint: 0 errors (379 files)
  • Tests: 1584 pass, 0 fail (15733 assertions across 53 files)

@github-actions
Copy link
Contributor

github-actions bot commented Mar 12, 2026

Semver Impact of This PR

🟢 Patch (bug fixes)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

Init

  • Add --team flag to relay team selection to project creation by MathurAditya724 in #403
  • Enforce canonical feature display order by betegon in #388
  • Accept multiple delimiter formats for --features flag by betegon in #386
  • Add git safety checks before wizard modifies files by betegon in #379
  • Add experimental warning before wizard runs by betegon in #378
  • Add init command for guided Sentry project setup by betegon in #283

Issue List

  • Auto-compact when table exceeds terminal height by BYK in #395
  • Redesign table to match Sentry web UI by BYK in #372

Other

  • (trial) Auto-prompt for Seer trial + sentry trial list/start commands by BYK in #399
  • Support SENTRY_HOST as alias for SENTRY_URL by betegon in #409
  • Add --dry-run flag to mutating commands by BYK in #387
  • Return-based output with OutputConfig on buildCommand by BYK in #380
  • Add --fields flag for context-window-friendly JSON output by BYK in #373
  • Magic @ selectors (@latest, @most_frequent) for issue commands by BYK in #371
  • Input hardening against agent hallucinations by BYK in #370
  • Add response caching for read-only API calls by BYK in #330

Bug Fixes 🐛

Init

  • Remove implementation detail from help text by betegon in #385
  • Truncate uncommitted file list to first 5 entries by MathurAditya724 in #381

Other

  • (api) Convert --data to query params for GET requests by BYK in #383
  • (docs) Remove double borders and fix column alignment on landing page tables by betegon in #369
  • Show human-friendly names in trial list and surface plan trials by BYK in #412
  • Add trace ID validation to trace view + UUID dash-stripping by BYK in #375

Internal Changes 🔧

Init

  • Remove --force flag by betegon in #377
  • Remove dead determine-pm step label by betegon in #374

Other

  • (log/list) Convert non-follow paths to return CommandOutput by BYK in #410
  • Unify all command functions as async generators by BYK in #413
  • Convert list command handlers to return data instead of writing stdout by BYK in #404
  • Split api-client.ts into focused domain modules by BYK in #405
  • Migrate non-streaming commands to CommandOutput with markdown rendering by BYK in #398
  • Convert Tier 2-3 commands to return-based output and consola by BYK in #394
  • Convert remaining Tier 1 commands to return-based output by BYK in #382
  • Converge Tier 1 commands to writeOutput helper by BYK in #376

Other

  • Minify JSON on read and pretty-print on write in init local ops by MathurAditya724 in #396

🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 12, 2026

Codecov Results 📊

104 passed | Total: 104 | Pass Rate: 100% | Execution Time: 0ms

📊 Comparison with Base Branch

Metric Change
Total Tests
Passed Tests
Failed Tests
Skipped Tests

✨ No test changes detected

All tests are passing successfully.

✅ Patch coverage is 100.00%. Project has 697 uncovered lines.
✅ Project coverage is 96.67%. Comparing base (base) to head (head).

Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    96.66%    96.67%    +0.01%
==========================================
  Files          159       160        +1
  Lines        20855     20914       +59
  Branches         0         0         —
==========================================
+ Hits         20158     20217       +59
- Misses         697       697         —
- Partials         0         0         —

Generated by Codecov Action

@BYK BYK force-pushed the feat/streaming-command branch from e7ea4be to f81ed82 Compare March 12, 2026 20:14
@BYK BYK force-pushed the feat/streaming-command branch from f81ed82 to 1eb34eb Compare March 12, 2026 20:25
@BYK BYK changed the title feat: add buildStreamingCommand + migrate log/list follow to generator refactor: unify all command functions as async generators Mar 12, 2026
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

if (fields && fields.length > 0) {
return logs.map((log) => filterFields(log, fields));
}
return logs;
Copy link

Choose a reason for hiding this comment

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

JSONL follow-mode outputs array-wrapped log entries

High Severity

In follow mode with --json, each JSONL line is emitted as a one-element array [{...}] instead of a bare object {...}. yieldStreamChunks wraps each individual log in { kind: "data", logs: [log] }, and jsonTransformLogOutput returns logs (the single-element array) directly. writeTransformedJson then serializes that array as-is. The old writeLogs called writeJson(stdout, log, fields) per log, emitting bare objects. This breaks the JSONL output contract for existing consumers.

Additional Locations (1)
Fix in Cursor Fix in Web

@BYK BYK force-pushed the feat/streaming-command branch 3 times, most recently from c648183 to f53bc98 Compare March 12, 2026 22:00
@BYK BYK closed this Mar 12, 2026
@BYK BYK reopened this Mar 12, 2026
All command functions now use async generator signatures. The framework
iterates each yielded value through the existing OutputConfig rendering
pipeline. Non-streaming commands yield once and return; streaming
commands (log list --follow) yield multiple times.

Key changes:
- buildCommand: func returns AsyncGenerator, wrapper uses for-await-of
- All ~27 command files: async func → async *func, return → yield
- log/list follow mode: drainStreamingOutput replaced by yield delegation
- Delete streaming-command.ts (151 lines) — absorbed into buildCommand
- output.ts: extracted applyJsonExclude/writeTransformedJson helpers,
  support undefined suppression for streaming text-only chunks

No new dependencies. Net -131 lines.
@BYK BYK force-pushed the feat/streaming-command branch from ee063a5 to ff35175 Compare March 12, 2026 22:05
@BYK BYK closed this Mar 12, 2026
@BYK BYK deleted the feat/streaming-command branch March 12, 2026 22:08
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.

1 participant