restore: recover deleted documentation, CI/CD, and infrastructure files

Restored from origin/main (b4663fb):
- .github/ workflows and issue templates
- .gitignore (proper exclusions)
- .opencode/agent/web_developer.md
- AGENTS.md, BUILD.md, PROGRESS.md
- dev-docs/ (9 architecture/implementation docs)
- docs/screenshots/ (4 UI screenshots)
- images/ (CodeNomad icons)
- package-lock.json (dependency lockfile)
- tasks/ (25+ project task files)

Also restored original source files that were modified:
- packages/ui/src/App.tsx
- packages/ui/src/lib/logger.ts
- packages/ui/src/stores/instances.ts
- packages/server/src/server/routes/workspaces.ts
- packages/server/src/workspaces/manager.ts
- packages/server/src/workspaces/runtime.ts
- packages/server/package.json

Kept new additions:
- Install-*.bat/.sh (enhanced installers)
- Launch-*.bat/.sh (new launchers)
- README.md (SEO optimized with GLM 4.7)
This commit is contained in:
Gemini AI
2025-12-23 13:03:48 +04:00
Unverified
parent b448d11991
commit 157449a9ad
70 changed files with 21384 additions and 276 deletions

180
dev-docs/INDEX.md Normal file
View File

@@ -0,0 +1,180 @@
# Documentation Index
Quick reference to all documentation files.
## Main Documents
### [README.md](../README.md)
Project overview, installation, and getting started guide.
### [SUMMARY.md](SUMMARY.md)
Executive summary of the entire project - **start here!**
### [MVP-PRINCIPLES.md](MVP-PRINCIPLES.md)
**MVP development philosophy** - Focus on functionality, NOT performance ⚡
---
## Specification Documents
### [architecture.md](architecture.md)
**Complete system architecture**
- Component layers and responsibilities
- State management structure
- Data flow diagrams
- Technology stack
- Security and performance considerations
**Read this to understand:** How the app is structured
### [user-interface.md](user-interface.md)
**Complete UI/UX specifications**
- Every screen and component layout
- Visual design specifications
- Interaction patterns
- Accessibility requirements
- Color schemes and typography
**Read this to understand:** What the app looks like and how users interact
### [technical-implementation.md](technical-implementation.md)
**Implementation details**
- File structure
- TypeScript interfaces
- Process management logic
- SDK integration patterns
- IPC communication
- Error handling strategies
**Read this to understand:** How to actually build it
### [build-roadmap.md](build-roadmap.md)
**Development plan**
- 8 phases of development
- Task dependencies
- Timeline estimates
- Success criteria
- Risk mitigation
**Read this to understand:** The development journey from start to finish
---
## Task Documents
### [tasks/README.md](../tasks/README.md)
**Task management guide**
- Task workflow
- Naming conventions
- How to work on tasks
- Progress tracking
### Task Files (in tasks/todo/)
- **001-project-setup.md** - Electron + SolidJS boilerplate
- **002-empty-state-ui.md** - Initial UI with folder selection
- **003-process-manager.md** - OpenCode server spawning
- **004-sdk-integration.md** - API client integration
- **005-session-picker-modal.md** - Session selection UI
More tasks will be added as we progress through phases.
---
## Reading Order
### For First-Time Readers:
1. [SUMMARY.md](SUMMARY.md) - Get the big picture
2. [architecture.md](architecture.md) - Understand the structure
3. [user-interface.md](user-interface.md) - See what you're building
4. [build-roadmap.md](build-roadmap.md) - Understand the plan
5. [tasks/README.md](../tasks/README.md) - Learn the workflow
### For Implementers:
1. [tasks/README.md](../tasks/README.md) - Understand task workflow
2. [technical-implementation.md](technical-implementation.md) - Implementation patterns
3. [tasks/todo/001-\*.md](../tasks/todo/) - Start with first task
4. Refer to architecture.md and user-interface.md as needed
### For Designers:
1. [user-interface.md](user-interface.md) - Complete UI specs
2. [architecture.md](architecture.md) - Component structure
3. [SUMMARY.md](SUMMARY.md) - Feature overview
### For Project Managers:
1. [SUMMARY.md](SUMMARY.md) - Executive overview
2. [build-roadmap.md](build-roadmap.md) - Timeline and phases
3. [tasks/README.md](../tasks/README.md) - Task tracking
---
## Quick Reference
### Common Questions
**Q: Where do I start?**
A: Read [SUMMARY.md](SUMMARY.md), then start [Task 001](../tasks/todo/001-project-setup.md)
**Q: How long will this take?**
A: See [build-roadmap.md](build-roadmap.md) - MVP in 3-7 weeks depending on commitment
**Q: What does the UI look like?**
A: See [user-interface.md](user-interface.md) for complete specifications
**Q: How does it work internally?**
A: See [architecture.md](architecture.md) for system design
**Q: How do I build feature X?**
A: See [technical-implementation.md](technical-implementation.md) for patterns
**Q: What's the development plan?**
A: See [build-roadmap.md](build-roadmap.md) for phases
---
## Document Status
| Document | Status | Last Updated |
| --------------------------- | ----------- | ------------ |
| README.md | ✅ Complete | 2024-10-22 |
| SUMMARY.md | ✅ Complete | 2024-10-22 |
| architecture.md | ✅ Complete | 2024-10-22 |
| user-interface.md | ✅ Complete | 2024-10-22 |
| technical-implementation.md | ✅ Complete | 2024-10-22 |
| build-roadmap.md | ✅ Complete | 2024-10-22 |
| tasks/README.md | ✅ Complete | 2024-10-22 |
| Task 001-005 | ✅ Complete | 2024-10-22 |
**Project phase:** Post-MVP (Phases 1-3 complete; Phase 4 work underway).
---
## Contributing to Documentation
When updating documentation:
1. Update the relevant file
2. Update "Last Updated" in this index
3. Update SUMMARY.md if adding major changes
4. Keep consistent formatting and style
---
_This index will be updated as more documentation is added._

326
dev-docs/MVP-PRINCIPLES.md Normal file
View File

@@ -0,0 +1,326 @@
# MVP Development Principles
## Core Philosophy
**Focus on functionality, NOT performance.**
The MVP (Minimum Viable Product) is about proving the concept and getting feedback. Performance optimization comes later, after we validate the product with real users.
---
## What We Care About in MVP
### ✅ DO Focus On:
1. **Functionality**
- Does it work?
- Can users complete their tasks?
- Are all core features present?
2. **Correctness**
- Does it produce correct results?
- Does error handling work?
- Is data persisted properly?
3. **User Experience**
- Is the UI intuitive?
- Are loading states clear?
- Are error messages helpful?
4. **Stability**
- Does it crash?
- Can users recover from errors?
- Does it lose data?
5. **Code Quality**
- Is code readable?
- Are types correct?
- Is it maintainable?
### ❌ DON'T Focus On:
1. **Performance Optimization**
- Virtual scrolling
- Message batching
- Lazy loading
- Memory optimization
- Render optimization
2. **Scalability**
- Handling 1000+ messages
- Multiple instances with 100+ sessions
- Large file attachments
- Massive search indexes
3. **Advanced Features**
- Plugins
- Advanced search
- Custom themes
- Workspace management
---
## Specific MVP Guidelines
### Messages & Rendering
**Simple approach:**
```typescript
// Just render everything - no virtual scrolling
<For each={messages()}>
{(message) => <MessageItem message={message} />}
</For>
```
**Don't worry about:**
- Sessions with 500+ messages
- Re-render performance
- Memory usage
- Scroll performance
**When to optimize:**
- Post-MVP (Phase 8)
- Only if users report issues
- Based on real-world usage data
### State Management
**Simple approach:**
- Use SolidJS signals directly
- No batching
- No debouncing
- No caching layers
**Don't worry about:**
- Update frequency
- Number of reactive dependencies
- State structure optimization
### Process Management
**Simple approach:**
- Spawn servers as needed
- Kill on close
- Basic error handling
**Don't worry about:**
- Resource limits (max processes)
- CPU/memory monitoring
- Restart optimization
- Process pooling
### API Communication
**Simple approach:**
- Direct SDK calls
- Basic error handling
- Simple retry (if at all)
**Don't worry about:**
- Request batching
- Response caching
- Optimistic updates
- Request deduplication
---
## Decision Framework
When implementing any feature, ask:
### Is this optimization needed for MVP?
**NO if:**
- It only helps with large datasets
- It only helps with many instances
- It's about speed, not correctness
- Users won't notice the difference
- It adds significant complexity
**YES if:**
- Users can't complete basic tasks without it
- App is completely unusable without it
- It prevents data loss
- It's a security requirement
### Examples
**Virtual Scrolling:** ❌ NO for MVP
- MVP users won't have 1000+ message sessions
- Simple list rendering works fine for <100 messages
- Add in Phase 8 if needed
**Error Handling:** ✅ YES for MVP
- Users need clear feedback when things fail
- Prevents frustration and data loss
- Core to usability
**Message Batching:** ❌ NO for MVP
- SolidJS handles updates efficiently
- Only matters at very high frequency
- Add later if users report lag
**Session Persistence:** ✅ YES for MVP
- Users expect sessions to persist
- Losing work is unacceptable
- Core functionality
---
## Testing Approach
### MVP Testing Focus
**Test for:**
- ✅ Correctness (does it work?)
- ✅ Error handling (does it fail gracefully?)
- ✅ Data integrity (is data saved?)
- ✅ User flows (can users complete tasks?)
**Don't test for:**
- ❌ Performance benchmarks
- ❌ Load testing
- ❌ Stress testing
- ❌ Scalability limits
### Acceptable Performance
For MVP, these are **acceptable:**
- 100 messages render in 1 second
- UI slightly laggy during heavy streaming
- Memory usage grows with message count
- Multiple instances slow down app
These become **unacceptable** only if:
- Users complain
- App becomes unusable
- Basic tasks can't be completed
---
## When to Optimize
### Post-MVP Triggers
Add optimization when:
1. **User Feedback**
- Multiple users report slowness
- Users abandon due to performance
- Performance prevents usage
2. **Measurable Issues**
- App freezes for >2 seconds
- Memory usage causes crashes
- UI becomes unresponsive
3. **Phase 8 Reached**
- MVP complete and validated
- User base established
- Performance becomes focus
### How to Optimize
When the time comes:
1. **Measure First**
- Profile actual bottlenecks
- Use real user data
- Identify specific problems
2. **Target Fixes**
- Fix the specific bottleneck
- Don't over-engineer
- Measure improvement
3. **Iterate**
- Optimize one thing at a time
- Verify with users
- Stop when "fast enough"
---
## Communication with Users
### During Alpha/Beta
**Be honest about performance:**
- "This is an MVP - expect some slowness with large sessions"
- "We're focused on functionality first"
- "Performance optimization is planned for v1.x"
**Set expectations:**
- Works best with <200 messages per session
- Multiple instances may slow things down
- We'll optimize based on your feedback
### Collecting Feedback
**Ask about:**
- ✅ What features are missing?
- ✅ What's confusing?
- ✅ What doesn't work?
- ✅ Is it too slow to use?
**Don't ask about:**
- ❌ How many milliseconds for X?
- ❌ Memory usage specifics
- ❌ Benchmark comparisons
---
## Summary
### The MVP Mantra
> **Make it work, then make it better, then make it fast.**
For CodeNomad MVP:
- **Phase 1-7:** Make it work, make it better
- **Phase 8+:** Make it fast
### Remember
- Premature optimization is the root of all evil
- Real users provide better optimization guidance than assumptions
- Functionality > Performance for MVP
- You can't optimize what users don't use
---
## Quick Reference
**When in doubt, ask:**
1. Is this feature essential for users to do their job? → Build it
2. Is this optimization essential for the feature to work? → Build it
3. Is this just making it faster/more efficient? → Defer to Phase 8
**MVP = Minimum _Viable_ Product**
- Viable = works and is useful
- Viable ≠ optimized and fast

348
dev-docs/SUMMARY.md Normal file
View File

@@ -0,0 +1,348 @@
# CodeNomad - Project Summary
## Current Status
We have completed the MVP milestones (Phases 1-3) and are now operating in post-MVP mode. Future work prioritizes multi-instance support, advanced input polish, and system integrations outlined in later phases.
## What We've Created
A comprehensive specification and task breakdown for building the CodeNomad desktop application.
## Directory Structure
```
packages/opencode-client/
├── docs/ # Comprehensive documentation
│ ├── architecture.md # System architecture & design
│ ├── user-interface.md # UI/UX specifications
│ ├── technical-implementation.md # Technical details & patterns
│ ├── build-roadmap.md # Phased development plan
│ └── SUMMARY.md # This file
├── tasks/
│ ├── README.md # Task management guide
│ ├── todo/ # Tasks to implement
│ │ ├── 001-project-setup.md
│ │ ├── 002-empty-state-ui.md
│ │ ├── 003-process-manager.md
│ │ ├── 004-sdk-integration.md
│ │ └── 005-session-picker-modal.md
│ └── done/ # Completed tasks (empty)
└── README.md # Project overview
```
## Documentation Overview
### 1. Architecture (architecture.md)
**What it covers:**
- High-level system design
- Component layers (Main process, Renderer, Communication)
- State management approach
- Tab hierarchy (Instance tabs → Session tabs)
- Data flow for key operations
- Technology stack decisions
- Security considerations
**Key sections:**
- Component architecture diagram
- Instance/Session state structures
- Communication patterns (HTTP, SSE)
- Error handling strategies
- Performance considerations
### 2. User Interface (user-interface.md)
**What it covers:**
- Complete UI layout specifications
- Visual design for every component
- Interaction patterns
- Keyboard shortcuts
- Accessibility requirements
- Empty states and error states
- Modal designs
**Key sections:**
- Detailed layout wireframes (ASCII art)
- Component-by-component specifications
- Message rendering formats
- Control bar designs
- Modal/overlay specifications
- Color schemes and typography
### 3. Technical Implementation (technical-implementation.md)
**What it covers:**
- Technology stack details
- Project file structure
- State management patterns
- Process management implementation
- SDK integration approach
- SSE event handling
- IPC communication
- Error handling strategies
- Performance optimizations
**Key sections:**
- Complete project structure
- TypeScript interfaces
- Process spawning logic
- SDK client management
- Message rendering implementation
- Build and packaging config
### 4. Build Roadmap (build-roadmap.md)
**What it covers:**
- 8 development phases
- Task dependencies
- Timeline estimates
- Success criteria per phase
- Risk mitigation
- Release strategy
**Phases:**
1. **Foundation** (Week 1) - Project setup, process management
2. **Core Chat** (Week 2) - Message display, SSE streaming
3. **Essential Features** (Week 3) - Markdown, agents, errors
4. **Multi-Instance** (Week 4) - Multiple projects support
5. **Advanced Input** (Week 5) - Commands, file attachments
6. **Polish** (Week 6) - UX refinements, settings
7. **System Integration** (Week 7) - Native features
8. **Advanced** (Week 8+) - Performance, plugins
## Task Breakdown
### Current Tasks (Phase 1)
**001 - Project Setup** (2-3 hours)
- Set up Electron + SolidJS + Vite
- Configure TypeScript, TailwindCSS
- Create basic project structure
- Verify build pipeline works
**002 - Empty State UI** (2-3 hours)
- Create empty state component
- Implement folder selection dialog
- Add keyboard shortcuts
- Style and test responsiveness
**003 - Process Manager** (4-5 hours)
- Spawn OpenCode server processes
- Parse stdout for port extraction
- Kill processes on command
- Handle errors and timeouts
- Auto-cleanup on app quit
**004 - SDK Integration** (3-4 hours)
- Create SDK client per instance
- Fetch sessions, agents, models
- Implement session CRUD operations
- Add error handling and retries
**005 - Session Picker Modal** (3-4 hours)
- Build modal with session list
- Agent selector for new sessions
- Keyboard navigation
- Loading and error states
**Total Phase 1 time: ~15-20 hours (2-3 weeks part-time)**
## Key Design Decisions
### 1. Two-Level Tabs
- **Level 1**: Instance tabs (one per project folder)
- **Level 2**: Session tabs (multiple per instance)
- Allows working on multiple projects with multiple conversations each
### 2. Process Management in Main Process
- Electron main process spawns servers
- Parses stdout to get port
- IPC sends port to renderer
- Ensures clean shutdown on app quit
### 3. One SDK Client Per Instance
- Each instance has its own HTTP client
- Connects to different port (different server)
- Isolated state prevents cross-contamination
### 4. SolidJS for Reactivity
- Fine-grained reactivity for SSE updates
- No re-render cascades
- Better performance for real-time updates
- Smaller bundle size than React
### 5. No Virtual Scrolling or Performance Optimization in MVP
- Start with simple list rendering
- Don't optimize for large sessions initially
- Focus on functionality, not performance
- Add optimizations in post-MVP phases if needed
- Reduces initial complexity and speeds up development
### 6. Messages and Tool Calls Inline
- All activity shows in main message stream
- Tool calls expandable/collapsible
- File changes visible inline
- Single timeline view
## Implementation Guidelines
### For Each Task:
1. Read task file completely
2. Review related documentation
3. Follow steps in order
4. Check off acceptance criteria
5. Test thoroughly
6. Move to done/ when complete
### Code Standards:
- TypeScript for everything
- No `any` types
- Descriptive variable names
- Comments for complex logic
- Error handling on all async operations
- Loading states for all network calls
### Testing Approach:
- Manual testing at each step
- Test on minimum window size (800x600)
- Test error cases
- Test edge cases (long text, special chars)
- Keyboard navigation verification
## Next Steps
### To Start Building:
1. **Read all documentation**
- Understand architecture
- Review UI specifications
- Study technical approach
2. **Start with Task 001**
- Set up project structure
- Install dependencies
- Verify build works
3. **Follow sequential order**
- Each task builds on previous
- Don't skip ahead
- Dependencies matter
4. **Track progress**
- Update task checkboxes
- Move completed tasks to done/
- Update roadmap as you go
### When You Hit Issues:
1. Review task prerequisites
2. Check documentation for clarification
3. Look at related specs
4. Ask questions on unclear requirements
5. Document blockers and solutions
## Success Metrics
### MVP (After Task 015)
- Can select folder → spawn server → chat
- Messages stream in real-time
- Can switch agents and models
- Tool executions visible
- Basic error handling works
- **Performance is NOT a concern** - focus on functionality
### Beta (After Task 030)
- Multi-instance support
- Advanced input (files, commands)
- Polished UX
- Settings and preferences
- Native menus
### v1.0 (After Task 035)
- System tray integration
- Auto-updates
- Crash reporting
- Production-ready stability
## Useful References
### Within This Project:
- `README.md` - Project overview and getting started
- `docs/architecture.md` - System design
- `docs/user-interface.md` - UI specifications
- `docs/technical-implementation.md` - Implementation details
- `tasks/README.md` - Task workflow guide
### External:
- OpenCode server API: https://opencode.ai/docs/server/
- Electron docs: https://electronjs.org/docs
- SolidJS docs: https://solidjs.com
- Kobalte UI: https://kobalte.dev
## Questions to Resolve
Before starting implementation, clarify:
1. Exact OpenCode CLI syntax for spawning server
2. Expected stdout format for port extraction
3. SDK package location and version
4. Any platform-specific gotchas
5. Icon and branding assets location
## Estimated Timeline
**Conservative estimate (part-time, ~15 hours/week):**
- Phase 1 (MVP Foundation): 2-3 weeks
- Phase 2 (Core Chat): 2 weeks
- Phase 3 (Essential): 2 weeks
- **MVP Complete: 6-7 weeks**
**Aggressive estimate (full-time, ~40 hours/week):**
- Phase 1: 1 week
- Phase 2: 1 week
- Phase 3: 1 week
- **MVP Complete: 3 weeks**
Add 2-4 weeks for testing, bug fixes, and polish before alpha release.
## This is a Living Document
As you build:
- Update estimates based on actual time
- Add new tasks as needed
- Refine specifications
- Document learnings
- Track blockers and solutions
Good luck! 🚀

View File

@@ -0,0 +1,228 @@
# Tool Call Rendering Implementation
This document describes how tool calls are rendered in the CodeNomad, following the patterns established in the TUI.
## Overview
Each tool type has specialized rendering logic that displays the most relevant information for that tool. This matches the TUI's approach of providing context-specific displays rather than generic input/output dumps.
## Tool-Specific Rendering
### 1. **read** - File Reading
- **Title**: `Read {filename}`
- **Body**: Preview of file content (first 6 lines) from `metadata.preview`
- **Use case**: Shows what file content the assistant is reading
### 2. **edit** - File Editing
- **Title**: `Edit {filename}`
- **Body**: Diff/patch showing changes from `metadata.diff`
- **Special**: Shows diagnostics if available in metadata
- **Use case**: Shows what changes are being made to files
### 3. **write** - File Writing
- **Title**: `Write {filename}`
- **Body**: File content being written (first 10 lines)
- **Special**: Shows diagnostics if available in metadata
- **Use case**: Shows new file content being created
### 4. **bash** - Shell Commands
- **Title**: `Shell {description}` (or command if no description)
- **Body**: Console-style display with `$ command` and output
```
$ npm install vitest
added 50 packages...
```
- **Output from**: `metadata.output`
- **Use case**: Shows command execution and results
### 5. **webfetch** - Web Fetching
- **Title**: `Fetch {url}`
- **Body**: Fetched content (first 10 lines)
- **Use case**: Shows web content being retrieved
### 6. **todowrite** - Task Planning
- **Title**: Dynamic based on todo phase:
- All pending: "Creating plan"
- All completed: "Completing plan"
- Mixed: "Updating plan"
- **Body**: Formatted todo list:
- `- [x] Completed task`
- `- [ ] Pending task`
- `- [ ] ~~Cancelled task~~`
- `- [ ] In progress task` (highlighted)
- **Use case**: Shows the AI's task planning
### 7. **task** - Delegated Tasks
- **Title**: `Task[subagent_type] {description}`
- **Body**: List of delegated tool calls with icons:
```
⚡ bash: npm install
📖 read package.json
✏️ edit src/app.ts
```
- **Special**: In TUI, includes navigation hints for session tree
- **Use case**: Shows what the delegated agent is doing
### 8. **todoread** - Plan Reading
- **Special**: Hidden in TUI, returns empty string
- **Use case**: Internal tool, not displayed to user
### 9. **glob** - File Pattern Matching
- **Title**: `Glob {pattern}`
- **Use case**: Shows file search patterns
### 10. **grep** - Content Search
- **Title**: `Grep "{pattern}"`
- **Use case**: Shows what content is being searched
### 11. **list** - Directory Listing
- **Title**: `List`
- **Use case**: Shows directory operations
### 12. **patch** - Patching Files
- **Title**: `Patch`
- **Use case**: Shows patch operations
### 13. **invalid** - Invalid Tool Calls
- **Title**: Name of the actual tool attempted
- **Use case**: Shows validation errors
### 14. **Default** - Unknown Tools
- **Title**: Capitalized tool name
- **Body**: Output truncated to 10 lines
- **Use case**: Fallback for any new or custom tools
## Status States
### Pending
- **Icon**: ⏸ (pause symbol)
- **Title**: Action text (e.g., "Writing command...", "Preparing edit...")
- **Border**: Accent color
- **Animation**: Shimmer effect on title
- **Expandable**: Shows "Waiting for permission..." message
### Running
- **Icon**: ⏳ (hourglass)
- **Title**: Same as completed state
- **Border**: Warning color (yellow/orange)
- **Animation**: Pulse on status icon
### Completed
- **Icon**: ✓ (checkmark)
- **Title**: Tool-specific title with arguments
- **Border**: Success color (green)
- **Body**: Tool-specific rendered content
### Error
- **Icon**: ✗ (X mark)
- **Title**: Same format but in error color
- **Border**: Error color (red)
- **Body**: Error message in highlighted box
## Title Rendering Logic
The title follows this pattern:
1. **Pending state**: Show action text
```
"Writing command..."
"Preparing edit..."
"Delegating..."
```
2. **Completed/Running/Error**: Show specific info
```
"Shell npm install"
"Edit src/app.ts"
"Read package.json"
"Task[general] Search for files"
```
3. **Special cases**:
- `todowrite`: Shows plan phase
- `todoread`: Just "Plan"
- `bash`: Uses description if available, otherwise shows command
## Metadata Usage
Tool calls use `metadata` for rich content:
- **read**: `metadata.preview` - file preview content
- **edit**: `metadata.diff` - patch/diff text
- **bash**: `metadata.output` - command output
- **todowrite**: `metadata.todos[]` - todo items with status
- **task**: `metadata.summary[]` - delegated tool calls
- **edit/write**: `metadata.diagnostics` - LSP diagnostics
## Design Principles
1. **Context-specific**: Each tool shows the most relevant information
2. **Progressive disclosure**: Collapsed by default, expand for details
3. **Visual hierarchy**: Icons, colors, and borders indicate status
4. **Truncation**: Long content is truncated (6-10 lines) to prevent overwhelming
5. **Consistency**: All tools follow same header/body/error structure
## Component Structure
```tsx
<div class="tool-call tool-call-status-{status}">
<button class="tool-call-header" onClick={toggle}>
<span class="tool-call-icon">▶/▼</span>
<span class="tool-call-emoji">{icon}</span>
<span class="tool-call-summary">{title}</span>
<span class="tool-call-status">{statusIcon}</span>
</button>
{expanded && (
<div class="tool-call-details">
{/* Tool-specific body content */}
{error && <div class="tool-call-error-content">{error}</div>}
</div>
)}
</div>
```
## CSS Classes
- `.tool-call` - Base container
- `.tool-call-status-{pending|running|completed|error}` - Status-specific styling
- `.tool-call-header` - Clickable header with expand/collapse
- `.tool-call-emoji` - Tool type icon
- `.tool-call-summary` - Tool title/description
- `.tool-call-details` - Expanded content area
- `.tool-call-content` - Code/output content (monospace)
- `.tool-call-todos` - Todo list container
- `.tool-call-task-summary` - Delegated task list
- `.tool-call-error-content` - Error message display
## Future Enhancements
1. **Syntax highlighting**: Use Shiki for code blocks in bash, read, write
2. **Diff rendering**: Better diff visualization for edit tool
3. **Copy buttons**: Quick copy for code/output
4. **File links**: Click filename to open in editor
5. **Diagnostics display**: Show LSP errors/warnings inline

312
dev-docs/architecture.md Normal file
View File

@@ -0,0 +1,312 @@
# CodeNomad Architecture
## Overview
CodeNomad is a cross-platform desktop application built with Electron that provides a multi-instance, multi-session interface for interacting with OpenCode servers. Each instance manages its own OpenCode server process and can handle multiple concurrent sessions.
## High-Level Architecture
```
┌─────────────────────────────────────────────────────────┐
│ Electron Main Process │
│ - Window management │
│ - Process spawning (opencode serve) │
│ - IPC bridge to renderer │
│ - File system operations │
└────────────────┬────────────────────────────────────────┘
│ IPC
┌────────────────┴────────────────────────────────────────┐
│ Electron Renderer Process │
│ ┌──────────────────────────────────────────────────┐ │
│ │ SolidJS Application │ │
│ │ ┌────────────────────────────────────────────┐ │ │
│ │ │ Instance Manager │ │ │
│ │ │ - Spawns/kills OpenCode servers │ │ │
│ │ │ - Manages SDK clients per instance │ │ │
│ │ │ - Handles port allocation │ │ │
│ │ └────────────────────────────────────────────┘ │ │
│ │ ┌────────────────────────────────────────────┐ │ │
│ │ │ State Management (SolidJS Stores) │ │ │
│ │ │ - instances[] │ │ │
│ │ │ - sessions[] per instance │ │ │
│ │ │ - normalized message store per session │ │ │
│ │ └────────────────────────────────────────────┘ │ │
│ │ ┌────────────────────────────────────────────┐ │ │
│ │ │ UI Components │ │ │
│ │ │ - InstanceTabs │ │ │
│ │ │ - SessionTabs │ │ │
│ │ │ - MessageSection │ │ │
│ │ │ - PromptInput │ │ │
│ │ └────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│ HTTP/SSE
┌────────────────┴────────────────────────────────────────┐
│ Multiple OpenCode Server Processes │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Instance 1 │ │ Instance 2 │ │ Instance 3 │ │
│ │ Port: 4096 │ │ Port: 4097 │ │ Port: 4098 │ │
│ │ ~/project-a │ │ ~/project-a │ │ ~/api │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
```
## Component Layers
### 1. Main Process Layer (Electron)
**Responsibilities:**
- Create and manage application window
- Spawn OpenCode server processes as child processes
- Parse server stdout to extract port information
- Handle process lifecycle (start, stop, restart)
- Provide IPC handlers for renderer requests
- Manage native OS integrations (file dialogs, menus)
**Key Modules:**
- `main.ts` - Application entry point
- `process-manager.ts` - OpenCode server process spawning
- `ipc-handlers.ts` - IPC communication handlers
- `menu.ts` - Native application menu
### 2. Renderer Process Layer (SolidJS)
**Responsibilities:**
- Render UI components
- Manage application state
- Handle user interactions
- Communicate with OpenCode servers via HTTP/SSE
- Real-time message streaming
**Key Modules:**
- `App.tsx` - Root component
- `stores/` - State management
- `components/` - UI components
- `contexts/` - SolidJS context providers
- `lib/` - Utilities and helpers
### 3. Communication Layer
**HTTP API Communication:**
- SDK client per instance
- RESTful API calls for session/config/file operations
- Error handling and retries
**SSE (Server-Sent Events):**
- One EventSource per instance
- Real-time message updates
- Event type routing
- Reconnection logic
**CLI Proxy Paths:**
- The CLI server terminates all HTTP/SSE traffic and forwards it to the correct OpenCode instance.
- Each `WorkspaceDescriptor` exposes `proxyPath` (e.g., `/workspaces/<id>/instance`), which acts as the base URL for both REST and SSE calls.
- The renderer never touches the random per-instance port directly; it only talks to `window.location.origin + proxyPath` so a single CLI port can front every session.
## Data Flow
### Instance Creation Flow
1. User selects folder via Electron file dialog
2. Main process receives folder path via IPC
3. Main process spawns `opencode serve --port 0`
4. Main process parses stdout for port number
5. Main process sends port + PID back to renderer
6. Renderer creates SDK client for that port
7. Renderer fetches initial session list
8. Renderer displays session picker
### Message Streaming Flow
1. User submits prompt in active session
2. Renderer POSTs to `/session/:id/message`
3. SSE connection receives `MessageUpdated` events
4. Events are routed to correct instance → session
5. Message state updates trigger UI re-render
6. Messages display with auto-scroll
### Child Session Creation Flow
1. OpenCode server creates child session
2. SSE emits `SessionUpdated` event with `parentId`
3. Renderer adds session to instance's session list
4. New session tab appears automatically
5. Optional: Auto-switch to new tab
## State Management
### Instance State
```
instances: Map<instanceId, {
id: string
folder: string
port: number
pid: number
proxyPath: string // `/workspaces/:id/instance`
status: 'starting' | 'ready' | 'error' | 'stopped'
client: OpenCodeClient
eventSource: EventSource
sessions: Map<sessionId, Session>
activeSessionId: string | null
logs: string[]
}>
```
### Session State
```
Session: {
id: string
title: string
parentId: string | null
messages: Message[]
agent: string
model: { providerId: string, modelId: string }
status: 'idle' | 'streaming' | 'error'
}
```
### Message State
```
Message: {
id: string
sessionId: string
type: 'user' | 'assistant'
parts: Part[]
timestamp: number
status: 'sending' | 'sent' | 'streaming' | 'complete' | 'error'
}
```
## Tab Hierarchy
### Level 1: Instance Tabs
Each tab represents one OpenCode server instance:
- Label: Folder name (with counter if duplicate)
- Icon: Folder icon
- Close button: Stops server and closes tab
- "+" button: Opens folder picker for new instance
### Level 2: Session Tabs
Each instance has multiple session tabs:
- Main session tab (always present)
- Child session tabs (auto-created)
- Logs tab (shows server output)
- "+" button: Creates new session
### Tab Behavior
**Instance Tab Switching:**
- Preserves session tabs
- Switches active SDK client
- Updates SSE event routing
**Session Tab Switching:**
- Loads messages for that session
- Updates agent/model controls
- Preserves scroll position
## Technology Stack
### Core
- **Electron** - Desktop wrapper
- **SolidJS** - Reactive UI framework
- **TypeScript** - Type safety
- **Vite** - Build tool
### UI
- **TailwindCSS** - Styling
- **Kobalte** - Accessible UI primitives
- **Shiki** - Code syntax highlighting
- **Marked** - Markdown parsing
### Communication
- **OpenCode SDK** - API client
- **EventSource** - SSE streaming
- **Node Child Process** - Process spawning
## Error Handling
### Process Errors
- Server fails to start → Show error in instance tab
- Server crashes → Attempt auto-restart once
- Port already in use → Find next available port
### Network Errors
- API call fails → Show inline error, allow retry
- SSE disconnects → Auto-reconnect with backoff
- Timeout → Show timeout error, allow manual retry
### User Errors
- Invalid folder selection → Show error dialog
- Permission denied → Show actionable error message
- Out of memory → Graceful degradation message
## Performance Considerations
**Note: Performance optimization is NOT a focus for MVP. These are future considerations.**
### Message Rendering (Post-MVP)
- Start with simple list rendering - no virtual scrolling
- No message limits initially
- Only optimize if users report issues
- Virtual scrolling can be added in Phase 8 if needed
### State Updates
- SolidJS fine-grained reactivity handles most cases
- No special optimizations needed for MVP
- Batching/debouncing can be added later if needed
### Memory Management (Post-MVP)
- No memory management in MVP
- Let browser/OS handle it
- Add limits only if problems arise in testing
## Security Considerations
- No remote code execution
- Server spawned with user permissions
- No eval() or dangerous innerHTML
- Sanitize markdown rendering
- Validate all IPC messages
- HTTPS only for external requests
## Extensibility Points
### Plugin System (Future)
- Custom slash commands
- Custom message renderers
- Theme extensions
- Keybinding customization
### Configuration (Future)
- Per-instance settings
- Global preferences
- Workspace-specific configs
- Import/export settings

391
dev-docs/build-roadmap.md Normal file
View File

@@ -0,0 +1,391 @@
# CodeNomad Build Roadmap
## Overview
This document outlines the phased approach to building the CodeNomad desktop application. Each phase builds incrementally on the previous, with clear deliverables and milestones.
**Status:** MVP (Phases 1-3) is complete. Focus now shifts to post-MVP phases starting with multi-instance support and advanced input refinements.
## MVP Scope (Phases 1-3)
The minimum viable product includes:
- Single instance management
- Session selection and creation
- Message display (streaming)
- Basic prompt input (text only)
- Agent/model selection
- Process lifecycle management
**Target: 3-4 weeks for MVP**
---
## Phase 1: Foundation (Week 1)
**Goal:** Running Electron app that can spawn OpenCode servers
### Tasks
1.**001-project-setup** - Electron + SolidJS + Vite boilerplate
2.**002-empty-state-ui** - Empty state UI with folder selection
3.**003-process-manager** - Spawn and manage OpenCode server processes
4.**004-sdk-integration** - Connect to server via SDK
5.**005-session-picker-modal** - Select/create session modal
### Deliverables
- App launches successfully
- Can select folder
- Server spawns automatically
- Session picker appears
- Can create/select session
### Success Criteria
- User can launch app → select folder → see session picker
- Server process runs in background
- Sessions fetch from API successfully
---
## Phase 2: Core Chat Interface (Week 2)
**Goal:** Display messages and send basic prompts
### Tasks
6. **006-instance-session-tabs** - Two-level tab navigation
7. **007-message-display** - Render user and assistant messages
8. **008-sse-integration** - Real-time message streaming
9. **009-prompt-input-basic** - Text input with send functionality
10. **010-tool-call-rendering** - Display tool executions inline
### Deliverables
- Tab navigation works
- Messages display correctly
- Real-time updates via SSE
- Can send text messages
- Tool calls show status
### Success Criteria
- User can type message → see response stream in real-time
- Tool executions visible and expandable
- Multiple sessions can be open simultaneously
---
## Phase 3: Essential Features (Week 3)
**Goal:** Feature parity with basic TUI functionality
### Tasks
11. **011-agent-model-selectors** - Dropdown for agent/model switching
12. **012-markdown-rendering** - Proper markdown with code highlighting
13. **013-logs-tab** - View server logs
14. **014-error-handling** - Comprehensive error states and recovery
15. **015-keyboard-shortcuts** - Essential keyboard navigation
### Deliverables
- Can switch agents and models
- Markdown renders beautifully
- Code blocks have syntax highlighting
- Server logs accessible
- Errors handled gracefully
- Cmd/Ctrl+N, K, L shortcuts work
### Success Criteria
- User experience matches TUI quality
- All error cases handled
- Keyboard-first navigation option available
---
## Phase 4: Multi-Instance Support (Week 4)
**Goal:** Work on multiple projects simultaneously
### Tasks
16. **016-instance-tabs** - Instance-level tab management
17. **017-instance-state-persistence** - Remember instances across restarts
18. **018-child-session-handling** - Auto-create tabs for child sessions
19. **019-instance-lifecycle** - Stop, restart, reconnect instances
20. **020-multiple-sdk-clients** - One SDK client per instance
### Deliverables
- Multiple instance tabs
- Persists across app restarts
- Child sessions appear as new tabs
- Can stop individual instances
- All instances work independently
### Success Criteria
- User can work on 3+ projects simultaneously
- App remembers state on restart
- No interference between instances
---
## Phase 5: Advanced Input (Week 5)
**Goal:** Full input capabilities matching TUI
### Tasks
21. **021-slash-commands** - Command palette with autocomplete
22. **022-file-attachments** - @ mention file picker
23. **023-drag-drop-files** - Drag files onto input
24. **024-attachment-chips** - Display and manage attachments
25. **025-input-history** - Up/down arrow message history
### Deliverables
- `/command` autocomplete works
- `@file` picker searches files
- Drag & drop attaches files
- Attachment chips removable
- Previous messages accessible
### Success Criteria
- Input feature parity with TUI
- File context easy to add
- Command discovery intuitive
---
## Phase 6: Polish & UX (Week 6)
**Goal:** Production-ready user experience
### Tasks
26. **026-message-actions** - Copy, edit, regenerate messages
27. **027-search-in-session** - Find text in conversation
28. **028-session-management** - Rename, share, export sessions
29. **029-settings-ui** - Preferences and configuration
30. **030-native-menus** - Platform-native menu bar
### Deliverables
- Message context menus
- Search within conversation
- Session CRUD operations
- Settings dialog
- Native File/Edit/View menus
### Success Criteria
- Feels polished and professional
- All common actions accessible
- Settings discoverable
---
## Phase 7: System Integration (Week 7)
**Goal:** Native desktop app features
### Tasks
31. **031-system-tray** - Background running with tray icon
32. **032-notifications** - Desktop notifications for events
33. **033-auto-updater** - In-app update mechanism
34. **034-crash-reporting** - Error reporting and recovery
35. **035-performance-profiling** - Optimize rendering and memory
### Deliverables
- Runs in background
- Notifications for session activity
- Auto-updates on launch
- Crash logs captured
- Smooth performance with large sessions
### Success Criteria
- App feels native to platform
- Updates seamlessly
- Crashes don't lose data
---
## Phase 8: Advanced Features (Week 8+)
**Goal:** Beyond MVP, power user features
### Tasks
36. **036-virtual-scrolling** - Handle 1000+ message sessions
37. **037-message-search-advanced** - Full-text search across sessions
38. **038-workspace-management** - Save/load workspace configurations
39. **039-theme-customization** - Custom themes and UI tweaks
40. **040-plugin-system** - Extension API for custom tools
### Deliverables
- Virtual scrolling for performance
- Cross-session search
- Workspace persistence
- Theme editor
- Plugin loader
### Success Criteria
- Handles massive sessions (5000+ messages)
- Can search entire project history
- Fully customizable
---
## Parallel Tracks
Some tasks can be worked on independently:
### Design Track
- Visual design refinements
- Icon creation
- Brand assets
- Marketing materials
### Documentation Track
- User guide
- Keyboard shortcuts reference
- Troubleshooting docs
- Video tutorials
### Infrastructure Track
- CI/CD pipeline
- Automated testing
- Release automation
- Analytics integration
---
## Release Strategy
### Alpha (After Phase 3)
- Internal testing only
- Frequent bugs expected
- Rapid iteration
### Beta (After Phase 6)
- Public beta program
- Feature complete
- Bug fixes and polish
### v1.0 (After Phase 7)
- Public release
- Stable and reliable
- Production-ready
### v1.x (Phase 8+)
- Regular feature updates
- Community-driven priorities
- Plugin ecosystem
---
## Success Metrics
### MVP Success
- 10 internal users daily
- Can complete full coding session
- <5 critical bugs
### Beta Success
- 100+ external users
- NPS >50
- <10 bugs per week
### v1.0 Success
- 1000+ users
- <1% crash rate
- Feature requests > bug reports
---
## Risk Mitigation
### Technical Risks
- **Process management complexity**
- Mitigation: Extensive testing, graceful degradation
- **SSE connection stability**
- Mitigation: Robust reconnection logic, offline mode
- **Performance with large sessions**
- Mitigation: NOT a concern for MVP - defer to Phase 8
- Accept slower performance initially, optimize later based on user feedback
### Product Risks
- **Feature creep**
- Mitigation: Strict MVP scope, user feedback prioritization
- **Over-optimization too early**
- Mitigation: Focus on functionality first, optimize in Phase 8
- Avoid premature performance optimization
- **Platform inconsistencies**
- Mitigation: Test on all platforms regularly
---
## Dependencies
### External
- OpenCode CLI availability
- OpenCode SDK stability
- Electron framework updates
### Internal
- Design assets
- Documentation
- Testing resources
---
## Milestone Checklist
### Pre-Alpha
- [ ] All Phase 1 tasks complete
- [ ] Can create instance and session
- [ ] Internal demo successful
### Alpha
- [ ] All Phase 2-3 tasks complete
- [ ] MVP feature complete
- [ ] 5+ internal users testing
### Beta
- [ ] All Phase 4-6 tasks complete
- [ ] Multi-instance stable
- [ ] 50+ external testers
### v1.0
- [ ] All Phase 7 tasks complete
- [ ] Documentation complete
- [ ] <5 known bugs
- [ ] Ready for public release

82
dev-docs/solidjs-llms.txt Normal file
View File

@@ -0,0 +1,82 @@
# SolidJS Documentation
> Solid is a modern JavaScript framework for building user interfaces with fine-grained reactivity. It compiles JSX to real DOM elements and updates only what changes, delivering exceptional performance without a virtual DOM. Solid provides reactive primitives like signals, effects, and stores for predictable state management.
SolidJS is a declarative JavaScript framework that prioritizes performance and developer experience. Unlike frameworks that re-run components on every update, Solid components run once during initialization and set up a reactive system that precisely updates the DOM when dependencies change.
Key principles:
- Fine-grained reactivity: Updates only the specific DOM nodes that depend on changed data
- Compile-time optimization: JSX transforms into efficient DOM operations
- Unidirectional data flow: Props are read-only, promoting predictable state management
- Component lifecycle: Components run once, with reactive primitives handling updates
**Use your web fetch tool on any of the following links to understand the relevant concept**.
## Quick Start
- [Overview](https://docs.solidjs.com/): Framework introduction and key advantages
- [Quick Start](https://docs.solidjs.com/quick-start): Installation and project setup with create-solid
- [Interactive Tutorial](https://www.solidjs.com/tutorial/introduction_basics): Learn Solid basics through guided examples
- [Playground](https://playground.solidjs.com/): Experiment with Solid directly in your browser
## Core Concepts
- [Intro to Reactivity](https://docs.solidjs.com/concepts/intro-to-reactivity): Signals, subscribers, and reactive principles
- [Understanding JSX](https://docs.solidjs.com/concepts/understanding-jsx): How Solid uses JSX and key differences from HTML
- [Components Basics](https://docs.solidjs.com/concepts/components/basics): Component trees, lifecycles, and composition patterns
- [Signals](https://docs.solidjs.com/concepts/signals): Core reactive primitive for state management with getters/setters
- [Effects](https://docs.solidjs.com/concepts/effects): Side effects, dependency tracking, and lifecycle functions
- [Stores](https://docs.solidjs.com/concepts/stores): Complex state management with proxy-based reactivity
- [Context](https://docs.solidjs.com/concepts/context): Cross-component state sharing without prop drilling
## Component APIs
- [Props](https://docs.solidjs.com/concepts/components/props): Passing data and handlers to child components
- [Event Handlers](https://docs.solidjs.com/concepts/components/event-handlers): Managing user interactions
- [Class and Style](https://docs.solidjs.com/concepts/components/class-style): Dynamic styling approaches
- [Refs](https://docs.solidjs.com/concepts/refs): Accessing DOM elements directly
## Control Flow
- [Conditional Rendering](https://docs.solidjs.com/concepts/control-flow/conditional-rendering): Show, Switch, and Match components
- [List Rendering](https://docs.solidjs.com/concepts/control-flow/list-rendering): For, Index, and keyed iteration
- [Dynamic](https://docs.solidjs.com/concepts/control-flow/dynamic): Dynamic component switching
- [Portal](https://docs.solidjs.com/concepts/control-flow/portal): Rendering outside component hierarchy
- [Error Boundary](https://docs.solidjs.com/concepts/control-flow/error-boundary): Graceful error handling
## Derived Values
- [Derived Signals](https://docs.solidjs.com/concepts/derived-values/derived-signals): Computed values from signals
- [Memos](https://docs.solidjs.com/concepts/derived-values/memos): Cached computed values for performance
## State Management
- [Basic State Management](https://docs.solidjs.com/guides/state-management): One-way data flow and lifting state
- [Complex State Management](https://docs.solidjs.com/guides/complex-state-management): Stores for scalable applications
- [Fetching Data](https://docs.solidjs.com/guides/fetching-data): Async data with createResource
## Routing
- [Routing & Navigation](https://docs.solidjs.com/guides/routing-and-navigation): @solidjs/router setup and usage
- [Dynamic Routes](https://docs.solidjs.com/guides/routing-and-navigation#dynamic-routes): Route parameters and validation
- [Nested Routes](https://docs.solidjs.com/guides/routing-and-navigation#nested-routes): Hierarchical route structures
- [Preload Functions](https://docs.solidjs.com/guides/routing-and-navigation#preload-functions): Parallel data fetching
## Advanced Topics
- [Fine-Grained Reactivity](https://docs.solidjs.com/advanced-concepts/fine-grained-reactivity): Deep dive into reactive system
- [TypeScript](https://docs.solidjs.com/configuration/typescript): Type safety and configuration
## Ecosystem
- [Solid Router](https://docs.solidjs.com/solid-router/): File-system routing and data APIs
- [SolidStart](https://docs.solidjs.com/solid-start/): Full-stack meta-framework
- [Solid Meta](https://docs.solidjs.com/solid-meta/): Document head management
- [Templates](https://github.com/solidjs/templates): Starter templates for different setups
## Optional
- [Ecosystem Libraries](https://www.solidjs.com/ecosystem): Community packages and tools
- [API Reference](https://docs.solidjs.com/reference/): Complete API documentation
- [Testing](https://docs.solidjs.com/guides/testing): Testing strategies and utilities
- [Deployment](https://docs.solidjs.com/guides/deploying-your-app): Build and deployment options

View File

@@ -0,0 +1,642 @@
# Technical Implementation Details
## Technology Stack
### Core Technologies
- **Electron** v28+ - Desktop application wrapper
- **SolidJS** v1.8+ - Reactive UI framework
- **TypeScript** v5.3+ - Type-safe development
- **Vite** v5+ - Fast build tool and dev server
### UI & Styling
- **TailwindCSS** v4+ - Utility-first styling
- **Kobalte** - Accessible UI primitives for SolidJS
- **Shiki** - Syntax highlighting for code blocks
- **Marked** - Markdown parsing
- **Lucide** - Icon library
### Communication
- **OpenCode SDK** (@opencode-ai/sdk) - API client
- **EventSource API** - Server-sent events
- **Node Child Process** - Process management
### Development Tools
- **electron-vite** - Electron + Vite integration
- **electron-builder** - Application packaging
- **ESLint** - Code linting
- **Prettier** - Code formatting
## Project Structure
```
packages/opencode-client/
├── electron/
│ ├── main/
│ │ ├── main.ts # Electron main entry
│ │ ├── window.ts # Window management
│ │ ├── process-manager.ts # OpenCode server spawning
│ │ ├── ipc.ts # IPC handlers
│ │ └── menu.ts # Application menu
│ ├── preload/
│ │ └── index.ts # Preload script (IPC bridge)
│ └── resources/
│ └── icon.png # Application icon
├── src/
│ ├── components/
│ │ ├── instance-tabs.tsx # Level 1 tabs
│ │ ├── session-tabs.tsx # Level 2 tabs
│ │ ├── message-stream-v2.tsx # Messages display (normalized store)
│ │ ├── message-item.tsx # Single message
│ │ ├── tool-call.tsx # Tool execution display
│ │ ├── prompt-input.tsx # Input with attachments
│ │ ├── agent-selector.tsx # Agent dropdown
│ │ ├── model-selector.tsx # Model dropdown
│ │ ├── session-picker.tsx # Startup modal
│ │ ├── logs-view.tsx # Server logs
│ │ └── empty-state.tsx # No instances view
│ ├── stores/
│ │ ├── instances.ts # Instance state
│ │ ├── sessions.ts # Session state per instance
│ │ └── ui.ts # UI state (active tabs, etc)
│ ├── lib/
│ │ ├── sdk-manager.ts # SDK client management
│ │ ├── sse-manager.ts # SSE connection handling
│ │ ├── port-finder.ts # Find available ports
│ │ └── markdown.ts # Markdown rendering utils
│ ├── hooks/
│ │ ├── use-instance.ts # Instance operations
│ │ ├── use-session.ts # Session operations
│ │ └── use-messages.ts # Message operations
│ ├── types/
│ │ ├── instance.ts # Instance types
│ │ ├── session.ts # Session types
│ │ └── message.ts # Message types
│ ├── App.tsx # Root component
│ ├── main.tsx # Renderer entry
│ └── index.css # Global styles
├── docs/ # Documentation
├── tasks/ # Task tracking
├── package.json
├── tsconfig.json
├── electron.vite.config.ts
├── tailwind.config.js
└── README.md
```
## State Management
### Instance Store
```typescript
interface InstanceState {
instances: Map<string, Instance>
activeInstanceId: string | null
// Actions
createInstance(folder: string): Promise<void>
removeInstance(id: string): Promise<void>
setActiveInstance(id: string): void
}
interface Instance {
id: string // UUID
folder: string // Absolute path
port: number // Server port
pid: number // Process ID
status: InstanceStatus
client: OpenCodeClient // SDK client
eventSource: EventSource | null // SSE connection
sessions: Map<string, Session>
activeSessionId: string | null
logs: LogEntry[]
}
type InstanceStatus =
| "starting" // Server spawning
| "ready" // Server connected
| "error" // Failed to start
| "stopped" // Server killed
interface LogEntry {
timestamp: number
level: "info" | "error" | "warn"
message: string
}
```
### Session Store
```typescript
interface SessionState {
// Per instance
getSessions(instanceId: string): Session[]
getActiveSession(instanceId: string): Session | null
// Actions
createSession(instanceId: string, agent: string): Promise<Session>
deleteSession(instanceId: string, sessionId: string): Promise<void>
setActiveSession(instanceId: string, sessionId: string): void
updateSession(instanceId: string, sessionId: string, updates: Partial<Session>): void
}
interface Session {
id: string
instanceId: string
title: string
parentId: string | null
agent: string
model: {
providerId: string
modelId: string
}
version: string
time: { created: number; updated: number }
revert?: {
messageID?: string
partID?: string
snapshot?: string
diff?: string
}
}
// Message content lives in the normalized message-v2 store
// keyed by instanceId/sessionId/messageId
type SessionStatus =
| "idle" // No activity
| "streaming" // Assistant responding
| "error" // Error occurred
```
### UI Store
```typescript
interface UIState {
// Tab state
instanceTabOrder: string[]
sessionTabOrder: Map<string, string[]> // instanceId -> sessionIds
// Modal state
showSessionPicker: string | null // instanceId or null
showSettings: boolean
// Actions
reorderInstanceTabs(newOrder: string[]): void
reorderSessionTabs(instanceId: string, newOrder: string[]): void
openSessionPicker(instanceId: string): void
closeSessionPicker(): void
}
```
## Process Management
### Server Spawning
**Strategy:** Spawn with port 0 (random), parse stdout for actual port
```typescript
interface ProcessManager {
spawn(folder: string): Promise<ProcessInfo>
kill(pid: number): Promise<void>
restart(pid: number, folder: string): Promise<ProcessInfo>
}
interface ProcessInfo {
pid: number
port: number
stdout: Readable
stderr: Readable
}
// Implementation approach:
// 1. Check if opencode binary exists
// 2. Spawn: spawn('opencode', ['serve', '--port', '0'], { cwd: folder })
// 3. Listen to stdout
// 4. Parse line matching: "Server listening on port 4096"
// 5. Resolve promise with port
// 6. Timeout after 10 seconds
```
### Port Parsing
```typescript
// Expected output from opencode serve:
// > Starting OpenCode server...
// > Server listening on port 4096
// > API available at http://localhost:4096
function parsePort(output: string): number | null {
const match = output.match(/port (\d+)/)
return match ? parseInt(match[1], 10) : null
}
```
### Error Handling
**Server fails to start:**
- Parse stderr for error message
- Display in instance tab with retry button
- Common errors: Port in use, permission denied, binary not found
**Server crashes after start:**
- Detect via process 'exit' event
- Attempt auto-restart once
- If restart fails, show error state
- Preserve session data for manual restart
## Communication Layer
### SDK Client Management
```typescript
interface SDKManager {
createClient(port: number): OpenCodeClient
destroyClient(port: number): void
getClient(port: number): OpenCodeClient | null
}
// One client per instance
// Client lifecycle tied to instance lifecycle
```
### SSE Event Handling
```typescript
interface SSEManager {
connect(instanceId: string, port: number): void
disconnect(instanceId: string): void
// Event routing
onMessageUpdate(handler: (instanceId: string, event: MessageUpdateEvent) => void): void
onSessionUpdate(handler: (instanceId: string, event: SessionUpdateEvent) => void): void
onError(handler: (instanceId: string, error: Error) => void): void
}
// Event flow:
// 1. EventSource connects to /event endpoint
// 2. Events arrive as JSON
// 3. Route to correct instance store
// 4. Update reactive state
// 5. UI auto-updates via signals
```
### Reconnection Logic
```typescript
// SSE disconnects:
// - Network issue
// - Server restart
// - Tab sleep (browser optimization)
class SSEConnection {
private reconnectAttempts = 0
private maxReconnectAttempts = 5
private reconnectDelay = 1000 // Start with 1s
reconnect() {
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
this.emitError(new Error("Max reconnection attempts reached"))
return
}
setTimeout(() => {
this.connect()
this.reconnectAttempts++
this.reconnectDelay *= 2 // Exponential backoff
}, this.reconnectDelay)
}
}
```
## Message Rendering
### Markdown Processing
```typescript
// Use Marked + Shiki for syntax highlighting
import { marked } from "marked"
import { markedHighlight } from "marked-highlight"
import { getHighlighter } from "shiki"
const highlighter = await getHighlighter({
themes: ["github-dark", "github-light"],
langs: ["typescript", "javascript", "python", "bash", "json"],
})
marked.use(
markedHighlight({
highlight(code, lang) {
return highlighter.codeToHtml(code, {
lang,
theme: isDark ? "github-dark" : "github-light",
})
},
}),
)
```
### Tool Call Rendering
```typescript
interface ToolCallComponent {
tool: string // "bash", "edit", "read"
input: any // Tool-specific input
output?: any // Tool-specific output
status: "pending" | "running" | "success" | "error"
expanded: boolean // Collapse state
}
// Render logic:
// - Default: Collapsed, show summary
// - Click: Toggle expanded state
// - Running: Show spinner
// - Complete: Show checkmark
// - Error: Show error icon + message
```
### Streaming Updates
```typescript
// Messages stream in via SSE
// Update strategy: Replace existing message parts
function handleMessagePartUpdate(event: MessagePartEvent) {
const session = getSession(event.sessionId)
const message = session.messages.find((m) => m.id === event.messageId)
if (!message) {
// New message
session.messages.push(createMessage(event))
} else {
// Update existing
const partIndex = message.parts.findIndex((p) => p.id === event.partId)
if (partIndex === -1) {
message.parts.push(event.part)
} else {
message.parts[partIndex] = event.part
}
}
// SolidJS reactivity triggers re-render
}
```
## Performance Considerations
**MVP Approach: Don't optimize prematurely**
### Message Rendering (MVP)
**Simple approach - no optimization:**
```typescript
// Render all messages - no virtual scrolling, no limits
<For each={messages()}>
{(message) => <MessageItem message={message} />}
</For>
// SolidJS will handle reactivity efficiently
// Only optimize if users report issues
```
### State Update Batching
**Not needed for MVP:**
- SolidJS reactivity is efficient enough
- SSE updates will just trigger normal re-renders
- Add batching only if performance issues arise
### Memory Management
**Not needed for MVP:**
- No message limits
- No pruning
- No lazy loading
- Let users create as many messages as they want
- Optimize later if problems occur
**When to add optimizations (post-MVP):**
- Users report slowness with large sessions
- Measurable performance degradation
- Memory usage becomes problematic
- See Phase 8 tasks for virtual scrolling and optimization
## IPC Communication
### Main Process → Renderer
```typescript
// Events sent from main to renderer
type MainToRenderer = {
"instance:started": { id: string; port: number; pid: number }
"instance:error": { id: string; error: string }
"instance:stopped": { id: string }
"instance:log": { id: string; entry: LogEntry }
}
```
### Renderer → Main Process
```typescript
// Commands sent from renderer to main
type RendererToMain = {
"folder:select": () => Promise<string | null>
"instance:create": (folder: string) => Promise<{ port: number; pid: number }>
"instance:stop": (pid: number) => Promise<void>
"app:quit": () => void
}
```
### Preload Script (Bridge)
```typescript
// Expose safe IPC methods to renderer
contextBridge.exposeInMainWorld("electronAPI", {
selectFolder: () => ipcRenderer.invoke("folder:select"),
createInstance: (folder: string) => ipcRenderer.invoke("instance:create", folder),
stopInstance: (pid: number) => ipcRenderer.invoke("instance:stop", pid),
onInstanceStarted: (callback) => ipcRenderer.on("instance:started", callback),
onInstanceError: (callback) => ipcRenderer.on("instance:error", callback),
})
```
## Error Handling Strategy
### Network Errors
```typescript
// HTTP request fails
try {
const response = await client.session.list()
} catch (error) {
if (error.code === "ECONNREFUSED") {
// Server not responding
showError("Cannot connect to server. Is it running?")
} else if (error.code === "ETIMEDOUT") {
// Request timeout
showError("Request timed out. Retry?", { retry: true })
} else {
// Unknown error
showError(error.message)
}
}
```
### SSE Errors
```typescript
eventSource.onerror = (error) => {
// Connection lost
if (eventSource.readyState === EventSource.CLOSED) {
// Attempt reconnect
reconnectSSE()
}
}
```
### User Input Errors
```typescript
// Validate before sending
function validatePrompt(text: string): string | null {
if (!text.trim()) {
return "Message cannot be empty"
}
if (text.length > 10000) {
return "Message too long (max 10000 characters)"
}
return null
}
```
## Security Measures
### IPC Security
- Use `contextIsolation: true`
- Whitelist allowed IPC channels
- Validate all data from renderer
- No `nodeIntegration` in renderer
### Process Security
- Spawn OpenCode with user permissions only
- No shell execution of user input
- Sanitize file paths
### Content Security
- Sanitize markdown before rendering
- Use DOMPurify for HTML sanitization
- No `dangerouslySetInnerHTML` without sanitization
- CSP headers in renderer
## Testing Strategy (Future)
### Unit Tests
- State management logic
- Utility functions
- Message parsing
### Integration Tests
- Process spawning
- SDK client operations
- SSE event handling
### E2E Tests
- Complete user flows
- Multi-instance scenarios
- Error recovery
## Build & Packaging
### Development
```bash
npm run dev # Start Electron + Vite dev server
npm run dev:main # Main process only
npm run dev:renderer # Renderer only
```
### Production
```bash
npm run build # Build all
npm run build:main # Build main process
npm run build:renderer # Build renderer
npm run package # Create distributable
```
### Distribution
- macOS: DMG + auto-update
- Windows: NSIS installer + auto-update
- Linux: AppImage + deb/rpm
## Configuration Files
### electron.vite.config.ts
```typescript
import { defineConfig } from "electron-vite"
import solid from "vite-plugin-solid"
export default defineConfig({
main: {
build: {
rollupOptions: {
external: ["electron"],
},
},
},
preload: {
build: {
rollupOptions: {
external: ["electron"],
},
},
},
renderer: {
plugins: [solid()],
resolve: {
alias: {
"@": "/src",
},
},
},
})
```
### tsconfig.json
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"jsx": "preserve",
"jsxImportSource": "solid-js",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"paths": {
"@/*": ["./src/*"]
}
}
}
```

493
dev-docs/user-interface.md Normal file
View File

@@ -0,0 +1,493 @@
# User Interface Specification
## Overview
The CodeNomad interface consists of a two-level tabbed layout with instance tabs at the top and session tabs below. Each session displays a message stream and prompt input.
## Layout Structure
```
┌──────────────────────────────────────────────────────────────┐
│ File Edit View Window Help ● ○ ◐ │ ← Native menu bar
├──────────────────────────────────────────────────────────────┤
│ [~/project-a] [~/project-a (2)] [~/api-service] [+] │ ← Instance tabs (Level 1)
├──────────────────────────────────────────────────────────────┤
│ [Main] [Fix login] [Write tests] [Logs] [+] │ ← Session tabs (Level 2)
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Messages Area │ │
│ │ │ │
│ │ User: How do I set up testing? │ │
│ │ │ │
│ │ Assistant: To set up testing, you'll need to... │ │
│ │ → bash: npm install vitest ✓ │ │
│ │ Output: added 50 packages │ │
│ │ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
├──────────────────────────────────────────────────────────────┤
│ Agent: Build ▼ Model: Claude 3.5 Sonnet ▼ │ ← Controls
├──────────────────────────────────────────────────────────────┤
│ [@file.ts] [@api.ts] [×] │ ← Attachments
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Type your message or /command... │ │ ← Prompt input
│ │ │ │
│ └────────────────────────────────────────────────────────┘ │
│ [▶] │ ← Send button
└──────────────────────────────────────────────────────────────┘
```
## Components Specification
### 1. Instance Tabs (Level 1)
**Visual Design:**
- Horizontal tabs at top of window
- Each tab shows folder name
- Icon: Folder icon (🗂️)
- Close button (×) on hover
- Active tab: Highlighted with accent color
- Inactive tabs: Muted background
**Tab Label Format:**
- Single instance: `~/project-name`
- Multiple instances of same folder: `~/project-name (2)`, `~/project-name (3)`
- Max width: 200px with ellipsis for long paths
- Tooltip shows full path on hover
**Actions:**
- Click: Switch to that instance
- Close (×): Stop server and close instance (with confirmation)
- Drag: Reorder tabs (future)
**New Instance Button (+):**
- Always visible at right end
- Click: Opens folder picker dialog
- Keyboard: Cmd/Ctrl+N
**States:**
- Starting: Loading spinner + "Starting..."
- Ready: Normal appearance
- Error: Red indicator + error icon
- Stopped: Grayed out (should not be visible, tab closes)
### 2. Session Tabs (Level 2)
**Visual Design:**
- Horizontal tabs below instance tabs
- Smaller than instance tabs
- Each tab shows session title or "Untitled"
- Active tab: Underline or bold
- Parent-child relationship: No visual distinction (all siblings)
**Tab Types:**
**Session Tab:**
- Label: Session title (editable on double-click)
- Icon: Chat bubble (💬) or none
- Close button (×) on hover
- Max width: 150px with ellipsis
**Logs Tab:**
- Label: "Logs"
- Icon: Terminal (⚡)
- Always present per instance
- Non-closable
- Shows server stdout/stderr
**Actions:**
- Click: Switch to that session
- Double-click label: Rename session
- Close (×): Delete session (with confirmation if has messages)
- Right-click: Context menu (Share, Export, Delete)
**New Session Button (+):**
- Click: Creates new session with default agent
- Keyboard: Cmd/Ctrl+T
### 3. Messages Area
**Container:**
- Scrollable viewport
- Auto-scroll to bottom when new messages arrive
- Manual scroll up: Disable auto-scroll
- "Scroll to bottom" button appears when scrolled up
**Message Layout:**
**User Message:**
```
┌──────────────────────────────────────────┐
│ You 10:32 AM │
│ How do I set up testing? │
│ │
│ [@src/app.ts] [@package.json] │ ← Attachments if any
└──────────────────────────────────────────┘
```
**Assistant Message:**
````
┌──────────────────────────────────────────┐
│ Assistant • Build 10:32 AM │
│ To set up testing, you'll need to │
│ install Vitest and configure it. │
│ │
│ ▶ bash: npm install vitest ✓ │ ← Tool call (collapsed)
│ │
│ ▶ edit src/vitest.config.ts ✓ │
│ │
│ Here's the configuration I added: │
│ ```typescript │
│ export default { │
│ test: { globals: true } │
│ } │
│ ``` │
└──────────────────────────────────────────┘
````
**Tool Call (Collapsed):**
```
▶ bash: npm install vitest ✓
^ ^ ^
| | |
Icon Tool name + summary Status
```
**Tool Call (Expanded):**
```
▼ bash: npm install vitest ✓
Input:
{
"command": "npm install vitest"
}
Output:
added 50 packages, and audited 51 packages in 2s
found 0 vulnerabilities
```
**Status Icons:**
- ⏳ Pending (spinner)
- ✓ Success (green checkmark)
- ✗ Error (red X)
- ⚠ Warning (yellow triangle)
**File Change Display:**
```
▶ edit src/vitest.config.ts ✓
Modified: src/vitest.config.ts
+12 lines, -3 lines
```
Click to expand: Show diff inline
### 4. Controls Bar
**Agent Selector:**
- Dropdown button showing current agent
- Click: Opens dropdown with agent list
- Shows: Agent name + description
- Grouped by category (if applicable)
**Model Selector:**
- Dropdown button showing current model
- Click: Opens dropdown with model list
- Shows: Provider icon + Model name
- Grouped by provider
- Displays: Context window, capabilities icons
**Layout:**
```
┌────────────────────────────────────────────┐
│ Agent: Build ▼ Model: Claude 3.5 ▼ │
└────────────────────────────────────────────┘
```
### 5. Prompt Input
**Input Field:**
- Multi-line textarea
- Auto-expanding (max 10 lines)
- Placeholder: "Type your message or /command..."
- Supports keyboard shortcuts
**Features:**
**Slash Commands:**
- Type `/` → Autocomplete dropdown appears
- Shows: Command name + description
- Filter as you type
- Enter to execute
**File Mentions:**
- Type `@` → File picker appears
- Search files by name
- Shows: File icon + path
- Enter to attach
**Attachments:**
- Display as chips above input
- Format: [@filename] [×]
- Click × to remove
- Drag & drop files onto input area
**Send Button:**
- Icon: Arrow (▶) or paper plane
- Click: Submit message
- Keyboard: Enter (without Shift)
- Disabled when: Empty input or server busy
**Keyboard Shortcuts:**
- Enter: New line
- Cmd+Enter (macOS) / Ctrl+Enter (Windows/Linux): Send message
- Cmd/Ctrl+K: Clear input
- Cmd/Ctrl+V: Paste (handles files)
- Cmd/Ctrl+L: Focus input
- Up/Down: Navigate message history (when input empty)
## Overlays & Modals
### Session Picker (Startup)
Appears when instance starts:
```
┌────────────────────────────────────────┐
│ OpenCode • ~/project-a │
├────────────────────────────────────────┤
│ Resume a session: │
│ │
│ > Fix login bug 2h ago │
│ Add dark mode 5h ago │
│ Refactor API Yesterday │
│ │
│ ────────────── or ────────────── │
│ │
│ Start new session: │
│ Agent: [Build ▼] [Start] │
│ │
│ [Cancel] │
└────────────────────────────────────────┘
```
**Actions:**
- Click session: Resume that session
- Click "Start": Create new session with selected agent
- Click "Cancel": Close instance
- Keyboard: Arrow keys to navigate, Enter to select
### Confirmation Dialogs
**Close Instance:**
```
┌────────────────────────────────────────┐
│ Stop OpenCode instance? │
├────────────────────────────────────────┤
│ This will stop the server for: │
│ ~/project-a │
│ │
│ Active sessions will be lost. │
│ │
│ [Cancel] [Stop Instance] │
└────────────────────────────────────────┘
```
**Delete Session:**
```
┌────────────────────────────────────────┐
│ Delete session? │
├────────────────────────────────────────┤
│ This will permanently delete: │
│ "Fix login bug" │
│ │
│ This cannot be undone. │
│ │
│ [Cancel] [Delete] │
└────────────────────────────────────────┘
```
## Empty States
### No Instances
```
┌──────────────────────────────────────────┐
│ │
│ [Folder Icon] │
│ │
│ Start Coding with AI │
│ │
│ Select a folder to start coding with AI │
│ │
│ [Select Folder] │
│ │
│ Keyboard shortcut: Cmd/Ctrl+N │
│ │
└──────────────────────────────────────────┘
```
### No Messages (New Session)
```
┌──────────────────────────────────────────┐
│ │
│ Start a conversation │
│ │
│ Type a message below or try: │
│ • /init-project │
│ • Ask about your codebase │
│ • Attach files with @ │
│ │
└──────────────────────────────────────────┘
```
### Logs Tab (No Logs Yet)
```
┌──────────────────────────────────────────┐
│ Waiting for server output... │
└──────────────────────────────────────────┘
```
## Visual Styling
### Color Scheme
**Light Mode:**
- Background: #FFFFFF
- Secondary background: #F5F5F5
- Border: #E0E0E0
- Text: #1A1A1A
- Muted text: #666666
- Accent: #0066FF
**Dark Mode:**
- Background: #1A1A1A
- Secondary background: #2A2A2A
- Border: #3A3A3A
- Text: #E0E0E0
- Muted text: #999999
- Accent: #0080FF
### Typography
- **Main text**: 14px, system font
- **Headers**: 16px, medium weight
- **Labels**: 12px, regular weight
- **Code**: Monospace font (Consolas, Monaco, Courier)
- **Line height**: 1.5
### Spacing
- **Padding**: 8px, 12px, 16px, 24px (consistent scale)
- **Margins**: Same as padding
- **Tab height**: 40px
- **Input height**: 80px (auto-expanding)
- **Message spacing**: 16px between messages
### Icons
- Use consistent icon set (Lucide, Heroicons, or similar)
- Size: 16px for inline, 20px for buttons
- Stroke width: 2px
## Responsive Behavior
### Minimum Window Size
- Width: 800px
- Height: 600px
### Behavior When Small
- Instance tabs: Scroll horizontally
- Session tabs: Scroll horizontally
- Messages: Always visible, scroll vertically
- Input: Fixed at bottom
## Accessibility
- All interactive elements keyboard-navigable
- ARIA labels for screen readers
- Focus indicators visible
- Color contrast WCAG AA compliant
- Tab trap in modals
- Escape key closes overlays
## Animation & Transitions
- Tab switching: Instant (no animation)
- Message appearance: Fade in (100ms)
- Tool expand/collapse: Slide (200ms)
- Dropdown menus: Fade + slide (150ms)
- Loading states: Spinner or skeleton
## Context Menus
### Session Tab Right-Click
- Rename
- Duplicate
- Share
- Export
- Delete
- Close Other Tabs
### Message Right-Click
- Copy message
- Copy code block
- Edit & regenerate
- Delete message
- Quote in reply
## Status Indicators
### Instance Tab
- Green dot: Server running
- Yellow dot: Server starting
- Red dot: Server error
- No dot: Server stopped
### Session Tab
- Blue pulse: Assistant responding
- No indicator: Idle
### Connection Status
- Bottom right corner: "Connected" or "Reconnecting..."