co-mono/packages/coding-agent/docs/themes.md
Mario Zechner bc670bc63c Fix lockstep versioning and improve documentation
- Sync all packages to version 0.7.7
- Rewrite sync-versions.js to handle ALL inter-package dependencies automatically
- Fix web-ui dependency on pi-ai (was 0.6.0, now 0.7.7)
- Move agent fix changelog entry to coding-agent CHANGELOG
- Remove redundant agent CHANGELOG.md
- Improve README.md with clearer lockstep versioning docs
- Add /changelog command to display full changelog in TUI (newest last)
- Fix changelog description (not a scrollable viewer, just displays in chat)
- Update CHANGELOG for 0.7.7 release
2025-11-13 23:37:43 +01:00

310 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Theme System Analysis
## Problem Statement
Issue #7: In terminals with light backgrounds, some outputs use dark colors that are hard to read. We need a theme system that allows users to choose between light and dark themes.
## Current Color Usage Analysis
### Color Usage Statistics
Total chalk color calls: 132 across 14 files
Most frequent colors:
- `chalk.dim` (48 occurrences) - Used for secondary text
- `chalk.gray` (28 occurrences) - Used for borders, metadata, dimmed content
- `chalk.bold` (20 occurrences) - Used for emphasis
- `chalk.blue` (12 occurrences) - Used for selections, borders, links
- `chalk.cyan` (9 occurrences) - Used for primary UI elements (logo, list bullets, code)
- `chalk.red` (7 occurrences) - Used for errors, stderr output
- `chalk.green` (6 occurrences) - Used for success, stdout output
- `chalk.yellow` (3 occurrences) - Used for headings in markdown
- `chalk.bgRgb` (6 occurrences) - Used for custom backgrounds in Text/Markdown
### Files Using Colors
#### coding-agent Package
1. **main.ts** - CLI output messages
2. **tui/assistant-message.ts** - Thinking text (gray italic), errors (red), aborted (red)
3. **tui/dynamic-border.ts** - Configurable border color (default blue)
4. **tui/footer.ts** - Stats and pwd (gray)
5. **tui/model-selector.ts** - Borders (blue), selection arrow (blue), provider badge (gray), checkmark (green)
6. **tui/session-selector.ts** - Border (blue), selection cursor (blue), metadata (dim)
7. **tui/thinking-selector.ts** - Border (blue)
8. **tui/tool-execution.ts** - stdout (green), stderr (red), dim lines (dim), line numbers
9. **tui/tui-renderer.ts** - Logo (bold cyan), instructions (dim/gray)
#### tui Package
1. **components/editor.ts** - Horizontal border (gray)
2. **components/loader.ts** - Spinner (cyan), message (dim)
3. **components/markdown.ts** - Complex color system:
- H1 headings: bold.underline.yellow
- H2 headings: bold.yellow
- H3+ headings: bold
- Code blocks: gray (delimiters), dim (indent), green (code)
- List bullets: cyan
- Blockquotes: gray (pipe), italic (text)
- Horizontal rules: gray
- Inline code: gray (backticks), cyan (code)
- Links: underline.blue (text), gray (URL)
- Strikethrough: strikethrough
- Tables: bold (headers)
4. **components/select-list.ts** - No matches (gray), selection arrow (blue), selected item (blue), description (gray)
5. **components/text.ts** - Custom bgRgb support
### Color System Architecture
#### Current Implementation
- Colors are hardcoded using `chalk` directly
- No centralized theme management
- No way to switch themes at runtime
- Some components accept color parameters (e.g., DynamicBorder, Text, Markdown)
#### Markdown Component Color System
The Markdown component has a `Color` type enum:
```typescript
type Color = "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white" | "gray" |
"bgBlack" | "bgRed" | "bgGreen" | "bgYellow" | "bgBlue" | "bgMagenta" | "bgCyan" | "bgWhite" | "bgGray"
```
It accepts optional `bgColor` and `fgColor` parameters, plus `customBgRgb`.
## Proposed Solution
### Theme Structure
Create a centralized theme system with semantic color names:
```typescript
interface Theme {
name: string;
// UI Chrome
border: ChalkFunction;
selection: ChalkFunction;
selectionText: ChalkFunction;
// Text hierarchy
primary: ChalkFunction;
secondary: ChalkFunction;
dim: ChalkFunction;
// Semantic colors
error: ChalkFunction;
success: ChalkFunction;
warning: ChalkFunction;
info: ChalkFunction;
// Code/output
code: ChalkFunction;
codeDelimiter: ChalkFunction;
stdout: ChalkFunction;
stderr: ChalkFunction;
// Markdown specific
heading1: ChalkFunction;
heading2: ChalkFunction;
heading3: ChalkFunction;
link: ChalkFunction;
linkUrl: ChalkFunction;
listBullet: ChalkFunction;
blockquote: ChalkFunction;
blockquotePipe: ChalkFunction;
inlineCode: ChalkFunction;
inlineCodeDelimiter: ChalkFunction;
// Backgrounds (optional, for components like Text/Markdown)
backgroundRgb?: { r: number; g: number; b: number };
}
type ChalkFunction = (str: string) => string;
```
### Built-in Themes
#### Dark Theme (current default)
```typescript
const darkTheme: Theme = {
name: "dark",
border: chalk.blue,
selection: chalk.blue,
selectionText: chalk.blue,
primary: (s) => s, // no color
secondary: chalk.gray,
dim: chalk.dim,
error: chalk.red,
success: chalk.green,
warning: chalk.yellow,
info: chalk.cyan,
code: chalk.green,
codeDelimiter: chalk.gray,
stdout: chalk.green,
stderr: chalk.red,
heading1: chalk.bold.underline.yellow,
heading2: chalk.bold.yellow,
heading3: chalk.bold,
link: chalk.underline.blue,
linkUrl: chalk.gray,
listBullet: chalk.cyan,
blockquote: chalk.italic,
blockquotePipe: chalk.gray,
inlineCode: chalk.cyan,
inlineCodeDelimiter: chalk.gray,
};
```
#### Light Theme
```typescript
const lightTheme: Theme = {
name: "light",
border: chalk.blue,
selection: chalk.blue,
selectionText: chalk.blue.bold,
primary: (s) => s,
secondary: chalk.gray,
dim: chalk.gray, // Don't use chalk.dim on light backgrounds
error: chalk.red.bold,
success: chalk.green.bold,
warning: chalk.yellow.bold,
info: chalk.cyan.bold,
code: chalk.green.bold,
codeDelimiter: chalk.gray,
stdout: chalk.green.bold,
stderr: chalk.red.bold,
heading1: chalk.bold.underline.blue,
heading2: chalk.bold.blue,
heading3: chalk.bold,
link: chalk.underline.blue,
linkUrl: chalk.blue,
listBullet: chalk.blue.bold,
blockquote: chalk.italic,
blockquotePipe: chalk.gray,
inlineCode: chalk.blue.bold,
inlineCodeDelimiter: chalk.gray,
};
```
### Implementation Plan
#### 1. Create Theme Module
**Location:** `packages/tui/src/theme.ts`
```typescript
export interface Theme { ... }
export const darkTheme: Theme = { ... };
export const lightTheme: Theme = { ... };
export const themes = { dark: darkTheme, light: lightTheme };
let currentTheme: Theme = darkTheme;
export function setTheme(theme: Theme): void {
currentTheme = theme;
}
export function getTheme(): Theme {
return currentTheme;
}
```
#### 2. Update Settings Manager
**Location:** `packages/coding-agent/src/settings-manager.ts`
Add `theme` field to Settings interface:
```typescript
export interface Settings {
lastChangelogVersion?: string;
theme?: "dark" | "light";
}
```
#### 3. Create Theme Selector Component
**Location:** `packages/coding-agent/src/tui/theme-selector.ts`
Similar to ModelSelector and ThinkingSelector, create a TUI component for selecting themes.
#### 4. Refactor Color Usage
Replace all hardcoded `chalk.*` calls with `theme.*`:
**Example - Before:**
```typescript
lines.push(chalk.blue("─".repeat(width)));
const cursor = chalk.blue(" ");
```
**Example - After:**
```typescript
const theme = getTheme();
lines.push(theme.border("─".repeat(width)));
const cursor = theme.selection(" ");
```
#### 5. Update Components
##### High Priority (User-facing content issues)
1. **markdown.ts** - Update all color calls to use theme
2. **tool-execution.ts** - stdout/stderr colors
3. **assistant-message.ts** - Error messages
4. **tui-renderer.ts** - Logo and instructions
5. **footer.ts** - Stats display
##### Medium Priority (UI chrome)
6. **dynamic-border.ts** - Accept theme parameter
7. **model-selector.ts** - Selection colors
8. **session-selector.ts** - Selection colors
9. **thinking-selector.ts** - Border colors
10. **select-list.ts** - Selection colors
11. **loader.ts** - Spinner color
12. **editor.ts** - Border color
##### Low Priority (CLI output)
13. **main.ts** - CLI messages
#### 6. Add Theme Slash Command
**Location:** `packages/coding-agent/src/tui/tui-renderer.ts`
Add `/theme` command similar to `/model` and `/thinking`.
#### 7. Initialize Theme on Startup
**Location:** `packages/coding-agent/src/main.ts`
```typescript
// Load theme from settings
const settingsManager = new SettingsManager();
const themeName = settingsManager.getTheme() || "dark";
const theme = themes[themeName] || darkTheme;
setTheme(theme);
```
### Migration Strategy
1. **Phase 1:** Create theme infrastructure (theme.ts, types, built-in themes)
2. **Phase 2:** Update TUI package components (markdown, text, loader, editor, select-list)
3. **Phase 3:** Update coding-agent TUI components (all tui/*.ts files)
4. **Phase 4:** Add theme selector and persistence
5. **Phase 5:** Update CLI output in main.ts (optional, low priority)
### Testing Plan
1. Test both themes in terminals with light backgrounds
2. Test both themes in terminals with dark backgrounds
3. Verify theme switching works at runtime via `/theme`
4. Verify theme persists across sessions via settings.json
5. Test all components for readability in both themes
### Open Questions
1. Should we support custom user themes loaded from a JSON file?
2. Should we auto-detect terminal background color and choose theme automatically?
3. Should theme apply to background colors used in Text/Markdown components?
4. Do we need more than two themes initially?
### Breaking Changes
None - the default theme will remain "dark" matching current behavior.
### Performance Considerations
- Theme getter is called frequently (on every render)
- Should be a simple variable access, not a function call chain
- Consider caching theme functions if performance becomes an issue