Skip to content

Expose AI sessions to apps/ui, grouped by owner site#3133

Merged
youknowriad merged 4 commits intotrunkfrom
claude/gifted-shirley-f29d91
Apr 18, 2026
Merged

Expose AI sessions to apps/ui, grouped by owner site#3133
youknowriad merged 4 commits intotrunkfrom
claude/gifted-shirley-f29d91

Conversation

@youknowriad
Copy link
Copy Markdown
Contributor

@youknowriad youknowriad commented Apr 18, 2026

How AI was used in this PR

Most of the scaffolding (shared-module move, IPC handlers, Connector plumbing, sidebar rewrite) was drafted by Claude under my direction. I reviewed each diff, made the design decisions below, and verified typecheck / lint / the full vitest suite locally. The Electron renderer itself was not booted as part of this change — the IPC contract is typed end-to-end but not runtime-exercised yet.

Proposed Changes

First step toward the new apps/ui: surface the AI sessions that the studio code CLI writes to disk, grouped by the site ("project") that owns them, instead of the current bottom-of-sidebar sites selector.

  • Shared sessions module: move the parts of apps/cli/ai/sessions/ that don't depend on CLI-only types (types, file-naming, summary, store, paths) into tools/common/ai/sessions/, parameterized on the sessions root directory. recorder, context and replay stay CLI-only; the CLI exposes a thin wrapper that binds its appdata root so existing callers and tests are unchanged. SDKMessage becomes unknown in the shared type so tools/common stays SDK-free; the CLI casts at its boundaries.
  • Owner site: AiSessionSummary gains ownerSitePath / ownerSiteName, computed from the first site.selected event in the JSONL (pin-on-create). The existing selectedSiteName keeps its meaning (latest in-session site). The recorder is unchanged, so sessions with no site remain valid and land in an "Unassigned" bucket.
  • Main-process IPC: new apps/studio/src/lib/ai-sessions.ts resolves the root via app.getPath('userData') (physically the same dir the CLI writes to). listAiSessions, loadAiSession, deleteAiSession exported from ipc-handlers.ts and wired through preload.ts.
  • Apps/ui: Connector gains getSessions / getSession / deleteSession, wired in the IPC connector. New useSessions / useSession / useDeleteSession hooks. The sidebar's SiteList is replaced by ProjectList: sites render as collapsible top-level groups with their sessions nested underneath, plus an "Unassigned" group for sessions with no owner. Clicking a session routes to a /sessions/$sessionId placeholder that confirms the session loaded — the AI chat UI will land on top of this in a follow-up.

Notable non-goals / deferred

  • "New session" and "Add site" buttons are visual placeholders — no action wired yet.
  • No AI chat UI yet (explicitly deferred per the issue of focus).
  • No reassigning a session to a different project yet. Since the binding is derived from a JSONL event, reassignment later can be done by appending a new event or a dedicated session.project event — no schema lock-in.
  • CLI site-switching behavior is unchanged: users can still switch sites mid-session; those switches don't move the session between projects in the sidebar.

Testing Instructions

  1. Run npm install if needed, then npm run typecheck and npm test — both should be green (1468 tests pass locally).
  2. Use the existing CLI to produce some sessions: npm run cli:build && node apps/cli/dist/cli/main.mjs code — send a prompt, select a site, then exit.
  3. Start the desktop app with npm start. The legacy UI is unaffected.
  4. For the new UI, build and open apps/ui once it's wired into the dev flow. You should see each site as a top-level project in the sidebar with its sessions underneath. Clicking a session navigates to a placeholder detail screen showing the first prompt, owner site name, and event count.

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors? (typecheck + lint + vitest all clean; no runtime exercise of the Electron IPC path)

🤖 Generated with Claude Code

Move the shared parts of the CLI's AI sessions module
(types, file-naming, summary, store, paths) to tools/common/ai/sessions
so the main process and the new apps/ui can read the same JSONL files
the CLI writes. The CLI keeps thin wrappers that bind its appdata root;
recorder/context/replay stay CLI-only.

Derive an ownerSitePath/ownerSiteName on AiSessionSummary from the
first site.selected event so each session has a stable project owner
even when the CLI switches sites mid-session.

Add listAiSessions / loadAiSession / deleteAiSession IPC handlers and
wire them through preload. Extend the apps/ui Connector with matching
methods, add a useSessions hook, and rework the sidebar into a
ProjectList that shows each site as a top-level project with its
sessions nested underneath, plus an "Unassigned" bucket for sessions
with no owner. A /sessions/$sessionId placeholder route confirms the
load path ahead of the AI chat UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@wpmobilebot
Copy link
Copy Markdown
Collaborator

wpmobilebot commented Apr 18, 2026

📊 Performance Test Results

Comparing 4bfe299 vs trunk

app-size

Metric trunk 4bfe299 Diff Change
App Size (Mac) 1439.57 MB 1439.59 MB +0.02 MB ⚪ 0.0%

site-editor

Metric trunk 4bfe299 Diff Change
load 1643 ms 1818 ms +175 ms 🔴 10.7%

site-startup

Metric trunk 4bfe299 Diff Change
siteCreation 8134 ms 8143 ms +9 ms ⚪ 0.0%
siteStartup 4953 ms 4955 ms +2 ms ⚪ 0.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

youknowriad and others added 3 commits April 18, 2026 13:12
… actions

- Turn on ThemeProvider density="compact" so all @wordpress/ui components
  shrink their paddings in unison, instead of patching sizes per-component.
- Drop orphaned sessions (owner site no longer exists) into the Unassigned
  bucket so they stay reachable instead of silently disappearing.
- Rework the project row so the trigger button spans the full width and
  its focus ring wraps the whole row; the "new session" plus sits on top
  as an absolutely-positioned IconButton that fades in on hover or
  focus-within.
- Tighten visual hierarchy: project titles use regular weight at 0.65
  opacity, session links sit at full neutral foreground, sessions and
  the empty-state message share the same left padding so they line up
  past the chevron.
- Collapse the Unassigned group by default and separate it from real
  projects with a divider.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Switch the chevron and the "Add site" plus from the raw @wordpress/icons
Icon (hardcoded sizes) to Button.Icon so they share the component-driven
layout inside a Button. Set both to size={16} to match the per-project
IconButton at size="small", and scale the SVG content to 0.75 so the
paths have visual padding inside their 16×16 box.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
apps/cli/ai/sessions/store.ts and the three functions in
apps/studio/src/lib/ai-sessions.ts were just partial application -
binding the sessions root directory before delegating to the
@studio/common store. That indirection costs more than it saves: every
caller now imports from @studio/common directly and passes
getAiSessionsRootDirectory() explicitly. Flatter, more honest.

Also sort the sidebar's project groups by the newest session's
updatedAt so the most-recently-used project lands at the top and
auto-expands on launch. Projects with no sessions drop to the bottom;
Unassigned stays pinned at the end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@youknowriad youknowriad merged commit c6b8008 into trunk Apr 18, 2026
10 checks passed
@youknowriad youknowriad deleted the claude/gifted-shirley-f29d91 branch April 18, 2026 14:51
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