Skip to content

Commit b9a3715

Browse files
committed
chore(lint): enforce command output conventions via Biome plugins
Add lint rules to enforce PR #433 buildCommand conventions: - GritQL plugins ban stdout.write() and process.stdout in command files (src/commands/), using file()-scoped patterns that produce inline editor diagnostics and run as part of bun run lint. - noRestrictedImports override bans chalk in command files, directing to colorTag() from the markdown rendering pipeline. - Fix muted() usage in issue/view.ts to respect NO_COLOR and SENTRY_PLAIN_OUTPUT via the isPlainOutput() pattern.
1 parent a3c6a91 commit b9a3715

4 files changed

Lines changed: 44 additions & 4 deletions

File tree

biome.jsonc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
{
22
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
33
"extends": ["ultracite/core"],
4+
"plugins": [
5+
"./lint-rules/no-stdout-write-in-commands.grit",
6+
"./lint-rules/no-process-stdout-in-commands.grit"
7+
],
48
"files": {
59
"includes": ["!docs", "!test/init-eval/templates"]
610
},
@@ -77,6 +81,31 @@
7781
}
7882
}
7983
}
84+
},
85+
{
86+
// Commands must use colorTag() from markdown.ts — not raw chalk.
87+
// Raw chalk bypasses the plain-output pipeline (NO_COLOR, SENTRY_PLAIN_OUTPUT).
88+
"includes": ["src/commands/**/*.ts"],
89+
"linter": {
90+
"rules": {
91+
"style": {
92+
"noRestrictedImports": {
93+
"level": "error",
94+
"options": {
95+
"paths": {
96+
"@stricli/core": {
97+
"importNames": ["buildCommand"],
98+
"message": "Import buildCommand from '../lib/command.js' instead. The wrapper injects telemetry, --log-level, and --verbose."
99+
},
100+
"chalk": {
101+
"message": "Use colorTag() from formatters/markdown.js for colored output. Raw chalk bypasses the plain-output pipeline (NO_COLOR, SENTRY_PLAIN_OUTPUT)."
102+
}
103+
}
104+
}
105+
}
106+
}
107+
}
108+
}
80109
}
81110
]
82111
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
file($name, $body) where {
2+
$name <: r".*src/commands/.*",
3+
$body <: contains `process.stdout` as $access,
4+
register_diagnostic(span=$access, message="Don't use process.stdout in commands. Yield CommandOutput and let the buildCommand wrapper handle output.")
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
file($name, $body) where {
2+
$name <: r".*src/commands/.*",
3+
$body <: contains `stdout.write($args)` as $call,
4+
register_diagnostic(span=$call, message="Don't call stdout.write() in commands. Yield CommandOutput instead and let the buildCommand wrapper handle output rendering.")
5+
}

src/commands/issue/view.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { buildCommand } from "../../lib/command.js";
1212
import {
1313
formatEventDetails,
1414
formatIssueDetails,
15+
isPlainOutput,
1516
muted,
1617
} from "../../lib/formatters/index.js";
1718
import { CommandOutput } from "../../lib/formatters/output.js";
@@ -159,11 +160,11 @@ export const viewCommand = buildCommand({
159160
if (spanTreeResult) {
160161
spanTreeLines = spanTreeResult.lines;
161162
} else if (!orgSlug) {
162-
spanTreeLines = [
163-
muted("\nOrganization context required to fetch span tree."),
164-
];
163+
const msg = "\nOrganization context required to fetch span tree.";
164+
spanTreeLines = [isPlainOutput() ? msg : muted(msg)];
165165
} else if (!event) {
166-
spanTreeLines = [muted("\nCould not fetch event to display span tree.")];
166+
const msg = "\nCould not fetch event to display span tree.";
167+
spanTreeLines = [isPlainOutput() ? msg : muted(msg)];
167168
}
168169

169170
const trace = spanTreeResult?.success

0 commit comments

Comments
 (0)