-
Notifications
You must be signed in to change notification settings - Fork 541
feat: Implement slash command menu with fixed positioning and dark mode #211
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
joshwilhelmi
wants to merge
34
commits into
siteboon:main
Choose a base branch
from
GobbyAI:feat/slash-commands
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 33 commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
582621c
feat: Add token budget tracking and multiple improvements
joshwilhelmi e64df37
feat: Add session processing state persistence
joshwilhelmi 5a11b45
feat: Make context window size configurable via environment variables
joshwilhelmi 70f0f5e
fix: Decode HTML entities in chat message display
joshwilhelmi d3e5c96
Merge branch 'main' into feat/token-budget-and-improvements
viper151 d3736c5
refactor: Align package.json with main branch standards
joshwilhelmi 61d6676
feat: Replace CLI implementation with Claude Agents SDK
joshwilhelmi 897f893
Update server/claude-sdk.js
joshwilhelmi 5650b41
Update server/index.js
joshwilhelmi 874b757
Update src/components/ChatInterface.jsx
joshwilhelmi ec9da70
Update src/components/ChatInterface.jsx
joshwilhelmi 41558a9
Update src/components/ChatInterface.jsx
joshwilhelmi 599b388
fix: Prevent stale token-usage data from updating state on session sw…
joshwilhelmi 22cc118
Update src/components/TokenUsagePie.jsx
joshwilhelmi 6714d2e
feat: Implement slash command menu with fixed positioning and dark mo…
joshwilhelmi dc0b69b
Update server/index.js
joshwilhelmi c614f85
Update server/utils/commandParser.js
joshwilhelmi d8466b8
Update src/components/ChatInterface.jsx
joshwilhelmi 5ac07a8
Update src/components/ChatInterface.jsx
joshwilhelmi e8369ac
Update server/routes/commands.js
joshwilhelmi d9cdd68
Update src/components/ChatInterface.jsx
joshwilhelmi 4e7bf64
Update server/index.js
joshwilhelmi 72a1600
Update server/utils/commandParser.js
joshwilhelmi 19ab4c2
fix: Add responsive width constraints to CommandMenu
joshwilhelmi fe52595
fix: Security and stability improvements for command execution and fi…
joshwilhelmi 0c6ecc3
fix: Wrap orphaned token-usage endpoint code in proper async handler
joshwilhelmi 27a8524
security: Add path traversal protection to file operation endpoints
joshwilhelmi db998bf
fix: Use WebSocket.OPEN constant instead of instance properties
joshwilhelmi 6d99039
fix: Improve token usage tracking and fix race conditions
joshwilhelmi 2d1098c
fix: Improve CommandMenu positioning for mobile devices
joshwilhelmi 0e07ba3
fix: Add click-outside detection and improve CommandMenu positioning
joshwilhelmi fe0f1ab
debug: Add console logging and improve mobile positioning logic
joshwilhelmi 67fac1f
fix: Use bottom positioning for CommandMenu on mobile
joshwilhelmi a72a35c
fix: Filter Invalid API key messages from session titles
joshwilhelmi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,307 @@ | ||
# Claude Code UI - Architecture Documentation | ||
|
||
Generated: 2025-10-13 | ||
Purpose: Foundation for slash commands implementation | ||
|
||
## Technology Stack | ||
|
||
### Backend | ||
- **Node.js** with ES Modules (`"type": "module"`) | ||
- **Express.js** v4.18.2 - Web framework | ||
- **WebSocket (ws)** v8.14.2 - Real-time communication | ||
- **Better-SQLite3** v12.2.0 - Session/message persistence | ||
- **Authentication**: JWT (jsonwebtoken v9.0.2) + bcrypt v6.0.0 | ||
- **Process Management**: | ||
- node-pty v1.1.0-beta34 (terminal emulation) | ||
- cross-spawn v7.0.3 (process spawning) | ||
- **Claude SDK**: @anthropic-ai/claude-agent-sdk v0.1.13 | ||
|
||
### Frontend | ||
- **React** v18.2.0 | ||
- **Build Tool**: Vite v7.0.4 | ||
- **Styling**: TailwindCSS v3.4.0 + @tailwindcss/typography | ||
- **Routing**: react-router-dom v6.8.1 | ||
- **Code Editor**: @uiw/react-codemirror v4.23.13 | ||
- **Markdown**: react-markdown v10.1.0 | ||
- **File Upload**: react-dropzone v14.2.3 | ||
- **Terminal**: @xterm/xterm v5.5.0 with WebGL addon | ||
|
||
## Project Structure | ||
|
||
``` | ||
claudecodeui/ | ||
├── server/ | ||
│ ├── index.js # Main server file (Express + WebSocket) | ||
│ ├── claude-sdk.js # Claude SDK wrapper | ||
│ ├── cursor-cli.js # Cursor CLI integration | ||
│ ├── projects.js # Project management utilities | ||
│ ├── database/ | ||
│ │ └── db.js # SQLite database initialization | ||
│ ├── middleware/ | ||
│ │ └── auth.js # JWT authentication & validation | ||
│ ├── routes/ | ||
│ │ ├── auth.js # Authentication endpoints | ||
│ │ ├── cursor.js # Cursor-specific routes | ||
│ │ ├── git.js # Git operations | ||
│ │ ├── mcp.js # MCP server management | ||
│ │ ├── mcp-utils.js # MCP utilities | ||
│ │ └── taskmaster.js # Task Master integration | ||
│ └── utils/ | ||
│ ├── mcp-detector.js # MCP server detection | ||
│ └── taskmaster-websocket.js # Task Master WebSocket | ||
├── src/ | ||
│ ├── components/ | ||
│ │ ├── ChatInterface.jsx # Main chat component (2908 lines) | ||
│ │ ├── TodoList.jsx # Task display | ||
│ │ ├── TokenUsagePie.jsx # Token budget visualization | ||
│ │ └── ... (other UI components) | ||
│ ├── App.jsx # Root application | ||
│ └── main.jsx # React entry point | ||
├── dist/ # Built frontend files | ||
└── .taskmaster/ # Task Master files | ||
``` | ||
|
||
## API Endpoints (Express Routes) | ||
|
||
### Authentication (`/api/auth`) | ||
- POST `/api/auth/register` - User registration | ||
- POST `/api/auth/login` - User login | ||
- All other endpoints require JWT authentication | ||
|
||
### Projects (`/api/projects`) | ||
- GET `/api/projects` - List all projects | ||
- GET `/api/projects/:projectName/sessions` - Get sessions for project | ||
- GET `/api/projects/:projectName/sessions/:sessionId/messages` - Get messages | ||
- POST `/api/projects/create` - Create new project | ||
- GET `/api/projects/:projectName/file` - Read file content | ||
- GET `/api/projects/:projectName/files` - List project files | ||
- GET `/api/projects/:projectName/files/content` - Serve binary files | ||
- POST `/api/projects/:projectName/upload-images` - Upload images | ||
|
||
### Other APIs | ||
- GET `/api/config` - Get WebSocket configuration | ||
- GET `/api/browse-filesystem` - Browse filesystem for project selection | ||
- POST `/api/transcribe` - Audio transcription | ||
- GET `/api/sessions/:sessionId/token-usage` - Get token usage stats | ||
- `/api/git/*` - Git operations (via git.js router) | ||
- `/api/mcp/*` - MCP server management (via mcp.js router) | ||
- `/api/cursor/*` - Cursor operations (via cursor.js router) | ||
- `/api/taskmaster/*` - Task Master operations (via taskmaster.js router) | ||
- `/api/mcp-utils/*` - MCP utilities (via mcp-utils.js router) | ||
|
||
## WebSocket Architecture | ||
|
||
### WebSocket Server Setup | ||
- **Single WebSocket server** handling multiple paths | ||
- **Authentication**: Token-based via query params or headers | ||
- **Port**: Same as HTTP server (3001 default) | ||
- **Connection verification** in `verifyClient` callback | ||
|
||
### WebSocket Paths | ||
|
||
#### 1. Chat WebSocket (`/ws`) | ||
**Purpose**: Main chat communication with Claude | ||
**Handler**: `handleChatConnection(ws)` | ||
|
||
**Incoming Messages**: | ||
- `type: 'claude-command'` - Send message to Claude SDK | ||
- `command`: User prompt | ||
- `options`: { sessionId, cwd, toolsSettings, permissionMode, images } | ||
- `type: 'cursor-command'` - Send message to Cursor | ||
- `type: 'abort-session'` - Abort active session | ||
|
||
**Outgoing Messages**: | ||
- `type: 'session-created'` - New session ID from backend | ||
- `type: 'claude-response'` - Streaming response from Claude | ||
- `content`: Message content | ||
- `isComplete`: Boolean for stream end | ||
- `sessionId`: Current session ID | ||
- `type: 'claude-complete'` - Session finished | ||
- `type: 'session-aborted'` - Session aborted | ||
- `type: 'error'` - Error occurred | ||
- `type: 'token-budget'` - Token usage update | ||
- `type: 'claude-status'` - Status updates during processing | ||
|
||
#### 2. Shell WebSocket (`/shell`) | ||
**Purpose**: Terminal emulation for interactive shells | ||
**Handler**: `handleShellConnection(ws)` | ||
|
||
**Features**: | ||
- Interactive terminal using node-pty | ||
- Supports PowerShell (Windows) and bash/zsh (Unix) | ||
- Environment variable injection | ||
- Real-time input/output streaming | ||
|
||
## ChatInterface.jsx State Management | ||
|
||
### Input & Chat State | ||
```javascript | ||
const [input, setInput] = useState(''); // Current input text | ||
const [chatMessages, setChatMessages] = useState([]); // Chat history | ||
const [isLoading, setIsLoading] = useState(false); // Loading state | ||
const [currentSessionId, setCurrentSessionId] = useState(null); | ||
``` | ||
|
||
### File Attachment State | ||
```javascript | ||
const [showFileDropdown, setShowFileDropdown] = useState(false); | ||
const [fileList, setFileList] = useState([]); // Available files | ||
const [filteredFiles, setFilteredFiles] = useState([]); // Filtered by @ query | ||
const [selectedFileIndex, setSelectedFileIndex] = useState(-1); | ||
const [attachedImages, setAttachedImages] = useState([]); // Image attachments | ||
const [uploadingImages, setUploadingImages] = useState(new Map()); | ||
``` | ||
|
||
### Command State (Existing but Not Implemented) | ||
```javascript | ||
const [showCommandMenu, setShowCommandMenu] = useState(false); | ||
const [slashCommands, setSlashCommands] = useState([]); | ||
const [filteredCommands, setFilteredCommands] = useState([]); | ||
const [selectedCommandIndex, setSelectedCommandIndex] = useState(-1); | ||
const [slashPosition, setSlashPosition] = useState(-1); | ||
``` | ||
|
||
### Other State | ||
```javascript | ||
const [permissionMode, setPermissionMode] = useState('default'); // Tool permissions | ||
const [tokenBudget, setTokenBudget] = useState(null); // Token usage tracking | ||
const [claudeStatus, setClaudeStatus] = useState(null); // Claude status display | ||
const [provider, setProvider] = useState('claude'); // Claude vs Cursor | ||
const [isUserScrolledUp, setIsUserScrolledUp] = useState(false); | ||
``` | ||
|
||
### Key Refs | ||
```javascript | ||
const textareaRef = useRef(null); // Input textarea | ||
const scrollContainerRef = useRef(null); // Messages container | ||
const messagesEndRef = useRef(null); // Auto-scroll target | ||
``` | ||
|
||
## Input Handling Flow | ||
|
||
### Current Implementation | ||
1. **Input Change**: `handleInputChange(e)` | ||
- Updates input state | ||
- Tracks cursor position | ||
- Handles @ file mentions (existing) | ||
- **Slash commands NOT implemented** | ||
|
||
2. **Submit**: `handleSubmit(e)` | ||
- Uploads images if attached | ||
- Creates user message | ||
- Sends via WebSocket as `claude-command` or `cursor-command` | ||
- Marks session as active | ||
|
||
3. **File Mention (@)** | ||
- Detects `@` symbol in input | ||
- Shows dropdown with project files | ||
- Filters files by query | ||
- Keyboard navigation (Arrow keys, Enter, Escape) | ||
|
||
## Authentication Flow | ||
|
||
1. User logs in via `/api/auth/login` | ||
2. Server returns JWT token | ||
3. Token stored in localStorage as `'auth-token'` | ||
4. All API requests include `Authorization: Bearer <token>` header | ||
5. WebSocket connections include token in query params or headers | ||
6. Middleware (`authenticateToken`, `authenticateWebSocket`) validates tokens | ||
|
||
## Database Schema (SQLite) | ||
|
||
### Tables | ||
- `users` - User accounts (username, passwordHash) | ||
- `sessions` - Chat sessions (id, userId, projectName, title, createdAt) | ||
- `messages` - Chat messages (id, sessionId, role, content, timestamp) | ||
|
||
## Missing Dependencies for Slash Commands | ||
|
||
### Required npm Packages | ||
- ✅ Already have: express, ws, react, react-dom | ||
- ❌ Need to add: **gray-matter** (for frontmatter parsing in .md commands) | ||
- ❌ Optional: **fuse.js** (for fuzzy search in command autocomplete) | ||
|
||
## File System Conventions | ||
|
||
### .claude/commands/ Structure | ||
- Project-level commands at `.claude/commands/` | ||
- User-level commands at `~/.claude/commands/` | ||
- Commands are markdown files (`.md`) | ||
- Can be organized in subdirectories | ||
- Example: `.claude/commands/tm/next/next-task.md` | ||
|
||
### Command File Format | ||
```markdown | ||
--- | ||
description: Command description | ||
allowed-tools: [list, of, tools] | ||
model: claude-3-5-sonnet-20241022 | ||
--- | ||
|
||
Command prompt content with: | ||
- $ARGUMENTS for all args | ||
- $1, $2 for positional args | ||
- @filename for file includes | ||
- !command for bash execution | ||
``` | ||
|
||
## Integration Points for Slash Commands | ||
|
||
### Backend | ||
1. **New Router**: `server/routes/commands.js` | ||
- Mount at `/api/commands` in server/index.js | ||
- Add to protected routes with `authenticateToken` | ||
|
||
2. **New Utility**: `server/utils/commandParser.js` | ||
- Parse markdown with gray-matter | ||
- Replace variables | ||
- Handle file includes | ||
- Execute bash commands safely | ||
|
||
### Frontend | ||
3. **ChatInterface.jsx Modifications** | ||
- Implement `handleInputChange` slash detection | ||
- Fetch commands on mount via `/api/commands/list` | ||
- Filter commands as user types | ||
- Show CommandMenu dropdown | ||
- Execute command on selection | ||
|
||
4. **New Component**: `src/components/CommandMenu.jsx` | ||
- Dropdown UI for command autocomplete | ||
- Keyboard navigation (Arrow keys, Enter, Escape, Tab) | ||
- Mouse hover/click selection | ||
- Positioned near cursor | ||
|
||
## Security Considerations | ||
|
||
### Existing Security | ||
- JWT authentication on all API endpoints | ||
- Token validation in WebSocket connections | ||
- Path traversal prevention in file operations | ||
- bcrypt password hashing | ||
|
||
### Additional for Commands | ||
- Validate command paths (prevent directory traversal) | ||
- Limit file include depth (max 3 levels) | ||
- Timeout bash command execution (30 seconds) | ||
- Allowlist for bash commands | ||
- Validate file sizes for includes (<1MB) | ||
- Rate limiting on command execution (10/minute) | ||
|
||
## Performance Considerations | ||
|
||
- Debounce command filtering (150ms recommended) | ||
- Cache parsed commands in memory | ||
- Virtual scrolling for >20 commands (react-window) | ||
- Lazy load command files (only parse on execution) | ||
- LocalStorage cache for command list per project | ||
|
||
## Next Steps | ||
|
||
1. ✅ **Task #1 Complete**: Architecture documented | ||
2. **Task #2**: Create commands API router | ||
3. **Task #3**: Implement command parser utility | ||
4. **Task #4**: Build-in command handlers | ||
5. **Task #5-8**: Frontend implementation | ||
6. **Task #9**: MCP integration | ||
7. **Task #10**: Testing & error handling |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the documented token-usage endpoint.
GET /api/sessions/:sessionId/token-usage
doesn’t exist; the code exposes/api/projects/:projectName/sessions/:sessionId/token-usage
. Update the documentation so readers hit the working route.🧰 Tools
🪛 LanguageTool
[grammar] ~82-~82: There might be a mistake here.
Context: ...pi/config
- Get WebSocket configuration - GET
/api/browse-filesystem` - Browse fi...(QB_NEW_EN)
[grammar] ~83-~83: There might be a mistake here.
Context: ... Browse filesystem for project selection - POST
/api/transcribe
- Audio transcrip...(QB_NEW_EN)
[grammar] ~84-~84: There might be a mistake here.
Context: ...
/api/transcribe
- Audio transcription - GET `/api/sessions/:sessionId/token-usag...(QB_NEW_EN)
🤖 Prompt for AI Agents