Skip to content

Commit f111da6

Browse files
committed
refactor: unify all command functions as async generators
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.
1 parent 585b88a commit f111da6

35 files changed

+590
-463
lines changed

AGENTS.md

Lines changed: 20 additions & 46 deletions
Large diffs are not rendered by default.

src/commands/api.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,7 +1155,7 @@ export const apiCommand = buildCommand({
11551155
n: "dry-run",
11561156
},
11571157
},
1158-
async func(this: SentryContext, flags: ApiFlags, endpoint: string) {
1158+
async *func(this: SentryContext, flags: ApiFlags, endpoint: string) {
11591159
const { stdin } = this;
11601160

11611161
const normalizedEndpoint = normalizeEndpoint(endpoint);
@@ -1168,14 +1168,15 @@ export const apiCommand = buildCommand({
11681168

11691169
// Dry-run mode: preview the request that would be sent
11701170
if (flags["dry-run"]) {
1171-
return {
1171+
yield {
11721172
data: {
11731173
method: flags.method,
11741174
url: resolveRequestUrl(normalizedEndpoint, params),
11751175
headers: resolveEffectiveHeaders(headers, body),
11761176
body: body ?? null,
11771177
},
11781178
};
1179+
return;
11791180
}
11801181

11811182
const verbose = flags.verbose && !flags.silent;
@@ -1210,6 +1211,7 @@ export const apiCommand = buildCommand({
12101211
throw new OutputError(response.body);
12111212
}
12121213

1213-
return { data: response.body };
1214+
yield { data: response.body };
1215+
return;
12141216
},
12151217
});

src/commands/auth/login.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ export const loginCommand = buildCommand({
4848
},
4949
},
5050
},
51-
async func(this: SentryContext, flags: LoginFlags): Promise<void> {
51+
// biome-ignore lint/correctness/useYield: void generator — writes to stdout directly, will be migrated to yield pattern later
52+
async *func(this: SentryContext, flags: LoginFlags) {
5253
// Check if already authenticated
5354
if (await isAuthenticated()) {
5455
if (isEnvTokenActive()) {

src/commands/auth/logout.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,12 @@ export const logoutCommand = buildCommand({
3636
parameters: {
3737
flags: {},
3838
},
39-
async func(this: SentryContext): Promise<{ data: LogoutResult }> {
39+
async *func(this: SentryContext) {
4040
if (!(await isAuthenticated())) {
41-
return {
41+
yield {
4242
data: { loggedOut: false, message: "Not currently authenticated." },
4343
};
44+
return;
4445
}
4546

4647
if (isEnvTokenActive()) {
@@ -55,11 +56,12 @@ export const logoutCommand = buildCommand({
5556
const configPath = getDbPath();
5657
await clearAuth();
5758

58-
return {
59+
yield {
5960
data: {
6061
loggedOut: true,
6162
configPath,
6263
},
6364
};
65+
return;
6466
},
6567
});

src/commands/auth/refresh.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ Examples:
6868
},
6969
},
7070
},
71-
async func(this: SentryContext, flags: RefreshFlags) {
71+
async *func(this: SentryContext, flags: RefreshFlags) {
7272
// Env var tokens can't be refreshed
7373
if (isEnvTokenActive()) {
7474
const envVar = getActiveEnvVarName();
@@ -104,6 +104,7 @@ Examples:
104104
: undefined,
105105
};
106106

107-
return { data: payload };
107+
yield { data: payload };
108+
return;
108109
},
109110
});

src/commands/auth/status.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export const statusCommand = buildCommand({
155155
},
156156
aliases: FRESH_ALIASES,
157157
},
158-
async func(this: SentryContext, flags: StatusFlags) {
158+
async *func(this: SentryContext, flags: StatusFlags) {
159159
applyFreshFlag(flags);
160160

161161
const auth = getAuthConfig();
@@ -189,6 +189,7 @@ export const statusCommand = buildCommand({
189189
verification: await verifyCredentials(),
190190
};
191191

192-
return { data };
192+
yield { data };
193+
return;
193194
},
194195
});

src/commands/auth/token.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ export const tokenCommand = buildCommand({
2020
"when stdout is not a TTY (e.g., when piped).",
2121
},
2222
parameters: {},
23-
func(this: SentryContext): void {
23+
// biome-ignore lint/correctness/useYield: void generator — writes to stdout directly
24+
// biome-ignore lint/suspicious/useAwait: sync body but async generator required by buildCommand
25+
async *func(this: SentryContext) {
2426
const { stdout } = this;
2527

2628
const token = getAuthToken();

src/commands/auth/whoami.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export const whoamiCommand = buildCommand({
4343
},
4444
aliases: FRESH_ALIASES,
4545
},
46-
async func(this: SentryContext, flags: WhoamiFlags) {
46+
async *func(this: SentryContext, flags: WhoamiFlags) {
4747
applyFreshFlag(flags);
4848

4949
if (!(await isAuthenticated())) {
@@ -65,6 +65,7 @@ export const whoamiCommand = buildCommand({
6565
// Cache update failure is non-essential — user identity was already fetched.
6666
}
6767

68-
return { data: user };
68+
yield { data: user };
69+
return;
6970
},
7071
});

src/commands/cli/feedback.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ export const feedbackCommand = buildCommand({
4242
},
4343
},
4444
},
45-
async func(
45+
async *func(
4646
this: SentryContext,
4747
// biome-ignore lint/complexity/noBannedTypes: Stricli requires empty object for commands with no flags
4848
_flags: {},
4949
...messageParts: string[]
50-
): Promise<{ data: FeedbackResult }> {
50+
) {
5151
const message = messageParts.join(" ");
5252

5353
if (!message.trim()) {
@@ -66,11 +66,12 @@ export const feedbackCommand = buildCommand({
6666
// Flush to ensure feedback is sent before process exits
6767
const sent = await Sentry.flush(3000);
6868

69-
return {
69+
yield {
7070
data: {
7171
sent,
7272
message,
7373
},
7474
};
75+
return;
7576
},
7677
});

src/commands/cli/fix.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ export const fixCommand = buildCommand({
678678
},
679679
},
680680
},
681-
async func(this: SentryContext, flags: FixFlags) {
681+
async *func(this: SentryContext, flags: FixFlags) {
682682
const dbPath = getDbPath();
683683
const dryRun = flags["dry-run"];
684684

@@ -734,6 +734,7 @@ export const fixCommand = buildCommand({
734734
throw new OutputError(result);
735735
}
736736

737-
return { data: result };
737+
yield { data: result };
738+
return;
738739
},
739740
});

0 commit comments

Comments
 (0)