Skip to content

Commit 200ac9c

Browse files
authored
refactor(3/12): add rendering engine and output formatting (#321)
## Summary This is **PR 3 of 12** in a stacked PR series that decouples the rendering pipeline from MCP transport. Depends on PR 2 (event types). This PR is mostly additive with minor changes to the existing next-steps renderer. Introduces the rendering engine that converts pipeline events into human-readable text. This is the core abstraction that enables the rendering pipeline refactor: tools emit events, and the rendering engine decides how to format them based on the output strategy (text for humans, JSON for machine consumption). ### Architecture **Render Session** (`src/rendering/render.ts`): The central abstraction. A session collects events, renders them into text, tracks error state, and supports image attachments. Two strategies: - `text`: Human-readable output with headers, status lines, grouped diagnostics, and ANSI colors (via `terminal-output.ts`) - `json`: JSONL format -- one JSON object per event per line The session exposes `emit(event)`, `finalize()`, `isError()`, and `getAttachments()`. The MCP boundary creates a session, passes `emit` to the tool handler, then calls `finalize()` to get the rendered string for the `ToolResponse`. The CLI boundary does the same but writes incrementally to stdout. **Event Formatting** (`src/utils/renderers/event-formatting.ts`): Pure functions that convert each `PipelineEvent` kind into formatted text. Handles header layout, status line icons, detail trees with indentation, diagnostic grouping (warnings batched until summary), and progress lines. These are the same formatters used by both strategies. **CLI Text Renderer** (`src/utils/renderers/cli-text-renderer.ts`): Wraps event formatting with terminal-aware features -- ANSI color codes, transient progress line overwriting via `CliProgressReporter`. **Next-Steps Renderer** (`src/utils/responses/next-steps-renderer.ts`): Simplified to remove runtime-conditional formatting. One canonical format for next-steps regardless of output target. ### Why rendering is separate from transport Previously, renderers were tightly coupled to their output target (MCP renderer, CLI renderer, JSONL renderer). This meant three parallel rendering paths that had to stay in sync. The new model has one rendering engine with pluggable strategies, and the output target is just a post-render concern (write to stdout vs wrap in ToolResponse). ## Stack navigation - PR 1/12: Remove deprecated logging tools - PR 2/12: Pipeline event types, parsers, and event builders - **PR 3/12** (this PR): Rendering engine and output formatting - PR 4/12: Build/test utility extraction, platform steps, xcodebuild pipeline - PR 5/12: Runtime handler contract and tool invoker - PR 6-9/12: Tool migrations - PR 10-12/12: Boundaries, config, tests ## Test plan - [ ] `npx vitest run` passes -- new tests for event formatting and CLI text renderer - [ ] Render session correctly tracks error state from status-line events - [ ] JSON strategy produces valid JSONL output - [ ] Text strategy groups diagnostics correctly (warnings batched, errors immediate)
1 parent 4cc895d commit 200ac9c

16 files changed

Lines changed: 1953 additions & 246 deletions

package-lock.json

Lines changed: 161 additions & 49 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
"@sentry/node": "^10.43.0",
8181
"bplist-parser": "^0.3.2",
8282
"chokidar": "^5.0.0",
83+
"glob": "^13.0.6",
8384
"uuid": "^11.1.0",
8485
"yaml": "^2.4.5",
8586
"yargs": "^17.7.2",

0 commit comments

Comments
 (0)