feat: align chat rendering with CLI and trim frontend load weight

- Merge thinking and assistant text into one assistant bubble with ordered blocks

- Restyle tool execution blocks to match CLI layout and status

- Remove startup splash screen and ship woff2-only fonts in public

- Add default avatars when agent or user image is unset

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-21 20:42:48 +08:00
parent 2742e19a2e
commit 767a776a3e
21 changed files with 506 additions and 711 deletions

View File

@@ -1,38 +1,63 @@
import { execFileSync } from "node:child_process";
import { existsSync, mkdirSync, readFileSync, statSync, unlinkSync } from "node:fs";
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const fontsDir = join(__dirname, "..", "public", "fonts");
const outputWoff2 = join(fontsDir, "lxgwwenkaimono-medium.woff2");
const sourceTtf = join(__dirname, "..", "assets", "fonts", "LXGWWenKaiMono-Medium.ttf");
const sourceCandidates = [
join(fontsDir, "LXGWWenKaiMono-Medium.ttf"),
join(__dirname, "..", "assets", "fonts", "LXGWWenKaiMono-Medium.ttf"),
];
const sourceTtf = sourceCandidates.find((path) => existsSync(path));
/** Full CJK font woff2 is typically 710 MB; reject obvious subset/corrupt output. */
const MIN_WOFF2_BYTES = 5_000_000;
if (!sourceTtf) {
console.warn("[prepare-font] LXGWWenKaiMono-Medium.ttf not found, skipping");
if (!existsSync(sourceTtf)) {
console.warn(`[prepare-font] source not found: ${sourceTtf}`);
process.exit(0);
}
mkdirSync(fontsDir, { recursive: true });
function removePublicTtfCopies() {
for (const name of readdirSync(fontsDir)) {
if (name.toLowerCase().endsWith(".ttf")) {
const path = join(fontsDir, name);
unlinkSync(path);
console.log(`[prepare-font] removed public TTF copy (woff2 only): ${path}`);
}
}
}
function woff2LooksValid() {
if (!existsSync(outputWoff2)) return false;
return readFileSync(outputWoff2).length >= MIN_WOFF2_BYTES;
}
function verifyGlyphCount() {
const py = [
"from fontTools.ttLib import TTFont",
"import sys",
"src, out = sys.argv[1], sys.argv[2]",
"source_glyphs = len(TTFont(src).getGlyphOrder())",
"output_glyphs = len(TTFont(out).getGlyphOrder())",
"if source_glyphs != output_glyphs:",
"\traise SystemExit(f'glyph count mismatch: source={source_glyphs}, output={output_glyphs}')",
"print(output_glyphs)",
].join("\n");
const count = execFileSync("python", ["-c", py, sourceTtf, outputWoff2], {
encoding: "utf8",
}).trim();
console.log(`[prepare-font] verified full glyph set (${count} glyphs)`);
}
removePublicTtfCopies();
if (woff2LooksValid()) {
const sourceMtime = statSync(sourceTtf).mtimeMs;
const outputMtime = statSync(outputWoff2).mtimeMs;
if (outputMtime >= sourceMtime) {
const sizeMb = (readFileSync(outputWoff2).length / (1024 * 1024)).toFixed(2);
console.log(`[prepare-font] up to date ${outputWoff2} (${sizeMb} MB)`);
console.log(`[prepare-font] up to date ${outputWoff2} (${sizeMb} MB, woff2 only)`);
process.exit(0);
}
}
@@ -42,12 +67,14 @@ if (existsSync(outputWoff2) && !woff2LooksValid()) {
unlinkSync(outputWoff2);
}
console.log("[prepare-font] converting full font to woff2 (no glyph subsetting, may take a few minutes)...");
console.log(
"[prepare-font] converting full font to woff2 (no glyph subsetting, glyf/loca/hmtx transforms)...",
);
const py = [
"from fontTools.ttLib.woff2 import compress",
"import sys",
"compress(sys.argv[1], sys.argv[2])",
"compress(sys.argv[1], sys.argv[2], transform_tables={'glyf', 'loca', 'hmtx'})",
].join("\n");
execFileSync("python", ["-c", py, sourceTtf, outputWoff2], { stdio: "inherit" });
@@ -59,5 +86,8 @@ if (sizeBytes < MIN_WOFF2_BYTES) {
);
}
verifyGlyphCount();
removePublicTtfCopies();
const sizeMb = (sizeBytes / (1024 * 1024)).toFixed(2);
console.log(`[prepare-font] wrote ${outputWoff2} (${sizeMb} MB, full glyph set)`);
console.log(`[prepare-font] wrote ${outputWoff2} (${sizeMb} MB, full glyph set, woff2 only)`);