Skip to content

feat(app): nest forked sessions under their parent in the session list#1423

Open
chphch wants to merge 1 commit into
slopus:mainfrom
chphch:feat/fork-lineage-indent
Open

feat(app): nest forked sessions under their parent in the session list#1423
chphch wants to merge 1 commit into
slopus:mainfrom
chphch:feat/fork-lineage-indent

Conversation

@chphch

@chphch chphch commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Forked sessions already persist parentSessionId in their (encrypted) metadata — it's set on every fork path (the Fork quick-action, duplicate-from-message, and the MCP open_session tool) and already surfaced as the "Forked From" link on the session info screen — but the session list ignored it, so a fork showed up as an unrelated row sorted only by recency and you couldn't tell at a glance what was branched from what. This renders forked children directly under their parent within each list section (the active project group, and each by-date group), indented by fork depth with a tree connector. A child whose parent isn't in the same section falls back to depth 0 so nesting never crosses section boundaries, and the visual indent caps at a max depth so deep chains never march off-screen (the underlying depth stays accurate). The reorder + indent math lives in a small pure module (utils/forkLineage.ts) with unit tests; both the compact active-session rows and the full by-date rows are covered.

Proof

Synthetic parent → two children → grandchild sessions rendered through the real SessionsList on Expo web (standalone server, dev_token URL bypass, driven with Playwright). Left = current behavior (forks scattered by recency, lineage invisible); right = this PR (children nested under their parent with a connector; the grandchild sits one level deeper). Both render paths are shown — the compact active group (top) and the full by-date "Today" group (bottom).

fork lineage before/after

utils/forkLineage.test.ts covers the ordering — multi-level chains, multiple children of one parent, the parent-not-in-section fallback, a parent-cycle guard, and deep-equal reference stability (10/10 passing). pnpm typecheck is clean.

Forked sessions already persist `parentSessionId` in their encrypted
metadata (set on every fork path — Fork action, duplicate-from-message,
and the MCP open_session tool), but the session list ignored it: a fork
appeared as an unrelated row sorted only by recency, so the lineage was
invisible.

Render forked children directly under their parent within each list
section, indented by fork depth with a "└" tree connector. A child whose
parent is not in the same section falls back to depth 0, so nesting never
crosses section boundaries. Both the compact active-sessions rows and the
full inactive (by-date) rows are covered.

The reorder + indent math lives in a pure, unit-tested util
(utils/forkLineage.ts); storage.ts nests within each date group and the
active group nests per project group. Visual indent caps at a max depth so
deep chains never march off-screen (forkDepth itself stays accurate).

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
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.

1 participant