Add terminal big mode, keyboard shortcuts menu, and UX refinements
- Reduce mobile terminal widths by 2 chars (portrait 42x24, landscape 86x24) - Add "Big mode" for mobile: desktop sizing (120x36) at 70% zoom - Click zoom percentage to reset to 100% - Add keyboard shortcuts submenu in session settings - Update PRD with all terminal features and documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -339,6 +339,38 @@ stream_session_response(session_id, callback)
|
||||
- Filters for `spiceflow-*` prefix
|
||||
- Returns managed sessions only
|
||||
|
||||
#### 4.1.5 External Tmux Session Import
|
||||
|
||||
Users can import existing tmux sessions not managed by Spiceflow:
|
||||
|
||||
1. **List External:** `GET /api/tmux/external` returns sessions without `spiceflow-` prefix
|
||||
2. **Import:** `POST /api/tmux/import` with session name
|
||||
3. **Rename:** Server renames `{name}` to `spiceflow-{name}`
|
||||
4. **Setup:** Enables pipe-pane capture for imported session
|
||||
5. **Return:** Session available in Spiceflow with new prefixed ID
|
||||
|
||||
#### 4.1.6 Session Rename
|
||||
|
||||
Sessions can be renamed via `PATCH /api/sessions/:id`:
|
||||
|
||||
**Claude/OpenCode:**
|
||||
- Updates title in database
|
||||
- Session ID remains unchanged
|
||||
|
||||
**Tmux:**
|
||||
- Renames tmux session via `tmux rename-session`
|
||||
- **Session ID changes** to new `spiceflow-{name}` format
|
||||
- Response includes `idChanged: true` and new session object
|
||||
- Client navigates to new URL with `replaceState`
|
||||
|
||||
#### 4.1.7 Session Eject (Tmux only)
|
||||
|
||||
Removes session from Spiceflow management while keeping it running:
|
||||
|
||||
1. Rename tmux session from `spiceflow-{name}` to `{name}`
|
||||
2. Delete session from Spiceflow database
|
||||
3. Session continues running, attachable via `tmux attach -t {name}`
|
||||
|
||||
### 4.2 Process Handle Structure
|
||||
|
||||
```clojure
|
||||
@@ -572,6 +604,11 @@ Permissions are recorded as assistant messages with metadata:
|
||||
- **Examples:** `spiceflow-brave-fox-0042`, `spiceflow-calm-owl-1337`
|
||||
- **Purpose:** Human-readable, unique identifiers
|
||||
|
||||
**Name Generation:**
|
||||
- 30 adjectives × 30 nouns = 900 base combinations
|
||||
- 4-digit random suffix (0000-9999)
|
||||
- Docker-style naming convention
|
||||
|
||||
#### 7.1.2 Output Capture
|
||||
|
||||
```bash
|
||||
@@ -635,10 +672,96 @@ tmux capture-pane -t {session-name} -p -e -S -1000
|
||||
|
||||
| Mode | Dimensions | Use Case |
|
||||
|------|------------|----------|
|
||||
| `portrait` | 40x24 | Phone portrait |
|
||||
| `landscape` | 65x24 | Phone landscape |
|
||||
| `desktop` | 100x24 | Split screen |
|
||||
| `fullscreen` | 180x24 | Full terminal |
|
||||
| `portrait` | 42x24 | Phone portrait |
|
||||
| `landscape` | 86x24 | Phone landscape |
|
||||
| `desktop` | 120x36 | Split screen |
|
||||
| `fullscreen` | 260x36 | Full terminal |
|
||||
|
||||
### 7.5 Auto Orientation Detection
|
||||
|
||||
On mobile devices, the terminal automatically resizes when the user rotates their phone:
|
||||
|
||||
```javascript
|
||||
screen.orientation.addEventListener('change', () => {
|
||||
const type = screen.orientation.type;
|
||||
if (type.includes('portrait')) {
|
||||
resizeScreen('portrait');
|
||||
} else if (type.includes('landscape')) {
|
||||
resizeScreen('landscape');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Trigger Conditions:**
|
||||
- Only on mobile (width < 640px or height < 450px)
|
||||
- Uses `screen.orientation` API (modern browsers)
|
||||
|
||||
### 7.6 Font Zoom Control
|
||||
|
||||
Terminal text size can be adjusted from 50% to 150% in 5% increments:
|
||||
|
||||
| Control | Action |
|
||||
|---------|--------|
|
||||
| `-` button | Decrease font scale |
|
||||
| `+` button | Increase font scale |
|
||||
| Percentage display | Shows current zoom; click to reset to 100% |
|
||||
|
||||
**Visibility:** Zoom controls hidden on mobile portrait, visible on landscape/desktop.
|
||||
|
||||
### 7.7 Big Mode
|
||||
|
||||
Mobile users can enable "Big mode" from the settings menu to view more terminal content:
|
||||
|
||||
- **Resize:** Sets terminal to desktop dimensions (120x36)
|
||||
- **Zoom:** Sets font scale to 70%
|
||||
- **Access:** Settings menu (gear icon) → "Big mode" button
|
||||
- **Visibility:** Only shown for tmux sessions on mobile devices
|
||||
|
||||
### 7.8 Session Eject
|
||||
|
||||
Tmux sessions can be "ejected" from Spiceflow management while keeping them running:
|
||||
|
||||
1. User clicks "Eject session" in settings menu
|
||||
2. Server renames session from `spiceflow-{name}` to `{name}`
|
||||
3. Session removed from Spiceflow database
|
||||
4. User can reattach manually via `tmux attach -t {name}`
|
||||
|
||||
**Use Case:** Transfer session to local terminal for continued work.
|
||||
|
||||
### 7.9 Keyboard Shortcuts
|
||||
|
||||
| Shortcut | Action |
|
||||
|----------|--------|
|
||||
| `Ctrl+Down` | Scroll to bottom |
|
||||
| `Ctrl+Shift+V` | Paste from clipboard |
|
||||
| `Shift+Enter` | Send literal newline |
|
||||
| `Shift+Tab` | Send reverse-tab escape sequence |
|
||||
| `^` toggle | Enable Ctrl mode (next letter sends control character) |
|
||||
|
||||
### 7.10 Quick Action Buttons
|
||||
|
||||
| Button | Function | Color |
|
||||
|--------|----------|-------|
|
||||
| `^` | Toggle Ctrl mode | Gray (cyan ring when active) |
|
||||
| `^C` | Send interrupt | Red |
|
||||
| `^D` | Send EOF | Amber |
|
||||
| `y` | Send 'y' | Green |
|
||||
| `n` | Send 'n' | Red |
|
||||
| `1-4` | Send number | Gray |
|
||||
| `⇥` | Send Tab | Cyan |
|
||||
| `⇤` | Send Shift+Tab | Cyan |
|
||||
| `↵` | Send Enter | Green |
|
||||
| `📋` | Paste clipboard | Violet |
|
||||
|
||||
**Visibility:** `^`, `y`, `n`, `1-4`, and paste hidden on mobile portrait.
|
||||
|
||||
### 7.11 ANSI Color Rendering
|
||||
|
||||
Terminal output preserves ANSI escape sequences:
|
||||
- Converted to HTML via `ansi-to-html` library
|
||||
- Default foreground: green (#22c55e)
|
||||
- Background: transparent
|
||||
- Supports standard terminal colors
|
||||
|
||||
---
|
||||
|
||||
@@ -954,6 +1077,23 @@ salt (16) || record_size (4) || keyid_len (1) || keyid (65) || ciphertext
|
||||
}
|
||||
```
|
||||
|
||||
#### POST /api/sessions/:id/eject
|
||||
|
||||
Ejects a tmux session from Spiceflow management (tmux only).
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "ejected",
|
||||
"message": "Session ejected. Reattach with: tmux attach -t {name}",
|
||||
"session-name": "my-session"
|
||||
}
|
||||
```
|
||||
|
||||
**Errors:**
|
||||
- 400: Not a tmux session
|
||||
- 404: Session not found
|
||||
|
||||
---
|
||||
|
||||
## 10. WebSocket Protocol
|
||||
@@ -1085,6 +1225,24 @@ salt (16) || record_size (4) || keyid_len (1) || keyid (65) || ciphertext
|
||||
- **Heartbeat:** Ping every 25 seconds
|
||||
- **Pong Timeout:** 10 seconds
|
||||
|
||||
### 10.5 Terminal Update Broadcasting
|
||||
|
||||
After tmux input, server broadcasts terminal updates:
|
||||
|
||||
1. Input received via `POST /api/sessions/:id/terminal/input`
|
||||
2. Input sent to tmux immediately
|
||||
3. 100ms delay for command execution
|
||||
4. Fresh terminal content captured
|
||||
5. Diff computed and broadcast via WebSocket
|
||||
6. Broadcast always sent (even if unchanged) to ensure client sync
|
||||
|
||||
### 10.6 Full Frame Refresh
|
||||
|
||||
To handle potential drift, the server periodically sends full frames:
|
||||
- Every 5 seconds during active streaming
|
||||
- On explicit `fresh=true` request
|
||||
- After terminal resize operations
|
||||
|
||||
---
|
||||
|
||||
## 11. User Interface
|
||||
@@ -1097,6 +1255,9 @@ salt (16) || record_size (4) || keyid_len (1) || keyid (65) || ciphertext
|
||||
┌─────────────────────────────────────────┐
|
||||
│ ☰ Spiceflow 🔔 + ↻ │
|
||||
├─────────────────────────────────────────┤
|
||||
│ ┌─────────────────────────────────┐ │
|
||||
│ │ ● 2 sessions processing │ │ (green badge, pulsing)
|
||||
│ └─────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────┐ │
|
||||
│ │ ● My Claude Session claude │ │
|
||||
@@ -1108,14 +1269,19 @@ salt (16) || record_size (4) || keyid_len (1) || keyid (65) || ciphertext
|
||||
│ │ /home/user 1d ago │ │
|
||||
│ └─────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────┐ │
|
||||
│ │ + Import tmux session │ │ (if external sessions exist)
|
||||
│ └─────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Elements:**
|
||||
- Header with branding and action buttons
|
||||
- Processing sessions counter (green pulsing badge)
|
||||
- Session cards with status indicators
|
||||
- Provider badges (color-coded)
|
||||
- Relative timestamps
|
||||
- Import button for external tmux sessions
|
||||
|
||||
#### Session Page (`/session/:id`)
|
||||
|
||||
@@ -1135,10 +1301,15 @@ salt (16) || record_size (4) || keyid_len (1) || keyid (65) || ciphertext
|
||||
│ └─────────────────────────────────┘ │
|
||||
│ │
|
||||
├─────────────────────────────────────────┤
|
||||
│ [Type a message... ] [➤] │
|
||||
│ [⌨] [Type a message... ] [➤] │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Mobile Keyboard Toggle:**
|
||||
- `⌨` button shows/hides mobile keyboard
|
||||
- Addresses issue where keyboard can hide input field
|
||||
- Toggles between up/down arrow indicators
|
||||
|
||||
**Terminal Mode (tmux):**
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
@@ -1164,7 +1335,7 @@ salt (16) || record_size (4) || keyid_len (1) || keyid (65) || ciphertext
|
||||
│ ⚠️ Claude needs permission │
|
||||
├─────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Write: /home/user/foo.md │
|
||||
│ Write: /home/user/foo.md .md │ (file extension badge)
|
||||
│ ┌─────────────────────────────────┐ │
|
||||
│ │ + 1 # My Haiku │ │
|
||||
│ │ + 2 │ │
|
||||
@@ -1177,6 +1348,14 @@ salt (16) || record_size (4) || keyid_len (1) || keyid (65) || ciphertext
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**File Diff Viewer:**
|
||||
- **Write operations:** All lines shown as green additions (+)
|
||||
- **Edit operations:** Old lines in red (-), new lines in green (+)
|
||||
- **Line numbers:** Shown for both old and new content
|
||||
- **File extension badge:** Displayed in top-right corner
|
||||
- **Hover highlighting:** Lines highlight on mouse over
|
||||
- **Tab handling:** Tabs rendered as 4 spaces
|
||||
|
||||
### 11.3 Component Inventory
|
||||
|
||||
| Component | Purpose | Props |
|
||||
@@ -1194,9 +1373,65 @@ salt (16) || record_size (4) || keyid_len (1) || keyid (65) || ciphertext
|
||||
|
||||
| Breakpoint | Header | Layout |
|
||||
|------------|--------|--------|
|
||||
| Portrait | Full header | Vertical stack |
|
||||
| Landscape mobile | Hamburger menu | Compact header |
|
||||
| Desktop | Full header | All controls visible |
|
||||
| Portrait (<640px width, >450px height) | Full header | Vertical stack |
|
||||
| Landscape mobile (<450px height) | Hamburger menu | Compact header |
|
||||
| Desktop (≥640px width, ≥450px height) | Full header | All controls visible |
|
||||
| XL Desktop (≥1280px width) | Full header | Mobile orientation buttons hidden |
|
||||
|
||||
### 11.5 Mobile-Specific UI Classes
|
||||
|
||||
| CSS Class | Behavior |
|
||||
|-----------|----------|
|
||||
| `portrait-hide` | Hidden on mobile portrait (width < 640px AND height > 450px) |
|
||||
| `desktop-only` | Hidden on mobile (width < 640px OR height < 450px) |
|
||||
| `mobile-only` | Hidden on XL desktop (width ≥ 1280px) |
|
||||
| `landscape-mobile:hidden` | Hidden when height < 450px |
|
||||
| `landscape-menu` | Shown only when height < 450px |
|
||||
|
||||
### 11.6 Message Condensing
|
||||
|
||||
Long messages (5+ lines) can be collapsed:
|
||||
|
||||
- **Threshold:** 5 lines minimum to show collapse toggle
|
||||
- **Preview:** Shows first 3 lines when collapsed
|
||||
- **Toggle:** Chevron indicator expands/collapses
|
||||
- **Bulk action:** "Condense all" in settings menu
|
||||
|
||||
### 11.7 Thinking Indicator
|
||||
|
||||
Animated indicator when Claude is processing:
|
||||
- Three bouncing dots (●●●)
|
||||
- Separate from streaming content display
|
||||
- Disappears when response completes or permission requested
|
||||
|
||||
### 11.8 Auto-Scroll Control
|
||||
|
||||
- **Default:** Enabled
|
||||
- **Persistence:** Saved to localStorage (`spiceflow-auto-scroll`)
|
||||
- **Toggle:** Available in session settings menu
|
||||
- **Behavior:** Scrolls to bottom on new content
|
||||
- **Override:** Ctrl+Down forces scroll regardless of setting
|
||||
|
||||
### 11.9 Session Status Indicators
|
||||
|
||||
| Status | Indicator |
|
||||
|--------|-----------|
|
||||
| Idle | Gray dot (static) |
|
||||
| Processing | Green dot (pulsing) |
|
||||
| Awaiting Permission | Amber dot (pulsing) |
|
||||
| Tmux Alive | Green dot |
|
||||
| Tmux Dead | Gray dot |
|
||||
|
||||
### 11.10 Markdown Rendering
|
||||
|
||||
Assistant messages render Markdown with:
|
||||
- Headings (h1-h6) with appropriate sizing
|
||||
- Code blocks with monospace font and background
|
||||
- Inline code with background highlight
|
||||
- Lists (ordered and unordered)
|
||||
- Blockquotes with left border
|
||||
- Links styled in orange (spice color)
|
||||
- Line breaks preserved (`breaks: true`)
|
||||
|
||||
---
|
||||
|
||||
@@ -1262,6 +1497,38 @@ salt (16) || record_size (4) || keyid_len (1) || keyid (65) || ciphertext
|
||||
8. User taps notification → app opens to session
|
||||
9. User sees permission UI, responds
|
||||
|
||||
### 12.6 Import External Tmux Session
|
||||
|
||||
1. User has existing tmux session running (e.g., `dev-session`)
|
||||
2. User opens Spiceflow home page
|
||||
3. "Import tmux session" button appears
|
||||
4. User clicks import → dropdown shows available sessions
|
||||
5. User selects `dev-session`
|
||||
6. Server renames to `spiceflow-dev-session`
|
||||
7. Session appears in Spiceflow list
|
||||
8. User can now manage session via Spiceflow
|
||||
|
||||
### 12.7 Eject Tmux Session
|
||||
|
||||
1. User opens tmux session in Spiceflow
|
||||
2. User clicks settings gear (⚙️)
|
||||
3. User clicks "Eject session"
|
||||
4. Confirmation alert shows reattach command
|
||||
5. Session renamed from `spiceflow-{name}` to `{name}`
|
||||
6. User redirected to home page
|
||||
7. Session removed from Spiceflow but continues running
|
||||
8. User can reattach via `tmux attach -t {name}`
|
||||
|
||||
### 12.8 Rotate Phone (Terminal)
|
||||
|
||||
1. User viewing terminal session on phone
|
||||
2. User rotates phone from portrait to landscape
|
||||
3. `screen.orientation` change event fires
|
||||
4. App detects orientation is now landscape
|
||||
5. Terminal automatically resizes to landscape dimensions (88x24)
|
||||
6. Fresh terminal content fetched after 150ms
|
||||
7. UI updates to show landscape-specific controls
|
||||
|
||||
---
|
||||
|
||||
## 13. Security Considerations
|
||||
|
||||
Reference in New Issue
Block a user