Skip to content

Commit 6bc04a4

Browse files
betegonclaude
andcommitted
refactor(init): use renderInlineMarkdown for spinner messages
Pipe spinner messages through the markdown rendering pipeline so file names, commands, and project names display as styled inline code in the terminal. Truncation happens on the plain markdown source before rendering, keeping truncateForTerminal simple. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 79e72c1 commit 6bc04a4

File tree

2 files changed

+26
-22
lines changed

2 files changed

+26
-22
lines changed

src/lib/init/wizard-runner.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { CLI_VERSION } from "../constants.js";
2525
import { getAuthToken } from "../db/auth.js";
2626
import { WizardError } from "../errors.js";
2727
import { terminalLink } from "../formatters/colors.js";
28+
import { renderInlineMarkdown } from "../formatters/markdown.js";
2829
import { resolveOrCreateTeam } from "../resolve-team.js";
2930
import { slugify } from "../utils.js";
3031
import {
@@ -112,7 +113,7 @@ export function describeLocalOp(payload: LocalOpPayload): string {
112113
const first = patches[0];
113114
if (patches.length === 1 && first) {
114115
const verb = patchActionVerb(first.action);
115-
return `${verb} ${basename(first.path)}...`;
116+
return `${verb} \`${basename(first.path)}\`...`;
116117
}
117118
const counts = patchActionCounts(patches);
118119
return `Applying ${patches.length} file changes (${counts})...`;
@@ -121,14 +122,14 @@ export function describeLocalOp(payload: LocalOpPayload): string {
121122
const cmds = payload.params.commands;
122123
const first = cmds[0];
123124
if (cmds.length === 1 && first) {
124-
return `Running ${first}...`;
125+
return `Running \`${first}\`...`;
125126
}
126-
return `Running ${cmds.length} commands (${first ?? "..."}, ...)...`;
127+
return `Running ${cmds.length} commands (\`${first ?? "..."}\`, ...)...`;
127128
}
128129
case "list-dir":
129130
return "Listing directory...";
130131
case "create-sentry-project":
131-
return `Creating project "${payload.params.name}" (${payload.params.platform})...`;
132+
return `Creating project \`${payload.params.name}\` (${payload.params.platform})...`;
132133
case "detect-sentry":
133134
return "Checking for existing Sentry setup...";
134135
default:
@@ -144,12 +145,12 @@ function describeFilePaths(verb: string, paths: string[]): string {
144145
return `${verb} files...`;
145146
}
146147
if (paths.length === 1) {
147-
return `${verb} ${basename(first)}...`;
148+
return `${verb} \`${basename(first)}\`...`;
148149
}
149150
if (paths.length === 2 && second) {
150-
return `${verb} ${basename(first)}, ${basename(second)}...`;
151+
return `${verb} \`${basename(first)}\`, \`${basename(second)}\`...`;
151152
}
152-
return `${verb} ${paths.length} files (${basename(first)}${second ? `, ${basename(second)}` : ""}, ...)...`;
153+
return `${verb} ${paths.length} files (\`${basename(first)}\`${second ? `, \`${basename(second)}\`` : ""}, ...)...`;
153154
}
154155

155156
/** Map a patch action to a user-facing verb. */
@@ -189,12 +190,12 @@ async function handleSuspendedStep(
189190

190191
if (payload.type === "local-op") {
191192
const message = describeLocalOp(payload);
192-
spin.message(truncateForTerminal(message));
193+
spin.message(renderInlineMarkdown(truncateForTerminal(message)));
193194

194195
const localResult = await handleLocalOp(payload, options);
195196

196197
if (localResult.message) {
197-
spin.stop(localResult.message);
198+
spin.stop(renderInlineMarkdown(localResult.message));
198199
spin.start("Processing...");
199200
}
200201

test/lib/init/wizard-runner.test.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -628,8 +628,11 @@ describe("runWizard", { timeout: TEST_TIMEOUT_MS }, () => {
628628
) as string[] | undefined;
629629
expect(call).toBeDefined();
630630
const msg = call?.[0] ?? "";
631-
expect(msg.length).toBeLessThanOrEqual(36);
632-
expect(msg.endsWith("…")).toBe(true);
631+
// The rendered message contains ANSI codes, so check visible content
632+
// biome-ignore lint/suspicious/noControlCharactersInRegex: stripping ANSI escape sequences
633+
const plain = msg.replace(/\x1b\[[^m]*m/g, "");
634+
expect(plain.length).toBeLessThanOrEqual(36);
635+
expect(plain.endsWith("…")).toBe(true);
633636
} finally {
634637
Object.defineProperty(process.stdout, "columns", {
635638
value: origColumns,
@@ -939,7 +942,7 @@ describe("describeLocalOp", () => {
939942
params: { paths: ["src/settings.py"] },
940943
})
941944
);
942-
expect(msg).toBe("Reading settings.py...");
945+
expect(msg).toBe("Reading `settings.py`...");
943946
});
944947

945948
test("two files shows both basenames", () => {
@@ -949,7 +952,7 @@ describe("describeLocalOp", () => {
949952
params: { paths: ["src/settings.py", "src/urls.py"] },
950953
})
951954
);
952-
expect(msg).toBe("Reading settings.py, urls.py...");
955+
expect(msg).toBe("Reading `settings.py`, `urls.py`...");
953956
});
954957

955958
test("three+ files shows count and first two basenames", () => {
@@ -961,7 +964,7 @@ describe("describeLocalOp", () => {
961964
},
962965
})
963966
);
964-
expect(msg).toBe("Reading 4 files (one.py, two.py, ...)...");
967+
expect(msg).toBe("Reading 4 files (`one.py`, `two.py`, ...)...");
965968
});
966969

967970
test("empty paths array", () => {
@@ -980,7 +983,7 @@ describe("describeLocalOp", () => {
980983
params: { paths: ["requirements.txt"] },
981984
})
982985
);
983-
expect(msg).toBe("Checking requirements.txt...");
986+
expect(msg).toBe("Checking `requirements.txt`...");
984987
});
985988

986989
test("multiple files shows count", () => {
@@ -990,7 +993,7 @@ describe("describeLocalOp", () => {
990993
params: { paths: ["a.py", "b.py", "c.py"] },
991994
})
992995
);
993-
expect(msg).toBe("Checking 3 files (a.py, b.py, ...)...");
996+
expect(msg).toBe("Checking 3 files (`a.py`, `b.py`, ...)...");
994997
});
995998
});
996999

@@ -1004,7 +1007,7 @@ describe("describeLocalOp", () => {
10041007
},
10051008
})
10061009
);
1007-
expect(msg).toBe("Creating sentry.py...");
1010+
expect(msg).toBe("Creating `sentry.py`...");
10081011
});
10091012

10101013
test("single modify shows verb and basename", () => {
@@ -1016,7 +1019,7 @@ describe("describeLocalOp", () => {
10161019
},
10171020
})
10181021
);
1019-
expect(msg).toBe("Modifying settings.py...");
1022+
expect(msg).toBe("Modifying `settings.py`...");
10201023
});
10211024

10221025
test("single delete shows verb and basename", () => {
@@ -1028,7 +1031,7 @@ describe("describeLocalOp", () => {
10281031
},
10291032
})
10301033
);
1031-
expect(msg).toBe("Deleting old.js...");
1034+
expect(msg).toBe("Deleting `old.js`...");
10321035
});
10331036

10341037
test("multiple patches shows count and breakdown", () => {
@@ -1056,7 +1059,7 @@ describe("describeLocalOp", () => {
10561059
params: { commands: ["pip install sentry-sdk"] },
10571060
})
10581061
);
1059-
expect(msg).toBe("Running pip install sentry-sdk...");
1062+
expect(msg).toBe("Running `pip install sentry-sdk`...");
10601063
});
10611064

10621065
test("multiple commands shows count and first", () => {
@@ -1068,7 +1071,7 @@ describe("describeLocalOp", () => {
10681071
},
10691072
})
10701073
);
1071-
expect(msg).toBe("Running 2 commands (pip install sentry-sdk, ...)...");
1074+
expect(msg).toBe("Running 2 commands (`pip install sentry-sdk`, ...)...");
10721075
});
10731076
});
10741077

@@ -1089,7 +1092,7 @@ describe("describeLocalOp", () => {
10891092
params: { name: "my-app", platform: "python-django" },
10901093
})
10911094
);
1092-
expect(msg).toBe('Creating project "my-app" (python-django)...');
1095+
expect(msg).toBe("Creating project `my-app` (python-django)...");
10931096
});
10941097
});
10951098
});

0 commit comments

Comments
 (0)