Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
60 changes: 60 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Deploy to GitHub Pages

on:
push:
branches: [dev]
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build with VitePress
run: pnpm exec vitepress build docs

- name: Copy install.sh to dist
run: |
cp docs/install.sh docs/.vitepress/dist/install.sh
cp docs/install.sh .

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: docs/.vitepress/dist

deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
147 changes: 147 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# AGENTS.md - Developer Guide for Persona

This file provides guidance for AI agents working on this codebase.

## Project Overview

**Persona** is a CLI tool to switch Claude CLI configurations between different model providers (DeepSeek, Zhipu GLM, Kimi, MiniMax, OpenAI, Ollama, etc.).

## Build & Run Commands

```bash
# Install dependencies (uses pnpm)
pnpm install

# Build executable
bun run build

# Development mode (run without building)
bun run dev

# Build and globally link (for CLI usage)
bun run link

# Documentation
bun run docs:dev # Start docs dev server
bun run docs:build # Build docs
bun run docs:preview # Preview docs
```

## Project Structure

```
src/
├── index.ts # CLI entry point, command routing
├── cli/ # CLI infrastructure (commands definition, help)
├── commands/ # Command implementations (add, switch, list, etc.)
├── config/ # Configuration management (store, templates)
├── types/ # TypeScript interfaces
├── utils/ # Utilities (api, crypto, theme, etc.)
│ ├── api/ # API testing utilities
│ └── crypto/ # Cryptographic utilities (masking)
└── tui/ # Terminal UI (OpenTUI/React-based)
├── components/ # UI components
│ ├── layout/ # Header, StatusBar
│ ├── detail/ # DetailPanel subcomponents
│ ├── dialogs/ # Confirm, Input, List dialogs
│ └── types/ # TUI-specific types
└── hooks/ # Custom React hooks
```

## Code Style Guidelines

### TypeScript

- Use **strict mode** (`strict: true` in tsconfig.json)
- Always define return types for functions when not obvious
- Use `interface` for object shapes, `type` for unions/aliases
- Avoid `any`, use `unknown` when type is uncertain

### Naming Conventions

- **Files**: camelCase (e.g., `useProviders.ts`, `apiUtils.ts`)
- **Components**: PascalCase (e.g., `DetailPanel.tsx`)
- **Interfaces**: PascalCase with `I` prefix only when necessary (prefer without)
- **Constants**: SCREAMING_SNAKE_CASE
- **Boolean variables**: prefix with `is`, `has`, `should`, `can`

### Imports

- Use absolute imports from project root (e.g., `@/utils/api`)
- Order imports: external → internal → types
- Use explicit file extensions for clarity: `from '../utils/api/index'`
- Group by: React hooks → external libs → internal modules → types

```typescript
// Good
import { useState, useCallback } from "react"
import type { CliRenderer } from "@opentui/core"
import { testProvider } from "../../utils/api"
import type { Provider } from "../../types"
import { configStore } from "../../config/store"
```

### React/TUI Patterns

- Use functional components with hooks
- Extract custom hooks for reusable logic (`useXxx`)
- Use `useCallback` for event handlers passed to child components
- Keep components focused: single responsibility
- Lift state up; avoid redundant local state

### Error Handling

- Use try/catch for async operations
- Provide meaningful error messages
- Exit with `process.exit(1)` on CLI errors
- Use `chalk.red()` for errors, `chalk.yellow()` for warnings

### UI Components (OpenTUI)

- Use JSX-style syntax with `@opentui/react`
- Available elements: `box`, `text`, `select`, `input`, `button`
- Use `position`, `width`, `height`, `flexDirection` for layout
- Apply colors from `themeColors` for consistency

### Formatting

- Use **double quotes** for strings
- Use **2 spaces** for indentation
- Add trailing commas in objects/arrays
- Maximum line length: 100 characters (soft limit)
- No semicolons at end of statements
- Use semicolons in TypeScript type definitions

### Best Practices

1. **Configuration**: Use `ConfigStore` singleton for persistence
2. **Provider switching**: Always call both `applyProviderToClaude()` and `setActiveProvider()`
3. **Theme**: Load theme via `loadThemeFromConfig()` before TUI initialization
4. **Dialogs**: Use Promise-based pattern (see `useDialogs` hook)
5. **Testing**: Test provider connectivity with `testProvider()` utility

## Testing

This project does not have a formal test suite yet. When adding tests:

- Use Vitest or Bun's built-in test runner
- Place tests alongside source files with `.test.ts` extension
- Mock external dependencies (file system, HTTP requests)

## Common Tasks

### Adding a new command

1. Create `src/commands/<command>.ts`
2. Export interactive function and optionally flag-based function
3. Import and add to switch case in `src/index.ts`

### Adding a new provider template

1. Add JSON file to `templates/<category>/<name>.json`
2. Template should include: name, website, baseUrl, apiFormat, defaultModels

### Adding a new theme

1. Add theme colors to `src/utils/theme.ts` in `themes` object
2. Theme colors should include: bg, text, primary, border, etc.
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
# Changelog

## v1.3.0

### Features
- **Codex CLI Support** - New support for OpenAI Codex CLI provider management
- Separate provider management for Claude CLI and Codex CLI
- `persona add --target codex` - Add provider for Codex
- `persona add --target claude` - Add provider for Claude (default)
- `persona use --target codex <provider-id>` - Switch Codex provider
- `persona use --target claude <provider-id>` - Switch Claude provider
- `persona ls --target codex` - List Codex providers
- `persona ls --target claude` - List Claude providers

### Codex-Specific
- **Wire API** - Configure API type (responses/completions/chat)
- **Authentication Options** - Support for custom env keys or OpenAI auth
- **Codex Templates** - New template category for Codex-compatible providers (Ollama)

### TUI Improvements
- **CLI Target Switching** - Press `Tab` to switch between Claude and Codex mode
- **Target-Aware Provider List** - Filter providers by selected CLI target
- **Enhanced Detail Panel** - Shows target-specific configuration

### Configuration Changes
- Separate config storage for Claude (`general/claude.json`) and Codex (`general/codex.toml`)
- Provider ID generation now includes target prefix for uniqueness
- Active provider tracking split into `activeClaudeProvider` and `activeCodexProvider`

### Refactoring
- Extract dialog logic to `useDialogs` hook
- Extract provider management to `useProviders` hook
- Modularize TUI components (ProviderList, detail panels)
- Add `@iarna/toml` for TOML file handling

## v1.2.2

### Features
Expand Down
114 changes: 24 additions & 90 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,104 +2,38 @@

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview
## Project

**Persona** is a CLI tool to switch Claude CLI configurations between different model providers. It allows users to configure and switch between 20+ AI model providers (DeepSeek, Zhipu GLM, Kimi, MiniMax, OpenAI, Ollama, etc.).
**Persona** - CLI tool to switch Claude CLI between different model providers (DeepSeek, Zhipu GLM, Kimi, MiniMax, OpenAI, Ollama, etc.)

## Commands
## Run

```bash
pnpm install # Install dependencies
bun run build # Compile TypeScript to single executable (dist/persona)
bun run dev # Run in development mode without building
bun run link # Build, compile, and globally link (for CLI usage, requires sudo)
bun run dev # Development mode
bun run build # Build executable (dist/persona)
```

### CLI Commands
```bash
persona # Start interactive TUI (default)
persona ls # List all configured providers
persona use <id> # Switch to provider by ID
persona add # Add new provider (interactive or with flags)
persona edit <id> # Edit existing provider
persona rm <id> # Delete provider
persona ping [id] # Test provider API (current or specified)
persona status # Show current active provider and config
persona templates # List available provider templates
persona theme [name] # Manage themes (list, show, or set)
persona env [edit] # Manage environment variable overrides
```

## Architecture

### File Structure
- `src/index.ts` - Entry point, CLI command routing with parseArgs for flags
- `src/commands/` - Command implementations (add, switch, list, delete, edit, test, config, theme, env)
- Each command supports both interactive (inquirer prompts) and flag-based modes
- `src/config/store.ts` - Configuration management (singleton ConfigStore class)
- `src/config/templates.ts` - Provider template loading from `templates/` directory
- `src/types/index.ts` - TypeScript interfaces
- `src/tui/` - **New React-based TUI using OpenTUI** (preferred for new development)
- `components/App.tsx` - Main TUI application
- `components/dialogs/` - Dialog components (Confirm, Input, List)
- `components/` - Header, DetailPanel, StatusBar components
- `src/utils/tui.ts` - **Legacy blessed-based TUI** (being phased out)
- `src/utils/api.ts` - API testing with timing breakdown (DNS, CONNECT, TTFB, API)
- `src/utils/theme.ts` - Theme system (persona, gruvbox, dracula, nord)
- `templates/` - Provider templates organized by category (e.g., `claude/*.json`)

### Key Patterns
- **ConfigStore** (singleton in `src/config/store.ts`) handles all persistence:
- Provider config stored in `~/.persona/config.json`
- Claude settings written to `~/.claude/settings.json`
- General env config in `~/.persona/general.json`

- **Commands** use inquirer for interactive prompts and support both interactive and flag-based modes
- Entry point parses flags with `util.parseArgs()`
- Commands fall back to interactive mode if flags are missing

- **TUI Architecture** - Two implementations coexist:
- **New (OpenTUI)**: React-based in `src/tui/` using `@opentui/core` and `@opentui/react`
- Entry point: `src/tui/index.tsx` exports `startInteractiveMode()`
- Component-based with proper React patterns
- Theme loaded via `loadThemeFromConfig()` before rendering
- **Legacy (blessed)**: Imperative in `src/utils/tui.ts`
- Avoid manual `up()/down()` calls on lists; use `setTimeout` after key events
- Still used but being phased out
## Key Files

- **Build System** uses Bun's `--compile` flag to create single-file executables
- Version auto-updated via `scripts/update-version.ts` before builds
- Output: `dist/persona` (platform-specific executable)
| File | Purpose |
|------|---------|
| `src/index.ts` | CLI entry, command routing |
| `src/commands/*.ts` | Command implementations (add, switch, list, rm, edit, ping, theme, env, sync) |
| `src/config/store.ts` | ConfigStore singleton - all persistence |
| `src/tui/` | React/OpenTUI TUI components |
| `src/utils/theme.ts` | Theme system (persona, gruvbox, dracula, nord) |
| `templates/` | Provider templates by category |

### Provider Configuration
Providers are configured with:
- `id` - Unique identifier (auto-generated)
- `name` - Display name
- `website` - Provider website URL
- `baseUrl` - API endpoint
- `apiKey` - Authentication token
- `apiFormat` - Either `anthropic-messages` or `openai-completions`
- `models` - Model mappings object with keys: `default`, `haiku`, `opus`, `sonnet`
- `extraEnv` - Additional environment variables (optional)
## Important Patterns

When switching providers, the tool:
1. Updates `~/.persona/config.json` with active provider
2. Writes provider settings to `~/.claude/settings.json`:
- `ANTHROPIC_BASE_URL` - Provider's base URL
- `ANTHROPIC_AUTH_TOKEN` - Provider's API key
- `ANTHROPIC_MODEL` - Model mapping
- Additional keys from `extraEnv`
3. Merges with environment overrides from `~/.persona/general.json`
- **Switch provider**: Call both `applyProviderToClaude()` and `setActiveProvider()` in `src/config/store.ts`
- **TUI**: Theme loaded via `loadThemeFromConfig()` before rendering
- **Config locations**:
- `~/.persona/config.json` - provider config
- `~/.claude/settings.json` - Claude settings (written by this tool)

### Template System
Provider templates in `templates/` directory are organized by category:
- `templates/claude/*.json` - Claude API-compatible providers
- Each template provides default values for baseUrl, apiFormat, models
- Access via `getTemplateNames()`, `getTemplateByFullName()`, `getTemplatesByCategory()`
## Add New

### Theme System
Themes control TUI colors and are stored in `src/utils/tui/components.ts`:
- Available themes: `persona` (default), `gruvbox`, `dracula`, `nord`
- Theme persisted in `~/.persona/config.json`
- Loaded via `loadThemeFromConfig()` before TUI initialization
- Colors accessed via `getColors()` helper
- **Command**: Add to `src/commands/<name>.ts`, import in `src/index.ts`
- **Template**: Add JSON to `templates/<category>/<name>.json` with name, baseUrl, apiFormat, models
- **Theme**: Add to `src/utils/theme.ts` themes object
Loading