feat: simplify session title chain + two-line list item (web + vscode)#153
feat: simplify session title chain + two-line list item (web + vscode)#153DrumRobot wants to merge 4 commits into
Conversation
Removes the currentSummary field used as a fallback in display titles. The fallback chain simplifies to customTitle > agentName > title. BREAKING CHANGES: - Drop SessionMeta.currentSummary and SessionTreeData.currentSummary fields - getDisplayTitle no longer accepts currentSummary; positional overload simplified to (customTitle, title, fallback?) - Drop DisplayTitleOptions.currentSummary - getSessionTooltip no longer renders summary as fallback content Affects core, web, and vscode-extension packages. Cross-session summary resolution (summaries array, leafUuid sort timestamps, analysis.summaryCount) is preserved; only the cached "first summary as title fallback" is removed. Version bumped from 0.4.8 to 0.5.0 (core/web/mcp + root). vscode-extension version unchanged (separate release cycle). Closes #140 Signed-off-by: DrumRobot <drumrobot43@gmail.com>
There was a problem hiding this comment.
Pull request overview
This PR removes the currentSummary field from the core/web/vscode type surface and eliminates its use as a title/tooltip fallback, standardizing the title display chain to customTitle > agentName > title. It also bumps published package versions to 0.5.0 to reflect the breaking API change.
Changes:
- Removed
currentSummaryfromSessionMeta/SessionTreeDataand from all UI call sites (web + VSCode extension). - Simplified
getDisplayTitlepositional overload and updated tests/fixtures accordingly. - Updated tree building/sorting to stop caching/using “first summary as title”, while preserving the
summaries[]resolution behavior.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| package.json | Bump workspace version to 0.5.0. |
| packages/core/package.json | Bump core package version to 0.5.0. |
| packages/core/src/types.ts | Remove currentSummary from core session types. |
| packages/core/src/utils.ts | Remove currentSummary from title/tooltip utilities and simplify overloads. |
| packages/core/src/utils.test.ts | Update getDisplayTitle tests for the new fallback chain. |
| packages/core/src/session/crud-helpers.ts | Stop accepting/returning currentSummary in buildSessionMeta. |
| packages/core/src/session/tree.ts | Remove currentSummary from tree building, sorting, filtering, and cache update. |
| packages/core/src/tests/tree.test.ts | Update tree/sort/filter tests for removed currentSummary. |
| packages/core/src/tests/sort-fields.test.ts | Update title-sort fixtures/expectations for removed currentSummary. |
| packages/core/src/tests/list.test.ts | Update list-session tests to reflect removal of currentSummary. |
| packages/core/src/tests/crud-helpers.test.ts | Update buildSessionMeta tests for removed currentSummary. |
| packages/mcp/package.json | Bump MCP package version to 0.5.0. |
| packages/web/package.json | Bump web package version to 0.5.0. |
| packages/web/src/lib/api.ts | Remove currentSummary from SessionData type. |
| packages/web/src/lib/stores/projectTree.ts | Remove currentSummary from SessionNode store model. |
| packages/web/src/lib/components/SessionViewer.svelte | Remove currentSummary prop usage when computing display title. |
| packages/web/src/lib/components/ProjectTree.svelte | Remove currentSummary usage and rename “summary fallback” styling to “title fallback”. |
| packages/web/src/lib/components/ProjectTree.stories.svelte | Remove currentSummary from story fixtures. |
| packages/web/src/lib/components/MainPage.stories.svelte | Remove currentSummary from story fixtures and component props. |
| packages/web/src/routes/+page.svelte | Remove currentSummary usage from title display and rename handler. |
| packages/web/src/routes/session/[project]/[id]/+page.svelte | Simplify local displayTitle and remove currentSummary state/props. |
| packages/vscode-extension/src/treeProvider.ts | Remove currentSummary from filtering/text display logic and update getDisplayTitle calls. |
Comments suppressed due to low confidence (2)
packages/core/src/utils.ts:155
DisplayTitleOptions.maxLengthis still part of the public options type, butgetDisplayTitleno longer reads or applies it. Callers in web (e.g.SessionViewerusesmaxLength: 50) will now see no effect, and the option is misleading. Either removemaxLengthfromDisplayTitleOptions(and update call sites) or reintroduce truncation (e.g. truncate the selected title/agentName output tomaxLength).
export interface DisplayTitleOptions {
agentName?: string
customTitle?: string
title?: string
createdAt?: string
maxLength?: number
fallback?: string
packages/web/src/routes/session/[project]/[id]/+page.svelte:220
- The rename modal is prefilled with
agentNamewhen there is nocustomTitle. SincerenameSessionwrites bothcustom-titleandagent-name, confirming without edits can create a redundant custom title (and potentially change metadata) even though the user didn’t actually rename anything. Consider prefilling withcustomTitle ?? session.title ?? ''(ordisplayTitle) and adding a no-op guard (skip API call when the trimmed input matches the current value).
showInput(
'Rename Session',
'Session title:',
customTitle ?? agentName ?? session.title ?? '',
async (newTitle) => {
closeInput()
const trimmed = newTitle.trim()
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Alphabetical by display title (customTitle > title) | ||
| const titleA = a.customTitle ?? a.title | ||
| const titleB = b.customTitle ?? b.title |
| @@ -135,7 +134,6 @@ | |||
| id: session.id, | |||
| title: session.title, | |||
| customTitle: data?.customTitle, | |||
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
📝 WalkthroughWalkthroughRemoves the deprecated session ChangesCore Type Contracts and Utility Functions
Session Metadata Building and Tree Operations
Web UI Components and Pages
VSCode Extension
Version Updates
🎯 3 (Moderate) | ⏱️ ~22 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
packages/core/src/types.tsESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox. packages/core/src/utils.tsESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox. packages/vscode-extension/src/treeProvider.tsESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
AI Review Summary — Superpowers requesting-code-review
Notes
Status⏳ Test plan: 5/7 ✅ (2 manual smoke verification items unchecked — web rename flow, VSCode tree datetime mode). Actionable: 0 from CodeRabbit, 2 low-confidence from Copilot. No code changes required from this consolidation; author (DrumRobot) to decide on the two Copilot consistency suggestions and verify the remaining manual smoke checks before merge. |
… list items Following review of PR #153, agentName is removed from the primary title fallback chain (was: customTitle ?? agentName ?? title) and rendered as a secondary metadata line via the new getSecondaryInfo() helper. Aligns with the official Claude Code extension's two-row layout. - Web: real two-line layout via flex-col (line 1 = title, line 2 = agentName · {relativeTime} · 💬 {count}). messageCount moved out of the right-side icon strip; agents/todos icons remain when count > 0 - VSCode: TreeItem.label = customTitle ?? title, TreeItem.description = secondary info rendered muted on the same row (TreeItem API does not support true two lines; matches the official extension) - New getSecondaryInfo({ agentName, updatedAt, messageCount, locale, separator }) helper exported from @claude-sessions/core with 10 unit tests - Standalone /session/[project]/[id] route and SessionViewer header now follow the same customTitle ?? title chain for consistency BREAKING CHANGES: - DisplayTitleOptions.agentName removed; use getSecondaryInfo() to render agentName as a secondary metadata line - SessionViewer no longer accepts the agentName prop Signed-off-by: DrumRobot <drumrobot43@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/web/src/routes/session/[project]/[id]/+page.svelte (1)
210-220:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winSkip no-op rename requests when the normalized value didn’t change.
The rename flow currently always calls
api.renameSession(...)after trim, even if the user confirms without edits. Add a normalized equality guard before Line 219 to avoid redundant writes.Suggested patch
showInput( 'Rename Session', 'Session title:', customTitle ?? session.title ?? '', async (newTitle) => { closeInput() const trimmed = newTitle.trim() + const current = (customTitle ?? session?.title ?? '').trim() + if (trimmed === current) return try { await api.renameSession(session!.projectName, session!.id, trimmed)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/web/src/routes/session/`[project]/[id]/+page.svelte around lines 210 - 220, Before calling api.renameSession in the showInput callback, compare the normalized (trimmed) newTitle against the current normalized title (use customTitle ?? session.title ?? '') and if they are equal, call closeInput() and return early to skip the no-op rename; update the callback in the showInput handler (the async (newTitle) => { ... } block) to perform this guard using trimmed and the existing title normalization before making the api.renameSession call.
🧹 Nitpick comments (1)
packages/core/src/utils.ts (1)
149-154: ⚡ Quick winRemove or implement
maxLengthinDisplayTitleOptionsto avoid a misleading API.
maxLengthis still part of the public options type (Line 153), butgetDisplayTitleno longer uses it (Lines 189-219). That makes existing callers think truncation still works when it does not.Also applies to: 189-219
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/core/src/utils.ts` around lines 149 - 154, The DisplayTitleOptions interface exposes maxLength but getDisplayTitle no longer uses it, causing a misleading API; either remove maxLength from DisplayTitleOptions (and update any callers/types/docs) or reintroduce truncation logic inside getDisplayTitle to honor options.maxLength (e.g., truncate title/customTitle/fallback with an ellipsis when length exceeds maxLength). Locate the type DisplayTitleOptions and the function getDisplayTitle and apply the chosen change consistently across code, types, and tests so the public API matches actual behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/vscode-extension/src/treeProvider.ts`:
- Around line 321-326: Session message counts are shown twice because
session.getSecondaryInfo(...) already includes "💬 {messageCount}" and
SessionTreeItem prepends the count; remove the redundant prepend in the
SessionTreeItem implementation (the code that builds the tree label/description)
so it no longer prepends {count}, relying on session.getSecondaryInfo to show
the message count; update both places where SessionTreeItem builds the
label/description that currently prepend the count to avoid duplicate display.
In `@packages/web/src/routes/session/`[project]/[id]/+page.svelte:
- Around line 80-82: The current displayTitle computed with nullish coalescing
treats an empty string as a valid title and can produce a blank <title>; update
the logic that computes displayTitle (the const displayTitle using customTitle
and session?.title) to use a truthy fallback instead of ?? (e.g., check
customTitle is non-empty/trimmed before using it) or call the existing
getDisplayTitle utility with (session, customTitle) so empty strings fall
through to session?.title and ultimately to 'Untitled'.
---
Outside diff comments:
In `@packages/web/src/routes/session/`[project]/[id]/+page.svelte:
- Around line 210-220: Before calling api.renameSession in the showInput
callback, compare the normalized (trimmed) newTitle against the current
normalized title (use customTitle ?? session.title ?? '') and if they are equal,
call closeInput() and return early to skip the no-op rename; update the callback
in the showInput handler (the async (newTitle) => { ... } block) to perform this
guard using trimmed and the existing title normalization before making the
api.renameSession call.
---
Nitpick comments:
In `@packages/core/src/utils.ts`:
- Around line 149-154: The DisplayTitleOptions interface exposes maxLength but
getDisplayTitle no longer uses it, causing a misleading API; either remove
maxLength from DisplayTitleOptions (and update any callers/types/docs) or
reintroduce truncation logic inside getDisplayTitle to honor options.maxLength
(e.g., truncate title/customTitle/fallback with an ellipsis when length exceeds
maxLength). Locate the type DisplayTitleOptions and the function getDisplayTitle
and apply the chosen change consistently across code, types, and tests so the
public API matches actual behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 18ff2b6e-d349-47df-b069-7699adb910ba
📒 Files selected for processing (8)
packages/core/src/index.tspackages/core/src/utils.test.tspackages/core/src/utils.tspackages/vscode-extension/src/treeProvider.tspackages/web/src/lib/components/ProjectTree.sveltepackages/web/src/lib/components/SessionViewer.sveltepackages/web/src/routes/+page.sveltepackages/web/src/routes/session/[project]/[id]/+page.svelte
💤 Files with no reviewable changes (2)
- packages/web/src/lib/components/SessionViewer.svelte
- packages/web/src/routes/+page.svelte
| // Display title for page title (customTitle ?? title chain — agentName demoted to secondary line in list items) | ||
| const displayTitle = $derived(customTitle ?? session?.title ?? 'Untitled') | ||
|
|
There was a problem hiding this comment.
Avoid blank page titles when customTitle is an empty string.
Using nullish coalescing here treats '' as a valid title. On Line 81 that can render an empty <title>. Prefer truthy fallback logic (or reuse getDisplayTitle) so empty strings fall through to session?.title.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/web/src/routes/session/`[project]/[id]/+page.svelte around lines 80
- 82, The current displayTitle computed with nullish coalescing treats an empty
string as a valid title and can produce a blank <title>; update the logic that
computes displayTitle (the const displayTitle using customTitle and
session?.title) to use a truthy fallback instead of ?? (e.g., check customTitle
is non-empty/trimmed before using it) or call the existing getDisplayTitle
utility with (session, customTitle) so empty strings fall through to
session?.title and ultimately to 'Untitled'.
… in description Two issues surfaced after the two-line patch landed on PR #153: 1. Description invisible for long titles. VSCode TreeView uses flex layout where the label has flex:1 and shrinks before the description, so any reasonably long session title pushed the secondary info off-screen. Pre-truncating the label to 40 chars + ellipsis reverses the priority and guarantees the description (count · agentName · time) stays visible. Full title remains available in the tooltip. 2. Count appeared twice in the description. SessionTreeItem's constructor already prefixes the session-type description with `${count} · ...`, so passing messageCount to getSecondaryInfo again produced "121 · agentName · 2h ago · 💬 121". Dropped messageCount from the getSecondaryInfo call here; the web ProjectTree still passes it (count only lives in the row icon strip there, not the description). Signed-off-by: DrumRobot <drumrobot43@gmail.com>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/core/src/utils.ts (1)
161-171:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
maxLengthoption is defined but never used.The
DisplayTitleOptionsinterface includesmaxLength?: number(line 165), but thegetDisplayTitleimplementation (lines 201-211) never reads or applies this option. Callers passingmaxLength(e.g., the web route atpackages/web/src/routes/+page.svelte:273passingmaxLength: Infinity) expect truncation behavior that no longer exists.Either remove
maxLengthfrom the interface to reflect the new behavior, or reintroduce truncation logic ingetDisplayTitle.Proposed fix: Remove the unused field
export interface DisplayTitleOptions { customTitle?: string title?: string createdAt?: string - maxLength?: number fallback?: string /** 'message' = first user message (default), 'datetime' = relative date/time */ mode?: TitleDisplayMode🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/core/src/utils.ts` around lines 161 - 171, DisplayTitleOptions declares maxLength but getDisplayTitle doesn't use it; reintroduce truncation in getDisplayTitle by reading options.maxLength (from the DisplayTitleOptions object) after computing the final title, treat undefined or Infinity as “no truncation”, and if maxLength is a finite number and the title length exceeds it, truncate to maxLength characters and append an ellipsis (or trim to maxLength-1 and append “…” to keep total length equal to maxLength). Update getDisplayTitle to apply this logic to the computed title so callers (e.g., those passing maxLength: Infinity) get the expected behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/core/src/utils.ts`:
- Around line 161-171: DisplayTitleOptions declares maxLength but
getDisplayTitle doesn't use it; reintroduce truncation in getDisplayTitle by
reading options.maxLength (from the DisplayTitleOptions object) after computing
the final title, treat undefined or Infinity as “no truncation”, and if
maxLength is a finite number and the title length exceeds it, truncate to
maxLength characters and append an ellipsis (or trim to maxLength-1 and append
“…” to keep total length equal to maxLength). Update getDisplayTitle to apply
this logic to the computed title so callers (e.g., those passing maxLength:
Infinity) get the expected behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 258c1bcc-6e9f-407e-ba31-ff8f0ce0dc68
📒 Files selected for processing (8)
package.jsonpackages/core/package.jsonpackages/core/src/types.tspackages/core/src/utils.tspackages/mcp/package.jsonpackages/vscode-extension/src/treeProvider.tspackages/web/package.jsonpackages/web/src/lib/components/ProjectTree.svelte
✅ Files skipped from review due to trivial changes (4)
- packages/mcp/package.json
- packages/web/package.json
- packages/core/package.json
- package.json
Summary
currentSummaryfield and its fallback usage from the title display chain.agentNamefrom the primary title fallback to a secondary metadata line (matches the official Claude Code extension UX). New chain:customTitle ?? title.getSecondaryInfo({ agentName, updatedAt, messageCount })helper that renders"{agentName} · {relativeTime} · 💬 {messageCount}". Used as line 2 on the web (true two-line layout) and asTreeItem.descriptionin the VSCode extension (muted text, same row — TreeItem API does not support true two lines).summariesarray, leafUuid sort timestamps,analysis.summaryCount) is preserved; only the cached "first summary as title" is dropped.vscode-extensionversion is unchanged (separate release cycle viabeta/open-vsx).Changes
packages/core/src/types.tsSessionMeta.currentSummaryandSessionTreeData.currentSummaryfieldspackages/core/src/utils.tsDisplayTitleOptions.currentSummaryandDisplayTitleOptions.agentName. Simplify positionalgetDisplayTitle(customTitle, title, fallback?). Remove currentSummary branches ingetSessionTooltip. AddSecondaryInfoOptionsinterface +getSecondaryInfohelper.packages/core/src/index.tsgetSecondaryInfoandSecondaryInfoOptionspackages/core/src/utils.test.tsgetDisplayTitletests for the newcustomTitle > titlechain. Adddescribe('getSecondaryInfo')with 10 unit tests (agentName/time/count combinations, empty/edge cases, custom separator)packages/core/src/session/crud-helpers.tsbuildSessionMetafields/returnpackages/core/src/session/tree.tspackages/core/src/__tests__/{tree,sort-fields,crud-helpers,list}.test.tspackages/web/src/lib/api.tsSessionDatatypepackages/web/src/lib/stores/projectTree.tsSessionNodeand defaultspackages/web/src/lib/components/ProjectTree.svelteisSummaryFallbackbranch; renamed toisTitleFallbackreflecting the chain. Two-line row template via flex-col: line 1 = title, line 2 =getSecondaryInfo(agentName · time · 💬 count).messageCountmoved out of right-side icon strip into line 2; agents/todos icons remain on the right and only render when count > 0.packages/web/src/lib/components/SessionViewer.svelteisSummaryFallbackbranch. Drop theagentNameprop (no longer used after chain change).packages/web/src/routes/+page.svelteSessionViewerprops. Stop passingagentNameto<SessionViewer>and drop it from the renamegetDisplayTitlecall.packages/web/src/routes/session/[project]/[id]/+page.sveltedisplayTitlesimplified tocustomTitle ?? title(agentName demoted). Stop passingagentNameto<SessionViewer>.packages/web/src/lib/components/{ProjectTree,MainPage}.stories.sveltepackages/vscode-extension/src/treeProvider.tsgetDisplayTitlecall. Replace conditional datetime-mode description with always-ongetSecondaryInfo:TreeItem.label=customTitle ?? title(with datetime mode still honored),TreeItem.description={agentName} · {relativeTime} · 💬 {messageCount}(muted text, same row).package.json,packages/{core,web,mcp}/package.json0.4.8→0.5.0BREAKING CHANGES
SessionMeta.currentSummaryandSessionTreeData.currentSummaryremovedgetDisplayTitlepositional overload simplified to(customTitle, title, fallback?). ThecurrentSummaryparameter is no longer acceptedDisplayTitleOptions.currentSummaryremovedDisplayTitleOptions.agentNameremoved.getDisplayTitleno longer falls back toagentName. Callers that need the old behavior should renderagentNameseparately via the newgetSecondaryInfo()helper.getSessionTooltipno longer renders summary as fallback contentSessionViewerno longer accepts theagentNameprop0.5.0Migration:
currentSummaryshould drop the argument. If the goal was to surface a session summary in the UI, read it fromsessionData.summaries[0]?.summarydirectly instead of relying on the cached fallback.agentNametogetDisplayTitleshould drop it from the call and render it throughgetSecondaryInfo({ agentName, updatedAt, messageCount })as a secondary line.Related Issues
Relates to #140
Test plan
pnpm -F core test— all 438 tests pass (was 429; +10 getSecondaryInfo, −3 obsolete agentName, +2 new chain tests after rewrite)pnpm -F core build—grep -r currentSummary packages/core/dist/returns 0 hitspnpm -F web build— SvelteKit production build succeedspnpm typecheck— 0 type errors across the monorepopnpm -F vscode-extension build— tsup build succeedscustomTitle ?? titlewithout summary or agentName fallback. Verified 2026-05-25 via chrome-devtools-mcp at port 5181 on head bearing the two-line patch: tree rows render as two visual lines (line 1 = title, line 2 ={agentName} · {relativeTime} · 💬 {count}); rename round-trip updates line 1 immediately, line 2 unchanged; API/api/sessionsresponse contains 0 occurrences ofcurrentSummary. Screenshot:~/ghq/github.com/es6kr/.ralph/docs/generated/pr153-twoline-smoke.png/vsixrebuild + install (just rebuilt + installed at 2026-05-25 ~23:21 KST) → TreeView label = title only, description ={agentName} · {relativeTime} · 💬 {count}rendered muted on the same row; titleDisplayMode toggle (message ↔ datetime) flips line 1 between first message and relative time, line 2 stays as agentName + time + count; filter input still matches across title, agentName, customTitle, and summaries🤖 Generated with Claude Code
Summary by CodeRabbit
Chores
New Features
Bug Fixes
Tests