Skip to content

fix(ui): catalog sessions select in place and continue from desktop-app sources#106074

Merged
steipete merged 5 commits into
mainfrom
claude/web-ui-codecs-cloud-sessions-318ff8
Jul 13, 2026
Merged

fix(ui): catalog sessions select in place and continue from desktop-app sources#106074
steipete merged 5 commits into
mainfrom
claude/web-ui-codecs-cloud-sessions-318ff8

Conversation

@steipete

@steipete steipete commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

External Codex/Claude Code sessions surfaced in the Control UI sidebar ("session catalog") were effectively unusable:

  1. Wrongly view-only. Almost every real Claude Code session on the gateway host showed "This external session source is view-only." Two causes:
    • Sessions driven through the Claude Code desktop app are recorded with source: "claude-desktop" during catalog discovery, and the anthropic plugin hard-required source === "claude-cli" for canContinue/continue — even though desktop sessions live in the same ~/.claude/projects JSONL store (discovery drops desktop records without one) and claude --resume --fork-session continues them identically.
    • The chat pane showed the view-only banner whenever catalog metadata wasn't loaded yet, so even continuable sessions flashed "view-only" while loading.
  2. Selection lifted the session into the chats block. Clicking a catalog row synthesized a phantom row in the regular sessions list labeled with the raw catalog:claude:gateway%3Alocal:… key (deep-link fallback in resolveSessionNavigation), and previously adopted sessions rendered twice — once in the catalog group and once in the regular list, jumping to the top on activity. Catalog rows also never showed a selected state.
  3. "Local Codex" / "Local Claude" noise. Rows carried the gateway-host label as subtitle whenever a catalog had more than one host, adding no signal (the group header already names the source).

Why This Change Was Made

Catalog sessions should feel like regular sessions that happen to run through Codex/Claude Code: click → selected in place, transcript shown, type → continue with streaming. All gating keys off the provider-reported per-session canContinue, so paired-node continuation (PR #105833) lights up in this UI automatically once it lands.

User Impact

  • Local Claude Code sessions (CLI and desktop app) are continuable from the web UI: type into the transcript view, the session is adopted, and the reply streams in as a normal session run.
  • The view-only banner never flashes during load; after metadata loads, any non-continuable state (including a failed lookup) shows the explanatory banner instead of a silently disabled composer.
  • Clicking a catalog session selects it in place. No phantom catalog:… row, no duplicate entry jumping to the top of the chats list. Adopted sessions render as full live session rows (run spinner, unread dot, pin/menu actions) inside their catalog group, bound immediately on adoption via a document-level openclaw-session-catalog-continued event instead of waiting for the next 30s catalog poll.
  • Host subtitles only show a paired node's machine name; "Local Codex"/"Local Claude" subtitles are gone.
  • Structure: sidebar catalog rendering moved to app-sidebar-session-catalogs.ts, the catalog metadata lookup to catalog-key.ts, and the Claude node-host commands to session-catalog-node-commands.ts (mirrors the codex plugin layout).

Evidence

  • Live verification against a scratch gateway built from this branch on a Mac with 40 real Claude Code sessions (mixed CLI/desktop):
    • Before: every session showed the view-only banner, and clicking created the phantom raw-key row.
    • After: sessions.catalog.list reports canContinue: true for desktop-source sessions, rows select in place with the active highlight, the composer is enabled, and sending ran the full flow — sessions.catalog.continue succeeded (adoption + history import), chat.send started a run through the claude-cli backend with useResume=true (gateway log), and the adopted row stayed inside the catalog group with the live run spinner and no duplicate in the chats block. (The CLI turn itself returned empty on that box because ~20 concurrent agent sessions were contending the local claude OAuth — standalone claude -p reproduced "Not logged in" in isolation; the resume path is the same shipped one used for claude-cli-source adoption.)
  • Tests (all passing locally via node scripts/run-vitest.mjs):
    • extensions/anthropic/session-catalog.test.ts (8) — incl. new: desktop-source rows list as continuable and adopt with the same one-shot fork binding.
    • ui/src/lib/sessions/navigation.test.ts (12) — incl. new: no synthesized row for catalog session keys.
    • ui/src/components/app-sidebar.test.ts (54 with navigation shard) — incl. new: node-only host subtitles; in-place active highlight without a phantom chat row; adopted rows render once (as live rows) inside the catalog group; catalog-continued event binds the adopted key immediately.
    • ui/src/e2e/codex-sessions.e2e.test.ts + ui/src/e2e/claude-sessions.e2e.test.ts (3) — existing catalog flows still pass.
  • pnpm tsgo:ui and pnpm tsgo:extensions pass locally.
  • Autoreview (Codex gpt-5.6-sol, thinking xhigh, branch vs origin/main): one P2 finding (silent disabled composer after failed lookup) — fixed in 47591df; rerun clean: "patch is correct", no actionable findings.

@steipete
steipete force-pushed the claude/web-ui-codecs-cloud-sessions-318ff8 branch from eec90a1 to 8d88b9a Compare July 13, 2026 06:08
@openclaw-barnacle openclaw-barnacle Bot added scripts Repository scripts size: L and removed size: M labels Jul 13, 2026
@clawsweeper

clawsweeper Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 13, 2026, 2:51 AM ET / 06:51 UTC.

Summary
The PR makes catalog sessions select and remain within their sidebar groups, deduplicates adopted sessions from normal chats, centralizes catalog lookup and rendering, and permits Claude desktop-app sessions to use the existing local continuation path.

PR surface: Source +228, Tests +273. Total +501 across 11 files.

Reproducibility: yes. at source level: current main synthesizes unmatched catalog keys into normal sidebar rows, while the Anthropic source gate excludes desktop records despite using the same project transcript store; focused regression tests cover both paths.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: serialized state: extensions/anthropic/session-catalog-node-commands.ts, serialized state: extensions/anthropic/session-catalog.test.ts, serialized state: extensions/anthropic/session-catalog.ts, serialized state: ui/src/lib/sessions/catalog-key.ts, serialized state: ui/src/lib/sessions/navigation.test.ts, unknown-data-model-change: extensions/anthropic/session-catalog.test.ts, and 2 more. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦐 gold shrimp
Patch quality: 🐚 platinum hermit
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add redacted evidence of a successful streamed reply from an adopted Claude desktop session.
  • Show a Codex catalog row still selects in place without a phantom or duplicate normal-session row on the refreshed head.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: After-fix evidence shows listing, in-place selection, adoption, history import, and run startup, but not a successful streamed reply; add redacted recording or logs, update the PR body, and request @clawsweeper re-review if review does not restart automatically.

Mantis proof suggestion
The remaining uncertainty is directly observable through the supported web UI chat proof lane. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis web UI chat proof: reproduce a Claude desktop catalog session selecting in place, continuing with a successful streamed reply, and remaining only in its catalog group; also verify a Codex catalog row selects without a phantom chat row, returning redacted evidence.

Risk before merge

  • [P1] The submitted real-environment attempt proves adoption and run startup but not the promised successful streamed assistant response.
  • [P1] The branch is behind current main, so a refreshed exact-head review must confirm that recent session and Control UI work still composes with the patch.
  • [P1] The required local sibling Codex checkout could not be inspected because read-only shell execution failed before commands ran; official upstream Codex source was inspected instead, so the repository's strongest dependency gate remains incomplete.

Maintainer options:

  1. Decide the mitigation before merge
    Keep the provider-owned Claude eligibility change and generic catalog-row selection and deduplication design, then merge only after the refreshed head proves a successful Claude desktop continuation and an unchanged Codex catalog flow.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P1] Review the exact refreshed head after complete Claude and Codex real-behavior proof; no concrete mechanical defect is established for an automated repair lane.

Security
Cleared: The patch adds no dependency, workflow, permission, secret-handling, artifact-download, or other concrete security or supply-chain concern.

Review details

Best possible solution:

Keep the provider-owned Claude eligibility change and generic catalog-row selection and deduplication design, then merge only after the refreshed head proves a successful Claude desktop continuation and an unchanged Codex catalog flow.

Do we have a high-confidence way to reproduce the issue?

Yes at source level: current main synthesizes unmatched catalog keys into normal sidebar rows, while the Anthropic source gate excludes desktop records despite using the same project transcript store; focused regression tests cover both paths.

Is this the best way to solve the issue?

Likely yes, but not fully proven: excluding catalog identities from normal-session synthesis and keeping Claude-specific eligibility in the Anthropic plugin is the narrow owner-aligned design, while complete real behavior and exact sibling-contract verification remain outstanding.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 4cbbb86d5e71.

Label changes

Label justifications:

  • P1: The PR repairs a broken user-facing Control UI workflow where external sessions appear view-only or create phantom and duplicate rows.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: After-fix evidence shows listing, in-place selection, adoption, history import, and run startup, but not a successful streamed reply; add redacted recording or logs, update the PR body, and request @clawsweeper re-review if review does not restart automatically.
Evidence reviewed

PR surface:

Source +228, Tests +273. Total +501 across 11 files.

View PR surface stats
Area Files Added Removed Net
Source 8 432 204 +228
Tests 3 274 1 +273
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 11 706 205 +501

What I checked:

  • Current-main phantom-row path: Current main synthesizes an active session for every selected non-unknown key and prepends it when no normal session matches, explaining why a catalog key appears as a phantom chat row. (ui/src/lib/sessions/navigation.ts:276, 4cbbb86d5e71)
  • Catalog identity fix: The patch excludes parsed catalog identities from normal-session synthesis, leaving their catalog rows responsible for selection. (ui/src/lib/sessions/navigation.ts:280, f4859e20dc7d)
  • Provider ownership: The scoped extension policy assigns vendor-specific catalog behavior to its provider plugin, matching the placement of Claude source eligibility under the Anthropic plugin. (extensions/AGENTS.md:4, 4cbbb86d5e71)
  • Desktop-source coverage: The added Anthropic regression test discovers a desktop-source record, verifies it is continuable, and exercises adoption through the existing fork binding. (extensions/anthropic/session-catalog.test.ts:157, f4859e20dc7d)
  • Codex sibling contract: The Codex plugin documents that catalog rows open through the normal Control UI chat surface and that transcript history uses bounded pagination, supporting provider-neutral UI handling of catalog identities. (extensions/codex/README.md:352, 4cbbb86d5e71)
  • Upstream Codex behavior: Official Codex app-server documentation defines separate thread identity, resume/fork operations, paginated thread listing, and paginated turn history; the patch does not alter those provider contracts. (../codex/codex-rs/app-server/README.md)

Likely related people:

  • steipete: Beyond authoring this patch, they also developed the adjacent paired-node Claude catalog continuation work and the coordinated UI, provider, and catalog tests, making them the clearest available routing candidate for this behavior. (role: current feature driver; confidence: medium; commits: 050aac219af5, 0a0eec17f1c8, 47591dfeaf92; files: ui/src/components/app-sidebar.ts, ui/src/pages/chat/chat-pane.ts, ui/src/lib/sessions/navigation.ts)
  • vincentkoc: Recent repository history includes shared Control UI and session-tab refactors, making them a plausible secondary reviewer for sidebar navigation and extraction boundaries, though the direct file-history trail was unavailable. (role: adjacent Control UI contributor; confidence: low; files: ui/src/components/app-sidebar.ts, ui/src/lib/sessions/navigation.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (2 earlier review cycles)
  • reviewed 2026-07-13T06:29:58.815Z sha 11a44a1 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-13T06:42:56.002Z sha f4859e2 :: needs real behavior proof before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. labels Jul 13, 2026
@steipete
steipete force-pushed the claude/web-ui-codecs-cloud-sessions-318ff8 branch from 11a44a1 to f4859e2 Compare July 13, 2026 06:35
@openclaw-barnacle openclaw-barnacle Bot removed the scripts Repository scripts label Jul 13, 2026
@openclaw-barnacle openclaw-barnacle Bot added the scripts Repository scripts label Jul 13, 2026
steipete added 5 commits July 13, 2026 00:39
…om desktop-app sources

- sidebar: no phantom chat row for catalog keys, active highlight on catalog rows,
  adopted sessions render as their live row inside the catalog group (deduped from
  the regular list), host subtitle only for paired-node rows
- chat: view-only banner only after catalog metadata proves canContinue=false
- chat->sidebar continued event binds the adopted row before the next catalog poll
- anthropic: local claude-desktop sessions share the ~/.claude/projects store, so
  list them as continuable and allow catalog continue to fork-resume them
…dules

Keeps app-sidebar/chat-pane/anthropic session-catalog under the LOC ratchet by
moving cohesive blocks: sidebar catalog groups + adopted-row binding into
app-sidebar-session-catalogs.ts, the catalog metadata lookup into
catalog-key.ts, and the Claude node-host commands into
session-catalog-node-commands.ts; ratchet baselines down for all three.
…pin SDK surface

The node-command module now owns its capability constant, projects-store
probe, and params parsing, so the catalog engine exports nothing new.
Repin the SDK surface budgets (+1 export/+1 callable landed on main
without a pin bump); unexport the UI helper types knip flagged.
@steipete
steipete force-pushed the claude/web-ui-codecs-cloud-sessions-318ff8 branch from 6ac8221 to 32f3b6e Compare July 13, 2026 07:46
@steipete
steipete merged commit c2521d7 into main Jul 13, 2026
93 of 100 checks passed
@steipete
steipete deleted the claude/web-ui-codecs-cloud-sessions-318ff8 branch July 13, 2026 07:49
wm0018 pushed a commit to wm0018/openclaw that referenced this pull request Jul 14, 2026
…pp sources (openclaw#106074)

* fix(ui): make catalog sessions selectable in place and continuable from desktop-app sources

- sidebar: no phantom chat row for catalog keys, active highlight on catalog rows,
  adopted sessions render as their live row inside the catalog group (deduped from
  the regular list), host subtitle only for paired-node rows
- chat: view-only banner only after catalog metadata proves canContinue=false
- chat->sidebar continued event binds the adopted row before the next catalog poll
- anthropic: local claude-desktop sessions share the ~/.claude/projects store, so
  list them as continuable and allow catalog continue to fork-resume them

* refactor(ui): extract catalog row rendering and lookup into shared modules

Keeps app-sidebar/chat-pane/anthropic session-catalog under the LOC ratchet by
moving cohesive blocks: sidebar catalog groups + adopted-row binding into
app-sidebar-session-catalogs.ts, the catalog metadata lookup into
catalog-key.ts, and the Claude node-host commands into
session-catalog-node-commands.ts; ratchet baselines down for all three.

* fix(ui): explain the disabled composer when catalog metadata cannot resolve a session

* style(ui): keep chat-pane within the LOC ratchet

* fix(anthropic): keep catalog node-command helpers module-local and repin SDK surface

The node-command module now owns its capability constant, projects-store
probe, and params parsing, so the catalog engine exports nothing new.
Repin the SDK surface budgets (+1 export/+1 callable landed on main
without a pin bump); unexport the UI helper types knip flagged.
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 14, 2026
…pp sources (openclaw#106074)

* fix(ui): make catalog sessions selectable in place and continuable from desktop-app sources

- sidebar: no phantom chat row for catalog keys, active highlight on catalog rows,
  adopted sessions render as their live row inside the catalog group (deduped from
  the regular list), host subtitle only for paired-node rows
- chat: view-only banner only after catalog metadata proves canContinue=false
- chat->sidebar continued event binds the adopted row before the next catalog poll
- anthropic: local claude-desktop sessions share the ~/.claude/projects store, so
  list them as continuable and allow catalog continue to fork-resume them

* refactor(ui): extract catalog row rendering and lookup into shared modules

Keeps app-sidebar/chat-pane/anthropic session-catalog under the LOC ratchet by
moving cohesive blocks: sidebar catalog groups + adopted-row binding into
app-sidebar-session-catalogs.ts, the catalog metadata lookup into
catalog-key.ts, and the Claude node-host commands into
session-catalog-node-commands.ts; ratchet baselines down for all three.

* fix(ui): explain the disabled composer when catalog metadata cannot resolve a session

* style(ui): keep chat-pane within the LOC ratchet

* fix(anthropic): keep catalog node-command helpers module-local and repin SDK surface

The node-command module now owns its capability constant, projects-store
probe, and params parsing, so the catalog engine exports nothing new.
Repin the SDK surface budgets (+1 export/+1 callable landed on main
without a pin bump); unexport the UI helper types knip flagged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui extensions: anthropic maintainer Maintainer-authored PR P1 High-priority user-facing bug, regression, or broken workflow. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. scripts Repository scripts size: L status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant