Skip to content

显示 Claude Code 自己的会话标题,而不是第一条 prompt - #293

Merged
erha19 merged 1 commit into
erha19:mainfrom
michaelawea:fix/claude-code-custom-title
Aug 31, 2026
Merged

显示 Claude Code 自己的会话标题,而不是第一条 prompt#293
erha19 merged 1 commit into
erha19:mainfrom
michaelawea:fix/claude-code-custom-title

Conversation

@michaelawea

@michaelawea michaelawea commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

问题

Island 里的 Claude Code 会话,标题显示的是用户的第一条 prompt,而不是 Claude Code 自己为这个会话显示的标题。而且它永远不变 —— 一个以「标题为什么不对?」开头的会话,之后无论聊到哪里,行上挂的还是这句话。

SessionState.displayTitle 的优先级是 sessionName → conversationInfo.summary → firstUserMessage → projectName,而 ConversationParsersummary 只有一个来源:transcript 中 {"type":"summary"} 的记录。

Claude Code 2.x 已经不再写这种记录了。它把自己 UI 上显示的标题存成另一种记录,并且每轮对话都会重写一次:

{"type":"custom-title","customTitle":"双窗口重复显示bug","sessionId":"faa1378d-…"}

在本地 ~/.claude/projects 上做了统计(418 份 transcript,Claude Code 2.1.247):含 summary 记录的 0 份,含 custom-title 的 88 份;最近两周内有改动的 118 份里 87 份带 custom-title。也就是说 summary 在实际使用中恒为 nil,当前所有 Claude Code 会话都会掉到 firstUserMessage,还被截断到 50 字符。

改动

parseContent 已有的倒序扫描里读取 custom-title,倒序第一个命中的就是最新标题,并优先于旧的 summary

标题喂给已有的 ConversationInfo.summary 字段,而不是新增一个字段,所以所有现有消费方 —— displayTitle、副标题 badge、Codex 辅助会话判断 —— 不需要任何改动即可生效。

兼容性:

  • 旧 transcript 以及其他仍然输出 summary 的 Claude 兼容客户端不受影响,该路径原样保留并作为 fallback。
  • 两种记录都没有的 transcript(短会话、subagent sidechain)仍然回退到第一条用户消息,与现状完全一致。
  • 空白标题会被忽略,不会把标题刷成一串空格。
  • 提前退出的条件改成接受任一来源,所以两种记录都没有的 transcript 扫描成本与现在相同,不会因为这次改动变差。
  • parse() 按文件 mtime 缓存,Claude Code 改写标题时会更新 mtime,标题能自动刷新,不需要额外的失效逻辑。

测试

新增 PingIslandTests/ConversationParserTests.swift(此前这个 parser 没有直接的测试覆盖):custom-title 优先于第一条用户消息、存在多条时取最新的、旧的 summary 路径仍可解析、两者都没有时回退、空白标题被忽略。

CI 的两项检查在本分支上于本地均已通过:swift test --package-path Prototype(129 tests)与 -only-testing:PingIslandTests

🤖 Generated with Claude Code

Claude Code 2.x 已经不再往 transcript 里写 `summary` 记录,它把自己 UI 上显示的
标题存成 `custom-title` 记录,并且每轮对话都会重写一次。`ConversationParser` 只
认 `summary`,所以对当前版本的 transcript 而言 `ConversationInfo.summary` 恒为
nil,`SessionState.displayTitle` 一路掉到被截断成 50 字符的第一条用户消息 —— 会
话不管聊到哪里,标题始终是用户最开始输入的那句话。

在已有的倒序扫描里读取 `custom-title`,倒序第一个命中的就是最新标题,并优先于旧
的 `summary`。空白标题会被忽略。提前退出的条件改成接受任一来源,因此两种记录都没
有的 transcript 仍然扫到文件末尾并回退到第一条用户消息,与改动前完全一致。

标题喂给已有的 `ConversationInfo.summary` 字段而不是新增字段,所以 `displayTitle`、
副标题 badge、Codex 辅助会话判断等现有消费方都不需要改动即可生效。

Tested: Prototype 129 tests;Xcode PingIslandTests,其中包含五个新增的
ConversationParser 用例,覆盖 custom-title 优先、取最新标题、旧 summary 路径、
无标题回退、空白标题被拒。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@michaelawea
michaelawea force-pushed the fix/claude-code-custom-title branch from 3dc1091 to 9912cd4 Compare August 30, 2026 19:52
@michaelawea michaelawea changed the title Show Claude Code's own session title instead of the first prompt 显示 Claude Code 自己的会话标题,而不是第一条 prompt Aug 30, 2026
@michaelawea

Copy link
Copy Markdown
Contributor Author

CI 的失败与本 PR 无关:报错是 SessionCompletionStateEvaluatorTests.swifttestCompletionNotificationRegistryUsesSharedCompletionKeyLogic() 以同步非隔离的方式调用了 @MainActorSessionCompletionNotificationRegistry,而本分支没有碰这个文件。两者都是 0566d13 引入的,该提交直接进了 main,而 pr-checks.yml 只在 pull_request 触发,所以一直没被 CI 覆盖到;给那个测试方法加上 @MainActor 即可。

@erha19

erha19 commented Aug 31, 2026

Copy link
Copy Markdown
Owner

LGTM

@erha19
erha19 merged commit 53b5ea3 into erha19:main Aug 31, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants