Skip to content

refactor: converge Tier 1 commands to writeOutput helper#376

Merged
BYK merged 1 commit intomainfrom
feat/write-output-convergence
Mar 10, 2026
Merged

refactor: converge Tier 1 commands to writeOutput helper#376
BYK merged 1 commit intomainfrom
feat/write-output-convergence

Conversation

@BYK
Copy link
Copy Markdown
Member

@BYK BYK commented Mar 10, 2026

Phase 2: writeOutput convergence

Builds on #373 (output: "json" centralization).

Enhance writeOutput with two new options and migrate 3 Tier 1 commands to use it.

New options on writeOutput

  • footer?: string — muted hint after human output, suppressed in JSON mode. Replaces separate writeFooter() calls.
  • jsonData?: J — separate data object for JSON when the serialized shape differs from the human formatter's input.

Commands migrated

Command What changed
auth/whoami jsonData narrows user to {id, name, username, email} for JSON
auth/refresh Inline formatHuman replaces 3-branch if/else
issue/explain footer replaces separate writeFooter() call

Commands with multi-part output or divergent data assembly (issue/view, event/view, trace/view, project/create, log/view) are intentionally left as-is — they don't fit the single-formatter pattern.

Tests

16 new tests in test/lib/formatters/output.test.ts cover JSON mode, human mode, footer, detectedFrom, and jsonData divergence.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 10, 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 init command for guided Sentry project setup by betegon in #283
  • (issue-list) Redesign table to match Sentry web UI by BYK in #372
  • 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 🐛

  • (docs) Remove double borders and fix column alignment on landing page tables by betegon in #369
  • 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

  • Converge Tier 1 commands to writeOutput helper by BYK in #376

🤖 This preview updates automatically when you update the PR.

@BYK BYK force-pushed the feat/write-output-convergence branch from f5f6ab3 to c42840e Compare March 10, 2026 10:12
Enhance writeOutput with footer and jsonData options, migrate
auth/whoami, auth/refresh, and issue/explain to use it.

- footer: muted hint after human output, suppressed in JSON mode
- jsonData: separate JSON data when shapes diverge from human formatter
- 16 new tests in test/lib/formatters/output.test.ts
@BYK BYK force-pushed the feat/write-output-convergence branch from c42840e to 8127a48 Compare March 10, 2026 10:16
@github-actions
Copy link
Copy Markdown
Contributor

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 898 uncovered lines.
✅ Project coverage is 95.46%. Comparing base (base) to head (head).

Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    95.45%    95.46%    +0.01%
==========================================
  Files          141       141         —
  Lines        19768     19758       -10
  Branches         0         0         —
==========================================
+ Hits         18868     18860        -8
- Misses         900       898        -2
- Partials         0         0         —

Generated by Codecov Action

@BYK BYK marked this pull request as ready for review March 10, 2026 11:25
@BYK BYK merged commit 23b4f98 into main Mar 10, 2026
22 checks passed
@BYK BYK deleted the feat/write-output-convergence branch March 10, 2026 12:03
BYK added a commit that referenced this pull request Mar 10, 2026
## Summary

Phase 3 of the output convergence plan ([Phase 1:
#373](#373), [Phase 2:
#376](#376)).

Commands can now declare an `OutputConfig` on `buildCommand` and return
bare data from `func`. The wrapper intercepts the return value and
renders automatically — selecting human vs JSON format based on
`--json`, applying `--fields` filtering, and writing to stdout. Runtime
hints like detection source or next-step footers use `[data, { hint }]`
tuples.

### What changed

**Core infrastructure** (`src/lib/formatters/output.ts`,
`src/lib/command.ts`):
- `OutputConfig<T>` — declared on `buildCommand` with `human` formatter
- `OutputMeta` — runtime hints (`{ hint?: string }`) returned via tuple
- `renderCommandOutput()` — renders data using config + merged runtime
context
- `buildCommand` `output` field accepts two forms:
  - `"json"` (string) — flag injection only (`--json`, `--fields`)
  - `{ json: true, human: fn }` — flag injection + auto-render
- Detects bare data vs `[data, meta]` tuple returns; `void`/`Error`
returns are ignored
- Renamed `detectedFrom` → `hint` throughout the output layer (callers
compose full message)

**4 Category A commands migrated** to return-based pattern:
- `auth/whoami` — `return user`
- `auth/refresh` — `return payload` with `formatRefreshResult` in config
- `issue/explain` — `return [causes, { hint }]` for next-step footer
- `org/view` — `return [org, { hint }]` for detection source, or bare
`org`

**jsonData eliminated** — single canonical data object for both JSON and
human renderers. The `--fields` flag handles field selection for
context-window-friendly output.

**JSON shapes normalized** for consistent `jq` ergonomics:
- `issue/view` — always includes `event: null` instead of omitting the
key
- `log/view` — always emits array (was single object for single ID)
- `project/view` — always emits array (was single object for single
project)

**Removed** (replaced by simpler pattern):
- `OutputResult<T, J>` branded type
- `output()` helper function
- `isOutputResult()` / `renderOutputResult()` functions
- `WriteOutputDivergentOptions<T, J>` type and `jsonData` from all
output APIs

**Tests**: All assertions updated for new shapes. Zero regressions (260
pre-existing failures on main, same on branch).

### Design decisions

- **Two-form output**: `"json"` for flag-only injection (most commands),
`OutputConfig` for full auto-render (4 migrated commands). No breaking
changes to existing `output: "json"` commands.
- **Bare return, not branded wrapper**: Commands return plain data
instead of `output(data, opts)`. Simpler, less ceremony, no brand symbol
machinery.
- **`[data, { hint }]` for runtime context**: Hints depend on
execution-time values (resolved issue arg, detection source). Declared
at return time, not build time.
- **`hint` replaces `detectedFrom` + `footer`**: Single generic field.
Callers compose the full text.
- **No jsonData**: One data shape for both human and JSON renderers. Use
`--fields` to control what appears in JSON output.
- **Always-array JSON**: Commands that return data return arrays even
for single results, for consistent `jq` pipelines.
- **Complex commands deferred**: event/view, trace/view, project/create,
issue/plan have `--web`, polling, stderr progress, etc. These need a
more advanced pattern (likely `buildStreamingCommand` variant) in
follow-up PRs.

### Stats
14 files changed, 756 insertions, 305 deletions
BYK added a commit that referenced this pull request Mar 10, 2026
Convert event view, issue view, issue plan, project create, and trace
view to the new return-based output pattern where commands return
{data} and the framework handles JSON serialization and human
formatting.

Each command now declares an output config with json: true and a human
formatter function, replacing manual stdout.write + writeJson calls.

Changes:
- event/view: extract buildEventData + formatEventOutput
- issue/view: extract buildIssueData + formatIssueOutput
- issue/plan: extract buildPlanData + formatPlanOutput, remove
  outputSolution helper
- project/create: extract formatProjectCreateOutput
- trace/view: extract buildTraceData + formatTraceOutput

Infrastructure:
- Add OutputResult type export from lib/command.ts
- Add writeHuman helper to formatters/output.ts for consistent
  newline-terminated human output
- Update tests to match new return signatures

Part of the output convergence plan (PR sequence #373#376#380).
BYK added a commit that referenced this pull request Mar 10, 2026
)

## Summary

Convert 5 remaining Tier 1 commands to the return-based
`CommandOutput<T>` pattern introduced in #380.

Each command now returns `{ data, hint?, footer? }` and declares an
`OutputConfig` with `json: true` and a `human` formatter — the framework
handles JSON serialization and human-readable rendering.

## Commands converted

| Command | Human formatter | Return shape |
|---------|----------------|-------------|
| `event/view` | `formatEventView()` | `{ data: { event, trace,
spanTreeLines }, hint }` |
| `issue/view` | `formatIssueView()` | `{ data: { issue, event, trace,
spanTreeLines }, footer }` |
| `issue/plan` | `formatPlanOutput()` | `{ data: { run_id, status,
solution } }` |
| `project/create` | `formatProjectCreated()` | `{ data:
ProjectCreatedResult }` |
| `trace/view` | `formatTraceView()` | `{ data: { summary, spans,
spanTreeLines }, footer }` |

## Infrastructure changes

- Added `footer?: string` to `CommandOutput<T>` and `RenderContext`
- `renderCommandOutput()` now renders footer via `writeFooter()`
- `handleReturnValue` in `command.ts` passes `value.footer` through

## What was removed

- `writeHumanOutput()` from trace/view (replaced by `formatTraceView`)
- `outputSolution()` from issue/plan (replaced by `formatPlanOutput` +
`buildPlanData`)
- Manual `writeJson`/`writeFooter`/`stdout.write` calls from all 5
commands
- `Writer` type imports (no longer needed)

## Test updates

- `test/commands/trace/view.func.test.ts`: `writeHumanOutput` tests
replaced with `formatTraceView` pure function tests
- `test/commands/project/create.test.ts`: `parsed.slug` →
`parsed.project.slug` (JSON shape now uses full `ProjectCreatedResult`)

Net: **-33 lines** (188 insertions, 221 deletions)

Part of the output convergence plan: #373#376#380 → this PR
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