# Ticket 10.5 — Resume OpenCode CLI Sessions

**Phase**: 10 — Feature Parity Enhancements
**Priority**: Medium
**Depends on**: None

## Description

Allow users to browse and resume sessions that were started in the OpenCode CLI terminal (not through the relay). claude-relay reads existing CLI sessions from `~/.claude/projects/{encoded-cwd}/` and presents them in a "Resume CLI Session" picker in the sidebar, converting CLI history to relay-compatible format and filtering already-imported sessions.

For OpenCode, sessions created via `opencode` CLI are stored in OpenCode's SQLite database and accessible via the REST API (`GET /session`). The relay already fetches sessions from OpenCode, but it doesn't distinguish between relay-created sessions and CLI-created sessions, nor does it offer a dedicated "resume" flow for sessions started outside the relay. This ticket adds:

- A "Resume CLI Session" action button in the sidebar
- A picker that shows sessions not currently tracked by the relay, with metadata (first prompt, model, timestamp)
- Clicking a session adds it to the relay's session list and switches to it

Note: Currently the sidebar has a crude "Resume with ID" button that uses a raw browser `prompt()` dialog. This ticket replaces that with a proper UI.

## Acceptance Criteria

### AC1: Resume button opens picker with untracked sessions
```gherkin
Given the user clicks the "Resume CLI Session" button in the sidebar
When the picker opens
Then it fetches all sessions from OpenCode via GET /session
  And displays only sessions not currently tracked by the relay
  And each session entry shows metadata (first prompt truncated, model, timestamp, git branch)
```

### AC2: Session metadata is displayed correctly
```gherkin
Given the resume picker is open with available sessions
When the user views the session list
Then each session shows the first user prompt truncated to 80 characters
  And the model name used for the session is displayed
  And the session timestamp is formatted as a relative time (e.g., "2 hours ago")
  And the git branch (if available) is displayed
```

### AC3: Clicking a session resumes it in the relay
```gherkin
Given the resume picker is open with available sessions
When the user clicks on a session entry
Then the session is added to the relay's tracked session list
  And the picker closes
  And the UI switches to the selected session
  And the session's message history is loaded and rendered
```

### AC4: Already-tracked sessions are filtered out
```gherkin
Given the relay is currently tracking sessions "abc123" and "def456"
  And OpenCode reports sessions "abc123", "def456", "ghi789", and "jkl012"
When the resume picker opens
Then only sessions "ghi789" and "jkl012" appear in the picker
  And sessions "abc123" and "def456" are excluded
```

### AC5: Raw prompt() dialog is replaced
```gherkin
Given the sidebar previously had a "Resume with ID" button using prompt()
When the user views the sidebar
Then the raw prompt() button is no longer present
  And the "Resume CLI Session" button with proper picker UI is shown instead
```

### AC6: Empty state when no untracked sessions exist
```gherkin
Given the relay is already tracking all sessions reported by OpenCode
When the user opens the resume picker
Then the picker displays an empty state message (e.g., "No CLI sessions to resume")
  And no session entries are listed
```

## Testable Components

| Component | Test Type | What to Assert |
|-----------|-----------|----------------|
| Session filtering (tracked vs untracked) | Unit | Given a list of all OpenCode sessions and a set of tracked session IDs, returns only sessions not in the tracked set |
| Session metadata parsing | Unit | Extracts first user prompt, model name, timestamp, and git branch from OpenCode session data; truncates prompt to 80 chars |
| Resume session flow | Integration | Clicking a session calls the correct API, adds it to the tracked list, switches the active session, and loads history |
| Resume picker UI rendering | E2E | Button opens picker overlay; sessions are listed with correct metadata; clicking a session closes picker and switches view |
| Empty state display | E2E | When all sessions are tracked, picker shows empty state message and no session entries |

## Reference

- claude-relay CLI session reader: `../claude-relay/lib/cli-sessions.js` (JSONL parsing, resume picker)
- claude-relay resume UI: `../claude-relay/lib/public/modules/sidebar.js` (resume picker in sidebar)
- Current resume hack: `conduit/src/lib/public/components/layout/Sidebar.svelte` (line 41, raw `prompt()`)
- OpenCode session API: `GET /session` (returns all sessions including CLI-created ones)
