Skip to content

Commit 73276e5

Browse files
committed
feat(formatters): render all terminal output via marked-terminal
Add marked-terminal as the rendering engine for all human-readable CLI output. All detail views (issue, event, org, project, log, trace, Seer) now build markdown internally and render through marked-terminal, producing Unicode box-drawing tables and styled headings. Streaming list output (log/trace rows) stays row-by-row for compatibility with follow/watch modes. - Add src/lib/formatters/markdown.ts with central renderMarkdown() utility - Rewrite formatters to return rendered string instead of string[] - Convert all detail sections to markdown tables (| **Label** | value | pattern) - Convert Seer root cause and solution output to fenced code blocks - Remove divider(), formatTable() dead code from human.ts - Escape SDK names in code spans to prevent markdown transformation of underscores - Update all formatter tests for new string return type and content-based checks
1 parent ad2f896 commit 73276e5

File tree

28 files changed

+1082
-1036
lines changed

28 files changed

+1082
-1036
lines changed

AGENTS.md

Lines changed: 96 additions & 2 deletions
Large diffs are not rendered by default.

bun.lock

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

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"@stricli/auto-complete": "^1.2.4",
3535
"@stricli/core": "^1.2.4",
3636
"@types/bun": "latest",
37+
"@types/marked-terminal": "^6.1.1",
3738
"@types/node": "^22",
3839
"@types/qrcode-terminal": "^0.12.2",
3940
"@types/semver": "^7.7.1",
@@ -63,5 +64,9 @@
6364
"packageManager": "bun@1.3.9",
6465
"patchedDependencies": {
6566
"@stricli/core@1.2.5": "patches/@stricli%2Fcore@1.2.5.patch"
67+
},
68+
"dependencies": {
69+
"marked": "^15",
70+
"marked-terminal": "^7.3.0"
6671
}
6772
}

src/commands/event/view.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,7 @@ type HumanOutputOptions = {
5454
function writeHumanOutput(stdout: Writer, options: HumanOutputOptions): void {
5555
const { event, detectedFrom, spanTreeLines } = options;
5656

57-
const lines = formatEventDetails(event, `Event ${event.eventID}`);
58-
59-
// Skip leading empty line for standalone display
60-
const output = lines.slice(1);
61-
stdout.write(`${output.join("\n")}\n`);
57+
stdout.write(`${formatEventDetails(event, `Event ${event.eventID}`)}\n`);
6258

6359
if (spanTreeLines && spanTreeLines.length > 0) {
6460
stdout.write(`${spanTreeLines.join("\n")}\n`);

src/commands/issue/explain.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,7 @@ export const explainCommand = buildCommand({
107107
}
108108

109109
// Human-readable output
110-
const lines = formatRootCauseList(causes);
111-
stdout.write(`${lines.join("\n")}\n`);
110+
stdout.write(`${formatRootCauseList(causes)}\n`);
112111
writeFooter(
113112
stdout,
114113
`To create a plan, run: sentry issue plan ${issueArg}`

src/commands/issue/list.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import {
3535
ValidationError,
3636
} from "../../lib/errors.js";
3737
import {
38-
divider,
3938
type FormatShortIdOptions,
4039
formatIssueListHeader,
4140
formatIssueRow,
@@ -118,7 +117,7 @@ function writeListHeader(
118117
): void {
119118
stdout.write(`${title}:\n\n`);
120119
stdout.write(muted(`${formatIssueListHeader(isMultiProject)}\n`));
121-
stdout.write(`${divider(isMultiProject ? 96 : 80)}\n`);
120+
stdout.write(muted(`${"─".repeat(isMultiProject ? 96 : 80)}\n`));
122121
}
123122

124123
/** Issue with formatting options attached */

src/commands/issue/plan.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,7 @@ function outputSolution(options: OutputSolutionOptions): void {
125125
}
126126

127127
if (solution) {
128-
const lines = formatSolution(solution);
129-
stdout.write(`${lines.join("\n")}\n`);
128+
stdout.write(`${formatSolution(solution)}\n`);
130129
} else {
131130
stderr.write("No solution found. Check the Sentry web UI for details.\n");
132131
}

src/commands/issue/view.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,13 @@ type HumanOutputOptions = {
5757
function writeHumanOutput(stdout: Writer, options: HumanOutputOptions): void {
5858
const { issue, event, spanTreeLines } = options;
5959

60-
const issueLines = formatIssueDetails(issue);
61-
stdout.write(`${issueLines.join("\n")}\n`);
60+
stdout.write(`${formatIssueDetails(issue)}\n`);
6261

6362
if (event) {
6463
// Pass issue permalink for constructing replay links
65-
const eventLines = formatEventDetails(
66-
event,
67-
"Latest Event",
68-
issue.permalink
64+
stdout.write(
65+
`${formatEventDetails(event, "Latest Event", issue.permalink)}\n`
6966
);
70-
stdout.write(`${eventLines.join("\n")}\n`);
7167
}
7268

7369
if (spanTreeLines && spanTreeLines.length > 0) {

src/commands/log/view.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,7 @@ function writeHumanOutput(
9292
orgSlug: string,
9393
detectedFrom?: string
9494
): void {
95-
const lines = formatLogDetails(log, orgSlug);
96-
stdout.write(`${lines.join("\n")}\n`);
95+
stdout.write(`${formatLogDetails(log, orgSlug)}\n`);
9796

9897
if (detectedFrom) {
9998
stdout.write(`\nDetected from ${detectedFrom}\n`);

src/commands/project/view.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { openInBrowser } from "../../lib/browser.js";
1515
import { buildCommand } from "../../lib/command.js";
1616
import { AuthError, ContextError } from "../../lib/errors.js";
1717
import {
18-
divider,
1918
formatProjectDetails,
2019
writeJson,
2120
writeOutput,
@@ -183,13 +182,11 @@ function writeMultipleProjects(
183182
const target = targets[i];
184183

185184
if (i > 0) {
186-
stdout.write(`\n${divider(60)}\n\n`);
185+
stdout.write(`\n${"─".repeat(60)}\n\n`);
187186
}
188187

189188
if (project) {
190-
const details = formatProjectDetails(project, dsn);
191-
stdout.write(details.join("\n"));
192-
stdout.write("\n");
189+
stdout.write(`${formatProjectDetails(project, dsn)}\n`);
193190
if (target?.detectedFrom) {
194191
stdout.write(`\nDetected from: ${target.detectedFrom}\n`);
195192
}

0 commit comments

Comments
 (0)