Skip to content

Commit 869b506

Browse files
committed
fix(cli): enhance welcome screen layout for better terminal width handling
1 parent 3c2c5ca commit 869b506

2 files changed

Lines changed: 55 additions & 2 deletions

File tree

‎packages/cli/src/tests/welcome-screen.test.ts‎

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import assert from "node:assert/strict";
33
import * as os from "os";
44
import * as path from "path";
55
import React from "react";
6-
import { renderToString } from "ink";
6+
import { Box, Static, renderToString } from "ink";
7+
import stringWidth from "string-width";
78
import { resolveSettingsSources } from "../../../core/src/settings";
89
import { buildWelcomeTips, formatHomeRelativePath } from "../ui";
910
import { AsciiLogo } from "../ui/ascii-art";
@@ -27,6 +28,57 @@ test("welcome logo clips its right edge without wrapping in narrow terminals", (
2728
}
2829
});
2930

31+
test("static welcome output stays within the terminal width and keeps the settings panel aligned", () => {
32+
const settings = resolveSettingsSources({}, {}, { model: "deepseek-flash", baseURL: "https://example.com" }, {});
33+
for (const width of [40, 60, 62, 70, 72, 73, 74, 80, 111, 112, 120]) {
34+
const output = stripTerminalControls(
35+
renderToString(
36+
React.createElement(
37+
Box,
38+
{ flexDirection: "column", width },
39+
React.createElement(Static<string>, {
40+
items: ["welcome"],
41+
children: (key) =>
42+
React.createElement(WelcomeScreen, { key, projectRoot: "/private/tmp", settings, skills: [], width }),
43+
})
44+
),
45+
{ columns: width }
46+
)
47+
);
48+
const lines = output.split("\n");
49+
for (const line of lines) {
50+
assert.ok(stringWidth(line) <= width, `terminal width: ${width}, line: ${line}`);
51+
}
52+
53+
const panelWidth = width < 112 ? width : 72;
54+
const panelTop = lines.findIndex((line) => line.startsWith(" ╭─"));
55+
assert.deepEqual(
56+
lines.slice(0, panelTop).filter((line) => line.trim()),
57+
AsciiLogo.split("\n").map((line) => ` ${line.slice(0, panelWidth - 3)}`.trimEnd()),
58+
`logo at terminal width: ${width}`
59+
);
60+
assert.equal(lines[panelTop], ` ╭${"─".repeat(panelWidth - 4)}╮`);
61+
const panelBottom = lines.findIndex((line) => line.startsWith(" ╰─"));
62+
assert.ok(panelBottom > panelTop);
63+
assert.equal(lines[panelBottom], ` ╰${"─".repeat(panelWidth - 4)}╯`);
64+
for (const line of lines.slice(panelTop + 1, panelBottom)) {
65+
assert.ok(line.startsWith(" │ ") && line.endsWith(" │"), line);
66+
assert.equal(stringWidth(line), panelWidth - 1, line);
67+
}
68+
for (const [label, value] of [
69+
["Model", settings.model],
70+
["Thinking Enabled", String(settings.thinkingEnabled)],
71+
["Reasoning Effort", settings.reasoningEffort],
72+
["CWD", "/private/tmp"],
73+
]) {
74+
assert.ok(
75+
lines.some((line) => line.includes(label) && line.includes(value)),
76+
`${label} and its value should share a row at terminal width: ${width}`
77+
);
78+
}
79+
}
80+
});
81+
3082
test("formatHomeRelativePath returns tilde for the home directory", () => {
3183
const home = path.resolve("/Users/example");
3284
assert.equal(formatHomeRelativePath(home, home), "~");

‎packages/cli/src/ui/views/WelcomeScreen.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ export function WelcomeScreen({ projectRoot, settings, skills, width }: WelcomeS
4040
const panelWidth = compact ? undefined : Math.min(width, 72);
4141

4242
return (
43-
<Box flexDirection="column" marginY={1}>
43+
// Static output does not inherit the terminal width; constrain it before clipping the logo.
44+
<Box flexDirection="column" width={width} marginY={1}>
4445
<Box flexDirection="column" width={panelWidth}>
4546
<Box flexDirection="column" paddingX={1}>
4647
<Box flexDirection="column" justifyContent="center" paddingX={1} overflowX="hidden">

0 commit comments

Comments
 (0)