diff --git a/codex-cli/bin/codex.js b/codex-cli/bin/codex.js index f24065170d..649a6ab7a1 100755 --- a/codex-cli/bin/codex.js +++ b/codex-cli/bin/codex.js @@ -93,6 +93,54 @@ function getUpdatedPath(newDirs) { return updatedPath; } +function sanitizeTitleSegment(segment) { + return segment + .replace(/[\u0000-\u001f\u007f]/g, " ") + .replace(/\s+/g, " ") + .trim(); +} + +function truncateWithEllipsis(text, maxLength) { + if (text.length <= maxLength) { + return text; + } + if (maxLength <= 1) { + return text.slice(0, maxLength); + } + return `${text.slice(0, maxLength - 1)}…`; +} + +function buildMacOSTabTitle(argv) { + const argsString = sanitizeTitleSegment(argv.join(" ")); + const truncatedArgs = argsString + ? truncateWithEllipsis(argsString, 60) + : null; + const cwdLabel = sanitizeTitleSegment(path.basename(process.cwd())); + const parts = ["codex"]; + if (truncatedArgs) { + parts.push(truncatedArgs); + } + let title = parts.join(" "); + if (cwdLabel) { + title = `${title} — ${cwdLabel}`; + } + return title; +} + +function updateMacOSTabTitle(argv) { + if (platform !== "darwin") { + return; + } + if (!process.stdout?.isTTY) { + return; + } + const title = buildMacOSTabTitle(argv); + if (!title) { + return; + } + process.stdout.write(`\u001B]0;${title}\u0007`); +} + const additionalDirs = []; const rgDir = await resolveRgDir(); if (rgDir) { @@ -100,6 +148,8 @@ if (rgDir) { } const updatedPath = getUpdatedPath(additionalDirs); +updateMacOSTabTitle(process.argv.slice(2)); + const child = spawn(binaryPath, process.argv.slice(2), { stdio: "inherit", env: { ...process.env, PATH: updatedPath, CODEX_MANAGED_BY_NPM: "1" },