Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
bc96f08
feat: add CLI config detection page and proxy Claude support
yodeput Jan 31, 2026
70f4dd6
feat: standardize UI and refactor profile system
yodeput Jan 31, 2026
3f32198
docs: add system tray implementation plan
yodeput Jan 31, 2026
1a0bd81
feat: add system tray with profile/workspace switching
yodeput Jan 31, 2026
a5032c8
Merge remote-tracking branch 'origin/main' into feat/proxy-claude
yodeput Jan 31, 2026
1515736
Merge remote-tracking branch 'origin/main' into feat/remote-access
yodeput Feb 1, 2026
9c28c3e
feat: implement remote access with WebSocket tRPC subscription
yodeput Feb 2, 2026
68ca699
feat: add chat state sync between desktop and web clients
yodeput Feb 2, 2026
300a621
feat: hide Settings & Remote Access icons from web view
yodeput Feb 2, 2026
5a5ab7e
feat: sync workspace and chat lists between desktop and web
yodeput Feb 2, 2026
a53814b
feat: add connection error overlay for web app when disconnected
yodeput Feb 2, 2026
da3b021
fix: resolve circular dependency and WebSocket routing issues
yodeput Feb 2, 2026
9c5f271
fix: resolve circular dependency by keeping types inline in atoms/ind…
yodeput Feb 2, 2026
9956ae9
fix: move activeConfigAtom to model-profiles-sync.ts to break circula…
yodeput Feb 2, 2026
079aee7
fix: resolve circular dependency and IPC cloning error
yodeput Feb 2, 2026
831df56
fix: web chat subscription and sync issues
yodeput Feb 2, 2026
d4ba8e1
docs: update plan with push-based sync protocol
yodeput Feb 2, 2026
953fc0a
docs: expand tRPC removal task with detailed steps
yodeput Feb 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,558 changes: 0 additions & 2,558 deletions bun.lock

This file was deleted.

Binary file modified bun.lockb
Binary file not shown.
77 changes: 77 additions & 0 deletions docs/features/system-tray.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# System Tray

The app includes a persistent system tray icon that allows quick access to profiles and workspaces even when all windows are closed.

## Platform Support

- **macOS**: Menu bar icon (template image, adapts to light/dark mode)
- **Windows**: System tray icon (bottom-right)
- **Linux**: System tray icon (desktop environment dependent)

## Features

### Left Click
- Restores or creates the main window
- If windows are minimized, brings them to front
- If no windows exist, creates a new one

### Right Click Menu

```
├── Show 1Code (macOS only)
├── ─────────
├── Profiles ⊳
│ ├── ✓ Active Profile
│ └── Other Profiles
├── ─────────
├── Workspaces ⊳
│ └── Project List
├── ─────────
├── New Workspace...
├── Settings...
├── ─────────
└── Quit
```

### Profile Switching
- Click any profile to switch immediately
- All windows reload with new profile
- Active profile shown with checkmark

### Workspace Navigation
- Click workspace to open new chat with that workspace selected
- Creates window if needed
- Sets workspace and reloads

### Background Mode
- App continues running when all windows are closed
- Only way to quit is via tray menu or Cmd+Q
- Windows can be restored by clicking tray icon

## Implementation

### Files
- `src/main/lib/tray.ts` - Tray initialization and menu building
- `src/renderer/lib/tray-events.ts` - Renderer event listeners
- `resources/icons/tray-*.png` - Tray icon assets

### Menu Updates
Menu rebuilds when:
- Profiles are added/removed/switched
- Projects are added/removed
- App starts

## Troubleshooting

### Tray icon not appearing (macOS)
- Check System Settings → Control Center → Menu Bar Only
- Ensure "Show in Menu Bar" is enabled for the app

### Tray icon not appearing (Linux)
- Ensure desktop environment supports system tray
- Install system tray extensions if using GNOME
- Check if `libappindicator` is installed

### App won't quit
- Use tray menu → Quit
- Or press Cmd+Q from menu bar (macOS)
188 changes: 188 additions & 0 deletions docs/plans/2025-01-31-multiple-model-profiles-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# Multiple Model Profiles - Design Document

**Date:** 2025-01-31
**Status:** Approved
**Author:** AI Brainstorming Session

## Overview

Enable users to create and manage multiple Claude API proxy configurations (profiles), each with their own `ANTHROPIC_BASE_URL`, `ANTHROPIC_API_KEY`, and model name. Users can quickly switch between profiles from the settings UI and directly from the active chat interface.

## Problem Statement

Currently, the app supports only a single "Override Model" configuration. Users with multiple proxy configurations (e.g., local proxy, cloud proxy, different API keys) must manually edit these settings each time they want to switch. This is cumbersome and error-prone.

## Solution

Replace the single "Override Model" card with a profile list UI that supports:
- Creating, editing, deleting, and switching between multiple profiles
- Quick profile selector in the chat header for fast switching
- Auto-detection of CLI config to suggest creating a profile
- Legacy migration from existing single config

## Section 1: UI Layout

### Model Profiles List

The "Override Model" section in [agents-models-tab.tsx](../src/renderer/components/dialogs/settings-tabs/agents-models-tab.tsx) will be replaced with a list of profile cards.

**ProfileRow Component Structure:**

```
┌─────────────────────────────────────────────────────────────────┐
│ Profile Name [Active] [⋮] │
│ Model: claude-3-7-sonnet-20250219 │
│ Proxy: http://localhost:8080 │
└─────────────────────────────────────────────────────────────────┘
```

- **Profile Name**: User-defined name (e.g., "Local Proxy", "Cloud Gateway")
- **Active Badge**: Shows which profile is currently active
- **Actions Menu (⋮)**: Edit, Delete, Set Active

**Empty State:**
- When no profiles exist (excluding offline), show "Add your first proxy configuration"
- Button to open the add form

## Section 2: Add/Edit Form & CRUD Operations

### Inline Add/Edit Form

When user clicks "Add Profile" or edits an existing profile, an inline form expands:

```tsx
interface ProfileFormState {
mode: 'add' | 'edit'
profileId?: string // set when editing
fields: {
name: string
model: string
token: string
baseUrl: string
}
}
```

**Form Fields:**
- Name (text input, required)
- Model (text input, placeholder: "claude-3-7-sonnet-20250219")
- API Token (password input, placeholder: "sk-ant-...")
- Base URL (text input, placeholder: "https://api.anthropic.com")

**Validation:**
- All fields required
- Token should start with "sk-ant-" (warning only, not blocking)
- Base URL should be a valid URL format

### CRUD Operations Table

| Operation | Action | Atoms Updated |
|-----------|--------|---------------|
| **Add** | Push new profile to `modelProfilesAtom` | `modelProfilesAtom`, `activeProfileIdAtom` (if first) |
| **Edit** | Find by ID and update in `modelProfilesAtom` | `modelProfilesAtom` |
| **Delete** | Filter out by ID from `modelProfilesAtom` | `modelProfilesAtom`, `activeProfileIdAtom` (if deleting active) |
| **Set Active** | Update `activeProfileIdAtom` | `activeProfileIdAtom` |

**Delete Behavior:**
- If deleting the active profile, auto-select the next available profile
- If no profiles remain, set `activeProfileIdAtom` to `null` (use default)
- Show confirmation dialog for delete

## Section 3: Integration

### Existing System Integration

The `activeConfigAtom` in [atoms/index.ts](../src/renderer/lib/atoms/index.ts) already handles the priority chain:

```typescript
// Priority chain:
// 1. Auto-offline (if enabled and no internet)
// 2. Active profile (if selected)
// 3. Legacy single config (backwards compat)
// 4. None (use Claude Code default)
```

**No changes needed to `activeConfigAtom`** - it already reads from `activeProfileIdAtom` and `modelProfilesAtom`.

### CLI Config Auto-Detection

The existing [cli-config-detected-page.tsx](../src/renderer/features/onboarding/cli-config-detected-page.tsx) detects environment variables. Extend it to offer creating a profile:

**Flow:**
1. User has `ANTHROPIC_BASE_URL` and/or `ANTHROPIC_API_KEY` in env
2. App shows "Configuration Detected" page
3. User clicks "Use Existing Configuration"
4. **NEW**: Prompt "Save as a profile?" with Yes/No
5. If Yes, open inline form with detected values pre-filled

### Legacy Migration

On app startup, check if `customClaudeConfigAtom` has values:

```typescript
// One-time migration
useEffect(() => {
const legacyConfig = get(customClaudeConfigAtom)
const profiles = get(modelProfilesAtom)

// Only migrate if legacy has values and profiles is default (only offline)
if (normalizeCustomClaudeConfig(legacyConfig) && profiles.length === 1) {
const migratedProfile: ModelProfile = {
id: crypto.randomUUID(),
name: "Migrated Config",
config: legacyConfig,
}
set(modelProfilesAtom, [OFFLINE_PROFILE, migratedProfile])
set(activeProfileIdAtom, migratedProfile.id)
// Clear legacy
set(customClaudeConfigAtom, EMPTY_CONFIG)
}
}, [])
```

### Quick Selector in Chat

Add a dropdown in the chat header ([active-chat.tsx](../src/renderer/features/agents/main/active-chat.tsx)) for fast profile switching:

```
┌─────────────────────────────────────────────────────────────────┐
│ [New Chat] [Profile: Local Proxy ▼] [Settings ⚙] │
└─────────────────────────────────────────────────────────────────┘
```

**Implementation:**
- Use `DropdownMenu` with `RadioGroup` for selection
- Show active profile with checkmark
- clicking updates `activeProfileIdAtom`
- Profile change takes effect on next message

## Files to Modify

1. **[agents-models-tab.tsx](../src/renderer/components/dialogs/settings-tabs/agents-models-tab.tsx)** - Replace Override Model section with profile list
2. **[cli-config-detected-page.tsx](../src/renderer/features/onboarding/cli-config-detected-page.tsx)** - Add "Save as profile" option
3. **[active-chat.tsx](../src/renderer/features/agents/main/active-chat.tsx)** - Add quick profile selector to header
4. **[atoms/index.ts](../src/renderer/lib/atoms/index.ts)** - Add migration logic (atoms already in place)

## Data Types (Already Defined)

```typescript
export type ModelProfile = {
id: string
name: string
config: CustomClaudeConfig
isOffline?: boolean
}

export type CustomClaudeConfig = {
model: string
token: string
baseUrl: string
}
```

## Future Enhancements (Out of Scope)

- Per-chat profile selection
- Profile import/export
- Connection testing before saving
- Profile templates (presets for common proxies)
Loading