add resizing

This commit is contained in:
2026-01-20 15:31:41 -05:00
parent 66b4acaf42
commit b6f772f901
22 changed files with 1727 additions and 420 deletions
+98 -128
View File
@@ -1,167 +1,137 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Spiceflow is an AI Session Orchestration PWA for monitoring and interacting with Claude Code and OpenCode CLI sessions from mobile devices or web browsers. It's a monorepo with three main components: a Clojure backend server, a SvelteKit frontend, and Playwright E2E tests.
## Commands
### Backend (Clojure)
```bash
./script/dev # Start backend + frontend
./script/test # Run E2E tests
```
### Backend
```bash
cd server
clj -M:run # Start server (port 3000)
clj -M:test # Run tests with Kaocha
clj -M:repl # Start REPL with nREPL for interactive development
clj -M:dev # Start REPL with dev tools
clj -M:run # Start server (production mode)
clj -M:test # Run unit tests
```
### Frontend (SvelteKit)
**REPL commands:**
```clojure
(go) ; Start server + file watcher
(reset) ; Reload code
(stop) ; Stop server
```
### Frontend
```bash
cd client
npm install # Install dependencies
npm run dev # Start dev server (port 5173, proxies /api to 3000)
npm run build # Production build
npm run check # Type checking with svelte-check
npm run check:watch # Watch mode for type checking
npm install
npm run dev # Dev server
npm run build # Production build
npm run check # TypeScript check
```
### E2E Tests (Playwright)
### E2E Tests
```bash
cd e2e
npm test # Run all tests (starts both servers automatically)
npm run test:headed # Run tests with visible browser
npm run test:ui # Interactive Playwright UI mode
npm test
npm run test:headed # Visible browser
npm run test:ui # Interactive explorer
```
E2E tests use a separate database (`server/test-e2e.db`).
### Development Scripts
```bash
./script/dev # Start backend + frontend concurrently
./script/test # Start servers and run E2E tests
```
The `dev` script starts both servers and waits for each to be ready before proceeding. The `test` script uses a separate test database and cleans up after tests complete.
## Architecture
### Backend
```
Claude Code/OpenCode CLI ↔ Spiceflow Server (Clojure) ↔ PWA Client (SvelteKit)
SQLite DB
server/src/spiceflow/
├── core.clj # Entry point
├── config.clj # Settings from config.edn
├── db/
│ ├── protocol.clj # DataStore interface
│ ├── sqlite.clj # SQLite implementation
│ └── memory.clj # In-memory (tests)
├── adapters/
│ ├── protocol.clj # AgentAdapter interface
│ ├── claude.clj # Claude Code CLI
│ ├── opencode.clj # OpenCode CLI
│ └── tmux.clj # Terminal multiplexer
├── api/
│ ├── routes.clj # HTTP endpoints
│ └── websocket.clj # Real-time streaming
└── session/
└── manager.clj # Session lifecycle
```
### Backend (`/server`)
### Frontend
- **Entry point**: `src/spiceflow/core.clj` - Ring/Jetty server with mount lifecycle
- **Routing**: `src/spiceflow/api/routes.clj` - Reitit-based REST API
- **Database**: Protocol-based abstraction (`db/protocol.clj`) with SQLite (`db/sqlite.clj`) and in-memory (`db/memory.clj`) implementations
- **Adapters**: Pluggable CLI integrations (`adapters/protocol.clj`) - Claude Code (`adapters/claude.clj`) and OpenCode (`adapters/opencode.clj`)
- **WebSocket**: `api/websocket.clj` - Real-time message streaming
- **Session management**: `session/manager.clj` - Session lifecycle
```
client/src/
├── routes/ # SvelteKit file-based routing
│ ├── +layout.svelte
│ ├── +page.svelte # Home (session list)
│ └── session/[id]/+page.svelte
├── lib/
│ ├── api.ts # HTTP + WebSocket client
│ ├── stores/sessions.ts
│ └── components/
└── app.css # Tailwind
```
### Frontend (`/client`)
### Protocols
- **Routes**: SvelteKit file-based routing in `src/routes/`
- **State**: Svelte stores in `src/lib/stores/` (sessions, runtime selection)
- **API client**: `src/lib/api.ts` - HTTP and WebSocket clients
- **Components**: `src/lib/components/` - UI components
- `MessageList.svelte` - Displays messages with collapsible long content
- `PermissionRequest.svelte` - Permission prompts with accept/deny/steer actions
- `FileDiff.svelte` - Expandable file diffs for Write/Edit operations
- `SessionSettings.svelte` - Session settings dropdown (auto-accept edits)
- `InputBar.svelte` - Message input with steer mode support
- **PWA**: vite-plugin-pwa with Workbox service worker
- **Responsive**: Landscape mobile mode collapses header to hamburger menu
Database and CLI adapters use protocols for swappability:
### Key Protocols
```clojure
(defprotocol DataStore
(get-sessions [this])
(save-message [this msg]))
**DataStore** (`db/protocol.clj`):
- `get-sessions`, `get-session`, `save-session`, `update-session`, `delete-session`
- `get-messages`, `save-message`
**AgentAdapter** (`adapters/protocol.clj`):
- `discover` - Find existing CLI sessions
- `spawn` - Start CLI process with session
- `send` - Pipe message to stdin
- `read-stream` - Parse JSONL output
- Adding new runtimes requires implementing this protocol
## Configuration
Server configuration via `server/resources/config.edn` or environment variables:
| Variable | Default | Description |
|----------|---------|-------------|
| `SPICEFLOW_PORT` | 3000 | Server port |
| `SPICEFLOW_HOST` | 0.0.0.0 | Server host |
| `SPICEFLOW_DB` | spiceflow.db | SQLite database path |
| `CLAUDE_SESSIONS_DIR` | ~/.claude/projects | Claude sessions directory |
| `OPENCODE_CMD` | opencode | OpenCode command |
## Features
### Permission Handling
When Claude Code requests permission for file operations (Write/Edit) or shell commands (Bash), Spiceflow intercepts these and presents them to the user:
- **Accept**: Grant permission and continue
- **Deny**: Reject the request
- **Steer ("No, and...")**: Redirect Claude with alternative instructions
File operations show expandable diffs displaying the exact changes being made.
### Auto-Accept Edits
Claude sessions can enable "Auto-accept edits" in session settings (gear icon) to automatically grant file operation permissions. When enabled:
- **Applies to**: `Write` and `Edit` tools only (file create/modify operations)
- **Does NOT apply to**: `Bash`, `WebFetch`, `WebSearch`, `NotebookEdit`, or other tools
- **Behavior**: Permission is still recorded in message history (green "accepted" status) but no user interaction required
- **Use case**: Reduces interruptions during coding sessions when you trust Claude to make file changes
Other permission types (shell commands, web access, etc.) will still prompt for manual approval.
### Session Management
- **Rename**: Click session title to rename
- **Delete**: Remove sessions from the session list
- **Condense**: Collapse long messages for easier scrolling
### Mobile Optimization
- Landscape mode collapses the header to a hamburger menu
- Compact file diffs with minimal padding
- Touch-friendly permission buttons
## Session Flow
1. User opens PWA → sees list of tracked sessions
2. User selects session → loads message history
3. User types message → POST to `/api/sessions/:id/send`
4. Server spawns CLI process with `--resume` flag
5. Server pipes user message to stdin
6. CLI streams response via stdout (JSONL format)
7. Server broadcasts to client via WebSocket
8. **If permission required** → WebSocket sends permission request → User accepts/denies/steers
9. Process completes → response saved to database
(defprotocol AgentAdapter
(spawn-session [this session])
(send-message [this session msg]))
```
## API Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/health` | GET | Health check |
| `/api/sessions` | GET | List all sessions |
| `/api/sessions` | POST | Create new session |
| `/api/sessions` | GET | List sessions |
| `/api/sessions` | POST | Create session |
| `/api/sessions/:id` | GET | Get session with messages |
| `/api/sessions/:id` | PATCH | Update session (title, auto-accept-edits) |
| `/api/sessions/:id` | PATCH | Update session |
| `/api/sessions/:id` | DELETE | Delete session |
| `/api/sessions/:id/send` | POST | Send message to session |
| `/api/sessions/:id/permission` | POST | Respond to permission request |
| `/ws` | WebSocket | Real-time message streaming |
| `/api/sessions/:id/send` | POST | Send message |
| `/api/sessions/:id/permission` | POST | Handle permission |
| `/api/sessions/:id/terminal` | GET | Get tmux content |
| `/api/sessions/:id/terminal/input` | POST | Send tmux input |
| `/api/ws` | WebSocket | Event streaming |
## Tech Stack
## Configuration
- **Backend**: Clojure 1.11, Ring/Jetty, Reitit, next.jdbc, SQLite, mount, Kaocha
- **Frontend**: SvelteKit 2.5, Svelte 4, TypeScript, Tailwind CSS, Vite, vite-plugin-pwa
- **E2E**: Playwright
Environment variables or `server/resources/config.edn`:
| Variable | Default | Description |
|----------|---------|-------------|
| `SPICEFLOW_PORT` | 3000 | Server port |
| `SPICEFLOW_HOST` | 0.0.0.0 | Server host |
| `SPICEFLOW_DB` | spiceflow.db | SQLite path |
| `CLAUDE_SESSIONS_DIR` | ~/.claude/projects | Claude sessions |
| `OPENCODE_CMD` | opencode | OpenCode binary |
## Subdirectory CLAUDE.md Files
Each directory has specific details:
- `server/` - REPL workflow, Mount lifecycle
- `server/src/spiceflow/db/` - Schema, queries
- `server/src/spiceflow/adapters/` - Adding adapters
- `server/src/spiceflow/api/` - HTTP handlers, WebSocket
- `server/src/spiceflow/session/` - Session state
- `client/` - SvelteKit, PWA
- `client/src/lib/` - API client, stores
- `client/src/routes/` - Pages, routing
- `e2e/` - E2E tests