From c58d1cc4ce2955468b8479ca1d669665ba2f5d01 Mon Sep 17 00:00:00 2001 From: Alex Southwell <4596216+saphid@users.noreply.github.com> Date: Tue, 3 Nov 2026 07:32:21 +1100 Subject: [PATCH] fix(cli): t3 thread start titles no longer end in a broken character Co-Authored-By: Claude Opus 5.5 --- apps/server/src/cli/thread.test.ts | 7 ++++++- apps/server/src/cli/thread.ts | 13 +++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/server/src/cli/thread.test.ts b/apps/server/src/cli/thread.test.ts index e09f3be00312b..1fab7881bcbb5 100644 --- a/apps/server/src/cli/thread.test.ts +++ b/apps/server/src/cli/thread.test.ts @@ -2,7 +2,7 @@ import { assert, it } from "@effect/vitest"; import { RunId, ThreadId } from "@t3tools/contracts"; import * as Effect from "effect/Effect"; -import { readLatestMessages, type ThreadTools, waitForRun } from "./thread.ts"; +import { readLatestMessages, type ThreadTools, titleFromMessage, waitForRun } from "./thread.ts"; const threadId = ThreadId.make("thread-1"); const runId = RunId.make("run-1"); @@ -160,3 +160,8 @@ it.effect("show returns a --messages count larger than one call can spread", () ); }), ); + +it("titles from a long first line without splitting an emoji", () => { + const title = titleFromMessage(`${"a".repeat(78)}😀 and the rest of a long first line`); + assert.strictEqual(title, `${"a".repeat(78)}…`); +}); diff --git a/apps/server/src/cli/thread.ts b/apps/server/src/cli/thread.ts index 5d944e2723ee4..7bfddda4723a2 100644 --- a/apps/server/src/cli/thread.ts +++ b/apps/server/src/cli/thread.ts @@ -508,11 +508,16 @@ const finishRun = Effect.fn("cli.thread.finishRun")(function* ( } }); -const titleFromMessage = (message: string) => { +export const titleFromMessage = (message: string) => { const firstLine = message.trim().split("\n")[0]?.trim() ?? ""; - return firstLine.length > TITLE_MAX_CHARS - ? `${firstLine.slice(0, TITLE_MAX_CHARS - 1).trimEnd()}…` - : firstLine; + if (firstLine.length <= TITLE_MAX_CHARS) return firstLine; + let end = TITLE_MAX_CHARS - 1; + const previous = firstLine.charCodeAt(end - 1); + const next = firstLine.charCodeAt(end); + if (previous >= 0xd800 && previous <= 0xdbff && next >= 0xdc00 && next <= 0xdfff) { + end -= 1; + } + return `${firstLine.slice(0, end).trimEnd()}…`; }; const launchWorkspaceStrategy = (input: {