diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6f3ca82..ae6703e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,33 +41,30 @@ jobs: working-directory: frontend run: pnpm build - - name: Create frontend zip - working-directory: frontend - run: | - cd out - zip -r ../frontend.zip . - - name: Upload frontend artifact uses: actions/upload-artifact@v4 with: - name: frontend - path: frontend/frontend.zip + name: frontend-dist + path: frontend/dist - build-cli: - name: Build CLI (${{ matrix.target }}) + build-server: + name: Build Server (${{ matrix.target }}) runs-on: ${{ matrix.os }} strategy: matrix: include: - target: x86_64-apple-darwin - os: macos-latest - name: opencode-studio-darwin-x86_64 + os: macos-13 + binary_name: server-darwin-x64 - target: aarch64-apple-darwin os: macos-latest - name: opencode-studio-darwin-arm64 + binary_name: server-darwin-arm64 - target: x86_64-unknown-linux-gnu os: ubuntu-latest - name: opencode-studio-linux-x86_64 + binary_name: server-linux-x64 + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + binary_name: server-linux-arm64 steps: - uses: actions/checkout@v4 @@ -76,6 +73,12 @@ jobs: with: targets: ${{ matrix.target }} + - name: Install cross-compilation tools (Linux ARM64) + if: matrix.target == 'aarch64-unknown-linux-gnu' + run: | + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu + - name: Cache cargo registry uses: actions/cache@v4 with: @@ -87,25 +90,29 @@ jobs: restore-keys: | ${{ runner.os }}-${{ matrix.target }}-cargo- - - name: Build CLI - run: cargo build --release --package opencode-studio --target ${{ matrix.target }} + - name: Build server + run: | + if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then + export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc + fi + cargo build --release --bin server --target ${{ matrix.target }} - - name: Package binary (Unix) + - name: Package binary run: | mkdir -p dist - cp target/${{ matrix.target }}/release/opencode-studio dist/${{ matrix.name }} - chmod +x dist/${{ matrix.name }} - cd dist && tar -czvf ${{ matrix.name }}.tar.gz ${{ matrix.name }} + cp target/${{ matrix.target }}/release/server dist/${{ matrix.binary_name }} + chmod +x dist/${{ matrix.binary_name }} + gzip -9 dist/${{ matrix.binary_name }} - - name: Upload CLI artifact + - name: Upload server artifact uses: actions/upload-artifact@v4 with: - name: ${{ matrix.name }} - path: dist/${{ matrix.name }}.tar.gz + name: ${{ matrix.binary_name }} + path: dist/${{ matrix.binary_name }}.gz release: name: Create Release - needs: [build-frontend, build-cli] + needs: [build-frontend, build-server] runs-on: ubuntu-latest permissions: contents: write @@ -120,10 +127,18 @@ jobs: - name: Prepare release assets run: | mkdir -p release - cp artifacts/frontend/frontend.zip release/ - cp artifacts/opencode-studio-darwin-x86_64/opencode-studio-darwin-x86_64.tar.gz release/ - cp artifacts/opencode-studio-darwin-arm64/opencode-studio-darwin-arm64.tar.gz release/ - cp artifacts/opencode-studio-linux-x86_64/opencode-studio-linux-x86_64.tar.gz release/ + + # Frontend + cd artifacts/frontend-dist + zip -r ../../release/frontend.zip . + cd ../.. + + # Server binaries + cp artifacts/server-darwin-x64/server-darwin-x64.gz release/ + cp artifacts/server-darwin-arm64/server-darwin-arm64.gz release/ + cp artifacts/server-linux-x64/server-linux-x64.gz release/ + cp artifacts/server-linux-arm64/server-linux-arm64.gz release/ + ls -la release/ - name: Get version @@ -144,40 +159,85 @@ jobs: prerelease: false files: | release/frontend.zip - release/opencode-studio-darwin-x86_64.tar.gz - release/opencode-studio-darwin-arm64.tar.gz - release/opencode-studio-linux-x86_64.tar.gz + release/server-darwin-x64.gz + release/server-darwin-arm64.gz + release/server-linux-x64.gz + release/server-linux-arm64.gz body: | ## OpenCode Studio v${{ steps.version.outputs.version }} - ### Installation + ### Installation via npx (Recommended) + + ```bash + npx opencode-studio + ``` + + ### Manual Installation + + **Prerequisites:** [OpenCode](https://opencode.ai) must be installed. **macOS (Apple Silicon)** ```bash - curl -L https://github.com/${{ github.repository }}/releases/download/v${{ steps.version.outputs.version }}/opencode-studio-darwin-arm64.tar.gz | tar xz - sudo mv opencode-studio-darwin-arm64 /usr/local/bin/opencode-studio + curl -L https://github.com/${{ github.repository }}/releases/download/v${{ steps.version.outputs.version }}/server-darwin-arm64.gz | gunzip > /usr/local/bin/opencode-studio-server + chmod +x /usr/local/bin/opencode-studio-server ``` **macOS (Intel)** ```bash - curl -L https://github.com/${{ github.repository }}/releases/download/v${{ steps.version.outputs.version }}/opencode-studio-darwin-x86_64.tar.gz | tar xz - sudo mv opencode-studio-darwin-x86_64 /usr/local/bin/opencode-studio + curl -L https://github.com/${{ github.repository }}/releases/download/v${{ steps.version.outputs.version }}/server-darwin-x64.gz | gunzip > /usr/local/bin/opencode-studio-server + chmod +x /usr/local/bin/opencode-studio-server ``` **Linux (x86_64)** ```bash - curl -L https://github.com/${{ github.repository }}/releases/download/v${{ steps.version.outputs.version }}/opencode-studio-linux-x86_64.tar.gz | tar xz - sudo mv opencode-studio-linux-x86_64 /usr/local/bin/opencode-studio + curl -L https://github.com/${{ github.repository }}/releases/download/v${{ steps.version.outputs.version }}/server-linux-x64.gz | gunzip > /usr/local/bin/opencode-studio-server + chmod +x /usr/local/bin/opencode-studio-server ``` - ### Usage - + **Linux (ARM64)** ```bash - # Navigate to any git/jj project and run: - opencode-studio + curl -L https://github.com/${{ github.repository }}/releases/download/v${{ steps.version.outputs.version }}/server-linux-arm64.gz | gunzip > /usr/local/bin/opencode-studio-server + chmod +x /usr/local/bin/opencode-studio-server ``` - The CLI will automatically: - 1. Initialize `.opencode-studio/` directory - 2. Download the frontend app (first run only) - 3. Start the server and open your browser + publish-npm: + name: Publish to npm + needs: [release] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + registry-url: 'https://registry.npmjs.org' + + - name: Download frontend artifact + uses: actions/download-artifact@v4 + with: + name: frontend-dist + path: dist/frontend + + - name: Get version + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT + else + echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT + fi + + - name: Update package.json version + run: | + npm version ${{ steps.version.outputs.version }} --no-git-tag-version + + - name: Publish to npm + run: npm publish --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 0497d50..91f071a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,10 @@ yarn-error.log* /dist /build +# Server binary (downloaded/built during install) +/bin/server +/bin/server.exe + # Environment variables .env .env.local @@ -43,6 +47,9 @@ pids *.seed *.pid.lock +# OpenCode Studio data (contains API keys) +.opencode-studio/ + # Coverage coverage/ *.lcov diff --git a/.opencode-studio/config.toml b/.opencode-studio/config.toml deleted file mode 100644 index d3137d0..0000000 --- a/.opencode-studio/config.toml +++ /dev/null @@ -1,6 +0,0 @@ -[project] -name = "opencode-os" - -[server] -port = 3001 -opencode_url = "http://localhost:4096" diff --git a/.opencode-studio/kanban/plans/02c83e72-f9d4-413a-a341-6995ff757a82.md b/.opencode-studio/kanban/plans/02c83e72-f9d4-413a-a341-6995ff757a82.md deleted file mode 100644 index 92a45fd..0000000 --- a/.opencode-studio/kanban/plans/02c83e72-f9d4-413a-a341-6995ff757a82.md +++ /dev/null @@ -1,218 +0,0 @@ -# Implementation Plan: Watch Idle - -**Task ID:** 02c83e72-f9d4-413a-a341-6995ff757a82 -**Title:** Watch idle -**Description:** x -**Generated:** 2025-01-01T01:36:13+01:00 - -## 1. Technical Analysis - -### Problem Statement -The task "Watch idle" with minimal description requires interpretation. Based on OpenCode Studio's architecture, this likely involves implementing idle detection and management for: -- Long-running OpenCode sessions that have become unresponsive -- Tasks stuck in intermediate states (Planning, InProgress, etc.) -- System resources monitoring for idle cleanup -- Session timeout management - -### Current System Context -- **Task Lifecycle:** TODO → PLANNING → PLANNING_REVIEW → IN_PROGRESS → AI_REVIEW → REVIEW → DONE -- **Session Management:** Each phase runs as separate OpenCode session -- **Event System:** `tokio::broadcast` event bus for real-time updates -- **Persistence:** SQLite database with task/session tracking -- **Known Issue:** Tasks timing out after 30s in `POST /api/tasks/{id}/execute` - -### Proposed Solution -Implement an **Idle Watch Service** that: -1. **Session Monitoring:** Detect OpenCode sessions running longer than threshold -2. **Task State Monitoring:** Identify tasks stuck in intermediate states -3. **Health Checks:** Periodic validation of OpenCode connectivity -4. **Cleanup Actions:** Automatic timeout handling and resource cleanup -5. **Notifications:** Event emission for idle state changes - -## 2. Files to Modify/Create - -### New Files -``` -crates/orchestrator/src/idle_watch.rs # Core idle monitoring logic -crates/orchestrator/src/idle_config.rs # Configuration structures -crates/server/src/routes/idle.rs # Idle management API endpoints -migrations/003_idle_tracking.sql # Database schema updates -``` - -### Files to Modify -``` -crates/orchestrator/src/lib.rs # Export new modules -crates/orchestrator/src/executor.rs # Integrate idle monitoring -crates/orchestrator/Cargo.toml # Add tokio-cron-scheduler dependency -crates/server/src/lib.rs # Register idle routes -crates/server/src/routes/mod.rs # Add idle module -crates/core/src/domain/session.rs # Add idle-related fields -crates/core/src/domain/task.rs # Add last_activity timestamp -crates/db/src/models/session.rs # Database model updates -crates/db/src/repositories/session_repository.rs # Idle queries -crates/events/src/types.rs # New idle events -``` - -## 3. Step-by-Step Implementation - -### Phase 1: Data Model Updates (30 min) -1. **Database Migration** - - Add `last_activity` timestamp to tasks table - - Add `idle_since` timestamp to sessions table - - Add `idle_threshold_minutes` configuration table - -2. **Domain Model Updates** - - Extend `Task` struct with idle tracking fields - - Extend `Session` struct with idle metadata - - Add `IdleStatus` enum: `Active`, `Idle`, `TimedOut` - -### Phase 2: Core Idle Detection (1 hour) -3. **Idle Watch Service (`idle_watch.rs`)** - ```rust - pub struct IdleWatchService { - db: Arc, - event_bus: EventBus, - config: IdleConfig, - } - - impl IdleWatchService { - pub async fn start_monitoring(&self) -> Result<(), Error> - pub async fn check_idle_sessions(&self) -> Result, Error> - pub async fn check_idle_tasks(&self) -> Result, Error> - pub async fn handle_idle_session(&self, session: &Session) -> Result<(), Error> - } - ``` - -4. **Configuration Management (`idle_config.rs`)** - ```rust - #[derive(Debug, Clone)] - pub struct IdleConfig { - pub session_idle_threshold: Duration, - pub task_idle_threshold: Duration, - pub check_interval: Duration, - pub auto_timeout_enabled: bool, - } - ``` - -### Phase 3: Scheduler Integration (45 min) -5. **Background Task Scheduler** - - Use `tokio-cron-scheduler` for periodic checks - - Default: check every 30 seconds - - Configurable via environment variables - -6. **Event Integration** - - Add `SessionIdle`, `SessionTimedOut`, `TaskIdle` events - - Emit through existing EventBus - - Update SSE streams to include idle events - -### Phase 4: API Endpoints (30 min) -7. **REST API (`routes/idle.rs`)** - ``` - GET /api/idle/sessions # List idle sessions - GET /api/idle/tasks # List idle tasks - POST /api/idle/timeout/{id} # Force timeout specific session - GET /api/idle/config # Get idle configuration - PUT /api/idle/config # Update idle configuration - ``` - -### Phase 5: Integration & Testing (45 min) -8. **Executor Integration** - - Update `run_full_cycle()` to track activity timestamps - - Add heartbeat mechanism for long-running operations - - Handle idle detection during OpenCode execution - -9. **Database Queries** - - Add `find_idle_sessions(threshold: Duration)` - - Add `find_idle_tasks(threshold: Duration)` - - Add `update_activity_timestamp(id: Uuid)` - -10. **Unit Tests** - - Idle detection logic tests - - Configuration parsing tests - - Database query tests - - Event emission tests - -## 4. Potential Risks - -### High Risk -- **Unclear Requirements:** Minimal task description requires assumptions -- **False Positives:** Legitimate long-running tasks marked as idle -- **Resource Cleanup:** Risk of prematurely terminating valid sessions -- **Database Locks:** Concurrent access during idle checks vs. normal operations - -### Medium Risk -- **Performance Impact:** Additional periodic database queries -- **Configuration Complexity:** Threshold tuning for different task types -- **Event Flooding:** Too frequent idle checks generating excessive events - -### Low Risk -- **Dependency Addition:** `tokio-cron-scheduler` increases binary size -- **API Surface Expansion:** New endpoints require documentation - -### Mitigation Strategies -1. **Gradual Rollout:** Start with monitoring-only mode, no automatic actions -2. **Configurable Thresholds:** Per-task-type idle timeouts -3. **Manual Override:** Always allow human intervention to prevent timeouts -4. **Comprehensive Logging:** Detailed audit trail for idle detection decisions -5. **Circuit Breaker:** Disable idle monitoring if system is under heavy load - -## 5. Estimated Complexity - -**Size:** **M (Medium)** - -### Justification -- **Lines of Code:** ~400-500 lines across multiple files -- **New Concepts:** Idle detection patterns, background scheduling -- **Integration Points:** 4 crates (orchestrator, server, core, db) -- **Database Changes:** Minor schema additions -- **Testing Effort:** ~10-15 unit tests required -- **Time Estimate:** 3-4 hours development + 1 hour testing - -### Complexity Factors -- **Low Complexity:** Well-defined async patterns in existing codebase -- **Medium Complexity:** Background scheduling, event integration -- **No High Complexity:** No major architectural changes required - -## Dependencies - -### New Dependencies -```toml -# crates/orchestrator/Cargo.toml -[dependencies] -tokio-cron-scheduler = "0.10" -``` - -### Environment Variables -```bash -IDLE_SESSION_TIMEOUT_MINUTES=60 -IDLE_TASK_TIMEOUT_MINUTES=120 -IDLE_CHECK_INTERVAL_SECONDS=30 -IDLE_AUTO_TIMEOUT_ENABLED=false -``` - -## Success Criteria - -1. **Functional** - - ✅ Detect sessions idle > threshold - - ✅ Detect tasks idle > threshold - - ✅ Emit appropriate events - - ✅ API endpoints respond correctly - - ✅ Background scheduler runs reliably - -2. **Performance** - - ✅ Idle checks complete in <100ms - - ✅ No more than 5% CPU overhead - - ✅ Database queries use appropriate indexes - -3. **Integration** - - ✅ All existing tests pass - - ✅ No clippy warnings - - ✅ SSE events include idle notifications - - ✅ OpenCode sessions properly tracked - -## Notes - -- **Assumption:** "Watch idle" means monitoring for unresponsive sessions/tasks -- **Alternative Interpretations:** Could also mean "watch when system is idle" for maintenance tasks -- **Follow-up Required:** Clarification needed on specific idle detection requirements -- **Implementation Order:** Start with monitoring/logging before implementing automatic timeouts \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/116942a0-0ca8-4215-a242-3573d7493df8.md b/.opencode-studio/kanban/plans/116942a0-0ca8-4215-a242-3573d7493df8.md deleted file mode 100644 index 1b261cd..0000000 --- a/.opencode-studio/kanban/plans/116942a0-0ca8-4215-a242-3573d7493df8.md +++ /dev/null @@ -1,236 +0,0 @@ -# Implementation Plan: Transition Test - -**Task ID**: 116942a0-0ca8-4215-a242-3573d7493df8 -**Title**: Transition Test -**Description**: Testing status transitions -**Created**: 2025-12-31T19:55:51Z - -## Technical Analysis - -### Current State Assessment - -OpenCode Studio implements a comprehensive task lifecycle state machine with 7 distinct states: - -``` -TODO → PLANNING → PLANNING_REVIEW → IN_PROGRESS → AI_REVIEW → REVIEW → DONE -``` - -**Existing Infrastructure:** -- **State Machine**: `crates/orchestrator/src/state_machine.rs` - Full transition validation logic -- **API Endpoints**: `crates/server/src/routes/tasks.rs` - `/api/tasks/{id}/transition` endpoint -- **Domain Models**: `crates/core/src/domain/task.rs` - TaskStatus enum with serialization -- **Event System**: SSE events for `task.status_changed` notifications -- **Current Tests**: 4 basic state machine unit tests (transition validation) - -**Gaps Identified:** -1. **Missing Integration Tests**: No end-to-end API testing for transitions -2. **Insufficient Edge Case Coverage**: Limited testing of error scenarios -3. **No Concurrency Testing**: Parallel transition attempts untested -4. **Missing Event Validation**: SSE event emission not verified -5. **No Database State Testing**: Task persistence during transitions not validated - -### Technical Dependencies - -- **Core Crates**: `opencode_core`, `orchestrator`, `server`, `db`, `events` -- **Testing Infrastructure**: Standard Rust `#[cfg(test)]` inline modules -- **API Framework**: Axum with OpenAPI/utoipa integration -- **Database**: SQLite with sqlx (async ORM) -- **Event Bus**: tokio::broadcast for SSE events - -## Files to Modify/Create - -### New Test Files -1. **`crates/orchestrator/src/state_machine_integration_tests.rs`** - - Comprehensive integration tests for state machine - - Multi-step transition sequences - - Error condition testing - -2. **`crates/server/src/routes/tasks_integration_tests.rs`** - - HTTP API endpoint testing - - Request/response validation - - Authentication/authorization edge cases - -3. **`crates/db/src/repositories/task_repository_transition_tests.rs`** - - Database persistence during transitions - - Concurrent update scenarios - - Transaction isolation testing - -### Modified Existing Files -1. **`crates/orchestrator/src/state_machine.rs`** - - Expand existing unit tests - - Add property-based testing - - Include stress testing scenarios - -2. **`crates/server/src/routes/tasks.rs`** - - Enhance error handling validation - - Add transition logging verification - - Improve event emission testing - -3. **`crates/core/src/domain/task.rs`** - - Add helper methods for test data generation - - Include transition history tracking (if needed) - -## Step-by-Step Implementation - -### Phase 1: Enhanced Unit Testing (1-2 hours) -1. **Expand State Machine Tests** - - Add comprehensive transition matrix validation - - Test all valid forward/backward transitions - - Validate all invalid transition rejections - - Add edge cases (same-state transitions, null checks) - -2. **Property-Based Testing** - - Generate random transition sequences - - Verify state machine invariants - - Test transition idempotency where applicable - -### Phase 2: Integration Testing (2-3 hours) -3. **API Integration Tests** - - Create test harness for HTTP endpoints - - Test complete transition workflows (TODO→DONE) - - Validate JSON serialization/deserialization - - Test error response formats and HTTP status codes - -4. **Database Integration Tests** - - Test task persistence during transitions - - Verify `updated_at` timestamp changes - - Test transaction rollback on failures - - Validate concurrent transition attempts - -### Phase 3: Event System Testing (1-2 hours) -5. **SSE Event Validation** - - Verify `TaskStatusChanged` events are emitted - - Test event payload format and content - - Validate event delivery timing - - Test event subscription/unsubscription - -6. **Event Bus Integration** - - Test event propagation across modules - - Verify event ordering guarantees - - Test event delivery failure scenarios - -### Phase 4: End-to-End Workflow Testing (2-3 hours) -7. **Complete Lifecycle Tests** - - Test full TODO→DONE automation flow - - Include OpenCode session integration - - Test human approval workflows - - Validate file generation (plans, reviews) - -8. **Error Recovery Testing** - - Test transition failures and rollbacks - - Validate system state consistency - - Test retry mechanisms - - Error logging and monitoring verification - -### Phase 5: Performance & Stress Testing (1-2 hours) -9. **Concurrency Testing** - - Multiple simultaneous transitions on different tasks - - Race condition detection - - Database lock testing - - Event bus throughput validation - -10. **Load Testing** - - High-frequency transition requests - - Memory usage monitoring - - Database connection pool testing - - SSE connection scaling - -## Potential Risks - -### High Risk -- **Database Corruption**: Concurrent transitions could corrupt task state -- **Event Loss**: SSE events might be lost during high load -- **State Inconsistency**: Orchestrator and database could diverge - -### Medium Risk -- **Test Flakiness**: Async nature might cause intermittent test failures -- **Performance Degradation**: New tests might slow CI pipeline -- **Mock Complexity**: OpenCode client mocking might be complex - -### Low Risk -- **Test Maintenance**: Additional tests require ongoing maintenance -- **Code Coverage**: Might reveal gaps in existing code coverage - -## Mitigation Strategies - -1. **Database Safety** - - Use database transactions for multi-step operations - - Implement proper locking mechanisms - - Add comprehensive rollback testing - -2. **Event Reliability** - - Implement event persistence for critical events - - Add retry mechanisms for event delivery - - Test event ordering guarantees - -3. **Test Stability** - - Use deterministic test data - - Implement proper async test patterns - - Add timeout handling for long-running tests - -4. **Performance Monitoring** - - Add benchmarks for critical paths - - Monitor test execution time - - Implement parallel test execution where safe - -## Success Criteria - -### Functional Requirements -- ✅ All valid transitions work correctly -- ✅ All invalid transitions are properly rejected -- ✅ Events are emitted for all status changes -- ✅ Database state remains consistent -- ✅ API responses are correctly formatted - -### Quality Requirements -- ✅ Test coverage >95% for transition-related code -- ✅ All tests complete within 30 seconds -- ✅ Zero flaky test failures -- ✅ Clean `cargo clippy` and `cargo fmt` output - -### Performance Requirements -- ✅ Single transition completes within 100ms -- ✅ 100 concurrent transitions complete within 5 seconds -- ✅ Memory usage remains stable during stress tests - -## Estimated Complexity: **MEDIUM (M)** - -### Justification -- **Scope**: Focused on existing functionality, not new features -- **Technical Depth**: Requires understanding of multiple system components -- **Integration Complexity**: Must test across database, API, and event systems -- **Time Estimate**: 8-12 hours total development time -- **Risk Level**: Medium due to concurrency and state management concerns - -### Complexity Breakdown -- **State Machine Logic**: Simple (well-defined state transitions) -- **API Testing**: Medium (HTTP integration complexity) -- **Database Testing**: Medium (transaction and concurrency concerns) -- **Event Testing**: Medium (async event propagation) -- **Integration Testing**: Complex (multiple system components) - -## Implementation Notes - -### Testing Strategy -- Prefer integration tests over mocking where possible -- Use real SQLite database for persistence testing -- Mock only external dependencies (OpenCode API) -- Implement proper test isolation and cleanup - -### Code Quality -- Follow existing project conventions (inline `#[cfg(test)]` modules) -- Maintain clippy compliance (`-D warnings`) -- Use proper error handling (`Result` patterns) -- Include comprehensive documentation for complex test scenarios - -### Future Considerations -- Consider adding transition audit logging -- Evaluate need for transition rate limiting -- Plan for eventual transition webhooks/notifications -- Consider adding transition analytics/metrics - ---- - -**Plan Status**: Ready for Implementation -**Next Step**: Begin Phase 1 - Enhanced Unit Testing -**Estimated Total Time**: 8-12 hours \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/15e199e2-08ad-4e67-af50-131803ca5edb.md b/.opencode-studio/kanban/plans/15e199e2-08ad-4e67-af50-131803ca5edb.md deleted file mode 100644 index 3faa91d..0000000 --- a/.opencode-studio/kanban/plans/15e199e2-08ad-4e67-af50-131803ca5edb.md +++ /dev/null @@ -1,343 +0,0 @@ -# Implementation Plan: Capture Test - -**Task ID**: 15e199e2-08ad-4e67-af50-131803ca5edb -**Title**: Capture test -**Description**: Capture raw events -**Created**: 2026-01-01T00:36:13Z - -## Technical Analysis - -### Current State Assessment - -OpenCode Studio implements a sophisticated event-driven architecture with the following components: - -**Existing Event Infrastructure:** -- **Event Bus**: `crates/events/src/bus.rs` - tokio::broadcast-based pub/sub system -- **Event Types**: `crates/events/src/types.rs` - 13 event types covering tasks, sessions, workspaces, projects -- **SSE Events**: Server-Sent Events for real-time frontend updates via `/api/events` -- **OpenCode Events**: `crates/orchestrator/src/opencode_events.rs` - Real-time OpenCode session monitoring -- **Event Count**: 8 existing tests in events crate, 108+ tests across workspace - -**Event Flow Architecture:** -``` -EventBus (tokio::broadcast) → SSE Stream → Frontend - ↑ ↑ -Orchestrator Server Routes - ↑ ↑ -Task Lifecycle HTTP API Endpoints -``` - -**Current Event Types:** -- Task events: created, updated, status_changed -- Session events: started, ended, agent.message, tool.execution -- Workspace events: created, merged, deleted -- Project events: opened, closed -- System events: errors - -**Gaps Identified:** -1. **No Event Capture Mechanism**: Events flow through broadcast channels but aren't persisted -2. **Testing Limitations**: No way to capture events during test runs for verification -3. **No Debugging Support**: Can't replay or analyze event sequences -4. **Missing Event History**: Events are ephemeral - no historical data -5. **No Event Filtering**: Cannot selectively capture specific event types - -### Technical Requirements - -The "Capture test" task appears to require implementing raw event capture functionality for: -- **Test Verification**: Capturing events during test runs to validate behavior -- **Debugging Support**: Recording event sequences for post-mortem analysis -- **Development Tools**: Event replay and inspection capabilities -- **Quality Assurance**: Ensuring all expected events are emitted - -### Architecture Decision - -Implement an **EventCapture** system that can: -1. Subscribe to the EventBus and record all events -2. Filter events by type, task_id, or time range -3. Persist captured events for later analysis -4. Provide replay capabilities for testing -5. Integrate with existing test infrastructure - -## Files to Modify/Create - -### New Core Files - -1. **`crates/events/src/capture.rs`** (NEW) - - `EventCapture` struct with configurable filtering - - `CaptureConfig` for filtering options - - `CapturedEvent` struct with metadata - - In-memory and persistent storage options - -2. **`crates/events/src/storage.rs`** (NEW) - - `EventStorage` trait for pluggable backends - - `MemoryEventStorage` for tests - - `FileEventStorage` for development/debugging - - `DatabaseEventStorage` for production (optional) - -### Database Extensions - -3. **`crates/db/migrations/002_event_capture.sql`** (NEW) - - `captured_events` table schema - - Indexes for efficient querying by type, timestamp, task_id - -4. **`crates/db/src/models/captured_event.rs`** (NEW) - - `CapturedEvent` model for database persistence - - Serialization/deserialization logic - -5. **`crates/db/src/repositories/event_repository.rs`** (NEW) - - Database CRUD operations for captured events - - Query methods with filtering support - -### Test Infrastructure - -6. **`crates/events/src/test_utils.rs`** (NEW) - - `EventCaptureTester` utility for test scenarios - - Helper macros for event assertions - - Test fixtures and mock data - -7. **`crates/orchestrator/src/executor_test_capture.rs`** (NEW) - - Integration tests using event capture - - Validate task lifecycle events are emitted correctly - - Test OpenCode session event capture - -### API Extensions - -8. **`crates/server/src/routes/events_capture.rs`** (NEW) - - `/api/events/capture/start` - Start capturing - - `/api/events/capture/stop` - Stop and return captured events - - `/api/events/capture/history` - Query historical events - - `/api/events/capture/replay` - Replay event sequence (dev only) - -### Modified Files - -9. **`crates/events/src/lib.rs`** - - Export new capture and storage modules - - Add feature flags for capture functionality - -10. **`crates/events/src/bus.rs`** - - Add optional capture integration - - Capture subscription management - -11. **`crates/server/src/lib.rs`** - - Include new events capture routes in OpenAPI schema - -12. **`crates/db/src/lib.rs`** - - Export new captured_event model and repository - -13. **`crates/orchestrator/src/executor.rs`** - - Optional event capture integration for development - - Capture configuration via environment variables - -## Step-by-Step Implementation Steps - -### Phase 1: Core Capture Infrastructure (Day 1-2) - -1. **Create Core Capture Module** - ```rust - // crates/events/src/capture.rs - pub struct EventCapture { - config: CaptureConfig, - storage: Box, - subscription: Option>, - } - ``` - -2. **Implement Storage Abstraction** - ```rust - // crates/events/src/storage.rs - #[async_trait] - pub trait EventStorage: Send + Sync { - async fn store(&mut self, event: CapturedEvent) -> Result<(), EventCaptureError>; - async fn query(&self, filter: EventFilter) -> Result, EventCaptureError>; - async fn clear(&mut self) -> Result<(), EventCaptureError>; - } - ``` - -3. **Add Memory Storage Implementation** - - `MemoryEventStorage` using `Vec` - - Thread-safe access with `Arc>>` - - Filtering and querying logic - -4. **Create CapturedEvent Model** - ```rust - pub struct CapturedEvent { - pub id: Uuid, - pub captured_at: DateTime, - pub event_envelope: EventEnvelope, - pub context: Option, // Additional debug info - } - ``` - -### Phase 2: Database Integration (Day 2-3) - -5. **Database Schema Migration** - ```sql - CREATE TABLE captured_events ( - id TEXT PRIMARY KEY, - captured_at DATETIME NOT NULL, - event_id TEXT NOT NULL, - event_type TEXT NOT NULL, - event_timestamp DATETIME NOT NULL, - event_data TEXT NOT NULL, -- JSON serialized EventEnvelope - task_id TEXT, - session_id TEXT, - context TEXT - ); - ``` - -6. **Database Models and Repository** - - Implement `CapturedEvent` sqlx model - - Create `EventRepository` with async methods - - Add filtering and pagination support - -7. **File Storage Implementation** - - `FileEventStorage` using JSONL format - - Rotation and cleanup policies - - Compression support for large captures - -### Phase 3: Test Infrastructure (Day 3-4) - -8. **Create Test Utilities** - ```rust - // crates/events/src/test_utils.rs - pub struct EventCaptureTester { - capture: EventCapture, - bus: EventBus, - } - - impl EventCaptureTester { - pub async fn assert_event_emitted(&self, predicate: F) - where F: Fn(&Event) -> bool; - - pub async fn assert_event_sequence(&self, expected: Vec); - } - ``` - -9. **Integration Test Suite** - - Test task lifecycle events are captured correctly - - Test OpenCode session events are captured - - Test event filtering and querying - - Test concurrent capture scenarios - -10. **Test Helper Macros** - ```rust - assert_event_captured!(capture, Event::TaskCreated { task_id, .. }); - assert_events_in_sequence!(capture, [ - Event::TaskCreated { .. }, - Event::TaskStatusChanged { .. } - ]); - ``` - -### Phase 4: API Integration (Day 4-5) - -11. **REST API Endpoints** - ```rust - POST /api/events/capture/start - { - "filter": { - "event_types": ["task.created", "task.status_changed"], - "task_id": "optional-uuid", - "duration_seconds": 300 - } - } - ``` - -12. **Server Integration** - - Add capture routes to server - - Integrate with existing SSE infrastructure - - Add authorization/permissions for capture endpoints - -13. **OpenAPI Documentation** - - Document all capture endpoints - - Add response schemas for captured events - - Include filtering parameter documentation - -### Phase 5: Advanced Features (Day 5-6) - -14. **Event Replay System** - - `EventReplayer` for recreating event sequences - - Timeline reconstruction capabilities - - Development/debugging tools - -15. **Configuration Management** - ```rust - pub struct CaptureConfig { - pub enabled: bool, - pub storage_type: StorageType, - pub max_events: Option, - pub retention_days: Option, - pub filter: EventFilter, - } - ``` - -16. **Performance Optimizations** - - Async batch writing for high-volume scenarios - - Background cleanup tasks - - Memory usage monitoring and limits - -### Phase 6: Testing and Documentation (Day 6-7) - -17. **Comprehensive Test Suite** - - Unit tests for all capture components - - Integration tests with real EventBus - - Performance tests for high event volumes - - Error condition and edge case tests - -18. **Documentation and Examples** - - Usage examples in code comments - - Integration guide for test developers - - Performance tuning recommendations - -## Potential Risks - -### Technical Risks -- **Performance Impact**: Event capture could slow down the EventBus - - **Mitigation**: Make capture optional, use async processing, implement batching - -- **Memory Usage**: Large event captures could consume excessive memory - - **Mitigation**: Implement size limits, streaming to disk, background cleanup - -- **Storage Scaling**: Database/file storage could grow large over time - - **Mitigation**: Retention policies, compression, archival strategies - -### Integration Risks -- **Test Flakiness**: Async event capture might introduce timing issues in tests - - **Mitigation**: Proper synchronization, deterministic test helpers - -- **Breaking Changes**: Adding capture might affect existing event flow - - **Mitigation**: Feature flags, backward compatibility, thorough testing - -### Development Risks -- **Complexity Creep**: Feature could become overcomplicated - - **Mitigation**: Start with minimal viable implementation, iterate - -- **Maintenance Burden**: Additional code to maintain and debug - - **Mitigation**: Good test coverage, clear documentation, simple design - -## Estimated Complexity: **L (Large)** - -### Justification -- **Multiple Crates Modified**: events, db, server, orchestrator (4 crates) -- **Database Schema Changes**: New table, migration, repository layer -- **New API Surface**: REST endpoints with filtering and querying -- **Complex Testing**: Integration tests across multiple components -- **Storage Abstractions**: Multiple storage backends to implement -- **Performance Considerations**: Async processing, memory management - -### Complexity Breakdown -- **Core Capture Logic**: M (Medium) - Event subscription and filtering -- **Storage Layer**: M (Medium) - Multiple storage implementations -- **Database Integration**: M (Medium) - Schema, models, repositories -- **API Layer**: S (Small) - Standard REST endpoints -- **Test Infrastructure**: L (Large) - Complex integration testing -- **Documentation**: S (Small) - Standard documentation tasks - -**Total Estimated Time**: 6-7 days for experienced Rust developer - -### Dependencies -- Requires understanding of existing EventBus architecture -- Database migration expertise (SQLite/sqlx) -- Async Rust patterns for performance -- Test infrastructure knowledge for integration tests - -This implementation will provide comprehensive event capture capabilities for testing, debugging, and development scenarios while maintaining performance and backward compatibility. \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/1e29f7ae-7ddb-45db-b3f7-474e24f8744f.md b/.opencode-studio/kanban/plans/1e29f7ae-7ddb-45db-b3f7-474e24f8744f.md deleted file mode 100644 index 38faf84..0000000 --- a/.opencode-studio/kanban/plans/1e29f7ae-7ddb-45db-b3f7-474e24f8744f.md +++ /dev/null @@ -1,370 +0,0 @@ -# Implementation Plan: Execute Test - Enhanced Testing & Issue Resolution - -**Task ID:** 1e29f7ae-7ddb-45db-b3f7-474e24f8744f -**Title:** Execute Test -**Description:** Test task execution with OpenCode -**Created:** 2025-12-31 19:55 -**Updated:** 2025-12-31 19:55 (Enhanced with recent findings) -**Estimated Complexity:** L (Large - due to critical issue resolution) - -## 1. Technical Analysis - -### Critical Issues Identified (Recent Testing) -Based on comprehensive E2E testing conducted previously: - -1. **🚨 Execution Timeout Issue** - - `POST /api/tasks/{id}/execute` times out after 30 seconds - - Endpoint blocks during execution instead of returning immediately - - **Root Cause**: Synchronous execution pattern in API handler - -2. **🚨 Status Synchronization Failure** - - Task status remains 'todo' in Studio DB despite OpenCode completion - - OpenCode successfully creates sessions and modifies files (confirmed: 300 additions, 59 deletions) - - **Root Cause**: Status update mechanism not working after OpenCode completion - -3. **🚨 Empty Session Activity** - - `/api/sessions/{id}/activity` endpoint returns empty data - - SSE events may not be properly captured - - **Root Cause**: Activity store not properly populated - -4. **✅ Confirmed Working** - - OpenCode integration creates sessions successfully - - File modifications occur as expected - - SSE events for `task.status_changed` and `session.started` work - - AGENTS.md generation works correctly - -### Architecture Assessment -Current execution flow: -``` -API Request → executor.execute_phase() → [BLOCKS] → OpenCode Session → File Changes → Status Update Fails -``` - -Required flow: -``` -API Request → Start Background Task → Immediate Response -Background: executor.execute_phase() → OpenCode Session → File Changes → Status Update → SSE Events -``` - -## 2. Files to Modify/Create - -### Critical Fixes Required -| File | Issue | Required Change | -|------|-------|-----------------| -| `crates/server/src/routes/tasks.rs` | 30s timeout | Convert to async background execution | -| `crates/orchestrator/src/executor.rs` | Status sync failure | Add proper status update callbacks | -| `crates/db/src/repositories/session_repository.rs` | Empty activity | Implement activity tracking | -| `crates/orchestrator/src/activity_store.rs` | SSE data missing | Fix activity capture and storage | - -### New Test Files -| File | Purpose | -|------|---------| -| `tests/e2e/critical_execution_flow.rs` | E2E test reproducing timeout/status issues | -| `crates/orchestrator/tests/executor_async_test.rs` | Async execution pattern testing | -| `crates/server/tests/execution_timeout_test.rs` | API timeout behavior testing | - -### Supporting Infrastructure -| File | Purpose | -|------|---------| -| `crates/server/src/background_tasks.rs` | Background task management (NEW) | -| `crates/events/src/task_events.rs` | Enhanced task event definitions | - -## 3. Step-by-Step Implementation - -### Phase 1: Fix Critical Timeout Issue (High Priority - 2-3 hours) - -1. **Create Background Task Infrastructure** - ```rust - // crates/server/src/background_tasks.rs - pub struct BackgroundTaskManager { - pub task_handles: Arc>>>>, - } - - impl BackgroundTaskManager { - pub async fn execute_task_async(&self, task_id: TaskId) -> Result<(), Error> - pub async fn get_execution_status(&self, task_id: TaskId) -> ExecutionStatus - } - ``` - -2. **Refactor Task Execution Endpoint** - ```rust - // crates/server/src/routes/tasks.rs - CRITICAL CHANGE - pub async fn execute_task( - Path(task_id): Path, - State(app_state): State, - ) -> Result, AppError> { - // OLD: let result = executor.execute_phase(&task).await; // BLOCKS! - - // NEW: Start background execution - let task_manager = &app_state.background_tasks; - task_manager.execute_task_async(task_id).await?; - - // Return immediately with execution started status - Ok(Json(ExecuteResponse { - task_id, - status: "execution_started".to_string(), - message: "Task execution started in background".to_string(), - })) - } - ``` - -3. **Test Timeout Fix** - ```rust - #[tokio::test] - async fn test_execute_returns_immediately() { - let response = client.post(format!("/api/tasks/{}/execute", task_id)).send().await; - - // Should return within 100ms, not 30+ seconds - assert!(response.status().is_success()); - assert_eq!(response.json::().await.status, "execution_started"); - } - ``` - -### Phase 2: Fix Status Synchronization (High Priority - 2-3 hours) - -4. **Add Status Update Callbacks to Executor** - ```rust - // crates/orchestrator/src/executor.rs - CRITICAL FIX - impl TaskExecutor { - pub async fn execute_phase_with_callbacks( - &self, - task: &Task, - status_callback: Box, - ) -> Result { - // Existing execution logic... - - // CRITICAL: Add status updates at each phase transition - match task.status { - TaskStatus::Todo => { - status_callback(TaskStatus::Planning); - // Execute planning... - status_callback(TaskStatus::PlanningReview); - } - TaskStatus::InProgress => { - // Execute implementation... - status_callback(TaskStatus::AiReview); - } - // etc. - } - } - } - ``` - -5. **Integrate Status Updates in Background Task** - ```rust - // Background task implementation - let status_callback = { - let task_repo = app_state.task_repository.clone(); - let event_bus = app_state.event_bus.clone(); - - Box::new(move |new_status: TaskStatus| { - // Update database - task_repo.update_task_status(task_id, new_status).await?; - - // Emit SSE event - event_bus.emit(TaskEvent::StatusChanged { task_id, new_status }).await?; - }) - }; - - executor.execute_phase_with_callbacks(&task, status_callback).await?; - ``` - -6. **Test Status Updates Work** - ```rust - #[tokio::test] - async fn test_status_updates_during_execution() { - // Start task execution - // Poll task status endpoint - // Verify status progression: Todo → Planning → PlanningReview → etc. - // Verify final status is not stuck at 'todo' - } - ``` - -### Phase 3: Fix Session Activity Tracking (Medium Priority - 2 hours) - -7. **Debug Activity Store Population** - ```rust - // crates/orchestrator/src/activity_store.rs - DEBUG - impl SessionActivityRegistry { - pub fn record_activity(&mut self, session_id: &str, activity: ActivityMessage) { - tracing::info!("Recording activity for session {}: {:?}", session_id, activity); - // Existing logic + debug logging - } - } - ``` - -8. **Fix Session Activity Endpoint** - ```rust - // Investigate why /api/sessions/{id}/activity returns empty - // Add proper activity capture during OpenCode session execution - // Ensure activity store is properly connected to executor - ``` - -### Phase 4: Comprehensive E2E Testing (Medium Priority - 2-3 hours) - -9. **Create Full Execution Test** - ```rust - #[tokio::test] - async fn test_full_task_execution_e2e() { - // 1. Create task via API - // 2. Start execution (should return immediately) - // 3. Poll status until completion - // 4. Verify OpenCode session was created - // 5. Verify file changes occurred - // 6. Verify final status is 'done' or appropriate end state - // 7. Verify session activity was captured - } - ``` - -10. **Test Concurrent Executions** - ```rust - #[tokio::test] - async fn test_multiple_concurrent_executions() { - // Start 5 tasks simultaneously - // Verify all execute without interfering - // Verify proper resource isolation - } - ``` - -### Phase 5: Performance & Monitoring (Low Priority - 1-2 hours) - -11. **Add Execution Monitoring** - - Metrics for execution duration - - Status update success/failure tracking - - OpenCode integration health monitoring - -12. **Load Testing** - - Test 10+ concurrent task executions - - Monitor memory usage and performance - - Verify database connection pooling works - -## 4. Potential Risks - -### Critical Risks (High Impact) -| Risk | Impact | Mitigation | -|------|--------|------------| -| **Background task crashes** | Task stuck in limbo | Add task timeout and recovery mechanisms | -| **Database transaction deadlock** | Status updates fail | Use proper transaction isolation and retry logic | -| **Memory leaks from long tasks** | Server instability | Implement task cleanup and resource limits | -| **OpenCode session orphaning** | Resources not cleaned up | Add session cleanup on task completion/failure | - -### Medium Risks -| Risk | Impact | Mitigation | -|------|--------|------------| -| **SSE connection failures** | UI not updated | Add connection retry and fallback polling | -| **VCS operation conflicts** | File corruption | Use proper locking and atomic operations | -| **Activity store corruption** | Lost execution logs | Add data validation and backup mechanisms | - -## 5. Estimated Complexity: L (Large) - -### Reasoning -- **Multiple critical issues** requiring architectural changes -- **Background execution** is a significant paradigm shift -- **Status synchronization** touches multiple systems (DB, events, OpenCode) -- **Testing complexity** requires E2E scenarios and race condition testing -- **Risk assessment** shows multiple high-impact failure modes - -### Time Breakdown -| Phase | Effort | Priority | -|-------|--------|----------| -| Fix timeout (async execution) | 2-3 hours | 🚨 Critical | -| Fix status synchronization | 2-3 hours | 🚨 Critical | -| Fix session activity | 2 hours | ⚠️ High | -| E2E testing | 2-3 hours | ⚠️ High | -| Performance & monitoring | 1-2 hours | ℹ️ Medium | -| **Total** | **9-13 hours** | | - -## 6. Success Criteria - -### Critical (Must Fix) -- [ ] `POST /api/tasks/{id}/execute` returns within 500ms -- [ ] Task status correctly progresses through lifecycle -- [ ] Task status updates are persisted to database -- [ ] Final task status reflects actual OpenCode completion -- [ ] No 30-second timeouts during normal operation - -### High Priority -- [ ] `/api/sessions/{id}/activity` returns populated data -- [ ] SSE events are emitted for all status changes -- [ ] Multiple concurrent executions work without interference -- [ ] OpenCode sessions are properly created and tracked - -### Medium Priority -- [ ] Comprehensive test coverage for new execution flow -- [ ] Performance metrics and monitoring in place -- [ ] Documentation updated with new architecture -- [ ] Error handling for all edge cases - -## 7. Testing Strategy - -### Critical Path Testing -```rust -// Test the exact scenario that failed before -#[tokio::test] -async fn test_reproduce_timeout_issue() { - // This test MUST pass to confirm fix - let start = Instant::now(); - let response = execute_task_api(task_id).await; - let duration = start.elapsed(); - - assert!(duration < Duration::from_millis(500)); // No more 30s timeouts! - assert_eq!(response.status, "execution_started"); -} - -#[tokio::test] -async fn test_reproduce_status_sync_issue() { - // This test MUST pass to confirm fix - execute_task_api(task_id).await; - - // Poll until completion (with reasonable timeout) - let final_status = poll_task_status_until_complete(task_id).await; - assert_ne!(final_status, TaskStatus::Todo); // Must not remain 'todo'! -} -``` - -### Regression Testing -- All existing tests must continue to pass -- Performance must not degrade for other operations -- UI must continue to work with new async execution model - -## 8. Rollback Plan - -### Immediate Rollback (if critical failures) -1. **Feature flag**: Disable new async execution, revert to synchronous -2. **Database rollback**: Restore task status update mechanism -3. **Monitor**: Watch for any database corruption or task stuck states - -### Partial Rollback (if some features fail) -- Keep async execution but disable concurrent execution limits -- Fall back to polling for status updates if SSE fails -- Disable session activity tracking if it causes performance issues - -## 9. Implementation Notes - -### Known Technical Debt to Address -- `crates/cli` still uses path dependencies instead of workspace dependencies -- Some clippy warnings may need resolution after changes -- OpenCode SDK integration may need error handling improvements - -### Integration Points to Verify -- **Frontend**: Ensure UI handles new async execution responses properly -- **SSE**: Verify frontend receives status update events -- **Database**: Confirm transaction isolation works with background tasks -- **VCS**: Ensure workspace operations don't conflict with concurrent executions - ---- - -**Next Steps:** -1. **IMMEDIATE**: Start with Phase 1 (timeout fix) - highest priority -2. **URGENT**: Implement Phase 2 (status sync) - critical for user experience -3. **HIGH**: Complete Phase 3 (activity tracking) - important for debugging -4. **VALIDATE**: Run comprehensive E2E tests to confirm all fixes work - -**Dependencies:** -- OpenCode server must be available for testing -- SQLite database for integration testing -- VCS operations (jj/git) for workspace testing - -**Success Metrics:** -- Zero execution timeouts during normal operation -- 100% status update success rate -- Sub-second API response times for execution requests \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/3173e278-12a5-4a29-b667-1b25d9883f7a.md b/.opencode-studio/kanban/plans/3173e278-12a5-4a29-b667-1b25d9883f7a.md deleted file mode 100644 index 0d1b83f..0000000 --- a/.opencode-studio/kanban/plans/3173e278-12a5-4a29-b667-1b25d9883f7a.md +++ /dev/null @@ -1,256 +0,0 @@ -# Implementation Plan: Capture Idle - -**Task ID:** 3173e278-12a5-4a29-b667-1b25d9883f7a -**Title:** Capture idle -**Description:** x -**Created:** 2025-01-01T01:36:13Z - -## Technical Analysis - -### Problem Interpretation -Given the minimal description "x", this task is interpreted as implementing idle state detection and management within OpenCode Studio. This involves: - -1. **Session Idle Detection**: Identifying OpenCode sessions that have been inactive -2. **Task Idle Detection**: Detecting tasks stuck in intermediate states -3. **Resource Cleanup**: Automatically handling idle resources to prevent resource leaks -4. **Monitoring & Metrics**: Tracking idle states for system health - -### System Context -OpenCode Studio orchestrates AI-powered development tasks through: -- Task lifecycle: `TODO → PLANNING → PLANNING_REVIEW → IN_PROGRESS → AI_REVIEW → REVIEW → DONE` -- OpenCode session management for each phase -- SSE events for real-time updates -- VCS workspace management - -### Idle State Scenarios -1. **Hanging Sessions**: OpenCode sessions that start but never complete -2. **Orphaned Tasks**: Tasks in intermediate states without active sessions -3. **Stale Workspaces**: VCS workspaces from abandoned tasks -4. **Resource Leaks**: Accumulated idle processes/connections - -## Files to Modify/Create - -### Core Domain -- `crates/core/src/domain/mod.rs` - Add idle detection traits -- `crates/core/src/domain/idle.rs` - New idle state domain models - -### Database Layer -- `crates/db/migrations/002_idle_tracking.sql` - New migration for idle tracking -- `crates/db/src/models/mod.rs` - Export idle models -- `crates/db/src/models/idle_tracker.rs` - New idle state persistence -- `crates/db/src/repositories/mod.rs` - Export idle repository -- `crates/db/src/repositories/idle_repository.rs` - New idle state queries - -### Orchestrator -- `crates/orchestrator/src/idle_monitor.rs` - New idle detection service -- `crates/orchestrator/src/cleanup.rs` - New cleanup service -- `crates/orchestrator/src/lib.rs` - Export new modules - -### Server API -- `crates/server/src/routes/mod.rs` - Add idle routes -- `crates/server/src/routes/idle.rs` - New idle management endpoints -- `crates/server/src/state.rs` - Add idle monitor to app state - -### Events -- `crates/events/src/types.rs` - Add idle-related events - -### Frontend (Optional) -- `frontend/src/components/monitoring/IdleMonitor.tsx` - New monitoring component -- `frontend/src/api/generated/idle/` - Generated API hooks - -## Step-by-Step Implementation - -### Phase 1: Core Domain & Database (2-3 hours) - -1. **Define Idle Domain Models** - ```rust - // crates/core/src/domain/idle.rs - pub struct IdleSession { - pub session_id: String, - pub task_id: String, - pub last_activity: DateTime, - pub idle_duration: Duration, - pub idle_type: IdleType, - } - - pub enum IdleType { - NoActivity, - UnresponsiveSession, - StuckInPhase, - OrphanedWorkspace, - } - ``` - -2. **Create Database Migration** - ```sql - -- migrations/002_idle_tracking.sql - CREATE TABLE idle_sessions ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - session_id TEXT NOT NULL, - task_id TEXT NOT NULL, - detected_at DATETIME NOT NULL, - last_activity DATETIME NOT NULL, - idle_type TEXT NOT NULL, - resolved BOOLEAN DEFAULT FALSE, - FOREIGN KEY (task_id) REFERENCES tasks(id) - ); - ``` - -3. **Implement Repository Layer** - - Database models and CRUD operations - - Queries for detecting idle patterns - -### Phase 2: Idle Detection Service (3-4 hours) - -4. **Create Idle Monitor Service** - ```rust - // crates/orchestrator/src/idle_monitor.rs - pub struct IdleMonitor { - db: Arc, - event_bus: Arc, - config: IdleConfig, - } - - impl IdleMonitor { - pub async fn scan_for_idle_sessions(&self) -> Result>; - pub async fn detect_hung_tasks(&self) -> Result>; - pub async fn cleanup_idle_resources(&self) -> Result; - } - ``` - -5. **Implement Detection Logic** - - Check for sessions inactive > threshold (e.g., 30 minutes) - - Detect tasks stuck in intermediate states > threshold (e.g., 2 hours) - - Identify orphaned VCS workspaces - -6. **Add Background Monitoring** - - Periodic scanning (every 5 minutes) - - Event-driven detection on session state changes - -### Phase 3: Cleanup & Recovery (2-3 hours) - -7. **Implement Cleanup Service** - ```rust - // crates/orchestrator/src/cleanup.rs - pub struct CleanupService { - workspace_manager: Arc, - opencode_client: Arc, - } - - impl CleanupService { - pub async fn cleanup_idle_session(&self, session_id: &str) -> Result<()>; - pub async fn recover_stuck_task(&self, task_id: &str) -> Result<()>; - pub async fn cleanup_orphaned_workspace(&self, workspace_id: &str) -> Result<()>; - } - ``` - -8. **Add Recovery Strategies** - - Graceful session termination - - Task state reset with notification - - Workspace cleanup with backup - -### Phase 4: API & Events (1-2 hours) - -9. **Create REST Endpoints** - ```rust - // GET /api/idle/sessions - List idle sessions - // POST /api/idle/cleanup - Trigger manual cleanup - // GET /api/idle/stats - Idle statistics - ``` - -10. **Add SSE Events** - ```rust - pub enum IdleEvent { - IdleSessionDetected { session_id: String, idle_type: IdleType }, - CleanupCompleted { cleanup_report: CleanupReport }, - RecoveryAttempted { task_id: String, success: bool }, - } - ``` - -### Phase 5: Integration & Testing (2-3 hours) - -11. **Integrate with Orchestrator** - - Start idle monitor as background service - - Wire into existing executor lifecycle - -12. **Add Configuration** - ```rust - pub struct IdleConfig { - pub session_timeout: Duration, - pub task_timeout: Duration, - pub scan_interval: Duration, - pub auto_cleanup: bool, - } - ``` - -13. **Write Comprehensive Tests** - - Unit tests for detection logic - - Integration tests for cleanup scenarios - - Mock OpenCode client responses - -### Phase 6: Frontend Integration (Optional - 1-2 hours) - -14. **Create Monitoring UI** - - Real-time idle session display - - Manual cleanup triggers - - System health dashboard - -## Potential Risks - -### High Risk -- **Resource Cleanup**: Aggressive cleanup could terminate valid long-running tasks -- **Race Conditions**: Cleanup while session is becoming active -- **Data Loss**: Improper workspace cleanup could lose uncommitted changes - -### Medium Risk -- **False Positives**: Detecting idle when OpenCode is processing -- **Performance**: Frequent scanning could impact database performance -- **Notification Fatigue**: Too many idle alerts - -### Low Risk -- **Configuration Complexity**: Tuning thresholds for different workload patterns -- **Monitoring Overhead**: Additional database storage for tracking - -### Mitigation Strategies -1. **Grace Periods**: Multiple confirmation checks before cleanup -2. **Backup Before Cleanup**: Preserve state before resource cleanup -3. **Manual Override**: Allow users to prevent cleanup of specific sessions -4. **Incremental Rollout**: Start with detection-only, add cleanup gradually -5. **Comprehensive Logging**: Full audit trail of all idle detection and cleanup actions - -## Estimated Complexity: **L (Large)** - -### Breakdown -- **Medium complexity** for core detection logic -- **High complexity** for safe cleanup mechanisms -- **Medium complexity** for integration with existing systems -- **Low complexity** for API and frontend components - -### Reasoning -- Requires careful state management across multiple systems -- Safety-critical cleanup logic needs extensive testing -- Integration with VCS, OpenCode, and database systems -- Moderate amount of new code (~800-1200 lines) -- Significant testing requirements for edge cases - -### Time Estimate -- **Development**: 10-15 hours -- **Testing**: 5-8 hours -- **Integration & Documentation**: 2-3 hours -- **Total**: 17-26 hours - -## Success Criteria - -1. **Detection Accuracy**: >95% correct identification of truly idle sessions -2. **Recovery Rate**: >90% successful recovery of stuck tasks -3. **Resource Efficiency**: <1% CPU overhead for monitoring -4. **Zero Data Loss**: No committed work lost during cleanup -5. **Event Reliability**: All idle events properly propagated via SSE - -## Future Enhancements - -1. **Machine Learning**: Adaptive thresholds based on historical patterns -2. **Predictive Cleanup**: Detect likely-to-become-idle sessions -3. **Resource Optimization**: Hibernate instead of terminate -4. **Advanced Recovery**: Smart retry with modified parameters -5. **Metrics Dashboard**: Comprehensive idle state analytics \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/42944d6d-7561-4030-afed-f425f9e4f279.md b/.opencode-studio/kanban/plans/42944d6d-7561-4030-afed-f425f9e4f279.md deleted file mode 100644 index 4793ae2..0000000 --- a/.opencode-studio/kanban/plans/42944d6d-7561-4030-afed-f425f9e4f279.md +++ /dev/null @@ -1,219 +0,0 @@ -# Implementation Plan: Test SSE v2 - -## Task Analysis -**Title:** Test SSE v2 -**Description:** Quick test -**Plan ID:** 42944d6d-7561-4030-afed-f425f9e4f279 -**Created:** 2026-01-01T01:36:13+01:00 - -## 1. Technical Analysis - -### Context -Based on project knowledge, OpenCode Studio has recently migrated from WebSocket to Server-Sent Events (SSE) for real-time communication. The SSE infrastructure is largely complete, but comprehensive testing is needed to ensure reliability and proper functionality. - -### Current SSE Implementation Status -- ✅ Backend SSE Infrastructure (Feature 1) - Complete -- ✅ Frontend SSE Hooks (Feature 2) - Complete -- ✅ Backend Activity Message Serialization (Feature 3) - Complete -- 🟡 WebSocket Code Cleanup (Feature 4) - In Progress -- ❌ Documentation & Testing (Feature 5) - Pending - -### Key SSE Components to Test -1. **Global Event Stream**: `/api/events` endpoint -2. **Session Activity Stream**: `/api/sessions/{id}/activity` endpoint -3. **Frontend Hooks**: `useEventStream` and `useSessionActivitySSE` -4. **Event Types**: `task.status_changed`, `session.started`, `session.ended` -5. **Reconnection Logic**: Auto-reconnect and history replay -6. **EventBuffer**: Server-side buffering for reconnection scenarios - -### Known Issues to Address -- `/api/sessions/{id}/activity` endpoint previously returned empty responses -- Task status synchronization issues between OpenCode and Studio DB -- 30-second timeout issues during task execution - -## 2. Files to Modify/Create - -### Test Files to Create -``` -crates/server/src/routes/events_test.rs # SSE endpoint integration tests -crates/server/src/routes/sessions_test.rs # Session activity SSE tests -frontend/src/hooks/__tests__/useEventStream.test.ts # Frontend hook unit tests -frontend/src/hooks/__tests__/useSessionActivitySSE.test.ts -tests/integration/sse_integration_test.rs # End-to-end SSE tests -tests/manual/sse_manual_test.md # Manual testing checklist -``` - -### Files to Review/Modify -``` -crates/server/src/routes/events.rs # Verify SSE implementation -crates/server/src/routes/sessions.rs # Check session activity endpoint -crates/orchestrator/src/executor.rs # Event emission verification -frontend/src/hooks/useEventStream.ts # Hook reliability -frontend/src/hooks/useSessionActivitySSE.ts # Session-specific SSE -crates/events/src/bus.rs # Event bus functionality -``` - -## 3. Step-by-Step Implementation - -### Phase 1: Backend SSE Testing (Day 1) -1. **Create SSE endpoint integration tests** - - Test `/api/events` connection establishment - - Verify proper SSE headers (`text/event-stream`, `Cache-Control: no-cache`) - - Test event emission for task status changes - - Test event emission for session lifecycle - -2. **Create session activity SSE tests** - - Test `/api/sessions/{id}/activity` endpoint - - Verify session-specific event filtering - - Test with valid and invalid session IDs - - Verify event format and data integrity - -3. **Test EventBuffer functionality** - - Test event buffering for reconnection scenarios - - Verify buffer size limits and cleanup - - Test history replay on reconnection - -### Phase 2: Event Emission Testing (Day 1-2) -4. **Verify orchestrator event emission** - - Test task status change events from `executor.rs` - - Test session started/ended events - - Verify event payload structure matches frontend expectations - -5. **Test event bus reliability** - - Test event delivery across multiple subscribers - - Test event ordering and timing - - Test error handling in event processing - -### Phase 3: Frontend Hook Testing (Day 2) -6. **Unit test useEventStream hook** - - Test connection establishment - - Test auto-reconnection logic - - Test event parsing and state updates - - Test cleanup on unmount - -7. **Unit test useSessionActivitySSE hook** - - Test session-specific event handling - - Test hook behavior with invalid session IDs - - Test event filtering and processing - -### Phase 4: Integration Testing (Day 2-3) -8. **End-to-end SSE flow testing** - - Create task → verify SSE event received - - Execute task → verify status change events - - Test concurrent connections from multiple clients - - Test browser tab switching and reconnection - -9. **Performance and reliability testing** - - Test with high event frequency - - Test connection stability over extended periods - - Test memory usage and cleanup - - Test graceful degradation scenarios - -### Phase 5: Manual Testing & Documentation (Day 3) -10. **Manual testing checklist** - - Browser DevTools Network tab verification - - Real-time UI updates validation - - Cross-browser compatibility check - - Mobile/responsive behavior - -11. **Update documentation** - - Document SSE testing procedures - - Update AGENTS.md with testing information - - Create troubleshooting guide for SSE issues - -## 4. Potential Risks - -### High Risk -- **SSE Connection Instability**: Intermittent connection drops could affect real-time updates -- **Event Loss**: Network issues or server restarts could cause event loss -- **Browser Compatibility**: Older browsers may have SSE limitations - -### Medium Risk -- **Performance Impact**: High-frequency events could impact server performance -- **Memory Leaks**: Improper cleanup of SSE connections or event buffers -- **Race Conditions**: Event ordering issues between task operations and SSE updates - -### Low Risk -- **Test Complexity**: Creating comprehensive SSE tests may require complex setup -- **Debugging Difficulty**: SSE issues can be harder to debug than traditional REST APIs -- **CORS Issues**: Cross-origin SSE requests may need special configuration - -## 5. Testing Strategy - -### Unit Tests -- Mock SSE connections for isolated testing -- Test event parsing and state management -- Test error handling and reconnection logic - -### Integration Tests -- Use real SSE connections within test environment -- Test full event flow from backend to frontend -- Test concurrent connections and scaling - -### Manual Tests -- Browser DevTools for connection monitoring -- Network simulation for connection drops -- UI validation for real-time updates - -### Performance Tests -- Load testing with multiple concurrent SSE connections -- Event frequency stress testing -- Memory usage monitoring over time - -## 6. Success Criteria - -### Functional Requirements -- [ ] SSE endpoints return proper headers and maintain connections -- [ ] Events are delivered correctly to all connected clients -- [ ] Frontend hooks handle events and update UI in real-time -- [ ] Reconnection logic works seamlessly on connection drops -- [ ] Session-specific events are properly filtered - -### Non-Functional Requirements -- [ ] SSE connections remain stable for 30+ minutes -- [ ] Event delivery latency < 100ms under normal load -- [ ] Memory usage remains stable with long-lived connections -- [ ] System handles 50+ concurrent SSE connections -- [ ] Graceful degradation when SSE is unavailable - -### Quality Requirements -- [ ] All unit tests pass (target: 95%+ coverage) -- [ ] All integration tests pass -- [ ] Manual testing checklist completed -- [ ] Documentation updated and reviewed -- [ ] Performance benchmarks meet targets - -## 7. Estimated Complexity: **M (Medium)** - -**Reasoning:** -- **Medium scope**: Testing existing SSE infrastructure rather than building new features -- **Well-defined requirements**: Clear understanding of what needs to be tested -- **Existing codebase**: SSE implementation already exists, reducing complexity -- **Standard testing patterns**: Can use established testing frameworks and patterns -- **Time estimate**: 2-3 days for comprehensive testing suite - -**Complexity breakdown:** -- Backend testing: Simple-Medium (standard HTTP endpoint testing) -- Frontend testing: Medium (SSE mock setup required) -- Integration testing: Medium (requires coordination between backend/frontend) -- Manual testing: Simple (straightforward browser testing) - -## 8. Dependencies - -- Existing SSE implementation in `crates/server/src/routes/events.rs` -- Frontend hooks in `frontend/src/hooks/useEventStream.ts` -- Event bus functionality in `crates/events/src/bus.rs` -- Test infrastructure and frameworks already in place - -## 9. Next Steps - -1. Begin with backend SSE endpoint testing -2. Validate event emission from orchestrator -3. Create frontend hook tests with proper mocking -4. Implement end-to-end integration tests -5. Conduct manual testing and documentation updates - ---- -**Plan Status:** Ready for Implementation -**Assigned:** Pending -**Priority:** Medium \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/4ad1886f-b145-4108-9744-1bd8b7f16460.md b/.opencode-studio/kanban/plans/4ad1886f-b145-4108-9744-1bd8b7f16460.md deleted file mode 100644 index 85137df..0000000 --- a/.opencode-studio/kanban/plans/4ad1886f-b145-4108-9744-1bd8b7f16460.md +++ /dev/null @@ -1,186 +0,0 @@ -# Implementation Plan: Test7 - -**Task ID:** 4ad1886f-b145-4108-9744-1bd8b7f16460 -**Title:** Test7 -**Description:** x -**Generated:** 2026-01-01 01:36:13 - -## 1. Technical Analysis - -### Task Overview -The task "Test7" with minimal description "x" appears to be a test case or placeholder task. Given the extremely limited specification, this analysis assumes this is either: - -1. A test task to verify the OpenCode Studio planning system -2. A placeholder requiring further clarification -3. A minimal reproduction case for testing purposes - -### Context Assessment -- **Project:** OpenCode Studio (AI-powered development orchestration platform) -- **Architecture:** Rust backend (Axum + SQLite) + React frontend -- **Current State:** Phase 6+ (GitHub Integration phase based on supermemory context) -- **Task Lifecycle Position:** Currently in PLANNING phase - -### Technical Constraints -- Must follow OpenCode Studio conventions (tabs, 100 char lines, no type suppression) -- Backend changes require passing `cargo clippy -D warnings` -- Frontend changes require TypeScript compilation success -- All changes must maintain 108+ passing unit tests - -## 2. Files to Modify/Create - -### Analysis-Based Assumptions -Given the minimal specification, the following files might be relevant depending on the actual requirement: - -#### Potential Backend Files -``` -crates/server/src/routes/ -├── health.rs # If testing health endpoints -├── tasks.rs # If testing task operations -└── mod.rs # Route registration - -crates/core/src/domain/ -├── task.rs # Domain model updates -└── session.rs # Session handling - -crates/db/src/repositories/ -└── task_repository.rs # Database operations -``` - -#### Potential Frontend Files -``` -frontend/src/components/ -├── kanban/TaskCard.tsx # Task display -└── dialogs/CreateTaskDialog.tsx # Task creation - -frontend/src/api/generated/ # Auto-generated API hooks -``` - -#### Configuration/Test Files -``` -crates/*/src/lib.rs # Test modules -.opencode-studio/kanban/plans/ # This planning file -``` - -## 3. Step-by-Step Implementation Steps - -### Phase 1: Requirements Clarification -1. **Analyze task intent** - Determine what "Test7" and "x" specifically require -2. **Identify scope** - Backend, frontend, or full-stack change -3. **Review existing tests** - Check if this relates to existing test cases -4. **Validate assumptions** - Confirm interpretation with stakeholders - -### Phase 2: Design & Planning -1. **Define acceptance criteria** based on clarified requirements -2. **Choose implementation approach** (API endpoint, UI component, etc.) -3. **Identify dependencies** - Required crates, external services -4. **Plan testing strategy** - Unit tests, integration tests, E2E tests - -### Phase 3: Implementation -1. **Backend changes** (if applicable): - ```bash - # Create/modify domain models - # Update repositories - # Add/modify API endpoints - # Update OpenAPI schema - ``` - -2. **Frontend changes** (if applicable): - ```bash - # Update/create React components - # Add API integration hooks - # Update routing if needed - # Add styling/UI updates - ``` - -3. **Integration testing**: - ```bash - cargo test --workspace - cargo clippy --workspace --all-features -- -D warnings - cd frontend && pnpm tsc --noEmit - ``` - -### Phase 4: Verification -1. **Run full test suite** - Ensure all 108+ tests pass -2. **Manual testing** - Verify functionality in running application -3. **SSE event verification** - Check task lifecycle events fire correctly -4. **OpenCode integration test** - Verify AI execution pipeline - -### Phase 5: Documentation -1. **Update AGENTS.md** if architectural changes made -2. **Add inline code comments** for complex logic -3. **Update API documentation** if new endpoints added - -## 4. Potential Risks - -### High Risk -- **Undefined requirements** - "Test7" and "x" provide insufficient specification -- **Breaking existing functionality** - Changes could affect 108+ existing tests -- **OpenCode integration failure** - Task execution pipeline disruption - -### Medium Risk -- **Type safety violations** - Accidental use of `as any` or type suppression -- **SSE event system disruption** - Breaking real-time task updates -- **Database migration issues** - Schema changes affecting existing data - -### Low Risk -- **Frontend styling inconsistencies** - UI changes not matching design system -- **Performance degradation** - Inefficient database queries or React renders -- **Documentation drift** - Failing to update docs after implementation - -### Mitigation Strategies -1. **Clarify requirements immediately** before implementation -2. **Implement comprehensive test coverage** for any new functionality -3. **Use feature flags** for risky changes -4. **Maintain backwards compatibility** where possible -5. **Follow established patterns** in the codebase - -## 5. Estimated Complexity - -### Assessment: **S (Small)** - -**Reasoning:** -- **Minimal scope** - Given the placeholder nature of the task -- **Low technical debt** - Project has clean architecture and good test coverage -- **Established patterns** - Well-defined conventions and tooling in place -- **Quick iteration** - Robust CI/CD and development workflow - -### Complexity Factors - -#### Factors Supporting Small (S) Complexity: -- Minimal description suggests small scope -- Existing robust test suite (108+ tests) -- Well-established development patterns -- Clean clippy and strong type safety - -#### Factors That Could Increase Complexity: -- Unclear requirements could lead to scope creep -- Integration with OpenCode AI execution pipeline -- Potential need for database schema changes -- SSE event system integration requirements - -### Time Estimates -- **Requirements clarification:** 30 minutes -- **Implementation:** 1-3 hours (depending on actual scope) -- **Testing & verification:** 1 hour -- **Documentation updates:** 30 minutes - -**Total estimated time:** 3-5 hours - -## 6. Next Steps - -1. **IMMEDIATE:** Clarify the actual requirements for "Test7" task -2. **Upon clarification:** Update this plan with specific technical details -3. **Implementation:** Follow the step-by-step process outlined above -4. **Review:** Conduct code review before marking task complete - -## 7. Notes - -- This plan assumes minimal scope due to placeholder-like task description -- Plan should be updated once actual requirements are clarified -- All implementation must follow OpenCode Studio conventions -- Maintain focus on the established task lifecycle: TODO → PLANNING → PLANNING_REVIEW → IN_PROGRESS → AI_REVIEW → REVIEW → DONE - ---- - -**Plan Status:** DRAFT - Awaiting requirements clarification -**Next Action:** Contact task creator for detailed requirements \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/4d3b9b45-a365-4f23-b0ea-b1f4e59ec9c7.md b/.opencode-studio/kanban/plans/4d3b9b45-a365-4f23-b0ea-b1f4e59ec9c7.md deleted file mode 100644 index 0d3380e..0000000 --- a/.opencode-studio/kanban/plans/4d3b9b45-a365-4f23-b0ea-b1f4e59ec9c7.md +++ /dev/null @@ -1,184 +0,0 @@ -# Implementation Plan: Test6 - -**Task ID:** 4d3b9b45-a365-4f23-b0ea-b1f4e59ec9c7 -**Title:** Test6 -**Description:** Test -**Generated:** 2026-01-01 01:36:13 AM - -## 1. Technical Analysis - -### Task Context -This appears to be a test task with minimal requirements. Based on the OpenCode Studio architecture, this could serve multiple purposes: - -1. **System Test**: Verify the task lifecycle automation (TODO → DONE) -2. **Workflow Test**: Validate the planning and review processes -3. **Integration Test**: Test OpenCode session creation and execution -4. **Performance Test**: Benchmark task execution timing - -### Current System State -- **Backend**: Rust/Axum with SQLite persistence -- **Task Lifecycle**: 7-stage workflow with AI automation -- **OpenCode Integration**: HTTP API via opencode_client SDK -- **Test Coverage**: 108+ unit tests across 9 crates -- **Real-time Events**: SSE-based communication - -### Technical Approach -Given the minimal description, I'll implement this as a **verification test** that: -- Creates a simple test task -- Exercises the basic CRUD operations -- Validates the task status transitions -- Confirms OpenCode integration functionality - -## 2. Files to Modify/Create - -### Backend Files -``` -crates/ -├── core/src/domain/ -│ └── task.rs # Verify task model -├── db/src/repositories/ -│ └── task_repository.rs # Test CRUD operations -├── orchestrator/src/ -│ ├── executor.rs # Test OpenCode integration -│ └── state_machine.rs # Verify status transitions -└── server/src/routes/ - └── tasks.rs # Test API endpoints -``` - -### Test Files -``` -crates/ -├── core/src/domain/ -│ └── task.rs # Add unit tests for Test6 scenario -├── db/src/repositories/ -│ └── task_repository.rs # Add CRUD test cases -└── orchestrator/src/ - └── executor.rs # Add integration test -``` - -### Generated Files (Expected) -``` -.opencode-studio/kanban/ -├── plans/ -│ └── 4d3b9b45-a365-4f23-b0ea-b1f4e59ec9c7.md # This plan -└── reviews/ - └── 4d3b9b45-a365-4f23-b0ea-b1f4e59ec9c7.md # Post-execution review -``` - -## 3. Step-by-Step Implementation - -### Phase 1: Task Creation Verification -1. **Validate Task Model** - - Ensure task creation with minimal description works - - Verify UUID generation and persistence - - Test required field validation - -2. **Database Operations** - - Create task in SQLite database - - Verify storage of minimal task data - - Test retrieval and status queries - -### Phase 2: API Endpoint Testing -1. **REST API Validation** - - `POST /api/tasks` - Create Test6 task - - `GET /api/tasks/{id}` - Retrieve task details - - `PUT /api/tasks/{id}` - Update task properties - - `DELETE /api/tasks/{id}` - Clean up test data - -2. **Status Transition Testing** - - `POST /api/tasks/{id}/start` - Begin execution - - `POST /api/tasks/{id}/execute` - OpenCode integration - - Monitor SSE events for status changes - -### Phase 3: OpenCode Integration -1. **Session Management** - - Verify OpenCode session creation - - Test task execution with minimal prompt - - Validate session state persistence - -2. **Event System** - - Monitor `task.status_changed` events - - Verify `session.started` and `session.ended` events - - Test SSE endpoint `/api/sessions/{id}/activity` - -### Phase 4: Lifecycle Completion -1. **Automated Workflow** - - Execute full TODO → DONE transition - - Verify AI planning and review stages - - Test human approval bypass for simple tasks - -2. **File Generation** - - Confirm plan file creation - - Verify review file generation - - Check workspace state preservation - -## 4. Potential Risks - -### High Risk -- **OpenCode Timeout**: The 30-second timeout issue identified in previous testing - - *Mitigation*: Implement async execution with proper status tracking - - *Fallback*: Manual status update if OpenCode session completes - -### Medium Risk -- **Database Consistency**: Task status discrepancies between Studio DB and OpenCode - - *Mitigation*: Add transaction boundaries and rollback mechanisms - - *Monitoring*: Enhanced logging for status transition failures - -### Low Risk -- **SSE Event Loss**: Missing real-time updates during task execution - - *Mitigation*: Event replay mechanism already implemented - - *Validation*: Test connection recovery scenarios - -### Technical Debt -- **Minimal Task Validation**: Very basic description may expose edge cases - - *Consideration*: Add validation for meaningful task descriptions - - *Documentation*: Update task creation guidelines - -## 5. Estimated Complexity: **S (Small)** - -### Justification -- **Scope**: Single test task with basic operations -- **Complexity**: Exercises existing functionality, no new features -- **Dependencies**: Uses established OpenCode integration -- **Testing**: Validates current system capabilities -- **Time Estimate**: 1-2 hours for complete lifecycle testing - -### Complexity Factors -- ✅ **Simple**: Leverages existing infrastructure -- ✅ **Well-defined**: Clear test objectives despite minimal description -- ✅ **Low Risk**: Uses proven system components -- ✅ **Fast Feedback**: Immediate validation of system health - -## Success Criteria - -### Functional Requirements -- [ ] Task created successfully with ID `4d3b9b45-a365-4f23-b0ea-b1f4e59ec9c7` -- [ ] All status transitions complete without errors -- [ ] OpenCode session executes within timeout limits -- [ ] SSE events fired correctly for all state changes -- [ ] Plan and review files generated in expected locations - -### Non-Functional Requirements -- [ ] Task execution completes within 30 seconds -- [ ] Database operations maintain ACID properties -- [ ] Event system handles concurrent connections -- [ ] API responses conform to OpenAPI specification - -### Quality Gates -- [ ] All existing tests continue passing (108+ tests) -- [ ] Clippy warnings remain at zero (`-D warnings`) -- [ ] No memory leaks or resource exhaustion -- [ ] Proper error handling and logging - -## Notes - -This implementation serves as a **system health check** for OpenCode Studio. The minimal task description is intentional, allowing the system to demonstrate its ability to handle edge cases and provide meaningful automation even with limited input. - -The plan validates the complete technology stack: -- Rust backend architecture -- SQLite persistence layer -- OpenCode AI integration -- React frontend updates -- Real-time event system - -**Next Steps**: Upon plan approval, execute this task to verify system integrity and identify any regression issues from recent migrations (WebSocket → SSE, opencode → opencode_client SDK). \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/4db84480-2f92-48ee-9592-2c73beef95d3.md b/.opencode-studio/kanban/plans/4db84480-2f92-48ee-9592-2c73beef95d3.md deleted file mode 100644 index 11a1417..0000000 --- a/.opencode-studio/kanban/plans/4db84480-2f92-48ee-9592-2c73beef95d3.md +++ /dev/null @@ -1,180 +0,0 @@ -# Implementation Plan: Test SSE Activity - -**Task ID:** 4db84480-2f92-48ee-9592-2c73beef95d3 -**Title:** Test SSE Activity -**Description:** Test if session activity SSE works -**Created:** 2026-01-01 01:36:13 - -## 1. Technical Analysis - -### Current SSE Infrastructure -- **Backend:** Axum-based SSE endpoints with `EventBuffer` for reconnection support -- **Frontend:** React hooks (`useEventStream`, `useSessionActivitySSE`) for SSE consumption -- **Target Endpoint:** `/api/sessions/{id}/activity` - currently returning empty in tests -- **Event Types:** `task.status_changed`, `session.started`, `session.ended`, session activity messages - -### Known Issues from Previous Testing -- `/api/sessions/{id}/activity` endpoint returned empty during E2E testing -- Task execution timeout after 30 seconds causing status discrepancies -- SSE events for task status changes confirmed working at global level - -### Testing Scope -1. **Backend SSE Generation:** Verify activity messages are properly created and queued -2. **SSE Transport:** Test the HTTP SSE stream delivery mechanism -3. **Frontend Consumption:** Verify React hooks receive and process SSE data -4. **Event Buffering:** Test reconnection scenarios and message replay -5. **Real-time Updates:** Confirm UI updates in response to SSE events - -## 2. Files to Examine/Modify - -### Backend Files to Examine -``` -crates/server/src/routes/sessions.rs # SSE endpoint implementation -crates/events/src/bus.rs # Event emission system -crates/events/src/types.rs # Event type definitions -crates/orchestrator/src/executor.rs # Activity generation during task execution -crates/orchestrator/src/activity_store.rs # Activity message storage/retrieval -crates/server/src/routes/events.rs # Global SSE endpoint (working baseline) -``` - -### Frontend Files to Examine -``` -frontend/src/hooks/useSessionActivitySSE.ts # Session-specific SSE hook -frontend/src/hooks/useEventStream.ts # Generic SSE stream hook -frontend/src/components/activity/ActivityFeed.tsx # Activity display component -frontend/src/components/activity/ActivityItem.tsx # Individual activity rendering -frontend/src/components/sessions/SessionCard.tsx # Session UI with activity -frontend/src/components/task-detail/TaskDetailPanel.tsx # Task detail with activity -``` - -### Test Files to Create -``` -crates/server/tests/integration_sse_activity.rs # Backend SSE integration test -frontend/src/__tests__/sse-activity.test.tsx # Frontend SSE hook tests -test-scripts/manual-sse-test.js # Manual browser testing script -``` - -## 3. Step-by-Step Implementation Steps - -### Phase 1: Backend Activity Generation Verification (2 hours) -1. **Trace Activity Creation Path** - - Add debug logging to `executor.rs` activity generation - - Verify activity messages are created during task execution - - Check `activity_store.rs` for proper message persistence - -2. **Test Activity Storage** - - Create unit test for activity message creation - - Verify database storage of session activities - - Test activity retrieval by session ID - -3. **Debug SSE Endpoint** - - Add logging to `/api/sessions/{id}/activity` route - - Test endpoint manually with curl/browser - - Verify EventBuffer is populated with session activities - -### Phase 2: SSE Transport Testing (1 hour) -1. **Manual SSE Testing** - - Create test session with known activities - - Connect to SSE endpoint via browser/curl - - Verify SSE headers and connection establishment - - Test message format and Content-Type - -2. **Integration Test Development** - - Create Axum test client for SSE endpoint testing - - Test SSE connection lifecycle (connect, receive, disconnect) - - Verify proper EventBuffer behavior and message ordering - -### Phase 3: Frontend SSE Hook Testing (2 hours) -1. **Hook Isolation Testing** - - Unit test `useSessionActivitySSE` hook - - Mock SSE EventSource behavior - - Test reconnection logic and error handling - - Verify activity message parsing - -2. **Component Integration Testing** - - Test ActivityFeed component with mock SSE data - - Verify real-time UI updates - - Test activity message rendering and formatting - -### Phase 4: End-to-End Testing (2 hours) -1. **Live System Testing** - - Start backend server with debug logging - - Create test task and execute it - - Monitor SSE connections in browser DevTools - - Verify activity messages flow through the system - -2. **Edge Case Testing** - - Test SSE reconnection after network interruption - - Verify activity history replay for new connections - - Test multiple concurrent SSE connections - - Verify activity filtering by session ID - -### Phase 5: Performance & Reliability Testing (1 hour) -1. **Load Testing** - - Test multiple sessions with concurrent activity - - Verify EventBuffer memory usage and cleanup - - Test SSE connection limits and scaling - -2. **Error Scenario Testing** - - Test behavior with invalid session IDs - - Verify graceful handling of SSE connection failures - - Test activity generation during OpenCode errors - -## 4. Potential Risks - -### High Risk -- **EventBuffer Memory Leaks:** Improper cleanup of session activity buffers could cause memory growth -- **SSE Connection Exhaustion:** Browser/server connection limits could block new SSE connections -- **Activity Generation Timing:** Race conditions between OpenCode execution and activity creation - -### Medium Risk -- **Cross-Browser SSE Compatibility:** Edge cases with EventSource implementation differences -- **Network Interruption Handling:** SSE reconnection failures in unstable network conditions -- **Activity Message Ordering:** Out-of-order delivery affecting UI state consistency - -### Low Risk -- **SSE Payload Size Limits:** Large activity messages exceeding SSE practical limits -- **CORS Configuration:** SSE-specific CORS requirements not properly configured -- **Content-Type Issues:** Improper SSE headers causing client connection failures - -## 5. Success Criteria - -- [ ] `/api/sessions/{id}/activity` endpoint returns live activity messages -- [ ] Frontend receives and displays activity updates in real-time -- [ ] SSE reconnection works properly after network interruption -- [ ] Activity history is properly replayed on new connections -- [ ] No memory leaks or connection exhaustion under normal load -- [ ] Integration tests pass for SSE activity functionality -- [ ] Manual E2E test demonstrates working activity feed - -## 6. Estimated Complexity - -**Size: M (Medium)** - -**Reasoning:** -- **Not a new feature implementation** - SSE infrastructure already exists -- **Primarily debugging/testing focused** - identifying why activity SSE isn't working -- **Well-defined scope** - specific to session activity SSE functionality -- **Moderate complexity** - involves backend event generation, SSE transport, and frontend consumption -- **Limited file changes expected** - mainly debugging, logging, and test additions - -**Time Estimate: 8 hours** -- Backend verification: 3 hours -- Frontend testing: 2 hours -- E2E testing: 2 hours -- Documentation/cleanup: 1 hour - -## 7. Dependencies & Prerequisites - -- Backend server running with SSE endpoints enabled -- Frontend development environment with React testing setup -- Access to browser DevTools for SSE connection monitoring -- Ability to create test sessions and execute OpenCode tasks -- Database access for activity storage verification - -## 8. Deliverables - -1. **Working SSE Activity Stream** - Live activity updates in browser -2. **Integration Test Suite** - Automated tests for SSE activity functionality -3. **Debug Documentation** - Findings from SSE investigation and fixes applied -4. **Manual Test Script** - Reproducible test procedure for SSE activity verification \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/5442e9b8-791b-4961-9fef-1e18bc3c5ad0.md b/.opencode-studio/kanban/plans/5442e9b8-791b-4961-9fef-1e18bc3c5ad0.md deleted file mode 100644 index 3eb569d..0000000 --- a/.opencode-studio/kanban/plans/5442e9b8-791b-4961-9fef-1e18bc3c5ad0.md +++ /dev/null @@ -1,68 +0,0 @@ -# Planning Analysis: Ahoj - -**Task ID:** 5442e9b8-791b-4961-9fef-1e18bc3c5ad0 -**Created:** 2025-12-31 -**Status:** BLOCKED - Insufficient Information - ---- - -## 1. Technical Analysis - -### Current State -The task contains only a greeting ("Ahoj") with no actionable requirements. - -### Problem Statement -**UNABLE TO PLAN** - The task description does not specify: -- What feature/fix is needed -- Which part of the codebase is involved -- What the expected outcome should be -- Any acceptance criteria - -### Assessment -This appears to be either: -1. A test task created accidentally -2. A placeholder that needs proper description -3. A greeting intended as a message, not a task - ---- - -## 2. Files to Modify/Create - -**Cannot determine** - No requirements specified. - ---- - -## 3. Step-by-Step Implementation - -1. **Clarify Requirements** - Task owner must provide: - - Clear description of what needs to be done - - Expected behavior/outcome - - Any relevant context (error messages, user stories, etc.) - -2. **Re-plan** - Once requirements are clear, create a proper implementation plan - ---- - -## 4. Potential Risks - -| Risk | Impact | Mitigation | -|------|--------|------------| -| Implementing wrong feature | High | Get clarification before proceeding | -| Wasted development time | Medium | Block task until requirements defined | - ---- - -## 5. Estimated Complexity - -**UNDETERMINED** - Cannot estimate without requirements. - ---- - -## Recommendation - -**ACTION REQUIRED:** Please update this task with a proper description including: -- What you want to accomplish -- Why it's needed -- Any specific technical requirements or constraints - -Once updated, this task can be re-planned with concrete implementation steps. diff --git a/.opencode-studio/kanban/plans/59a8e4fb-799b-4449-b025-e30a071820a1.md b/.opencode-studio/kanban/plans/59a8e4fb-799b-4449-b025-e30a071820a1.md deleted file mode 100644 index 19807ac..0000000 --- a/.opencode-studio/kanban/plans/59a8e4fb-799b-4449-b025-e30a071820a1.md +++ /dev/null @@ -1,198 +0,0 @@ -# Implementation Plan: Prompt Test - -**Task ID:** 59a8e4fb-799b-4449-b025-e30a071820a1 -**Title:** Prompt test -**Description:** x -**Generated:** 2025-01-01T01:36:13+01:00 - -## 1. Technical Analysis - -### Problem Statement -The task "Prompt test" with minimal description "x" suggests testing the prompt engineering capabilities within OpenCode Studio. Given the AI-powered nature of the platform and the existing prompt infrastructure, this likely involves: -- Testing the prompt generation and execution system -- Validating prompt templates and their effectiveness -- Ensuring prompt consistency across different task phases -- Testing edge cases and prompt robustness - -### Current System Context -- **Prompt Infrastructure:** Located in `crates/orchestrator/src/prompts.rs` -- **AI Integration:** OpenCode client SDK handles prompt execution -- **Task Lifecycle:** TODO → PLANNING → PLANNING_REVIEW → IN_PROGRESS → AI_REVIEW → REVIEW → DONE -- **Session Management:** Each phase uses separate OpenCode sessions with specific prompts -- **Known Components:** - - `implementation_with_plan()` - Implementation prompts - - `replan()` - Re-planning prompts - - Planning and review prompt templates - -### Proposed Solution -Implement a **Prompt Testing Framework** that: -1. **Prompt Validation:** Test all existing prompt templates for syntax and completeness -2. **Mock Testing:** Create mock scenarios to test prompt behavior -3. **Integration Testing:** Validate prompts work correctly with OpenCode client -4. **Performance Testing:** Measure prompt execution times and token usage -5. **Edge Case Testing:** Test prompts with unusual inputs and edge cases - -## 2. Files to Modify/Create - -### New Files -``` -crates/orchestrator/src/prompt_tests.rs # Core prompt testing logic -crates/orchestrator/src/test_scenarios.rs # Test scenarios and mock data -crates/server/src/routes/prompt_test.rs # Prompt testing API endpoints -tests/integration/prompt_integration_tests.rs # Integration tests for prompts -``` - -### Files to Modify -``` -crates/orchestrator/src/lib.rs # Export new testing modules -crates/orchestrator/src/prompts.rs # Add testing utilities -crates/orchestrator/Cargo.toml # Add testing dependencies (mockall, tokio-test) -crates/server/src/lib.rs # Register prompt test routes -crates/server/src/routes/mod.rs # Add prompt_test module -crates/core/src/domain/mod.rs # Add prompt test domain models -frontend/src/components/prompt-test/ # Frontend testing interface (optional) -``` - -### Configuration Files -``` -.opencode-studio/prompt-test-config.toml # Test configuration -tests/fixtures/prompt_test_data.json # Test data and scenarios -``` - -## 3. Step-by-Step Implementation Steps - -### Phase 1: Infrastructure Setup (2-3 hours) -1. **Create prompt testing module** - - Initialize `crates/orchestrator/src/prompt_tests.rs` - - Define test result structures and enums - - Implement basic prompt validation functions - -2. **Add test scenarios** - - Create `crates/orchestrator/src/test_scenarios.rs` - - Define mock task data, edge cases, and invalid inputs - - Implement scenario generators - -3. **Update dependencies** - - Add `mockall = "0.12"` to orchestrator Cargo.toml - - Add `tokio-test = "0.4"` for async testing - - Update module exports in lib.rs - -### Phase 2: Core Testing Logic (3-4 hours) -1. **Implement prompt validation** - ```rust - pub fn validate_prompt_template(template: &str) -> PromptValidationResult - pub fn test_prompt_with_mock_data(prompt: &str, data: &MockData) -> TestResult - pub fn measure_prompt_performance(prompt: &str) -> PerformanceMetrics - ``` - -2. **Mock OpenCode client** - - Create mock implementation of OpenCode client - - Simulate various response scenarios (success, timeout, error) - - Test prompt execution without actual API calls - -3. **Edge case testing** - - Test with empty task descriptions - - Test with extremely long descriptions - - Test with special characters and unicode - - Test with malformed JSON inputs - -### Phase 3: Integration Testing (2-3 hours) -1. **Create integration tests** - - Test prompts with actual OpenCode client (if available) - - Validate end-to-end prompt execution - - Test prompt behavior across all task phases - -2. **Performance benchmarking** - - Measure token usage for different prompt templates - - Track execution times and response quality - - Generate performance reports - -### Phase 4: API Endpoints (2 hours) -1. **Create prompt test API** - ```rust - GET /api/prompt-test/validate/{template_id} # Validate specific template - POST /api/prompt-test/execute # Execute test scenario - GET /api/prompt-test/results # Get test results - GET /api/prompt-test/performance # Performance metrics - ``` - -2. **Add OpenAPI documentation** - - Document all new endpoints - - Add request/response schemas - - Update Swagger UI - -### Phase 5: Optional Frontend Interface (2-3 hours) -1. **Create testing dashboard** - - Component for running prompt tests - - Display test results and metrics - - Visual prompt template editor - -2. **Integration with existing UI** - - Add prompt test tab to admin interface - - Integrate with existing state management - -## 4. Potential Risks - -### High Risk -- **OpenCode API Dependency:** Testing requires OpenCode server to be running - - *Mitigation:* Implement comprehensive mocking system - - *Fallback:* Offline validation and mock testing only - -- **Prompt Template Changes:** Existing prompts might fail validation - - *Mitigation:* Start with read-only validation before modifying templates - - *Recovery:* Maintain backup of working prompt templates - -### Medium Risk -- **Performance Impact:** Running extensive prompt tests might slow down system - - *Mitigation:* Implement async testing with rate limiting - - *Solution:* Run tests in background with progress tracking - -- **Test Data Management:** Mock data might not represent real scenarios - - *Mitigation:* Use anonymized real task data for testing - - *Validation:* Regularly update test scenarios based on production usage - -### Low Risk -- **Integration Complexity:** Adding new API endpoints might conflict with existing routes - - *Mitigation:* Use `/api/prompt-test/*` namespace to avoid conflicts - - *Testing:* Comprehensive route testing before deployment - -- **Frontend Dependencies:** Optional UI might introduce new dependencies - - *Mitigation:* Keep frontend testing interface minimal and optional - - *Alternative:* CLI-based testing interface only - -## 5. Estimated Complexity: **M (Medium)** - -### Complexity Breakdown -- **Backend Core Logic:** Medium (3-4 hours for prompt testing framework) -- **Integration Testing:** Medium (2-3 hours for OpenCode integration) -- **API Development:** Low-Medium (2 hours for REST endpoints) -- **Frontend Interface:** Low-Medium (2-3 hours, optional) -- **Documentation:** Low (1 hour for API docs and README updates) - -### Total Estimated Time: **10-15 hours** - -### Complexity Justification -- **Medium complexity** due to need for careful prompt validation and mocking -- Well-defined scope with existing prompt infrastructure as foundation -- Limited external dependencies beyond current OpenCode integration -- Clear testing patterns available from existing codebase (109 passing tests) -- Can be implemented incrementally with each phase delivering value - -### Success Criteria -1. ✅ All existing prompt templates pass validation -2. ✅ Mock testing framework executes without errors -3. ✅ Integration tests confirm prompts work with OpenCode client -4. ✅ Performance benchmarks establish baseline metrics -5. ✅ API endpoints respond correctly and are documented -6. ✅ Build passes with `cargo test --workspace` -7. ✅ Clippy warnings remain clean with `-D warnings` - -### Dependencies -- OpenCode client SDK (existing) -- SQLite database (existing) -- Axum server framework (existing) -- No new external service dependencies required - ---- - -**Note:** This is a test scenario plan. The minimal description "x" has been interpreted as a prompt testing requirement based on the AI-powered nature of OpenCode Studio. The plan can be adapted once more specific requirements are provided. \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/67d5bc95-691b-4083-b3a1-81fb89a63ec0.md b/.opencode-studio/kanban/plans/67d5bc95-691b-4083-b3a1-81fb89a63ec0.md deleted file mode 100644 index 87c4500..0000000 --- a/.opencode-studio/kanban/plans/67d5bc95-691b-4083-b3a1-81fb89a63ec0.md +++ /dev/null @@ -1,191 +0,0 @@ -# Implementation Plan: Test5 - -**Task ID:** 67d5bc95-691b-4083-b3a1-81fb89a63ec0 -**Title:** Test5 -**Description:** Test -**Created:** 2026-01-01T01:36:13+01:00 - -## Executive Summary - -**⚠️ CRITICAL ISSUE: Insufficient Task Specification** - -This task has minimal description ("Test5" / "Test"), making it impossible to create a meaningful implementation plan. This analysis provides a framework for what would be required once proper requirements are established. - -## 1. Technical Analysis - -### Current State Assessment -- **Task Clarity**: ❌ Extremely poor - no functional requirements -- **Scope Definition**: ❌ Undefined - could range from unit test to integration test to feature test -- **Success Criteria**: ❌ None provided -- **Context**: ✅ OpenCode Studio platform (Rust backend + React frontend) - -### Assumptions Based on Context -Given the OpenCode Studio environment, this could be: -1. **Unit Test Addition** - Testing specific backend functionality -2. **Integration Test** - Testing API endpoints or task lifecycle -3. **E2E Test** - Testing complete user workflows -4. **Feature Test** - Testing a new feature implementation -5. **System Test** - Testing overall system behavior - -### Technology Stack Analysis -- **Backend**: Rust (Axum + SQLite + SQLx) -- **Frontend**: React + TypeScript + Vite -- **Testing**: Cargo test (backend), potentially Vitest (frontend) -- **Current Test Status**: 108+ passing backend tests, clean clippy - -## 2. Files to Modify/Create - -### Scenario A: Backend Unit Test -``` -crates/ -├── core/src/domain/task.rs (if testing task logic) -├── db/src/repositories/ (if testing database operations) -├── server/src/routes/ (if testing API endpoints) -└── orchestrator/src/ (if testing task orchestration) -``` - -### Scenario B: Frontend Test -``` -frontend/ -├── src/components/__tests__/ -├── src/hooks/__tests__/ -└── tests/e2e/ (if integration testing) -``` - -### Scenario C: Integration Test -``` -crates/server/tests/ -└── integration_tests.rs -``` - -## 3. Step-by-Step Implementation Steps - -### Phase 1: Requirements Clarification (REQUIRED) -1. **Define Test Purpose** - - What functionality needs testing? - - What behavior should be verified? - - What are the success/failure criteria? - -2. **Identify Test Type** - - Unit test (isolated component testing) - - Integration test (component interaction testing) - - E2E test (full workflow testing) - -3. **Scope Definition** - - Which modules/components are in scope? - - What data/state setup is required? - - What external dependencies need mocking? - -### Phase 2: Test Design (Pending Requirements) -1. **Test Structure Planning** - ```rust - #[cfg(test)] - mod tests { - use super::*; - - #[test] - fn test_placeholder() { - // Setup - // Execute - // Assert - } - } - ``` - -2. **Mock/Fixture Setup** - - Database fixtures (if needed) - - API mocks (if needed) - - Test data preparation - -3. **Test Case Design** - - Happy path scenarios - - Edge cases - - Error conditions - -### Phase 3: Implementation (Pending Requirements) -1. **Write Test Code** - - Follow existing test patterns in codebase - - Use appropriate testing utilities - - Ensure proper cleanup - -2. **Verify Test Execution** - ```bash - cargo test test_name - cargo clippy --workspace - ``` - -3. **Integration Verification** - - Ensure test doesn't break existing functionality - - Verify test isolation - - Confirm CI compatibility - -## 4. Potential Risks - -### High Risk -- **🔴 Undefined Requirements**: Cannot proceed without clear specification -- **🔴 Scope Creep**: "Test" could mean anything from simple unit test to complex system test - -### Medium Risk -- **🟡 Test Environment**: May need specific test data or environment setup -- **🟡 Flaky Tests**: Could introduce timing or state-dependent issues -- **🟡 Performance Impact**: Large test suites might slow CI pipeline - -### Low Risk -- **🟢 Breaking Changes**: Unlikely for test-only changes -- **🟢 API Compatibility**: Test changes shouldn't affect public interfaces - -## 5. Estimated Complexity - -**Current Assessment: CANNOT ESTIMATE** - -Based on potential scenarios: -- **S (Simple)**: Single unit test for existing functionality (1-2 hours) -- **M (Medium)**: Integration test with setup/teardown (4-8 hours) -- **L (Large)**: E2E test suite with complex workflows (1-2 days) -- **XL (Extra Large)**: Comprehensive testing framework overhaul (3-5 days) - -## 6. Dependencies & Prerequisites - -### Must Have Before Implementation -1. **Clear Requirements** - What exactly needs to be tested? -2. **Test Strategy** - Unit/Integration/E2E approach decision -3. **Acceptance Criteria** - How to verify success? - -### Technical Dependencies -- Existing test infrastructure ✅ (109 tests passing) -- Development environment ✅ (Rust toolchain ready) -- CI/CD pipeline ✅ (GitHub Actions configured) - -## 7. Success Metrics - -### Definition of Done (To Be Defined) -- [ ] Test requirements clearly specified -- [ ] Test implementation follows project patterns -- [ ] All tests pass (`cargo test --workspace`) -- [ ] No clippy warnings (`cargo clippy -D warnings`) -- [ ] Test provides meaningful coverage/validation -- [ ] CI pipeline remains green - -## 8. Next Actions Required - -### Immediate (BLOCKING) -1. **🚨 CLARIFY REQUIREMENTS** - This task cannot proceed without proper specification -2. **Define test scope and objectives** -3. **Establish success criteria** - -### Once Requirements Clear -1. Update this plan with specific implementation details -2. Begin implementation following established patterns -3. Execute testing and validation procedures - -## Notes - -- This plan serves as a template until proper requirements are provided -- OpenCode Studio has robust testing infrastructure already in place -- Follow existing patterns in `crates/*/tests/` for consistency -- Consider impact on 108+ existing tests when making changes - ---- - -**Status**: ⏸️ BLOCKED - Awaiting requirement clarification -**Next Reviewer**: Task creator (requirements definition needed) \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/775a800e-bf7a-41b7-a30f-c99cdc2e7d8a.md b/.opencode-studio/kanban/plans/775a800e-bf7a-41b7-a30f-c99cdc2e7d8a.md deleted file mode 100644 index 129e1d4..0000000 --- a/.opencode-studio/kanban/plans/775a800e-bf7a-41b7-a30f-c99cdc2e7d8a.md +++ /dev/null @@ -1,727 +0,0 @@ -# API Integration Test: Full OpenCode Integration - -## Task Summary -**Task ID:** 775a800e-bf7a-41b7-a30f-c99cdc2e7d8a -**Title:** API Integration Test -**Description:** Test full OpenCode integration -**Updated:** 2025-12-31 - ---- - -## 1. Technical Analysis - -### Current State Assessment - -The codebase has migrated to a single OpenCode integration approach: - -**OpenAPI-Generated SDK** (`crates/opencode-client/`) -- Generated from OpenCode OpenAPI specification -- Used exclusively by `TaskExecutor` in orchestrator crate -- Type-safe with comprehensive coverage of OpenCode API -- No unit tests (generated code, tested via integration) - -### Existing Test Coverage - -| Component | Tests | Coverage | -|-----------|-------|----------| -| Unit Tests (workspace-wide) | 108+ tests | Excellent | -| OpenCode Integration | 0 integration tests | None | -| SSE Event Streaming | 8 event tests | Good | -| Full Task Lifecycle | 0 end-to-end tests | None | -| API Endpoints | 12 server tests | Good (mocked) | - -### Key Integration Points - -``` -HTTP API (/api/tasks/{id}/execute) - ↓ -TaskExecutor (crates/orchestrator/src/executor.rs) - ↓ -opencode-client SDK (crates/opencode-client/) - ↓ -OpenCode HTTP API (OPENCODE_URL, default: localhost:4096) - ↓ -SSE Events (EventBus -> /api/events, /api/sessions/{id}/activity) - ↓ -File Management (.opencode-studio/kanban/plans|reviews) - ↓ -VCS Workspace Management (Jujutsu/Git) -``` - -### Critical Gaps Identified - -1. **No end-to-end API integration tests** - All tests use mocked OpenCode responses -2. **Full task lifecycle untested** - Complete TODO→DONE flow not verified -3. **Concurrent session handling untested** - Multiple OpenCode sessions not tested -4. **Error recovery scenarios untested** - OpenCode failures, network issues, timeouts -5. **VCS workspace integration untested** - Workspace creation/cleanup during OpenCode operations -6. **File persistence untested during failures** - Plan/review file handling edge cases -7. **SSE event emission verification missing** - Real-time events during OpenCode operations -8. **Performance characteristics unknown** - No load or timing tests - ---- - -## 2. Files to Modify/Create - -### New Integration Test Files - -**Primary Test Suite:** -``` -crates/server/tests/ -├── api_integration_test.rs # Main integration test suite -├── common/ -│ ├── mod.rs # Shared test infrastructure -│ ├── opencode_mock.rs # OpenCode server mock/simulator -│ ├── test_fixtures.rs # Test data and factories -│ ├── assertions.rs # Custom assertion helpers -│ └── database_utils.rs # Test database utilities -``` - -**Specialized Test Files:** -``` -crates/orchestrator/tests/ -├── full_lifecycle_test.rs # Complete task lifecycle tests -└── concurrent_execution_test.rs # Concurrent OpenCode session tests - -crates/server/tests/ -├── sse_integration_test.rs # Real-time event verification tests -└── performance_test.rs # Load and timing tests -``` - -### Files to Modify - -| File | Changes Required | -|------|------------------| -| `crates/server/Cargo.toml` | Add integration test dependencies (`wiremock`, `tokio-test`, `tempfile`, `uuid`) | -| `crates/orchestrator/Cargo.toml` | Add test dependencies for async testing | -| `crates/db/src/pool.rs` | Add test database utilities for isolated testing | -| `crates/server/src/lib.rs` | Export test configuration utilities | -| `.github/workflows/ci.yml` | Add integration test job (optional) | - -### Enhanced Monitoring Files - -| File | Purpose | -|------|---------| -| `crates/server/tests/test_config.rs` | Test environment configuration | -| `docs/testing/integration_testing.md` | Integration testing documentation | - ---- - -## 3. Step-by-Step Implementation - -### Phase 1: Test Infrastructure Setup (2 days) - -**Step 1.1: Test Dependencies and Environment** -```rust -// crates/server/tests/common/mod.rs -/// Integration test utilities requiring live OpenCode server -/// Run with: OPENCODE_URL=http://localhost:4096 cargo test --package server --test api_integration_test - -use std::env; -use opencode_client::apis::configuration::Configuration; - -pub fn get_opencode_config() -> Option { - env::var("OPENCODE_URL").ok().map(|url| { - Configuration { - base_path: url, - ..Default::default() - } - }) -} - -pub fn skip_if_no_opencode() -> bool { - env::var("OPENCODE_URL").is_err() -} -``` - -**Step 1.2: OpenCode Mock Server Infrastructure** -```rust -// crates/server/tests/common/opencode_mock.rs -use wiremock::{MockServer, Mock, ResponseTemplate}; -use opencode_client::models::{SessionCreateRequest, SessionPromptRequest}; - -pub struct OpenCodeMock { - pub server: MockServer, - pub base_url: String, -} - -impl OpenCodeMock { - pub async fn start() -> Self { /* Implementation */ } - pub fn mock_session_create(&self) -> Mock { /* Implementation */ } - pub fn mock_session_prompt(&self) -> Mock { /* Implementation */ } - pub fn simulate_delay(&self, ms: u64) { /* Implementation */ } - pub fn simulate_error(&self, status: u16) { /* Implementation */ } -} -``` - -**Step 1.3: Test Database and File System Setup** -```rust -// crates/server/tests/common/test_fixtures.rs -use tempfile::TempDir; -use uuid::Uuid; - -pub struct TestEnvironment { - pub temp_dir: TempDir, - pub db_url: String, - pub task_id: Uuid, - pub opencode_config: Configuration, -} - -impl TestEnvironment { - pub async fn setup() -> Self { /* Implementation */ } - pub async fn cleanup(&self) { /* Implementation */ } - pub fn create_test_task(&self) -> Task { /* Implementation */ } -} -``` - -**Step 1.4: SSE Event Testing Infrastructure** -```rust -// crates/server/tests/common/sse_test_client.rs -use futures::stream::StreamExt; - -pub struct SSETestClient { - client: reqwest::Client, - base_url: String, -} - -impl SSETestClient { - pub async fn connect(&self, endpoint: &str) -> EventStream { /* Implementation */ } - pub async fn collect_events_for(&self, duration: Duration) -> Vec { /* Implementation */ } -} -``` - -### Phase 2: API Endpoint Integration Tests (3 days) - -**Step 2.1: Task CRUD with Real Database** -```rust -// Test: POST /api/tasks creates task in database -#[tokio::test] -async fn test_create_task_integration() { - let env = TestEnvironment::setup().await; - let response = test_client - .post("/api/tasks") - .json(&CreateTaskRequest { - title: "Integration Test Task".to_string(), - description: "Test full OpenCode integration".to_string() - }) - .send().await?; - - assert_eq!(response.status(), 201); - let task: Task = response.json().await?; - assert_eq!(task.status, TaskStatus::Todo); - - // Verify database persistence - let db_task = env.task_repository.find_by_id(task.id).await?.unwrap(); - assert_eq!(db_task.title, "Integration Test Task"); -} -``` - -**Step 2.2: Task State Transitions** -- Test: `POST /api/tasks/{id}/transition` with valid state changes -- Test: Invalid transitions return 400 Bad Request -- Test: Task status persisted to database -- Test: Events emitted via SSE stream - -**Step 2.3: Task Execution Endpoint - Basic Tests** -- Test: `POST /api/tasks/{id}/execute` with mocked OpenCode -- Test: Response format matches `ExecuteResponse` schema -- Test: Task status updated after execution -- Test: Session persistence to database - -### Phase 3: Full Task Lifecycle Integration Tests (4 days) - -**Step 3.1: Live OpenCode Planning Phase** -```rust -#[tokio::test] -async fn test_planning_phase_with_live_opencode() { - if skip_if_no_opencode() { return; } - - let env = TestEnvironment::setup().await; - let task = env.create_test_task(); - - // Execute planning phase - let response = test_client - .post(&format!("/api/tasks/{}/execute", task.id)) - .send().await?; - - let result: ExecuteResponse = response.json().await?; - - // Verify planning completion - assert!(matches!(result.result, PhaseResultDto::PlanCreated { .. })); - assert_eq!(result.task.status, TaskStatus::PlanningReview); - - // Verify plan file created - let plan_path = format!(".opencode-studio/kanban/plans/{}.md", task.id); - assert!(tokio::fs::metadata(&plan_path).await.is_ok()); - - // Verify session persisted - let sessions = env.session_repository.find_by_task_id(task.id).await?; - assert_eq!(sessions.len(), 1); - assert_eq!(sessions[0].phase, SessionPhase::Planning); -} -``` - -**Step 3.2: Implementation Phase with VCS Workspace** -- Test: VCS workspace created for implementation -- Test: Plan file loaded and included in implementation prompt -- Test: OpenCode tool calls executed in workspace context -- Test: Activity messages captured and stored -- Test: Workspace diff available after implementation - -**Step 3.3: AI Review Phase** -- Test: Diff retrieved from VCS workspace -- Test: Review prompt includes actual code changes -- Test: "APPROVED" response format recognized correctly -- Test: "CHANGES_REQUESTED" triggers fix iteration -- Test: Max review iterations enforced (default 3) - -**Step 3.4: Complete Task Lifecycle** -```rust -#[tokio::test] -async fn test_complete_todo_to_done_lifecycle() { - if skip_if_no_opencode() { return; } - - let env = TestEnvironment::setup().await; - let task = env.create_test_task(); - - // Execute full cycle with relaxed approval settings - let executor_config = ExecutorConfig::new(&env.temp_dir.path()) - .with_plan_approval(false) // Auto-approve for testing - .with_human_review(false); // Auto-approve for testing - - let result = env.task_executor - .run_full_cycle(&mut task).await?; - - assert!(matches!(result, PhaseResult::Completed)); - assert_eq!(task.status, TaskStatus::Done); - - // Verify all phases executed - let sessions = env.session_repository.find_by_task_id(task.id).await?; - assert!(sessions.len() >= 2); // At least planning + implementation -} -``` - -### Phase 4: Error Handling and Edge Cases (3 days) - -**Step 4.1: OpenCode Server Failure Scenarios** -```rust -#[tokio::test] -async fn test_opencode_server_unavailable() { - let env = TestEnvironment::setup().await; - let task = env.create_test_task(); - - // Configure with invalid OpenCode URL - env::set_var("OPENCODE_URL", "http://localhost:9999"); - - let response = test_client - .post(&format!("/api/tasks/{}/execute", task.id)) - .send().await?; - - // Should return 500 Internal Server Error - assert_eq!(response.status(), 500); - - // Task status should remain unchanged - let updated_task = env.task_repository.find_by_id(task.id).await?.unwrap(); - assert_eq!(updated_task.status, TaskStatus::Todo); -} -``` - -**Step 4.2: Database Consistency During Failures** -- Test: Session persistence rolled back on OpenCode failure -- Test: Task status remains consistent after network errors -- Test: Activity store cleanup on session failure -- Test: File system cleanup on workspace errors - -**Step 4.3: Concurrent Session Management** -```rust -#[tokio::test] -async fn test_concurrent_task_execution() { - if skip_if_no_opencode() { return; } - - let env = TestEnvironment::setup().await; - let tasks = (0..3).map(|_| env.create_test_task()).collect::>(); - - // Execute all tasks concurrently - let futures = tasks.iter().map(|task| { - test_client.post(&format!("/api/tasks/{}/execute", task.id)).send() - }); - - let results = futures::future::join_all(futures).await; - - // All should succeed - for result in results { - assert_eq!(result?.status(), 200); - } - - // Verify isolated execution (no state pollution) - for task in &tasks { - let updated_task = env.task_repository.find_by_id(task.id).await?.unwrap(); - assert!(updated_task.status != TaskStatus::Todo); - } -} -``` - -**Step 4.4: Resource Cleanup and Limits** -- Test: VCS workspace cleanup after session completion -- Test: Plan/review file cleanup policies -- Test: Activity store memory limits during long sessions -- Test: OpenCode session cleanup on abort - -### Phase 5: SSE Event Verification and Real-time Updates (2 days) - -**Step 5.1: Global Event Stream Testing** -```rust -#[tokio::test] -async fn test_global_event_stream_during_execution() { - if skip_if_no_opencode() { return; } - - let env = TestEnvironment::setup().await; - let task = env.create_test_task(); - - // Connect to global events stream - let sse_client = SSETestClient::new(&env.server_url); - let mut event_stream = sse_client.connect("/api/events").await?; - - // Trigger task execution - let _response = test_client - .post(&format!("/api/tasks/{}/execute", task.id)) - .send().await?; - - // Collect events for 30 seconds - let events = sse_client.collect_events_for(Duration::from_secs(30)).await; - - // Verify expected event sequence - assert!(events.iter().any(|e| matches!(e, Event::SessionStarted { task_id, .. } if *task_id == task.id))); - assert!(events.iter().any(|e| matches!(e, Event::TaskStatusChanged { task_id, .. } if *task_id == task.id))); - assert!(events.iter().any(|e| matches!(e, Event::SessionEnded { task_id, .. } if *task_id == task.id))); -} -``` - -**Step 5.2: Session-Specific Activity Stream** -- Test: `/api/sessions/{id}/activity` returns live OpenCode activity -- Test: Activity history + real-time streaming pattern -- Test: Reconnection delivers missed events -- Test: Activity parsing from OpenCode message parts - -**Step 5.3: Event Buffer and Reconnection** -```rust -#[tokio::test] -async fn test_activity_reconnection_with_history() { - if skip_if_no_opencode() { return; } - - let env = TestEnvironment::setup().await; - let task = env.create_test_task(); - - // Start execution to generate activity - let execute_future = test_client.post(&format!("/api/tasks/{}/execute", task.id)).send(); - - // Wait for session to start, then connect to activity stream - tokio::time::sleep(Duration::from_secs(2)).await; - - let session = env.session_repository.find_by_task_id(task.id).await?.first().unwrap().clone(); - let activity_stream = sse_client.connect(&format!("/api/sessions/{}/activity", session.id)).await?; - - // Should receive history + live updates - let activities = sse_client.collect_events_for(Duration::from_secs(20)).await; - assert!(!activities.is_empty()); - - execute_future.await?; -} -``` - -### Phase 6: Performance and Documentation (2 days) - -**Step 6.1: Performance Benchmarks** -- Test: API response times under normal load -- Test: Memory usage during multiple concurrent sessions -- Test: Database query performance during complex operations -- Test: File system I/O performance for plan/review operations - -**Step 6.2: Load Testing** -```rust -#[tokio::test] -async fn test_sustained_load_performance() { - if skip_if_no_opencode() { return; } - - let env = TestEnvironment::setup().await; - let start_time = Instant::now(); - - // Create 10 tasks and execute them sequentially - for i in 0..10 { - let task = env.create_test_task(); - let response = test_client - .post(&format!("/api/tasks/{}/execute", task.id)) - .send().await?; - assert_eq!(response.status(), 200); - } - - let total_time = start_time.elapsed(); - println!("10 sequential executions took: {:?}", total_time); - assert!(total_time < Duration::from_secs(300)); // 5 minute limit -} -``` - -**Step 6.3: Test Documentation and CI Integration** -- Create `docs/testing/integration_testing.md` with setup instructions -- Add integration test job to `.github/workflows/ci.yml` (optional) -- Document test environment variables and dependencies -- Add troubleshooting guide for common test failures - ---- - -## 4. Potential Risks - -### High Risk - -| Risk | Impact | Mitigation | -|------|--------|------------| -| **OpenCode server dependency for tests** | Tests cannot run without external service | Use comprehensive mocking with wiremock, implement optional integration mode with `OPENCODE_URL` env var | -| **Non-deterministic AI responses** | Flaky test failures due to varying OpenCode outputs | Assert on response structure/format rather than content, use controlled prompts, implement response validation patterns | -| **Long test execution times** | CI slowdown, developer workflow interruption | Implement test timeouts (5-30s per test), categorize fast vs. slow tests, use concurrent execution where safe | -| **Test data isolation failures** | Tests interfere with each other through shared state | Use isolated test databases per test case, implement thorough cleanup, use UUID-based test identifiers | - -### Medium Risk - -| Risk | Impact | Mitigation | -|------|--------|------------| -| **VCS workspace conflicts** | Tests fail due to workspace state pollution | Use temporary directories for each test, implement workspace cleanup, use isolated Git/Jujutsu repos | -| **Database transaction deadlocks** | Concurrent tests fail with database errors | Use test database connection pooling, implement retry logic, serialize database-heavy tests | -| **SSE connection management** | Event streams leak or fail to close properly | Implement connection timeouts, proper stream cleanup, connection pooling limits | -| **File system race conditions** | Plan/review file operations conflict | Use file locking, atomic write operations, unique file names per test | - -### Low Risk - -| Risk | Impact | Mitigation | -|------|--------|------------| -| **CI resource exhaustion** | Tests consume excessive CI resources | Monitor resource usage, implement resource limits, optimize test efficiency | -| **OpenCode API rate limiting** | Tests throttled during rapid execution | Add delays between OpenCode requests, implement request queuing | -| **Environment variable conflicts** | Test configuration interferes with development | Use test-specific environment variable prefixes, document configuration clearly | - ---- - -## 5. Estimated Complexity - -**Overall: XL (Extra Large)** - -| Phase | Complexity | Days | Rationale | -|-------|------------|------|-----------| -| Test Infrastructure Setup | L | 2 | Complex async test framework, OpenCode mocking, database setup | -| API Endpoint Integration | M | 3 | HTTP integration testing, database verification | -| Full Task Lifecycle | XL | 4 | Multi-phase OpenCode integration, VCS workspace management, file operations | -| Error Handling & Edge Cases | L | 3 | Network failures, concurrent scenarios, resource cleanup | -| SSE Events & Real-time | M | 2 | Event streaming, timing-sensitive tests | -| Performance & Documentation | S | 2 | Benchmarking, documentation | - -**Detailed Effort Breakdown:** -- **Test Infrastructure (2 days)**: OpenCode mock server, test database utilities, SSE test client, file system mocking -- **API Integration (3 days)**: CRUD operations, state transitions, basic execution endpoint testing -- **Lifecycle Testing (4 days)**: Planning → Implementation → Review → Done flow, VCS integration, file persistence -- **Error Scenarios (3 days)**: Network failures, database consistency, concurrent execution, resource limits -- **Real-time Events (2 days)**: SSE stream verification, activity streaming, reconnection logic -- **Performance & Docs (2 days)**: Load testing, benchmarks, documentation, CI integration - -**Total Estimated Effort: 16 days** - -### Complexity Factors - -**High Complexity Elements:** -- Async coordination between API, database, OpenCode, VCS, and file system -- OpenCode response parsing and activity message handling -- Concurrent session management and isolation -- State consistency verification across distributed operations -- SSE event timing and sequence verification - -**Medium Complexity Elements:** -- Test database setup and migration management -- HTTP integration testing patterns -- File system operations testing -- Error simulation and recovery testing - -**Low Complexity Elements:** -- Basic API endpoint testing -- Simple state transition verification -- Test fixture creation and cleanup -- Documentation writing - ---- - -## 6. Test Strategy - -### Test Pyramid Enhancement - -``` - /\ - / \ - / E2E \ (10-15 integration tests) - / \ - /--------\ - / Integration \ (35-50 tests total) - / \ - /----------------\ - / Unit Tests \ (existing 108+ tests) - /____________________\ -``` - -**Test Categories:** -- **Unit Tests (108+)**: Existing crate-level tests covering individual components -- **Integration Tests (35-50)**: New API integration tests with live/mocked OpenCode -- **End-to-End (10-15)**: Complete task lifecycle tests with full system integration - -### Test Execution Modes - -**Mode 1: Mock-Only Integration Tests (Default)** -```bash -# Fast execution, no external dependencies -cargo test --package server --test api_integration_test -``` - -**Mode 2: Live OpenCode Integration Tests** -```bash -# Requires running OpenCode server -OPENCODE_URL=http://localhost:4096 cargo test --package server --test api_integration_test -``` - -**Mode 3: Performance and Load Tests** -```bash -# Long-running performance tests -OPENCODE_URL=http://localhost:4096 cargo test --package server --test performance_test --release -``` - -### Environment Configuration - -```toml -# crates/server/Cargo.toml -[dev-dependencies] -wiremock = "0.6" -tokio-test = "0.4" -tempfile = "3.10" -uuid = { version = "1.6", features = ["v4"] } -futures = "0.3" - -[[test]] -name = "api_integration_test" -path = "tests/api_integration_test.rs" - -[[test]] -name = "performance_test" -path = "tests/performance_test.rs" -``` - -### Test Data Management - -```rust -// Test isolation strategy -pub struct TestEnvironment { - pub temp_dir: TempDir, // Isolated file system - pub db_url: String, // Unique test database - pub opencode_config: Configuration, - pub test_id: Uuid, // Test run identifier -} - -impl Drop for TestEnvironment { - fn drop(&mut self) { - // Automatic cleanup of all test resources - } -} -``` - ---- - -## 7. Success Criteria - -### Must Have (Required for Completion) -- [ ] **Full task lifecycle tested end-to-end** - Complete TODO→DONE automation verified -- [ ] **All OpenCode integration points covered** - Planning, implementation, review phases tested -- [ ] **Error handling scenarios verified** - OpenCode failures, network issues, timeouts handled gracefully -- [ ] **Database consistency maintained** - All operations maintain data integrity during failures -- [ ] **SSE event emission verified** - Real-time events properly emitted during task execution -- [ ] **VCS workspace integration tested** - Workspace creation, diff retrieval, cleanup working correctly -- [ ] **Concurrent session support** - Multiple OpenCode sessions can run simultaneously without interference - -### Should Have (Highly Desirable) -- [ ] **Performance benchmarks established** - Response time and resource usage metrics documented -- [ ] **Test execution time optimized** - Full integration test suite completes in under 10 minutes -- [ ] **Comprehensive error scenarios** - Network failures, database errors, file system issues covered -- [ ] **Activity stream verification** - Real-time activity updates tested end-to-end -- [ ] **Resource cleanup verified** - No resource leaks or orphaned processes after test completion - -### Nice to Have (Optional Enhancement) -- [ ] **CI integration configured** - Tests run automatically in CI environment -- [ ] **Load testing implemented** - System behavior under sustained load documented -- [ ] **Test documentation comprehensive** - Setup, troubleshooting, and maintenance guides available -- [ ] **Mock vs. live test modes** - Tests can run with both mocked and real OpenCode server - ---- - -## 8. Dependencies - -### Critical Dependencies -- **OpenCode Server**: Live OpenCode instance required for integration testing -- **Database**: SQLite database with migration capabilities -- **VCS**: Git or Jujutsu for workspace management testing -- **File System**: Write permissions for plan/review file operations - -### Development Dependencies -- **Rust Test Framework**: tokio-test, wiremock for async testing -- **Temporary Resources**: tempfile for isolated test environments -- **HTTP Client**: reqwest for API testing -- **Event Streaming**: SSE client capabilities for real-time verification - -### Optional Dependencies -- **Docker**: For containerized OpenCode testing environment -- **CI Environment**: GitHub Actions or similar for automated testing -- **Monitoring Tools**: Performance measurement and resource tracking - ---- - -## 9. Implementation Notes - -### Current Codebase Integration - -**Generated OpenCode Client Usage:** -```rust -// Current implementation in crates/orchestrator/src/executor.rs -use opencode_client::apis::configuration::Configuration; -use opencode_client::apis::default_api; -use opencode_client::models::{SessionCreateRequest, SessionPromptRequest}; -``` - -**Key Architectural Components:** -- `TaskExecutor` in `crates/orchestrator/src/executor.rs` - Main OpenCode integration point -- `SessionActivityRegistry` - Real-time activity management -- `FileManager` - Plan/review file persistence -- `WorkspaceManager` - VCS integration for code changes - -### Test Infrastructure Patterns - -**Following Existing Patterns from Current Tests:** -1. **Isolated Test Databases**: Each test uses separate SQLite database -2. **Temporary Directories**: Use tempfile crate for file system isolation -3. **Async Test Coordination**: tokio-test for async test execution -4. **Mock Server Integration**: wiremock for controlled OpenCode simulation - -### Critical Testing Areas - -**State Machine Verification:** -- Task status transitions follow defined state machine rules -- Invalid transitions properly rejected -- Database and memory state remain consistent - -**Event System Testing:** -- EventBus properly emits events during operations -- SSE streams deliver events in correct order -- Event buffers handle reconnection scenarios - -**Resource Management:** -- VCS workspaces created and cleaned up properly -- OpenCode sessions properly terminated -- Activity stores don't leak memory during long operations - ---- - -**Next Steps:** -1. **Environment Setup**: Configure development environment with required dependencies -2. **Phase 1 Implementation**: Begin with test infrastructure setup (OpenCode mock, database utils) -3. **Incremental Development**: Implement one test phase at a time with regular verification -4. **Stabilization**: Run tests repeatedly to identify and fix flaky behavior -5. **Documentation**: Document test setup, execution, and troubleshooting procedures diff --git a/.opencode-studio/kanban/plans/7ae0d472-d61f-41db-9451-6da9e344654b.md b/.opencode-studio/kanban/plans/7ae0d472-d61f-41db-9451-6da9e344654b.md deleted file mode 100644 index 2f3cac5..0000000 --- a/.opencode-studio/kanban/plans/7ae0d472-d61f-41db-9451-6da9e344654b.md +++ /dev/null @@ -1,246 +0,0 @@ -# Implementation Plan: Final Test - -**Task ID:** 7ae0d472-d61f-41db-9451-6da9e344654b -**Title:** Final test -**Description:** x -**Created:** 2025-01-01T01:36:13+01:00 - -## 1. Technical Analysis - -### Context Assessment -Based on the minimal task description "x", this appears to be a comprehensive system validation test for OpenCode Studio. Given the project's current state: - -- **Recent migrations completed:** WebSocket → SSE, OpenCode client SDK migration -- **Backend state:** 108+ passing tests, clean clippy, 9 crates in workspace -- **Frontend state:** Next.js integration with Rust backend, Orval-generated API hooks -- **Integration status:** Full task lifecycle automation (TODO→DONE) implemented - -### Interpretation -This "Final test" likely represents a comprehensive end-to-end validation of: -1. Complete task lifecycle automation -2. SSE real-time communication -3. OpenCode integration functionality -4. CLI user experience -5. Frontend/backend API integration - -### Technical Scope -- **System integration testing:** Full stack validation -- **Workflow testing:** Complete task lifecycle (7 states) -- **Real-time features:** SSE events and activity streaming -- **OpenCode integration:** AI-powered task execution -- **User experience:** CLI + Web UI workflows - -## 2. Files to Modify/Create - -### Test Files to Create -``` -tests/ -├── integration/ -│ ├── final_system_test.rs # Main integration test suite -│ ├── task_lifecycle_test.rs # Complete workflow validation -│ ├── sse_integration_test.rs # Real-time communication tests -│ └── opencode_integration_test.rs # OpenCode execution validation -├── e2e/ -│ ├── cli_workflow_test.rs # CLI user experience tests -│ └── web_ui_workflow_test.rs # Frontend workflow tests -└── fixtures/ - ├── test_project/ # Sample project for testing - └── test_scenarios.json # Test case definitions -``` - -### Configuration Files -``` -.opencode-studio/ -├── test-config.toml # Test environment configuration -└── kanban/ - ├── test-plans/ # Test plan storage - └── test-reviews/ # Test review storage -``` - -### Documentation Files -``` -docs/ -├── testing/ -│ ├── final-test-results.md # Test execution results -│ ├── performance-benchmarks.md # Performance validation -│ └── integration-report.md # Integration test report -└── TESTING.md # Updated testing documentation -``` - -## 3. Step-by-Step Implementation Steps - -### Phase 1: Test Infrastructure Setup -1. **Create test workspace** - - Initialize isolated test environment - - Set up test database and configuration - - Prepare test project fixtures - -2. **Configure test harness** - - Set up integration test framework - - Configure mock OpenCode server if needed - - Initialize test data and scenarios - -### Phase 2: Backend Integration Testing -1. **Database and persistence tests** - - Verify all 9 crate interactions - - Test task/session CRUD operations - - Validate data consistency across operations - -2. **OpenCode integration validation** - - Test OpenCode client SDK functionality - - Verify session creation and management - - Validate file modification tracking - -3. **SSE communication testing** - - Test event broadcasting (TaskStatusChanged, SessionStarted, etc.) - - Verify event buffer and reconnection logic - - Validate activity streaming per session - -### Phase 3: Task Lifecycle Validation -1. **Complete workflow automation** - ``` - TODO → PLANNING → PLANNING_REVIEW → IN_PROGRESS → AI_REVIEW → REVIEW → DONE - ``` - - Test each state transition - - Verify OpenCode session creation per phase - - Validate file generation (plans, reviews) - -2. **Error handling and recovery** - - Test timeout scenarios (30s execution limit) - - Validate failure state handling - - Test retry mechanisms - -3. **VCS integration testing** - - Test Jujutsu workspace management - - Validate Git fallback functionality - - Test conflict resolution workflows - -### Phase 4: Frontend Integration Testing -1. **API connectivity validation** - - Test all 25+ REST endpoints - - Verify Orval-generated types and hooks - - Validate real-time updates via SSE - -2. **UI workflow testing** - - Test Kanban board functionality - - Validate task detail panel updates - - Test session activity feed - -3. **Type safety validation** - - Verify no TypeScript compilation errors - - Test proper error boundary functionality - - Validate loading states and error handling - -### Phase 5: CLI Experience Testing -1. **Single-command workflow** - - Test `opencode-studio` auto-initialization - - Verify frontend download and serving - - Validate browser auto-opening - -2. **Project management** - - Test project initialization - - Verify workspace detection (jj/git) - - Test configuration management - -### Phase 6: Performance and Load Testing -1. **Concurrent operations** - - Test multiple task executions - - Verify SSE connection scaling - - Test database performance under load - -2. **Resource usage validation** - - Monitor memory usage during long operations - - Test OpenCode session cleanup - - Verify file system resource management - -### Phase 7: End-to-End Scenarios -1. **Complete user workflows** - - New user onboarding (`opencode-studio init`) - - Task creation → execution → completion - - Multiple project management - -2. **Integration scenarios** - - GitHub integration workflows - - Complex task dependencies - - Error recovery and human intervention - -### Phase 8: Documentation and Reporting -1. **Generate comprehensive test report** - - Performance benchmarks - - Feature coverage analysis - - Integration status summary - -2. **Update documentation** - - Test results and findings - - Known limitations or issues - - Recommendations for production deployment - -## 4. Potential Risks - -### High Risk -- **OpenCode integration timeouts:** The 30-second timeout issue previously identified - - *Mitigation:* Implement proper async handling and status polling - -- **SSE connection stability:** New SSE implementation under load - - *Mitigation:* Stress testing and connection recovery validation - -- **Database concurrency issues:** SQLite under concurrent access - - *Mitigation:* Transaction testing and lock contention analysis - -### Medium Risk -- **VCS workspace conflicts:** Jujutsu/Git operation conflicts - - *Mitigation:* Comprehensive conflict scenario testing - -- **Frontend state synchronization:** Real-time UI updates with SSE - - *Mitigation:* Race condition testing and state consistency validation - -- **File system race conditions:** Concurrent file operations - - *Mitigation:* Atomic operation testing and file locking validation - -### Low Risk -- **Test environment isolation:** Test data contamination - - *Mitigation:* Proper test cleanup and isolation - -- **Performance degradation:** Resource leaks during testing - - *Mitigation:* Memory and resource monitoring - -## 5. Estimated Complexity: **L (Large)** - -### Justification -- **Scope:** Comprehensive system-wide validation across 9 crates -- **Dependencies:** Integration of multiple complex systems (OpenCode, VCS, SSE) -- **Test coverage:** End-to-end workflows with real external dependencies -- **Risk factors:** Multiple integration points with potential failure modes -- **Time estimate:** 2-3 days for complete implementation and validation - -### Complexity Breakdown -- **Test infrastructure setup:** Medium (1 day) -- **Integration test implementation:** High (1-2 days) -- **Frontend/UI testing:** Medium (0.5 days) -- **Documentation and reporting:** Low (0.5 days) - -### Success Criteria -1. All existing 108+ backend tests continue to pass -2. New integration tests achieve >90% coverage of critical paths -3. Complete task lifecycle executes successfully in <30 seconds -4. SSE communication remains stable under normal load -5. CLI workflow completes successfully from init to task completion -6. Frontend UI reflects backend state changes in real-time -7. OpenCode integration executes tasks without timeout errors -8. Documentation accurately reflects current system capabilities - -### Dependencies -- OpenCode server must be running and accessible -- Test project fixtures must be prepared -- Database migrations must be current -- Frontend build must be successful -- All recent migrations (SSE, OpenCode client) must be stable - ---- - -**Next Steps:** -1. Review and approve this implementation plan -2. Set up test environment and fixtures -3. Begin Phase 1 test infrastructure setup -4. Execute phases sequentially with validation checkpoints -5. Generate final test report and recommendations \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/92361bd1-a25e-414a-a417-5a7f733c96cc.md b/.opencode-studio/kanban/plans/92361bd1-a25e-414a-a417-5a7f733c96cc.md deleted file mode 100644 index e256b55..0000000 --- a/.opencode-studio/kanban/plans/92361bd1-a25e-414a-a417-5a7f733c96cc.md +++ /dev/null @@ -1,335 +0,0 @@ -# Implementation Plan: Add Greeting Function - -## Task Overview -**Title:** Add greeting function -**Description:** Create a simple greeting.rs file in crates/core/src/ with a pub fn greet(name: &str) -> String function that returns Hello, {name}! -**Task ID:** 92361bd1-a25e-414a-a417-5a7f733c96cc -**Generated:** 2025-12-31T19:55:51Z -**Updated:** 2025-12-31T20:55:51Z -**Complexity:** S (Small) -**Estimated Time:** 5-10 minutes - -## 1. Technical Analysis - -### Current State -- The `opencode_core` crate follows a clean domain-driven architecture -- Current structure in `crates/core/src/`: - - `lib.rs` - Main module file that re-exports domain modules - - `domain/mod.rs` - Domain module aggregator (contains session.rs, task.rs) - - `error.rs` - Error handling types -- The crate exports as `opencode_core` to avoid Rust reserved word conflicts -- No existing greeting functionality present - -### Proposed Solution -Add a simple utility function at the root level of the crate. This placement is appropriate since greeting functionality is a utility function rather than core business logic, and should remain outside the domain layer. - -### Architecture Considerations -- The greeting function must be pure (no I/O) to align with the core crate's constraints -- Should follow standard Rust conventions for public APIs -- Minimal implementation with clear, testable behavior -- Follows the "NO I/O" rule for the core crate as specified in AGENTS.md - -### Dependencies & Integration -- No external dependencies required (uses only std library) -- No impact on existing workspace dependency graph -- Will be accessible as `opencode_core::greet` from other crates - -## 2. Files to Create/Modify - -### 2.1 Create `crates/core/src/greeting.rs` -**Type:** New File -**Purpose:** Contains the greeting function implementation - -**Content Structure:** -```rust -/// Generates a greeting message for the given name -/// -/// # Arguments -/// * `name` - The name to include in the greeting -/// -/// # Returns -/// A String containing "Hello, {name}!" -/// -/// # Examples -/// ``` -/// use opencode_core::greet; -/// -/// let message = greet("World"); -/// assert_eq!(message, "Hello, World!"); -/// ``` -pub fn greet(name: &str) -> String { - format!("Hello, {}!", name) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_greet_simple() { - let result = greet("World"); - assert_eq!(result, "Hello, World!"); - } - - #[test] - fn test_greet_empty_string() { - let result = greet(""); - assert_eq!(result, "Hello, !"); - } - - #[test] - fn test_greet_with_spaces() { - let result = greet("John Doe"); - assert_eq!(result, "Hello, John Doe!"); - } - - #[test] - fn test_greet_unicode() { - let result = greet("世界"); - assert_eq!(result, "Hello, 世界!"); - } -} -``` - -### 2.2 Modify `crates/core/src/lib.rs` -**Type:** File Modification -**Purpose:** Add module declaration and public re-export - -**Current Content (lines 1-6):** -```rust -pub mod domain; -pub mod error; - -pub use domain::*; -pub use error::*; -``` - -**Required Changes:** -```rust -pub mod domain; -pub mod error; -pub mod greeting; // ADD THIS LINE - -pub use domain::*; -pub use error::*; -pub use greeting::*; // ADD THIS LINE -``` - -## 3. Step-by-Step Implementation - -### Step 1: Create the greeting module -1. Navigate to `crates/core/src/` -2. Create new file `greeting.rs` -3. Implement the function with: - - Complete rustdoc documentation with examples - - Main `greet` function implementation using `format!` macro - - Comprehensive test suite covering edge cases: - - Basic functionality test - - Empty string handling - - Multi-word names with spaces - - Unicode character support - -### Step 2: Update module system -1. Open `crates/core/src/lib.rs` -2. Add `pub mod greeting;` declaration after existing module declarations -3. Add `pub use greeting::*;` re-export after existing re-exports -4. Maintain consistent formatting with existing code - -### Step 3: Verify implementation -1. **Compilation check:** `cargo check -p opencode_core` -2. **Test execution:** `cargo test -p opencode_core` -3. **Lint verification:** `cargo clippy -p opencode_core -- -D warnings` -4. **Format check:** `cargo fmt` -5. **Documentation test:** Verify rustdoc examples work correctly - -### Step 4: Integration verification -1. Verify the function can be imported as `opencode_core::greet` -2. Check that existing exports still work correctly -3. Ensure no breaking changes to the public API -4. Confirm workspace-level tests still pass: `cargo test --workspace` - -## 4. Potential Risks - -### Low Risk Items - -**4.1 Module System Integration** -- **Risk:** The module might not be properly exposed through lib.rs -- **Impact:** Function not accessible from other crates -- **Mitigation:** Follow exact pattern used by existing modules (domain, error) -- **Detection:** Test import with `use opencode_core::greet;` - -**4.2 Function Signature Compliance** -- **Risk:** Function might not match exact specification -- **Impact:** Does not meet requirements -- **Mitigation:** Implement exactly as specified: `pub fn greet(name: &str) -> String` -- **Detection:** Unit tests verify exact output format - -### Minimal Risk Items - -**4.3 Breaking Changes** -- **Risk:** New public API might conflict with existing code -- **Impact:** Build failures in dependent crates -- **Assessment:** Extremely unlikely - this is purely additive -- **Mitigation:** New function addition only, no modifications to existing code - -**4.4 Performance Impact** -- **Risk:** String allocation on each call -- **Impact:** Slight memory overhead -- **Assessment:** Acceptable for a utility function -- **Mitigation:** Using efficient `format!` macro, standard approach - -**4.5 Memory Safety** -- **Risk:** String handling issues -- **Impact:** Runtime errors or memory leaks -- **Assessment:** Negligible - using standard library functions -- **Mitigation:** Rust's memory safety guarantees apply, no unsafe code - -### Risk Mitigation Matrix - -| Risk | Likelihood | Impact | Mitigation Strategy | -|------|------------|---------|-------------------| -| Module integration | Low | Medium | Follow existing patterns exactly | -| Function signature | Very Low | Medium | Implement per spec, test thoroughly | -| Breaking changes | Very Low | High | Additive changes only | -| Performance | Low | Low | Accept trade-off for simplicity | -| Memory safety | Very Low | High | Use standard library only | - -## 5. Testing Strategy - -### 5.1 Unit Tests (Included in implementation) -```rust -#[test] -fn test_greet_simple() { - let result = greet("World"); - assert_eq!(result, "Hello, World!"); -} - -#[test] -fn test_greet_empty_string() { - let result = greet(""); - assert_eq!(result, "Hello, !"); -} - -#[test] -fn test_greet_with_spaces() { - let result = greet("John Doe"); - assert_eq!(result, "Hello, John Doe!"); -} - -#[test] -fn test_greet_unicode() { - let result = greet("世界"); - assert_eq!(result, "Hello, 世界!"); -} -``` - -### 5.2 Integration Tests -- **Module Export Test:** Verify `use opencode_core::greet` works from external code -- **Documentation Test:** Ensure rustdoc examples compile and run correctly -- **Workspace Test:** Confirm no regressions in other crates - -### 5.3 Verification Commands -```bash -# 1. Compilation verification -cargo check -p opencode_core - -# 2. Test execution -cargo test -p opencode_core - -# 3. Lint checking (strict warnings) -cargo clippy -p opencode_core -- -D warnings - -# 4. Format verification -cargo fmt --check - -# 5. Workspace-wide test -cargo test --workspace - -# 6. Documentation test -cargo test --doc -p opencode_core -``` - -### 5.4 Test Coverage Expectations -- **Function coverage:** 100% (all branches covered) -- **Edge case coverage:** 90%+ (empty strings, Unicode, spaces) -- **Documentation coverage:** 100% (all examples tested) - -## 6. Estimated Complexity: S (Small) - -### 6.1 Complexity Justification -- **Single function implementation** - minimal scope -- **No external dependencies** - uses only std library -- **No database changes** - pure function only -- **No API modifications** - internal utility function -- **Straightforward testing** - clear input/output relationship -- **Well-defined scope** - exact specification provided -- **Zero breaking changes** - additive only - -### 6.2 Time Estimation Breakdown -| Activity | Estimated Time | Percentage | -|----------|---------------|------------| -| File creation & function implementation | 3-5 minutes | 40% | -| Test suite development | 2-3 minutes | 25% | -| Module integration (lib.rs) | 1-2 minutes | 15% | -| Documentation & rustdoc | 2-3 minutes | 20% | -| **Total Implementation Time** | **8-13 minutes** | **100%** | - -### 6.3 Confidence Assessment -- **Confidence Level:** Very High (95%+) -- **Risk of overrun:** Very Low -- **Complexity creep potential:** None (scope well-defined) -- **Dependency on external factors:** None - -## 7. Success Criteria - -### 7.1 Functional Requirements -- [ ] Function `greet(name: &str) -> String` exists and is publicly accessible -- [ ] Function returns exactly `"Hello, {name}!"` format for any input -- [ ] Function handles edge cases gracefully (empty strings, Unicode, spaces) -- [ ] Function is accessible as `opencode_core::greet` from external crates -- [ ] All test cases pass successfully - -### 7.2 Technical Requirements -- [ ] Code compiles without errors: `cargo check -p opencode_core` -- [ ] All tests pass: `cargo test -p opencode_core` -- [ ] Lint checks pass: `cargo clippy -p opencode_core -- -D warnings` -- [ ] Code formatting is correct: `cargo fmt --check` -- [ ] Documentation tests pass: `cargo test --doc -p opencode_core` -- [ ] Workspace tests still pass: `cargo test --workspace` - -### 7.3 Code Quality Requirements -- [ ] Function includes comprehensive rustdoc documentation -- [ ] Documentation includes working examples -- [ ] Test coverage > 90% for new code -- [ ] Follows project Rust conventions and style guidelines -- [ ] No new clippy warnings introduced -- [ ] Maintains crate's "no I/O" constraint - -### 7.4 Integration Requirements -- [ ] Module properly declared in `lib.rs` -- [ ] Function properly exported through `pub use` -- [ ] No conflicts with existing module names -- [ ] No breaking changes to existing API surface -- [ ] Function works from other crates in workspace - -## 8. Implementation Notes - -### 8.1 Design Decisions -- **Placement:** Root level of crate (not in domain/) since this is utility functionality -- **Error Handling:** Minimal - `format!` cannot fail with basic string inputs -- **Performance:** Accepting String allocation for simplicity and clarity -- **API Design:** Using `&str` parameter for efficiency (no unnecessary allocations) - -### 8.2 Code Style Adherence -- Follow existing rustdoc comment patterns -- Use consistent indentation and formatting -- Include comprehensive examples in documentation -- Maintain inline test pattern: `#[cfg(test)] mod tests` - -### 8.3 Future Extensibility -- Function is designed to be self-contained -- Could be extended later for internationalization -- Template-based greeting formats could be added -- No architectural constraints for future enhancements - -This implementation plan ensures a clean, well-tested, and properly integrated greeting function that follows all project conventions and requirements. \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/9976ffdf-9ff8-44f7-85c4-b71602352831.md b/.opencode-studio/kanban/plans/9976ffdf-9ff8-44f7-85c4-b71602352831.md deleted file mode 100644 index 3a17e78..0000000 --- a/.opencode-studio/kanban/plans/9976ffdf-9ff8-44f7-85c4-b71602352831.md +++ /dev/null @@ -1,262 +0,0 @@ -# SSE Test 3 - Implementation Plan - -## Task Overview -**Title:** SSE Test 3 -**Description:** test -**Complexity:** M (Medium) -**Estimated Time:** 4-6 hours - -## Technical Analysis - -### Context -This is the third iteration of Server-Sent Events (SSE) testing for OpenCode Studio. Previous tests identified several issues: - -1. `/api/sessions/{id}/activity` endpoint returning empty responses -2. `POST /api/tasks/{id}/execute` timing out after 30 seconds -3. Task status discrepancies between OpenCode completion and Studio DB -4. Need for comprehensive real-time event verification - -### Current SSE Infrastructure Status -- ✅ Backend SSE Infrastructure (Feature 1) - Complete -- ✅ Frontend SSE Hooks (Feature 2) - Complete -- ✅ Backend Activity Message Serialization (Feature 3) - Complete -- 🔄 WebSocket Code Cleanup (Feature 4) - In progress -- ⏳ Documentation & Testing (Feature 5) - Pending - -### Test Objectives -Based on the migration status and previous test results, this test should focus on: - -1. **Session Activity Stream Validation** - Fix empty activity responses -2. **Task Lifecycle Event Integrity** - Ensure real-time status updates work end-to-end -3. **SSE Connection Resilience** - Test auto-reconnect and event replay -4. **Frontend Hook Integration** - Verify `useEventStream` and `useSessionActivitySSE` -5. **Load Testing** - Multiple concurrent SSE connections - -## Files to Modify/Create - -### Test Files to Create -``` -tests/integration/ -├── sse_test_3.rs # Main integration test -├── helpers/ -│ ├── sse_client.rs # SSE client for testing -│ └── task_lifecycle_helper.rs # Task creation/execution helpers -└── fixtures/ - └── test_tasks.json # Test task definitions -``` - -### Files to Potentially Modify -``` -crates/server/src/ -├── routes/sessions.rs # Session activity endpoint fixes -├── routes/events.rs # Global SSE endpoint improvements -└── routes/tasks.rs # Task execution timeout handling - -crates/orchestrator/src/ -├── executor.rs # Event emission during task execution -└── activity_store.rs # Activity message persistence - -crates/events/src/ -├── bus.rs # Event bus reliability improvements -└── types.rs # Event type definitions - -frontend/src/ -├── hooks/useEventStream.ts # Connection resilience testing -├── hooks/useSessionActivitySSE.ts # Session-specific SSE testing -└── __tests__/ - └── sse-hooks.test.tsx # Frontend hook unit tests -``` - -## Step-by-Step Implementation - -### Phase 1: Diagnostic Investigation (1-2 hours) -1. **Reproduce Previous Issues** - - Set up task execution with SSE monitoring - - Capture network traffic for `/api/sessions/{id}/activity` - - Document exact failure scenarios - -2. **Activity Store Audit** - - Verify `ActivityStore` is properly storing session messages - - Check database state after task execution - - Validate event emission timing - -3. **SSE Endpoint Analysis** - - Test `/api/events` global stream - - Test `/api/sessions/{id}/activity` per-session stream - - Verify EventBuffer functionality - -### Phase 2: Backend Fixes (1-2 hours) -1. **Session Activity Endpoint Fix** - ```rust - // In crates/server/src/routes/sessions.rs - async fn get_session_activity( - Path(session_id): Path, - State(app_state): State, - ) -> Result { - // Fix: Ensure activity messages are properly retrieved - // Fix: Verify SSE formatting of activity events - } - ``` - -2. **Task Execution Timeout Handling** - ```rust - // In crates/server/src/routes/tasks.rs - async fn execute_task( - Path(task_id): Path, - State(app_state): State, - ) -> Result { - // Fix: Implement proper async task execution - // Fix: Return immediately with 202 Accepted - // Fix: Use background processing for long-running tasks - } - ``` - -3. **Event Emission Verification** - ```rust - // In crates/orchestrator/src/executor.rs - // Ensure proper event emission at each lifecycle stage: - // - task.status_changed (TODO → PLANNING → IN_PROGRESS → etc.) - // - session.started - // - session.activity (for each OpenCode interaction) - // - session.completed - ``` - -### Phase 3: Comprehensive Integration Test (1-2 hours) -1. **Create SSE Test Client** - ```rust - // tests/integration/helpers/sse_client.rs - struct SSETestClient { - client: reqwest::Client, - base_url: String, - } - - impl SSETestClient { - async fn connect_global_stream(&self) -> SSEStream; - async fn connect_session_stream(&self, session_id: Uuid) -> SSEStream; - async fn wait_for_event(&mut self, event_type: &str, timeout: Duration) -> Option; - } - ``` - -2. **Full Task Lifecycle Test** - ```rust - // tests/integration/sse_test_3.rs - #[tokio::test] - async fn test_complete_task_lifecycle_with_sse() { - // 1. Connect to global SSE stream - // 2. Create a test task - // 3. Execute task (non-blocking) - // 4. Monitor SSE events for: - // - task.status_changed events - // - session.started event - // - session.activity events - // - session.completed event - // 5. Verify final task status in database - // 6. Verify session activity history - } - ``` - -3. **Concurrent Connection Test** - ```rust - #[tokio::test] - async fn test_multiple_concurrent_sse_connections() { - // Test 5-10 concurrent SSE connections - // Verify all receive the same events - // Test connection drops and reconnects - } - ``` - -### Phase 4: Frontend Integration Verification (30-60 minutes) -1. **Hook Testing** - ```typescript - // frontend/src/__tests__/sse-hooks.test.tsx - describe('SSE Hooks', () => { - test('useEventStream handles reconnection', () => { - // Test auto-reconnect functionality - }); - - test('useSessionActivitySSE receives activity events', () => { - // Test session-specific activity stream - }); - }); - ``` - -2. **Manual Browser Testing** - - Open developer tools Network tab - - Execute a task through the UI - - Verify SSE connections in Network tab - - Verify real-time UI updates - -### Phase 5: Documentation and Cleanup (30 minutes) -1. **Update Test Documentation** - - Document test results in AGENTS.md - - Update SSE migration status - - Note any remaining issues - -2. **Clean Up Test Artifacts** - - Remove temporary test files if needed - - Ensure no test data pollution in database - -## Potential Risks - -### High Risk -1. **Activity Store Race Conditions** - - Risk: Events emitted before ActivityStore is ready - - Mitigation: Add proper synchronization and event ordering - -2. **Database Transaction Issues** - - Risk: Task status updates in separate transactions causing inconsistency - - Mitigation: Use database transactions properly for state changes - -### Medium Risk -1. **SSE Connection Limits** - - Risk: Too many concurrent connections could overwhelm server - - Mitigation: Implement connection limits and graceful degradation - -2. **Event Message Size** - - Risk: Large activity messages could cause SSE performance issues - - Mitigation: Implement message size limits and pagination - -### Low Risk -1. **Browser SSE Implementation Differences** - - Risk: Different browsers handle SSE differently - - Mitigation: Test in multiple browsers, use EventSource polyfill if needed - -2. **Network Connectivity Issues** - - Risk: Flaky network causing test failures - - Mitigation: Implement proper retry logic in tests - -## Expected Outcomes - -### Success Criteria -1. ✅ `/api/sessions/{id}/activity` returns proper activity events -2. ✅ Task execution no longer times out on the API level -3. ✅ Real-time task status updates work end-to-end -4. ✅ Multiple concurrent SSE connections work reliably -5. ✅ Frontend hooks properly handle reconnection and event replay -6. ✅ All existing tests continue to pass (108+ backend tests) -7. ✅ Clean clippy run with `-D warnings` - -### Performance Targets -- SSE connection establishment: < 100ms -- Event delivery latency: < 50ms -- Support for 20+ concurrent SSE connections -- Task execution API response: < 1 second (returns 202 Accepted) - -### Deliverables -1. **Fixed SSE Endpoints** - Session activity and global event streams working properly -2. **Comprehensive Integration Tests** - Full task lifecycle with SSE monitoring -3. **Performance Validation** - Concurrent connection handling verified -4. **Updated Documentation** - AGENTS.md reflects SSE testing status -5. **Frontend Validation** - UI real-time updates working properly - -## Next Steps After Completion - -1. **Feature 4 Completion** - Continue WebSocket code cleanup -2. **Feature 5 Implementation** - Complete documentation & testing phase -3. **Production Readiness** - Implement monitoring and alerting for SSE health -4. **Load Testing** - More comprehensive performance testing with realistic loads - ---- - -*Generated: 2025-01-01T01:36:13Z* -*Task ID: 9976ffdf-9ff8-44f7-85c4-b71602352831* \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/9f333a20-9cff-4b76-82a3-b33115066584.md b/.opencode-studio/kanban/plans/9f333a20-9cff-4b76-82a3-b33115066584.md deleted file mode 100644 index 3c2c759..0000000 --- a/.opencode-studio/kanban/plans/9f333a20-9cff-4b76-82a3-b33115066584.md +++ /dev/null @@ -1,132 +0,0 @@ -# Implementation Plan: Změň title aplikace na BiCom Platform v2 - -**Task ID:** 9f333a20-9cff-4b76-82a3-b33115066584 -**Created:** 2025-01-01T01:36:00Z -**Estimated Complexity:** S (Small) - -## Technical Analysis - -The task requires changing the application title from "OpenCode Studio" to "BiCom Platform v2" across multiple locations in the codebase. Based on codebase analysis, the application name appears in: - -1. **Frontend HTML title** - Main browser tab title -2. **Backend API specification** - OpenAPI documentation -3. **CLI tool descriptions** - Command-line interface messages -4. **Package metadata** - NPM package naming -5. **Generated API files** - Auto-generated from OpenAPI spec (will update automatically) - -The change is primarily cosmetic and affects user-facing strings without modifying core functionality. - -## Files to Modify - -### Primary Files (Manual Changes Required) - -| File | Line(s) | Current Value | New Value | -|------|---------|---------------|-----------| -| `frontend/index.html` | 7 | `OpenCode Studio` | `BiCom Platform v2` | -| `crates/server/src/lib.rs` | 19 | `title = "OpenCode Studio API"` | `title = "BiCom Platform v2 API"` | -| `crates/server/src/lib.rs` | 21 | `description = "API for OpenCode Studio - AI-powered development platform"` | `description = "API for BiCom Platform v2 - AI-powered development platform"` | -| `crates/cli/src/main.rs` | 52, 58, 248, 308, 423, 549, 617 | Various "OpenCode Studio" references | Replace with "BiCom Platform v2" | -| `crates/cli/Cargo.toml` | 5 | `description = "CLI for OpenCode Studio - AI-powered development platform"` | `description = "CLI for BiCom Platform v2 - AI-powered development platform"` | -| `frontend/package.json` | 2 | `"name": "opencode-studio"` | `"name": "bicom-platform-v2"` | - -### Auto-Generated Files (No Manual Changes) - -- **All files in `frontend/src/api/generated/`** - These will be automatically updated when the OpenAPI spec is regenerated after changing `crates/server/src/lib.rs` - -### Documentation Files (Optional - Depends on Scope) - -- `agents.md` - Root documentation -- `product-prd.md` - Product requirements document -- `frontend/AGENTS.md` - Frontend documentation -- `crates/AGENTS.md` - Backend documentation -- Various roadmap files - -## Step-by-Step Implementation - -### Phase 1: Core Application Files -1. **Update frontend HTML title** - - Modify `frontend/index.html` line 7 - - Change `OpenCode Studio` to `BiCom Platform v2` - -2. **Update backend API specification** - - Modify `crates/server/src/lib.rs` lines 19 and 21 - - Update OpenAPI title and description - -3. **Update CLI package description** - - Modify `crates/cli/Cargo.toml` line 5 - - Update package description - -### Phase 2: CLI Messages -4. **Update CLI user messages** - - Modify `crates/cli/src/main.rs` - - Replace all instances of "OpenCode Studio" with "BiCom Platform v2" in user-facing messages - - Lines to update: 52, 58, 248, 308, 423, 549, 617 - -### Phase 3: Package Metadata -5. **Update frontend package name** - - Modify `frontend/package.json` line 2 - - Change package name from "opencode-studio" to "bicom-platform-v2" - -### Phase 4: Regenerate API Client -6. **Regenerate frontend API client** - - Run `cd frontend && pnpm generate:api` - - This will update all auto-generated API files with new titles - -### Phase 5: Verification -7. **Build and test** - - Run `pnpm build` to ensure no build errors - - Test frontend in browser to verify title appears correctly - - Verify CLI help messages show new name - - Check OpenAPI documentation at `/swagger-ui` - -## Potential Risks - -### Low Risk Issues -- **Browser caching:** Users might need to hard refresh to see the new title -- **Package name conflicts:** New NPM package name might conflict (unlikely with private package) - -### Medium Risk Issues -- **Documentation inconsistency:** Documentation files might contain stale references if not updated -- **CLI script references:** Any deployment or build scripts referencing the old name might break - -### Mitigation Strategies -- **Test thoroughly:** Run full build and manual testing -- **Clear documentation:** Update key documentation files if within scope -- **Gradual rollout:** Deploy to staging environment first - -## Testing Checklist - -- [ ] Frontend title displays "BiCom Platform v2" in browser tab -- [ ] CLI `--help` shows new application name -- [ ] OpenAPI documentation at `/swagger-ui` shows new API title -- [ ] Build completes without errors (`pnpm build`) -- [ ] Frontend package installs correctly -- [ ] Generated API client files contain new references - -## Success Criteria - -1. **Browser tab title** shows "BiCom Platform v2" -2. **CLI tool** references new name in all user messages -3. **API documentation** reflects new branding -4. **No build errors** after changes -5. **All generated files** updated automatically - -## Estimated Complexity: S (Small) - -**Rationale:** -- Simple string replacements in known locations -- No logic changes required -- Auto-generation handles most derivative files -- Low risk of breaking functionality -- Estimated time: 30-60 minutes including testing - -## Dependencies - -- **None** - This is a standalone cosmetic change -- **Build tools** - Requires functional build environment for regeneration and testing - -## Notes - -- Consider updating major documentation files (`agents.md`, `product-prd.md`) if this is part of a larger rebranding effort -- The package name change in `frontend/package.json` is cosmetic for a private package but maintains consistency -- All generated API client files will automatically reflect the new name after regeneration \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/aaa6885f-7257-47ad-b1a9-d0818708cd49.md b/.opencode-studio/kanban/plans/aaa6885f-7257-47ad-b1a9-d0818708cd49.md deleted file mode 100644 index e9e1c54..0000000 --- a/.opencode-studio/kanban/plans/aaa6885f-7257-47ad-b1a9-d0818708cd49.md +++ /dev/null @@ -1,173 +0,0 @@ -# Implementation Plan: SSE Test 2 - -## Task Overview -- **Title:** SSE Test 2 -- **Description:** test -- **Type:** Testing/Verification -- **Priority:** Medium - -## Technical Analysis - -### Context -This task appears to be a follow-up test for the Server-Sent Events (SSE) functionality in OpenCode Studio. The system has recently migrated from WebSocket to SSE for real-time communication, and previous testing revealed some issues that need verification. - -### Current SSE Infrastructure -- **Backend SSE Endpoints:** - - `/api/events` - Global SSE event stream - - `/api/sessions/{id}/activity` - Per-session activity stream -- **Frontend Hooks:** - - `useEventStream` - Global events with auto-reconnect - - `useSessionActivitySSE` - Session-specific activity with history replay -- **Event Types:** - - `task.status_changed` - Task lifecycle updates - - `session.started` - OpenCode session initialization - - `session.ended` - OpenCode session completion - - Activity messages for ongoing session operations - -### Known Issues from Previous Testing -1. `/api/sessions/{id}/activity` endpoint returning empty responses -2. Potential task status synchronization issues between Studio DB and OpenCode -3. 30-second timeout on `/api/tasks/{id}/execute` endpoint -4. Need to verify SSE reconnection and history replay functionality - -## Files to Modify/Create - -### Test Files to Create -1. **`tests/integration/sse_integration_test.rs`** - Comprehensive SSE integration tests -2. **`frontend/src/__tests__/hooks/useEventStream.test.ts`** - Frontend SSE hook tests -3. **`frontend/src/__tests__/hooks/useSessionActivitySSE.test.ts`** - Session activity hook tests - -### Files to Potentially Modify -1. **`crates/server/src/routes/events.rs`** - Event stream endpoint (if issues found) -2. **`crates/server/src/routes/sessions.rs`** - Session activity endpoint (if fixes needed) -3. **`crates/events/src/bus.rs`** - Event bus logic (if event propagation issues) -4. **`frontend/src/hooks/useEventStream.ts`** - Global event stream hook (if improvements needed) -5. **`frontend/src/hooks/useSessionActivitySSE.ts`** - Session activity hook (if fixes required) - -### Configuration/Documentation -1. **Update test documentation in relevant README files** -2. **Add SSE testing guidelines to AGENTS.md if patterns are established** - -## Step-by-Step Implementation Steps - -### Phase 1: Backend SSE Testing (2-3 hours) -1. **Create integration test framework** - - Set up test client for SSE connections - - Create helper functions for event assertion - - Test connection establishment and basic event flow - -2. **Test global events endpoint (`/api/events`)** - - Verify connection establishment - - Test event broadcasting for task status changes - - Test session lifecycle events (started/ended) - - Verify event format and JSON serialization - -3. **Test session activity endpoint (`/api/sessions/{id}/activity`)** - - Create test session and verify activity stream - - Test real-time activity message propagation - - Verify session-specific filtering - - Test behavior with non-existent session IDs - -4. **Test reconnection and buffering** - - Verify EventBuffer functionality for missed events - - Test client disconnect/reconnect scenarios - - Validate event ordering and deduplication - -### Phase 2: Frontend SSE Testing (2-3 hours) -1. **Test useEventStream hook** - - Mock SSE connection and verify hook behavior - - Test auto-reconnect functionality - - Verify proper cleanup on unmount - - Test error handling and retry logic - -2. **Test useSessionActivitySSE hook** - - Verify session-specific event filtering - - Test history replay functionality - - Test real-time activity updates - - Verify proper subscription management - -3. **Integration testing with backend** - - Test end-to-end event flow from backend to frontend - - Verify proper React state updates - - Test multiple concurrent connections - -### Phase 3: Task Lifecycle Integration Testing (2-4 hours) -1. **Test complete task execution flow** - - Create task via API - - Execute task and monitor SSE events - - Verify status transitions via SSE - - Confirm session activity stream updates - -2. **Test edge cases** - - Task execution failures - - Network interruptions during execution - - Concurrent task operations - - Session timeout scenarios - -3. **Performance testing** - - Test with multiple concurrent SSE connections - - Verify memory usage with EventBuffer - - Test event throughput under load - -### Phase 4: Documentation and Cleanup (1 hour) -1. **Document test patterns and findings** -2. **Update AGENTS.md with SSE testing guidelines** -3. **Clean up any temporary test utilities** -4. **Ensure all tests pass in CI/CD pipeline** - -## Potential Risks - -### High Risk -- **Event loss during reconnection**: If EventBuffer isn't working correctly, clients might miss critical events -- **Memory leaks**: Improper SSE connection cleanup could cause server memory issues -- **Race conditions**: Concurrent task operations might cause event ordering issues - -### Medium Risk -- **Frontend state synchronization**: React state updates from SSE events might cause rendering issues -- **Authentication in SSE**: Long-lived SSE connections might face auth token expiration -- **Cross-browser compatibility**: SSE implementation might behave differently across browsers - -### Low Risk -- **Test environment setup**: Integration tests might require specific database states -- **Mock complexity**: Frontend tests might need complex SSE mocking -- **Documentation drift**: Test documentation might become outdated - -## Mitigation Strategies - -1. **For event loss**: Implement comprehensive integration tests that verify EventBuffer behavior -2. **For memory leaks**: Add monitoring and stress tests for SSE connections -3. **For race conditions**: Use proper event sequencing and add concurrent operation tests -4. **For state sync**: Test React state updates thoroughly with SSE event mocks -5. **For auth issues**: Test SSE connections with token refresh scenarios - -## Success Criteria - -- [ ] All SSE endpoints respond correctly with proper event formatting -- [ ] Frontend hooks handle SSE events reliably with proper state updates -- [ ] Event buffering and reconnection work as expected -- [ ] Complete task lifecycle generates appropriate SSE events -- [ ] No memory leaks or connection issues under normal load -- [ ] All integration tests pass consistently -- [ ] Documentation updated with testing patterns - -## Estimated Complexity: **M (Medium)** - -**Justification:** -- **Moderate scope**: Testing existing SSE infrastructure rather than building new features -- **Known domain**: SSE patterns are well-established, testing approaches are standard -- **Existing codebase**: Building on completed SSE migration work -- **Clear requirements**: Verification of known functionality with specific issue areas identified -- **Manageable risk**: Issues are likely configuration or edge-case related rather than architectural - -**Time Estimate:** 6-10 hours total -- Backend testing: 2-3 hours -- Frontend testing: 2-3 hours -- Integration testing: 2-4 hours -- Documentation: 1 hour - -## Notes - -- This test should focus on validating the completed SSE migration rather than implementing new features -- Pay special attention to the session activity endpoint which showed issues in previous testing -- Consider adding automated tests to prevent regression of SSE functionality -- The "test" description suggests this might be exploratory - be prepared to expand scope based on findings \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/c36bdcae-886d-4f9d-bb2c-0de0056bd07c.md b/.opencode-studio/kanban/plans/c36bdcae-886d-4f9d-bb2c-0de0056bd07c.md deleted file mode 100644 index 820d300..0000000 --- a/.opencode-studio/kanban/plans/c36bdcae-886d-4f9d-bb2c-0de0056bd07c.md +++ /dev/null @@ -1,59 +0,0 @@ -# Planning: Ahoj - -**Task ID:** c36bdcae-886d-4f9d-bb2c-0de0056bd07c -**Created:** 2025-12-31 - ---- - -## 1. Technical Analysis - -**Status: BLOCKED - Insufficient Specification** - -The task title "Ahoj" and description "Ahoj" contain no actionable requirements. "Ahoj" is a Czech/Slovak greeting meaning "Hello" - this appears to be either: -- A test/placeholder task -- An incomplete task submission -- A greeting intended for a human, not a task specification - -**No technical analysis possible** without understanding: -- What feature, fix, or change is requested? -- What problem needs to be solved? -- What is the expected outcome? - ---- - -## 2. Files to Modify/Create - -**Unknown** - Cannot determine without task specification. - ---- - -## 3. Step-by-Step Implementation - -**Cannot be determined** - No requirements provided. - ---- - -## 4. Potential Risks - -| Risk | Impact | Mitigation | -|------|--------|------------| -| Implementing without clear requirements | High | Request clarification before proceeding | -| Misinterpreting intent | High | Confirm understanding with stakeholder | - ---- - -## 5. Estimated Complexity - -**N/A** - Cannot estimate without understanding scope. - ---- - -## Recommendation - -**ACTION REQUIRED:** Please provide a clear task description that includes: -1. What needs to be done (feature, bug fix, refactor, etc.) -2. Where in the codebase this applies -3. Expected behavior or outcome -4. Any relevant context or constraints - -Once specification is provided, this plan will be updated with actionable implementation steps. diff --git a/.opencode-studio/kanban/plans/ce214e5a-749c-444b-9f51-dac91cc93389.md b/.opencode-studio/kanban/plans/ce214e5a-749c-444b-9f51-dac91cc93389.md deleted file mode 100644 index 2e32191..0000000 --- a/.opencode-studio/kanban/plans/ce214e5a-749c-444b-9f51-dac91cc93389.md +++ /dev/null @@ -1,149 +0,0 @@ -# E2E SSE Test Implementation Plan - -**Task:** E2E SSE Test -**Description:** Say hello world and nothing else -**Created:** 2025-01-01T18:55:51Z -**Complexity:** S (Small) - -## Technical Analysis - -### Overview -Create a simple end-to-end test for the Server-Sent Events (SSE) infrastructure that verifies a "hello world" message can be sent and received through the SSE pipeline. This test will validate the complete SSE flow from backend emission to frontend reception. - -### Current SSE Infrastructure (Based on Existing Codebase) -- **Backend SSE Infrastructure:** ✅ Complete with SSE endpoints and EventBuffer -- **Frontend SSE Hooks:** ✅ Complete with `useEventStream` and `useSessionActivitySSE` -- **Event System:** Events crate with tokio::broadcast bus -- **Existing Endpoints:** `/api/events` (global), `/api/sessions/{id}/activity` (per-session) - -### Test Scope -- **Type:** Integration test (E2E) -- **Objective:** Verify SSE message delivery with minimal "hello world" payload -- **Coverage:** Backend emission → Network transport → Frontend reception - -## Files to Modify/Create - -### 1. Test Endpoint (Backend) -**Create:** `crates/server/src/routes/test_sse.rs` -- Simple test-only SSE endpoint that emits "hello world" -- Should be conditionally compiled for test builds only - -### 2. Route Registration -**Modify:** `crates/server/src/routes/mod.rs` -- Add test_sse module import (conditional) -- Register test route in router - -### 3. E2E Test File -**Create:** `crates/server/tests/e2e_sse_test.rs` -- Integration test that starts server and connects to SSE endpoint -- Validates "hello world" message reception - -### 4. Test Configuration -**Modify:** `crates/server/Cargo.toml` -- Add any additional test dependencies if needed - -## Step-by-Step Implementation - -### Phase 1: Create Test SSE Endpoint -1. **Create test endpoint** (`crates/server/src/routes/test_sse.rs`) - ```rust - #[cfg(test)] - use axum::response::sse::{Event, Sse}; - - // Simple endpoint that sends "hello world" via SSE - pub async fn hello_world_sse() -> Sse>> { - // Implementation details... - } - ``` - -2. **Register route conditionally** in `crates/server/src/routes/mod.rs` - ```rust - #[cfg(test)] - pub mod test_sse; - ``` - -3. **Add route to router** (test builds only) - -### Phase 2: Create E2E Test -1. **Create integration test** (`crates/server/tests/e2e_sse_test.rs`) - - Use `tokio_test` or similar for async testing - - Start test server instance - - Create SSE client connection - - Listen for "hello world" message - - Assert message content and timing - -2. **Test structure:** - ```rust - #[tokio::test] - async fn test_hello_world_sse() { - // 1. Start test server - // 2. Connect SSE client to /test/hello-world-sse - // 3. Wait for "hello world" message - // 4. Assert message received correctly - // 5. Cleanup - } - ``` - -### Phase 3: Validation & Cleanup -1. **Run test:** `cargo test test_hello_world_sse` -2. **Verify:** Test passes and SSE message flows correctly -3. **Documentation:** Add test description to codebase docs -4. **Cleanup:** Ensure test endpoint is only available in test builds - -## Potential Risks - -### Low Risk -- **Test Isolation:** Test endpoint might interfere with production routes - - *Mitigation:* Use `#[cfg(test)]` conditional compilation -- **Port Conflicts:** Test server might conflict with running dev server - - *Mitigation:* Use dynamic port allocation in tests - -### Medium Risk -- **SSE Connection Timing:** Race conditions between server start and client connect - - *Mitigation:* Add proper wait mechanisms and timeouts -- **Test Flakiness:** Network-dependent test might be unstable - - *Mitigation:* Use localhost only, reasonable timeouts - -### Very Low Risk -- **Message Format:** SSE event format might not match expectations - - *Mitigation:* Use existing SSE infrastructure patterns - -## Success Criteria - -1. ✅ Test endpoint successfully emits "hello world" via SSE -2. ✅ E2E test successfully receives the message -3. ✅ Test runs reliably in CI environment -4. ✅ No impact on production code (test-only compilation) -5. ✅ Test completes within reasonable time (< 5 seconds) - -## Complexity Assessment: S (Small) - -**Justification:** -- **SSE Infrastructure:** Already exists and working -- **Test Pattern:** Follows existing integration test patterns -- **Scope:** Minimal ("hello world" only) -- **Dependencies:** Uses existing libraries -- **Time Estimate:** 1-2 hours - -**Complexity Breakdown:** -- Backend endpoint: 30 minutes -- E2E test setup: 45 minutes -- Testing & refinement: 30 minutes -- Documentation: 15 minutes - -## Dependencies - -**Required:** -- Existing SSE infrastructure (✅ Available) -- Axum testing utilities (✅ Available) -- Tokio test runtime (✅ Available) - -**Optional:** -- Additional SSE client libraries (if eventsource crate insufficient) - -## Notes - -- This test serves as a foundation for more complex SSE testing -- Can be extended later for multi-message scenarios -- Validates the complete SSE pipeline with minimal overhead -- Aligns with existing test patterns in the codebase \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/d0f5a117-4a01-446f-9073-e08298aee88b.md b/.opencode-studio/kanban/plans/d0f5a117-4a01-446f-9073-e08298aee88b.md deleted file mode 100644 index 8aeb05c..0000000 --- a/.opencode-studio/kanban/plans/d0f5a117-4a01-446f-9073-e08298aee88b.md +++ /dev/null @@ -1,218 +0,0 @@ -# Test SSE Implementation Plan - -**Task ID:** d0f5a117-4a01-446f-9073-e08298aee88b -**Title:** Test SSE -**Description:** test -**Generated:** 2026-01-01T01:36:13Z - -## 1. Technical Analysis - -### Current SSE Implementation State -Based on the codebase analysis, OpenCode Studio has completed a migration from WebSocket to Server-Sent Events (SSE) for real-time communication. The current implementation includes: - -**Backend SSE Infrastructure:** -- Global events endpoint: `/api/events` -- Session-specific events: `/api/sessions/{id}/activity` -- `EventBuffer` for reconnection handling -- Event types: `task.status_changed`, `session.started`, `session.ended` - -**Frontend SSE Hooks:** -- `useEventStream` for global events with auto-reconnect -- `useSessionActivitySSE` for per-session activity with history replay - -**Known Issues to Address:** -- `/api/sessions/{id}/activity` endpoint returning empty (identified in previous testing) -- Task status update failures after OpenCode execution completion -- Potential synchronous behavior issues in execute endpoint - -### Testing Scope -This task requires comprehensive testing of: -1. SSE connection establishment and maintenance -2. Event delivery reliability and ordering -3. Reconnection behavior and history replay -4. Cross-browser compatibility -5. Concurrent connection handling -6. Performance under load -7. Error handling and edge cases - -## 2. Files to Modify/Create - -### New Test Files -``` -crates/server/src/routes/events_test.rs # Backend SSE endpoint tests -crates/orchestrator/src/activity_store_test.rs # Event buffer tests -frontend/src/hooks/useEventStream.test.ts # Frontend SSE hook tests -frontend/src/hooks/useSessionActivitySSE.test.ts # Session SSE tests -tests/integration/sse_integration_test.rs # E2E SSE tests -tests/performance/sse_load_test.rs # Load testing -``` - -### Existing Files to Modify -``` -crates/server/src/routes/events.rs # Add test utilities -crates/orchestrator/src/activity_store.rs # Add test helpers -frontend/src/hooks/useEventStream.ts # Add debug logging -frontend/src/hooks/useSessionActivitySSE.ts # Add debug logging -``` - -### Test Utilities to Create -``` -tests/utils/sse_test_server.rs # Mock SSE server -tests/utils/sse_client.rs # Test SSE client -frontend/src/test-utils/sse-mocks.ts # Frontend SSE mocks -``` - -## 3. Step-by-Step Implementation Steps - -### Phase 1: Backend Unit Tests (Days 1-2) -1. **EventBuffer Testing** - - Test event storage and retrieval - - Test buffer size limits and cleanup - - Test concurrent access safety - - Test history replay functionality - -2. **SSE Endpoints Testing** - - Test `/api/events` connection establishment - - Test event serialization and delivery - - Test connection lifecycle management - - Test error handling for invalid connections - -3. **Event Bus Testing** - - Test event publishing reliability - - Test subscriber management - - Test event filtering and routing - - Test memory cleanup on disconnect - -### Phase 2: Frontend Unit Tests (Days 2-3) -1. **useEventStream Hook Testing** - - Test connection establishment with EventSource API - - Test auto-reconnection logic and backoff - - Test event parsing and state management - - Test cleanup on unmount - -2. **useSessionActivitySSE Hook Testing** - - Test session-specific event filtering - - Test history replay from EventBuffer - - Test connection management per session - - Test error boundary behavior - -3. **Component Integration Testing** - - Test SSE hooks integration with React Query - - Test real-time UI updates from SSE events - - Test loading states during connection - - Test error states and user feedback - -### Phase 3: Integration Tests (Days 3-4) -1. **End-to-End SSE Flow** - - Test complete task lifecycle with SSE events - - Test session creation → progress → completion flow - - Test event ordering and consistency - - Test data synchronization between frontend/backend - -2. **Cross-Component Event Flow** - - Test Kanban board real-time updates - - Test session activity feed updates - - Test task detail panel synchronization - - Test notification system integration - -3. **Error Scenario Testing** - - Test network interruption and recovery - - Test server restart during active connections - - Test invalid session ID handling - - Test malformed event data handling - -### Phase 4: Performance & Load Tests (Day 4-5) -1. **Connection Load Testing** - - Test multiple concurrent SSE connections - - Test memory usage under load - - Test event delivery latency - - Test server resource consumption - -2. **Event Volume Testing** - - Test high-frequency event publishing - - Test large event payloads - - Test EventBuffer performance under load - - Test garbage collection impact - -3. **Browser Compatibility Testing** - - Test SSE behavior across major browsers - - Test mobile browser compatibility - - Test connection limits per domain - - Test EventSource API edge cases - -### Phase 5: Documentation & Bug Fixes (Day 5) -1. **Test Documentation** - - Document SSE testing patterns - - Create debugging guides for SSE issues - - Update AGENTS.md with SSE testing info - - Create troubleshooting playbook - -2. **Bug Fix Implementation** - - Fix identified `/api/sessions/{id}/activity` empty response issue - - Address task status synchronization problems - - Fix any performance bottlenecks found - - Improve error handling based on test results - -## 4. Potential Risks - -### High Risk -- **EventSource Browser Limitations**: Different browsers have varying SSE connection limits and behaviors -- **Memory Leaks**: EventBuffer and long-lived connections could cause memory issues -- **Race Conditions**: Concurrent event publishing and connection management may cause inconsistencies - -### Medium Risk -- **Performance Degradation**: High event frequency could impact server performance -- **Data Synchronization**: Events arriving out of order could cause UI inconsistencies -- **Network Reliability**: Poor network conditions may cause frequent reconnections - -### Low Risk -- **Test Environment Setup**: Creating realistic SSE test scenarios may be complex -- **Debug Complexity**: SSE issues can be difficult to reproduce and debug -- **Cross-Platform Issues**: Different OS/browser combinations may behave differently - -### Risk Mitigation Strategies -1. Implement comprehensive integration tests with realistic scenarios -2. Add extensive logging and monitoring for SSE connections -3. Create mock servers for controlled testing environments -4. Implement circuit breaker patterns for connection failures -5. Add performance monitoring and alerting for SSE endpoints - -## 5. Estimated Complexity: **L (Large)** - -### Complexity Justification -- **Scope**: Comprehensive testing of real-time system across frontend/backend -- **Technical Depth**: Requires understanding of SSE protocol, browser APIs, and concurrent systems -- **Integration Complexity**: Testing spans multiple layers (HTTP, SSE, React, state management) -- **Performance Testing**: Load testing and browser compatibility require specialized setup -- **Bug Fixing**: May uncover complex issues requiring significant debugging - -### Time Estimate: 5 days -- Backend tests: 1.5 days -- Frontend tests: 1 day -- Integration tests: 1.5 days -- Performance/load tests: 0.5 days -- Documentation & fixes: 0.5 days - -### Dependencies -- Existing SSE implementation must be stable -- Test infrastructure and CI pipeline must be available -- Access to multiple browsers/devices for compatibility testing -- Performance testing environment setup - -### Success Criteria -- [ ] 95%+ test coverage for SSE-related code -- [ ] All identified SSE bugs fixed and verified -- [ ] Performance benchmarks established and documented -- [ ] Cross-browser compatibility verified -- [ ] Integration tests passing in CI pipeline -- [ ] Documentation updated with SSE testing practices - -## Implementation Notes - -1. **Test Strategy**: Focus on realistic scenarios that match production usage patterns -2. **Debugging**: Add comprehensive logging that can be enabled during development -3. **Monitoring**: Implement metrics collection for SSE connection health -4. **Fallback**: Ensure graceful degradation when SSE is not available -5. **Security**: Verify SSE endpoints respect authentication and authorization - -This plan provides comprehensive coverage for testing the SSE implementation while addressing the known issues and ensuring robust real-time communication in OpenCode Studio. \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/da6912ec-2191-4cee-ac12-e627da4be4a7.md b/.opencode-studio/kanban/plans/da6912ec-2191-4cee-ac12-e627da4be4a7.md deleted file mode 100644 index 5e23f95..0000000 --- a/.opencode-studio/kanban/plans/da6912ec-2191-4cee-ac12-e627da4be4a7.md +++ /dev/null @@ -1,163 +0,0 @@ -# Implementation Plan: Test v3 - -**Task ID:** da6912ec-2191-4cee-ac12-e627da4be4a7 -**Title:** Test v3 -**Description:** Another test -**Generated:** 2026-01-01 01:36:13 AM - -## 1. Technical Analysis - -### Context -This appears to be a test task within the OpenCode Studio platform. Given the minimal description "Another test", this likely represents a validation or experimental feature to verify system functionality. - -### Scope Assessment -- **Type**: Test/Validation task -- **Impact**: Likely minimal system changes required -- **Integration**: May involve testing existing OpenCode Studio components -- **Dependencies**: Existing task lifecycle, OpenCode integration, and SSE event system - -### Assumptions -- This is a test to validate current system functionality -- May involve testing the full task lifecycle (TODO → DONE) -- Could be testing recent SSE migration or OpenCode client integration -- Minimal new functionality required - -## 2. Files to Modify/Create - -### Backend (Rust) -``` -crates/ -├── server/src/routes/ -│ └── test.rs # New test endpoint (if needed) -├── orchestrator/src/ -│ └── test_executor.rs # Test-specific execution logic (if needed) -└── db/migrations/ - └── 00X_test_data.sql # Test data migration (if needed) -``` - -### Frontend (React) -``` -frontend/src/ -├── components/test/ -│ └── TestComponent.tsx # Test UI component (if needed) -├── api/generated/ -│ └── [auto-generated] # Updated API hooks (if backend changes) -└── types/generated/ - └── [auto-generated] # Updated types (if backend changes) -``` - -### Configuration -``` -.opencode-studio/ -├── kanban/plans/ -│ └── da6912ec-2191-4cee-ac12-e627da4be4a7.md # This plan file -└── kanban/reviews/ - └── da6912ec-2191-4cee-ac12-e627da4be4a7.md # Future review file -``` - -## 3. Step-by-Step Implementation Steps - -### Phase 1: Analysis & Setup -1. **Clarify Requirements** - - Determine specific test objectives - - Identify which components need validation - - Define success criteria - -2. **Environment Preparation** - - Ensure development environment is running (`pnpm dev`) - - Verify database connectivity (`studio.db`) - - Confirm OpenCode integration is available - -### Phase 2: Implementation -1. **Backend Changes** (if required) - - Add test endpoint in `crates/server/src/routes/test.rs` - - Update route registration in `crates/server/src/lib.rs` - - Add test logic in orchestrator if needed - - Update OpenAPI schema - -2. **Frontend Changes** (if required) - - Generate new API hooks: `cd frontend && pnpm generate:api` - - Create test component if UI validation needed - - Add test route/navigation if applicable - -3. **Database Changes** (if required) - - Create migration for test data if needed - - Run migration: `sqlx migrate run` - -### Phase 3: Testing & Validation -1. **Unit Tests** - - Add tests to relevant crates - - Run: `cargo test --workspace` - - Ensure clippy passes: `cargo clippy --workspace -- -D warnings` - -2. **Integration Tests** - - Test full task lifecycle if applicable - - Verify SSE events are emitted correctly - - Test OpenCode integration if involved - -3. **Manual Testing** - - Start development server - - Execute test functionality via UI or API - - Verify expected behavior - -### Phase 4: Documentation & Cleanup -1. **Update Documentation** - - Update relevant sections in `AGENTS.md` if needed - - Document any new API endpoints - -2. **Code Review** - - Self-review implementation - - Ensure code follows project conventions - - Check for anti-patterns (no `@ts-ignore`, empty catch blocks, etc.) - -## 4. Potential Risks - -### Technical Risks -- **Low Risk**: Task appears to be simple test validation -- **Integration Risk**: If testing OpenCode integration, external dependency could fail -- **Database Risk**: Minimal - likely no schema changes needed -- **SSE Risk**: If testing real-time features, ensure proper event handling - -### Development Risks -- **Scope Creep**: Minimal description could lead to unclear requirements -- **Time Estimation**: Without clear requirements, timing could vary significantly -- **Testing Gaps**: Test task might not have clear acceptance criteria - -### Mitigation Strategies -- Clarify requirements early in implementation phase -- Start with minimal viable implementation -- Leverage existing patterns and infrastructure -- Use transaction rollback for any database changes during testing - -## 5. Estimated Complexity: **S (Small)** - -### Justification -- **Scope**: Minimal description suggests simple test case -- **Technical Complexity**: Likely leveraging existing infrastructure -- **Integration**: Uses established patterns in OpenCode Studio -- **Time Estimate**: 2-4 hours maximum - -### Complexity Breakdown -- **Analysis**: 30 minutes -- **Implementation**: 1-2 hours -- **Testing**: 30-60 minutes -- **Documentation**: 15-30 minutes - -### Dependencies -- No external dependencies expected -- Leverages existing OpenCode Studio infrastructure -- May depend on OpenCode service availability for integration tests - -## Next Steps - -1. **Immediate**: Clarify specific test requirements with stakeholder -2. **Implementation**: Begin with minimal implementation following existing patterns -3. **Validation**: Test against current system to ensure no regressions -4. **Completion**: Mark task complete in OpenCode Studio workflow - ---- - -**Plan Status**: Ready for implementation -**Estimated Start**: Immediate -**Estimated Completion**: Same day -**Review Required**: No (unless implementation reveals complexity) \ No newline at end of file diff --git a/.opencode-studio/kanban/plans/f35484e8-c2a7-4786-8ed9-68e38251f4c1.md b/.opencode-studio/kanban/plans/f35484e8-c2a7-4786-8ed9-68e38251f4c1.md deleted file mode 100644 index 9ccd2c7..0000000 --- a/.opencode-studio/kanban/plans/f35484e8-c2a7-4786-8ed9-68e38251f4c1.md +++ /dev/null @@ -1,214 +0,0 @@ -# Implementation Plan: Activity Test - Say Hello - -**Task ID:** f35484e8-c2a7-4786-8ed9-68e38251f4c1 -**Title:** Activity Test -**Description:** Say hello -**Plan Generated:** 2025-01-01 01:36:13 -**Estimated Complexity:** S (Small) - ---- - -## 1. Technical Analysis - -### Purpose & Context -This task serves as a lightweight integration test for the OpenCode Studio orchestration pipeline. While the surface requirement is simple ("say hello"), the underlying goal is to validate: - -- Task lifecycle execution (TODO → PLANNING → IN_PROGRESS → DONE) -- OpenCode session creation and management -- File system operations within the workspace -- Status tracking and event emission -- VCS integration (Jujutsu/Git) - -### System Components Involved -- **Orchestrator**: Task state machine and execution logic -- **OpenCode Client**: Session creation and prompt execution -- **VCS Workspace**: Version control operations -- **Event Bus**: Status change notifications -- **Database**: Task and session persistence -- **File Manager**: Plan/review file creation - -### Implementation Strategy -Create a minimal, observable change that exercises the full pipeline without adding complexity. The "hello" output will be implemented as: -1. A simple text file creation or modification -2. A log entry or comment in existing code -3. A basic test file addition - ---- - -## 2. Files to Modify/Create - -### Primary Target (Choose One) -``` -Option A: Create new file -├── hello.txt # Simple text file with greeting -└── .opencode-studio/ - └── activity-test-output.log # Execution log - -Option B: Modify existing file -├── crates/server/src/main.rs # Add hello log on startup -└── README.md # Add activity test section - -Option C: Create test file -├── crates/core/src/lib.rs # Add hello() function -└── crates/core/src/tests/ # Add integration test -``` - -### Supporting Files (Auto-generated) -``` -.opencode-studio/ -├── kanban/ -│ ├── plans/f35484e8-c2a7-4786-8ed9-68e38251f4c1.md # This file -│ └── reviews/f35484e8-c2a7-4786-8ed9-68e38251f4c1.md # Post-implementation -└── sessions/ - └── {session-id}.json # OpenCode session metadata -``` - ---- - -## 3. Step-by-Step Implementation - -### Phase 1: Pre-Implementation Setup -1. **Workspace Validation** - - Verify current working directory is clean (`jj status` / `git status`) - - Ensure no conflicting changes in progress - - Validate OpenCode connection is active - -2. **Session Initialization** - - Create OpenCode session via `/api/sessions` - - Initialize workspace if needed - - Set task status to `IN_PROGRESS` - -### Phase 2: Core Implementation -3. **Choose Implementation Path** - - **Recommended**: Option A (new file) - least invasive - - Create `hello.txt` with content: "Hello from OpenCode Studio Activity Test!" - - Add timestamp and task ID for traceability - -4. **File Operations** - ```bash - echo "Hello from OpenCode Studio Activity Test!" > hello.txt - echo "Generated: $(date)" >> hello.txt - echo "Task ID: f35484e8-c2a7-4786-8ed9-68e38251f4c1" >> hello.txt - ``` - -5. **Verification Steps** - - Confirm file creation successful - - Validate file content matches expectations - - Check file permissions and ownership - -### Phase 3: Integration Validation -6. **VCS Operations** - - Stage changes (`jj add` / `git add`) - - Create commit with descriptive message - - Verify workspace status clean - -7. **Event Emission** - - Emit `task.file_created` event - - Emit `task.status_changed` to `AI_REVIEW` - - Log activity to session activity stream - -8. **Session Completion** - - Mark OpenCode session as completed - - Update task status to `AI_REVIEW` → `REVIEW` → `DONE` - - Generate review file with implementation summary - ---- - -## 4. Potential Risks & Mitigations - -### Risk 1: OpenCode Session Timeout -**Impact:** Medium - Task may remain in `IN_PROGRESS` state -**Probability:** Medium (known issue from previous testing) -**Mitigation:** -- Implement 30-second timeout handling -- Add retry logic for failed sessions -- Graceful fallback to manual completion - -### Risk 2: File System Permissions -**Impact:** Low - File creation might fail -**Probability:** Low -**Mitigation:** -- Validate write permissions before execution -- Use temporary file + rename pattern -- Clear error messaging for permission issues - -### Risk 3: VCS Conflicts -**Impact:** Medium - Workspace state corruption -**Probability:** Low -**Mitigation:** -- Pre-check for clean workspace state -- Use atomic operations where possible -- Implement rollback on failure - -### Risk 4: Event Bus Failure -**Impact:** Low - Silent status update failures -**Probability:** Low -**Mitigation:** -- Add event emission verification -- Implement retry mechanism for critical events -- Log all event attempts for debugging - ---- - -## 5. Success Criteria - -### Primary Objectives -- [ ] Task transitions through complete lifecycle (TODO → DONE) -- [ ] OpenCode session created and completed successfully -- [ ] "Hello" output generated and persisted -- [ ] No errors in application logs -- [ ] VCS workspace remains clean - -### Secondary Objectives -- [ ] SSE events emitted for status changes -- [ ] Session activity logged to database -- [ ] Review file generated with implementation details -- [ ] Execution time < 30 seconds (within timeout window) - -### Verification Commands -```bash -# Check file creation -ls -la hello.txt -cat hello.txt - -# Verify VCS status -jj status # or git status - -# Check database state -sqlite3 studio.db "SELECT status FROM tasks WHERE id = 'f35484e8-c2a7-4786-8ed9-68e38251f4c1';" - -# Validate session completion -sqlite3 studio.db "SELECT status FROM sessions WHERE task_id = 'f35484e8-c2a7-4786-8ed9-68e38251f4c1';" -``` - ---- - -## 6. Estimated Complexity: S (Small) - -**Rationale:** -- Minimal code changes required (single file creation) -- Well-understood system components -- Low risk of breaking existing functionality -- Fast execution time expected -- Clear success/failure indicators - -**Time Estimate:** 5-10 minutes for execution + validation - -**Dependencies:** None (self-contained test) - ---- - -## 7. Post-Implementation Notes - -This task primarily serves as a system health check rather than feature development. Success indicates: -- OpenCode integration is functional -- Task lifecycle automation works end-to-end -- VCS workspace management operates correctly -- Event system and database persistence are stable - -Failure modes will help identify specific areas needing attention in the OpenCode Studio pipeline. - ---- - -**Plan Status:** Ready for Implementation -**Next Phase:** Await execution trigger via task management system \ No newline at end of file diff --git a/.opencode-studio/studio.db b/.opencode-studio/studio.db deleted file mode 100644 index 7338346..0000000 Binary files a/.opencode-studio/studio.db and /dev/null differ diff --git a/.opencode-studio/studio.db-shm b/.opencode-studio/studio.db-shm deleted file mode 100644 index fe9ac28..0000000 Binary files a/.opencode-studio/studio.db-shm and /dev/null differ diff --git a/.opencode-studio/studio.db-wal b/.opencode-studio/studio.db-wal deleted file mode 100644 index e69de29..0000000 diff --git a/Cargo.lock b/Cargo.lock index 940e1f8..97e1751 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,18 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -127,6 +139,28 @@ dependencies = [ "serde_json", ] +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-trait" version = "0.1.89" @@ -167,7 +201,7 @@ checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", "axum-macros", - "base64", + "base64 0.22.1", "bytes", "form_urlencoded", "futures-util", @@ -255,6 +289,12 @@ dependencies = [ "url", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -267,6 +307,21 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "2.10.0" @@ -285,6 +340,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + [[package]] name = "bumpalo" version = "3.19.1" @@ -535,6 +601,25 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -874,6 +959,29 @@ dependencies = [ "syn", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fancy-regex" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -1095,9 +1203,24 @@ dependencies = [ "thiserror 2.0.17", "tokio", "tracing", + "ts-rs", + "utoipa", "wiremock", ] +[[package]] +name = "globset" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + [[package]] name = "h2" version = "0.4.12" @@ -1117,6 +1240,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.15.5" @@ -1134,6 +1266,15 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "hashlink" version = "0.10.0" @@ -1316,7 +1457,7 @@ version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-core", @@ -1468,6 +1609,22 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "ignore" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + [[package]] name = "indexmap" version = "2.12.1" @@ -1606,7 +1763,7 @@ version = "9.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" dependencies = [ - "base64", + "base64 0.22.1", "js-sys", "pem", "ring", @@ -1755,6 +1912,27 @@ dependencies = [ "uuid", ] +[[package]] +name = "mcp-wiki" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "chrono", + "futures", + "rmcp", + "schemars", + "serde", + "serde_json", + "tempfile", + "thiserror 2.0.17", + "tokio", + "tracing", + "tracing-subscriber", + "uuid", + "wiki", +] + [[package]] name = "md-5" version = "0.10.6" @@ -1970,7 +2148,7 @@ checksum = "e2dfd11f6efbd39491d71a3864496f0b6f45e2d01b73b26c55d631c4e0dafaef" dependencies = [ "arc-swap", "async-trait", - "base64", + "base64 0.22.1", "bytes", "cfg-if", "chrono", @@ -2219,7 +2397,7 @@ version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ - "base64", + "base64 0.22.1", "serde_core", ] @@ -2357,7 +2535,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.1.1", "rustls", "socket2", "thiserror 2.0.17", @@ -2377,7 +2555,7 @@ dependencies = [ "lru-slab", "rand 0.9.2", "ring", - "rustc-hash", + "rustc-hash 2.1.1", "rustls", "rustls-pki-types", "slab", @@ -2475,6 +2653,26 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -2559,7 +2757,7 @@ version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "encoding_rs", "futures-core", @@ -2630,7 +2828,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f0d0d5493be0d181a62db489eab7838669b81885972ca00ceca893cf6ac2883" dependencies = [ - "base64", + "base64 0.22.1", "chrono", "futures", "paste", @@ -2678,6 +2876,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rusqlite" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink 0.9.1", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rust-embed" version = "8.9.0" @@ -2727,6 +2939,12 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hash" version = "2.1.1" @@ -3036,6 +3254,7 @@ dependencies = [ "uuid", "vcs", "which", + "wiki", "wiremock", ] @@ -3179,6 +3398,15 @@ dependencies = [ "der", ] +[[package]] +name = "sqlite-vec" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec77b84fb8dd5f0f8def127226db83b5d1152c5bf367f09af03998b76ba554a" +dependencies = [ + "cc", +] + [[package]] name = "sqlx" version = "0.8.6" @@ -3198,7 +3426,7 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "crc", "crossbeam-queue", @@ -3209,7 +3437,7 @@ dependencies = [ "futures-io", "futures-util", "hashbrown 0.15.5", - "hashlink", + "hashlink 0.10.0", "indexmap", "log", "memchr", @@ -3271,7 +3499,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", - "base64", + "base64 0.22.1", "bitflags", "byteorder", "bytes", @@ -3313,7 +3541,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", - "base64", + "base64 0.22.1", "bitflags", "byteorder", "crc", @@ -3519,6 +3747,22 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tiktoken-rs" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44075987ee2486402f0808505dd65692163d243a337fc54363d49afac41087f6" +dependencies = [ + "anyhow", + "base64 0.21.7", + "bstr", + "fancy-regex", + "lazy_static", + "parking_lot", + "regex", + "rustc-hash 1.1.0", +] + [[package]] name = "time" version = "0.3.44" @@ -3635,6 +3879,19 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "tokio-test" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", +] + [[package]] name = "tokio-tungstenite" version = "0.28.0" @@ -4046,7 +4303,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d047458f1b5b65237c2f6dc6db136945667f40a7668627b3490b9513a3d43a55" dependencies = [ "axum", - "base64", + "base64 0.22.1", "mime_guess", "regex", "rust-embed", @@ -4266,6 +4523,37 @@ dependencies = [ "wasite", ] +[[package]] +name = "wiki" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "chrono", + "eventsource-stream", + "futures", + "ignore", + "rayon", + "regex", + "reqwest", + "rusqlite", + "serde", + "serde_json", + "sqlite-vec", + "tempfile", + "thiserror 2.0.17", + "tiktoken-rs", + "tokio", + "tokio-test", + "tracing", + "ts-rs", + "url", + "urlencoding", + "uuid", + "wiremock", +] + [[package]] name = "winapi-util" version = "0.1.11" @@ -4598,7 +4886,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08db1edfb05d9b3c1542e521aea074442088292f00b5f28e435c714a98f85031" dependencies = [ "assert-json-diff", - "base64", + "base64 0.22.1", "deadpool", "futures", "http", diff --git a/Cargo.toml b/Cargo.toml index 707ea39..1499583 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,8 @@ members = [ "crates/events", "crates/github", "crates/mcp-findings", + "crates/mcp-wiki", + "crates/wiki", ] [workspace.package] @@ -28,6 +30,8 @@ vcs = { path = "crates/vcs" } events = { path = "crates/events" } github = { path = "crates/github" } mcp-findings = { path = "crates/mcp-findings" } +mcp-wiki = { path = "crates/mcp-wiki" } +wiki = { path = "crates/wiki" } # HTTP client reqwest = { version = "0.12", features = ["json", "stream"] } @@ -61,6 +65,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] } uuid = { version = "1.0", features = ["v4", "serde"] } chrono = { version = "0.4", features = ["serde"] } async-trait = "0.1" +regex = "1.11" # Type generation for TypeScript ts-rs = { version = "10.1", features = ["uuid-impl", "chrono-impl", "serde-compat"] } diff --git a/bin/opencode-studio.mjs b/bin/opencode-studio.mjs new file mode 100755 index 0000000..5f93a2c --- /dev/null +++ b/bin/opencode-studio.mjs @@ -0,0 +1,200 @@ +#!/usr/bin/env node + +import { spawn, execSync } from 'node:child_process'; +import { existsSync } from 'node:fs'; +import { join, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { createServer } from 'node:http'; +import { createReadStream } from 'node:fs'; +import { readFile } from 'node:fs/promises'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const ROOT = join(__dirname, '..'); + +// Configuration +const OPENCODE_PORT = 4199; // Dedicated port for opencode-studio +const SERVER_PORT = process.env.PORT || 3001; +const OPENCODE_URL = `http://localhost:${OPENCODE_PORT}`; + +// Parse CLI arguments +const args = process.argv.slice(2); +const showHelp = args.includes('--help') || args.includes('-h'); + +if (showHelp) { + console.log(` +opencode-studio - AI-powered code analysis and documentation + +Usage: + npx opencode-studio [options] + +Options: + --port Server port (default: 3001) + --help, -h Show this help message + +Environment: + PORT Server port (default: 3001) + OPENCODE_URL OpenCode server URL (default: http://localhost:4199) +`); + process.exit(0); +} + +// Find opencode binary +function findOpencodeBinary() { + const homeDir = process.env.HOME || process.env.USERPROFILE; + + // Check ~/.opencode/bin/opencode + if (homeDir) { + const opencodePath = join(homeDir, '.opencode', 'bin', 'opencode'); + if (existsSync(opencodePath)) { + return opencodePath; + } + } + + // Try to find in PATH + try { + const which = process.platform === 'win32' ? 'where' : 'which'; + const result = execSync(`${which} opencode`, { encoding: 'utf-8' }).trim(); + if (result) return result.split('\n')[0]; + } catch { + // Not found in PATH + } + + return null; +} + +// Check if server is healthy +async function healthCheck(url) { + try { + const response = await fetch(`${url}/doc`, { + signal: AbortSignal.timeout(500) + }); + return response.ok; + } catch { + return false; + } +} + +// Wait for server to be ready +async function waitForServer(url, maxAttempts = 20) { + for (let i = 0; i < maxAttempts; i++) { + if (await healthCheck(url)) { + return true; + } + await new Promise(resolve => setTimeout(resolve, 500)); + } + return false; +} + +// Find the server binary +function findServerBinary() { + // Check for prebuilt binary in package + const binaryName = process.platform === 'win32' ? 'server.exe' : 'server'; + const prebuiltPath = join(ROOT, 'bin', binaryName); + if (existsSync(prebuiltPath)) { + return prebuiltPath; + } + + // Check target/release (for development) + const releasePath = join(ROOT, 'target', 'release', binaryName); + if (existsSync(releasePath)) { + return releasePath; + } + + // Check target/debug (for development) + const debugPath = join(ROOT, 'target', 'debug', binaryName); + if (existsSync(debugPath)) { + return debugPath; + } + + return null; +} + +async function main() { + console.log('🚀 Starting opencode-studio...\n'); + + // 1. Check for opencode + const opencodeBinary = findOpencodeBinary(); + if (!opencodeBinary) { + console.error('❌ OpenCode not found!\n'); + console.error('Install with: curl -fsSL https://opencode.ai/install.sh | sh\n'); + process.exit(1); + } + console.log(`✓ Found opencode: ${opencodeBinary}`); + + // 2. Check if opencode is already running on our port + const opencodeRunning = await healthCheck(OPENCODE_URL); + let opencodeProcess = null; + + if (!opencodeRunning) { + console.log(` Starting opencode on port ${OPENCODE_PORT}...`); + + opencodeProcess = spawn(opencodeBinary, ['serve', '--port', String(OPENCODE_PORT)], { + stdio: ['ignore', 'pipe', 'pipe'], + detached: false, + }); + + opencodeProcess.on('error', (err) => { + console.error(`❌ Failed to start opencode: ${err.message}`); + process.exit(1); + }); + + // Wait for opencode to be ready + const ready = await waitForServer(OPENCODE_URL); + if (!ready) { + console.error('❌ OpenCode failed to start within timeout'); + opencodeProcess.kill(); + process.exit(1); + } + } + console.log(`✓ OpenCode ready at ${OPENCODE_URL}`); + + // 3. Start the server + const serverBinary = findServerBinary(); + if (!serverBinary) { + console.error('❌ Server binary not found!'); + console.error('Run: cargo build --release'); + if (opencodeProcess) opencodeProcess.kill(); + process.exit(1); + } + + console.log(` Starting server on port ${SERVER_PORT}...`); + + const serverProcess = spawn(serverBinary, [], { + stdio: 'inherit', + env: { + ...process.env, + PORT: String(SERVER_PORT), + OPENCODE_URL: OPENCODE_URL, + }, + }); + + serverProcess.on('error', (err) => { + console.error(`❌ Failed to start server: ${err.message}`); + if (opencodeProcess) opencodeProcess.kill(); + process.exit(1); + }); + + console.log(`\n✓ opencode-studio ready at http://localhost:${SERVER_PORT}\n`); + + // Handle shutdown + const cleanup = () => { + console.log('\n🛑 Shutting down...'); + serverProcess.kill(); + if (opencodeProcess) opencodeProcess.kill(); + process.exit(0); + }; + + process.on('SIGINT', cleanup); + process.on('SIGTERM', cleanup); + + // Wait for server to exit + serverProcess.on('exit', (code) => { + if (opencodeProcess) opencodeProcess.kill(); + process.exit(code || 0); + }); +} + +main().catch((err) => { + console.error('❌ Fatal error:', err); + process.exit(1); +}); diff --git a/crates/AGENTS.md b/crates/AGENTS.md index 24f027c..4fd204d 100644 --- a/crates/AGENTS.md +++ b/crates/AGENTS.md @@ -2,7 +2,7 @@ ## OVERVIEW -9-crate Rust workspace. Core domain logic, persistence, orchestration, and HTTP server. +11-crate Rust workspace. Core domain logic, persistence, orchestration, wiki generation, and HTTP server. ## CRATE MAP @@ -15,6 +15,8 @@ | `vcs` | VCS abstraction | `VersionControl`, `WorkspaceManager`, `JujutsuVcs`, `GitVcs` | 20 | | `events` | Event bus | `EventBus`, `TaskEvent`, `SessionEvent` | 8 | | `github` | GitHub API (octocrab) | `GitHubClient`, `PullRequest`, `Issue` | 11 | +| `wiki` | AI wiki generation | `WikiEngine`, `WikiSyncService`, `CodeIndexer`, `RagEngine` | 64 | +| `mcp-wiki` | MCP server for wiki | `WikiService`, tools: search_code, ask_codebase | 7 | | `server` | Axum HTTP + SSE | `AppState`, `router`, `OpenApi` | 20 | | `cli` | Binary: `opencode-studio` | Commands: init, serve, status, update | 0 | @@ -22,13 +24,15 @@ ``` server (aggregates all) -├── orchestrator → core, opencode-client, db, vcs, events +├── orchestrator → core, opencode-client, db, vcs, events, wiki ├── db → core ├── vcs → core ├── github → core +├── wiki → (external: rusqlite, sqlite-vec, reqwest, tiktoken-rs) +├── mcp-wiki → wiki └── cli → db, server (uses path deps - tech debt) -Foundational (no internal deps): core, events, opencode-client +Foundational (no internal deps): core, events, opencode-client, wiki ``` ## WHERE TO LOOK @@ -49,6 +53,11 @@ Foundational (no internal deps): core, events, opencode-client | VCS operations | `vcs` | `src/jj.rs` (primary), `src/git.rs` (fallback) | | Event emission | `events` | `src/types.rs` for new event types | | GitHub integration | `github` | `src/client.rs` | +| Wiki indexing | `wiki` | `src/indexer/mod.rs` | +| Wiki generation | `wiki` | `src/generator/mod.rs` | +| Wiki RAG Q&A | `wiki` | `src/rag/mod.rs` | +| Wiki sync | `wiki` | `src/sync.rs` | +| Wiki MCP tools | `mcp-wiki` | `src/lib.rs` | ## ORCHESTRATOR SERVICES @@ -67,6 +76,47 @@ The `orchestrator` crate uses a modular service architecture in `src/services/`: The main `executor.rs` (~530 lines) delegates to these services. +## WIKI CRATE + +AI-powered codebase documentation with semantic search. Uses rusqlite + sqlite-vec (NOT sqlx). + +### Architecture + +``` +wiki/src/ +├── domain/ # Data models: CodeChunk, WikiPage, IndexStatus +├── openrouter/ # OpenRouter API client with retry logic +├── vector_store/ # SQLite + sqlite-vec for embeddings +├── chunker/ # Token-based text splitting +├── indexer/ # File reading, chunking, embedding creation +├── generator/ # Wiki page generation with Mermaid diagrams +├── rag/ # RAG engine for Q&A +└── sync.rs # WikiSyncService for auto-sync +``` + +### Key Types + +| Type | Purpose | +|:-----|:--------| +| `WikiConfig` | Configuration: branches, API key, models, db_path | +| `WikiEngine` | Main orchestrator for indexing and search | +| `WikiSyncService` | Sync service with needs_reindex, sync_if_needed | +| `CodeIndexer` | Creates embeddings, stores chunks | +| `WikiGenerator` | Generates pages with AI | +| `RagEngine` | Q&A with conversation history | +| `VectorStore` | rusqlite + sqlite-vec operations | + +### MCP Wiki Server + +Binary: `opencode-mcp-wiki`. Provides 5 tools: +- `search_code`: Semantic code search +- `get_documentation`: Retrieve wiki pages +- `ask_codebase`: RAG Q&A +- `list_wiki_pages`: Structure navigation +- `get_index_status`: Indexing status + +Environment: `OPENROUTER_API_KEY` (required), `OPENCODE_WIKI_*` (optional). + ## CONVENTIONS - `core` exports as `opencode_core` (reserved word collision) @@ -87,6 +137,7 @@ The main `executor.rs` (~530 lines) delegates to these services. ```bash cargo test --workspace # All tests cargo test -p orchestrator # 55 tests +cargo test -p wiki # 64 tests cargo test -p server -- --nocapture # 20 tests with output cargo clippy --workspace -- -D warnings # Lint check ``` diff --git a/crates/cli/src/opencode_manager.rs b/crates/cli/src/opencode_manager.rs index 2a3079b..a07e15a 100644 --- a/crates/cli/src/opencode_manager.rs +++ b/crates/cli/src/opencode_manager.rs @@ -31,11 +31,7 @@ impl OpenCodeManager { /// Ensure OpenCode server is running, starting it if necessary pub async fn ensure_running(&mut self) -> Result<()> { - println!( - " {} {}", - "●".cyan(), - "Checking OpenCode server...".white() - ); + println!(" {} {}", "●".cyan(), "Checking OpenCode server...".white()); // First, check if server is already running if self.health_check().await { diff --git a/crates/core/bindings/ConvertToTaskResponse.ts b/crates/core/bindings/ConvertToTaskResponse.ts new file mode 100644 index 0000000..0fc0640 --- /dev/null +++ b/crates/core/bindings/ConvertToTaskResponse.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Response for convert feature to task + */ +export type ConvertToTaskResponse = { task_id: string, feature_id: string, }; diff --git a/crates/core/bindings/CreateTaskRequest.ts b/crates/core/bindings/CreateTaskRequest.ts new file mode 100644 index 0000000..a4aa840 --- /dev/null +++ b/crates/core/bindings/CreateTaskRequest.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type CreateTaskRequest = { title: string, description: string, roadmap_item_id: string | null, }; diff --git a/crates/core/bindings/GenerateRoadmapRequest.ts b/crates/core/bindings/GenerateRoadmapRequest.ts new file mode 100644 index 0000000..bc6bde4 --- /dev/null +++ b/crates/core/bindings/GenerateRoadmapRequest.ts @@ -0,0 +1,10 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Request to generate a roadmap + */ +export type GenerateRoadmapRequest = { +/** + * Force regeneration even if roadmap exists + */ +force: boolean, }; diff --git a/crates/core/bindings/Roadmap.ts b/crates/core/bindings/Roadmap.ts new file mode 100644 index 0000000..6a813ec --- /dev/null +++ b/crates/core/bindings/Roadmap.ts @@ -0,0 +1,50 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { RoadmapFeature } from "./RoadmapFeature"; +import type { RoadmapPhase } from "./RoadmapPhase"; +import type { RoadmapStatus } from "./RoadmapStatus"; +import type { TargetAudience } from "./TargetAudience"; + +/** + * The complete roadmap + */ +export type Roadmap = { +/** + * Unique identifier + */ +id: string, +/** + * Project name + */ +project_name: string, +/** + * Roadmap version + */ +version: string, +/** + * Product vision statement + */ +vision: string, +/** + * Target audience information + */ +target_audience: TargetAudience, +/** + * Roadmap phases + */ +phases: Array, +/** + * All features in the roadmap + */ +features: Array, +/** + * Overall roadmap status + */ +status: RoadmapStatus, +/** + * Creation timestamp + */ +created_at: string, +/** + * Last update timestamp + */ +updated_at: string, }; diff --git a/crates/core/bindings/RoadmapComplexity.ts b/crates/core/bindings/RoadmapComplexity.ts new file mode 100644 index 0000000..dba2e36 --- /dev/null +++ b/crates/core/bindings/RoadmapComplexity.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Complexity level for roadmap features + */ +export type RoadmapComplexity = "low" | "medium" | "high"; diff --git a/crates/core/bindings/RoadmapFeature.ts b/crates/core/bindings/RoadmapFeature.ts new file mode 100644 index 0000000..4439f60 --- /dev/null +++ b/crates/core/bindings/RoadmapFeature.ts @@ -0,0 +1,62 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { RoadmapComplexity } from "./RoadmapComplexity"; +import type { RoadmapFeatureStatus } from "./RoadmapFeatureStatus"; +import type { RoadmapImpact } from "./RoadmapImpact"; +import type { RoadmapPriority } from "./RoadmapPriority"; + +/** + * A feature in the roadmap + */ +export type RoadmapFeature = { +/** + * Unique identifier + */ +id: string, +/** + * Feature title + */ +title: string, +/** + * Feature description + */ +description: string, +/** + * Rationale - why this feature matters + */ +rationale: string, +/** + * Priority (MoSCoW) + */ +priority: RoadmapPriority, +/** + * Complexity estimate + */ +complexity: RoadmapComplexity, +/** + * Impact estimate + */ +impact: RoadmapImpact, +/** + * Phase this feature belongs to + */ +phase_id: string, +/** + * Feature IDs this depends on + */ +dependencies: Array, +/** + * Current status + */ +status: RoadmapFeatureStatus, +/** + * Acceptance criteria + */ +acceptance_criteria: Array, +/** + * User stories + */ +user_stories: Array, +/** + * Linked task ID (when converted to task) + */ +linked_task_id: string | null, }; diff --git a/crates/core/bindings/RoadmapFeatureStatus.ts b/crates/core/bindings/RoadmapFeatureStatus.ts new file mode 100644 index 0000000..456be46 --- /dev/null +++ b/crates/core/bindings/RoadmapFeatureStatus.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Status of a roadmap feature + */ +export type RoadmapFeatureStatus = "under_review" | "planned" | "in_progress" | "done"; diff --git a/crates/core/bindings/RoadmapGenerationPhase.ts b/crates/core/bindings/RoadmapGenerationPhase.ts new file mode 100644 index 0000000..eebacf3 --- /dev/null +++ b/crates/core/bindings/RoadmapGenerationPhase.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Status of roadmap generation process + */ +export type RoadmapGenerationPhase = "idle" | "analyzing" | "discovering" | "generating" | "complete" | "error"; diff --git a/crates/core/bindings/RoadmapGenerationStatus.ts b/crates/core/bindings/RoadmapGenerationStatus.ts new file mode 100644 index 0000000..d6de235 --- /dev/null +++ b/crates/core/bindings/RoadmapGenerationStatus.ts @@ -0,0 +1,23 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { RoadmapGenerationPhase } from "./RoadmapGenerationPhase"; + +/** + * Status of roadmap generation + */ +export type RoadmapGenerationStatus = { +/** + * Current phase + */ +phase: RoadmapGenerationPhase, +/** + * Progress percentage (0-100) + */ +progress: number, +/** + * Current message/status + */ +message: string, +/** + * Error message if phase is Error + */ +error: string | null, }; diff --git a/crates/core/bindings/RoadmapImpact.ts b/crates/core/bindings/RoadmapImpact.ts new file mode 100644 index 0000000..6db5b0f --- /dev/null +++ b/crates/core/bindings/RoadmapImpact.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Impact level for roadmap features + */ +export type RoadmapImpact = "low" | "medium" | "high"; diff --git a/crates/core/bindings/RoadmapMilestone.ts b/crates/core/bindings/RoadmapMilestone.ts new file mode 100644 index 0000000..1d7a2a8 --- /dev/null +++ b/crates/core/bindings/RoadmapMilestone.ts @@ -0,0 +1,27 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { RoadmapPhaseStatus } from "./RoadmapPhaseStatus"; + +/** + * A milestone within a roadmap phase + */ +export type RoadmapMilestone = { +/** + * Unique identifier + */ +id: string, +/** + * Milestone title + */ +title: string, +/** + * Milestone description + */ +description: string, +/** + * Feature IDs included in this milestone + */ +features: Array, +/** + * Milestone status + */ +status: RoadmapPhaseStatus, }; diff --git a/crates/core/bindings/RoadmapPhase.ts b/crates/core/bindings/RoadmapPhase.ts new file mode 100644 index 0000000..8d8515b --- /dev/null +++ b/crates/core/bindings/RoadmapPhase.ts @@ -0,0 +1,36 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { RoadmapMilestone } from "./RoadmapMilestone"; +import type { RoadmapPhaseStatus } from "./RoadmapPhaseStatus"; + +/** + * A phase in the roadmap (e.g., Foundation, Enhancement, Scale) + */ +export type RoadmapPhase = { +/** + * Unique identifier + */ +id: string, +/** + * Phase name + */ +name: string, +/** + * Phase description + */ +description: string, +/** + * Order in the roadmap (1-based) + */ +order: number, +/** + * Phase status + */ +status: RoadmapPhaseStatus, +/** + * Feature IDs in this phase + */ +features: Array, +/** + * Milestones within this phase + */ +milestones: Array, }; diff --git a/crates/core/bindings/RoadmapPhaseStatus.ts b/crates/core/bindings/RoadmapPhaseStatus.ts new file mode 100644 index 0000000..b83b53c --- /dev/null +++ b/crates/core/bindings/RoadmapPhaseStatus.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Status of a roadmap phase + */ +export type RoadmapPhaseStatus = "planned" | "in_progress" | "completed"; diff --git a/crates/core/bindings/RoadmapPriority.ts b/crates/core/bindings/RoadmapPriority.ts new file mode 100644 index 0000000..498287b --- /dev/null +++ b/crates/core/bindings/RoadmapPriority.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Priority level for roadmap features (MoSCoW method) + */ +export type RoadmapPriority = "must" | "should" | "could" | "wont"; diff --git a/crates/core/bindings/RoadmapStats.ts b/crates/core/bindings/RoadmapStats.ts new file mode 100644 index 0000000..0112efc --- /dev/null +++ b/crates/core/bindings/RoadmapStats.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { RoadmapComplexity } from "./RoadmapComplexity"; +import type { RoadmapFeatureStatus } from "./RoadmapFeatureStatus"; +import type { RoadmapPriority } from "./RoadmapPriority"; + +/** + * Statistics about a roadmap + */ +export type RoadmapStats = { total_features: number, total_phases: number, by_priority: { [key in RoadmapPriority]?: number }, by_status: { [key in RoadmapFeatureStatus]?: number }, by_complexity: { [key in RoadmapComplexity]?: number }, }; diff --git a/crates/core/bindings/RoadmapStatus.ts b/crates/core/bindings/RoadmapStatus.ts new file mode 100644 index 0000000..035b9a1 --- /dev/null +++ b/crates/core/bindings/RoadmapStatus.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Overall status of the roadmap + */ +export type RoadmapStatus = "draft" | "active" | "archived"; diff --git a/crates/core/bindings/Session.ts b/crates/core/bindings/Session.ts new file mode 100644 index 0000000..5b62d58 --- /dev/null +++ b/crates/core/bindings/Session.ts @@ -0,0 +1,13 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { SessionPhase } from "./SessionPhase"; +import type { SessionStatus } from "./SessionStatus"; + +export type Session = { id: string, task_id: string, opencode_session_id: string | null, phase: SessionPhase, status: SessionStatus, started_at: string | null, completed_at: string | null, created_at: string, +/** + * For multi-phase implementation: current phase number (1-indexed) + */ +implementation_phase_number: number | null, +/** + * For multi-phase implementation: current phase title + */ +implementation_phase_title: string | null, }; diff --git a/crates/core/bindings/SessionPhase.ts b/crates/core/bindings/SessionPhase.ts new file mode 100644 index 0000000..2203ce6 --- /dev/null +++ b/crates/core/bindings/SessionPhase.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type SessionPhase = "planning" | "implementation" | "review" | "fix"; diff --git a/crates/core/bindings/SessionStatus.ts b/crates/core/bindings/SessionStatus.ts new file mode 100644 index 0000000..5509c39 --- /dev/null +++ b/crates/core/bindings/SessionStatus.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type SessionStatus = "pending" | "running" | "completed" | "failed" | "aborted"; diff --git a/crates/core/bindings/TargetAudience.ts b/crates/core/bindings/TargetAudience.ts new file mode 100644 index 0000000..c305310 --- /dev/null +++ b/crates/core/bindings/TargetAudience.ts @@ -0,0 +1,26 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Target audience for the product + */ +export type TargetAudience = { +/** + * Primary user persona + */ +primary: string, +/** + * Secondary user personas + */ +secondary: Array, +/** + * Pain points the target audience faces + */ +pain_points: Array, +/** + * Goals the target audience wants to achieve + */ +goals: Array, +/** + * Usage context (when/where/how they use the product) + */ +usage_context: string | null, }; diff --git a/crates/core/bindings/Task.ts b/crates/core/bindings/Task.ts new file mode 100644 index 0000000..f228ed4 --- /dev/null +++ b/crates/core/bindings/Task.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { TaskStatus } from "./TaskStatus"; + +export type Task = { id: string, title: string, description: string, status: TaskStatus, roadmap_item_id: string | null, workspace_path: string | null, created_at: string, updated_at: string, }; diff --git a/crates/core/bindings/TaskStatus.ts b/crates/core/bindings/TaskStatus.ts new file mode 100644 index 0000000..0b13ebe --- /dev/null +++ b/crates/core/bindings/TaskStatus.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type TaskStatus = "todo" | "planning" | "planning_review" | "in_progress" | "ai_review" | "fix" | "review" | "done"; diff --git a/crates/core/bindings/UpdateFeatureRequest.ts b/crates/core/bindings/UpdateFeatureRequest.ts new file mode 100644 index 0000000..d5c5d99 --- /dev/null +++ b/crates/core/bindings/UpdateFeatureRequest.ts @@ -0,0 +1,8 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { RoadmapFeatureStatus } from "./RoadmapFeatureStatus"; +import type { RoadmapPriority } from "./RoadmapPriority"; + +/** + * Request to update a feature + */ +export type UpdateFeatureRequest = { status: RoadmapFeatureStatus | null, phase_id: string | null, priority: RoadmapPriority | null, linked_task_id: string | null, }; diff --git a/crates/core/bindings/UpdateTaskRequest.ts b/crates/core/bindings/UpdateTaskRequest.ts new file mode 100644 index 0000000..8864df2 --- /dev/null +++ b/crates/core/bindings/UpdateTaskRequest.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { TaskStatus } from "./TaskStatus"; + +export type UpdateTaskRequest = { title: string | null, description: string | null, status: TaskStatus | null, workspace_path: string | null, }; diff --git a/crates/core/src/domain/mod.rs b/crates/core/src/domain/mod.rs index 6783b75..73d9080 100644 --- a/crates/core/src/domain/mod.rs +++ b/crates/core/src/domain/mod.rs @@ -1,5 +1,7 @@ +mod roadmap; mod session; mod task; +pub use roadmap::*; pub use session::*; pub use task::*; diff --git a/crates/core/src/domain/roadmap.rs b/crates/core/src/domain/roadmap.rs new file mode 100644 index 0000000..b080b3a --- /dev/null +++ b/crates/core/src/domain/roadmap.rs @@ -0,0 +1,710 @@ +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; + +// ============================================ +// Enums +// ============================================ + +/// Priority level for roadmap features (MoSCoW method) +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, Default, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +#[serde(rename_all = "snake_case")] +pub enum RoadmapPriority { + /// Critical for MVP - users cannot function without this + Must, + /// Important but not critical - significant value + #[default] + Should, + /// Nice to have - enhances experience + Could, + /// Not planned for foreseeable future + Wont, +} + +impl RoadmapPriority { + pub fn as_str(&self) -> &'static str { + match self { + Self::Must => "must", + Self::Should => "should", + Self::Could => "could", + Self::Wont => "wont", + } + } + + pub fn parse(s: &str) -> Option { + match s.to_lowercase().as_str() { + "must" => Some(Self::Must), + "should" => Some(Self::Should), + "could" => Some(Self::Could), + "wont" | "won't" => Some(Self::Wont), + _ => None, + } + } +} + +/// Complexity level for roadmap features +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, Default, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +#[serde(rename_all = "snake_case")] +pub enum RoadmapComplexity { + /// 1-2 files, single component, < 1 day + Low, + /// 3-10 files, multiple components, 1-3 days + #[default] + Medium, + /// 10+ files, architectural changes, > 3 days + High, +} + +impl RoadmapComplexity { + pub fn as_str(&self) -> &'static str { + match self { + Self::Low => "low", + Self::Medium => "medium", + Self::High => "high", + } + } + + pub fn parse(s: &str) -> Option { + match s.to_lowercase().as_str() { + "low" => Some(Self::Low), + "medium" => Some(Self::Medium), + "high" => Some(Self::High), + _ => None, + } + } +} + +/// Impact level for roadmap features +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, Default, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +#[serde(rename_all = "snake_case")] +pub enum RoadmapImpact { + /// Edge cases, polish, nice-to-have + Low, + /// Improves experience, addresses secondary needs + #[default] + Medium, + /// Core user need, differentiator, revenue driver + High, +} + +impl RoadmapImpact { + pub fn as_str(&self) -> &'static str { + match self { + Self::Low => "low", + Self::Medium => "medium", + Self::High => "high", + } + } + + pub fn parse(s: &str) -> Option { + match s.to_lowercase().as_str() { + "low" => Some(Self::Low), + "medium" => Some(Self::Medium), + "high" => Some(Self::High), + _ => None, + } + } +} + +/// Status of a roadmap feature +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, Default, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +#[serde(rename_all = "snake_case")] +pub enum RoadmapFeatureStatus { + /// Feature is being reviewed/considered + #[default] + UnderReview, + /// Feature is planned for implementation + Planned, + /// Feature is currently being implemented (linked to task) + InProgress, + /// Feature implementation is complete + Done, +} + +impl RoadmapFeatureStatus { + pub fn as_str(&self) -> &'static str { + match self { + Self::UnderReview => "under_review", + Self::Planned => "planned", + Self::InProgress => "in_progress", + Self::Done => "done", + } + } + + pub fn parse(s: &str) -> Option { + match s.to_lowercase().as_str() { + "under_review" | "idea" => Some(Self::UnderReview), + "planned" => Some(Self::Planned), + "in_progress" => Some(Self::InProgress), + "done" => Some(Self::Done), + _ => None, + } + } +} + +/// Status of a roadmap phase +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +#[serde(rename_all = "snake_case")] +pub enum RoadmapPhaseStatus { + /// Phase is planned but not started + #[default] + Planned, + /// Phase is currently in progress + InProgress, + /// Phase is completed + Completed, +} + +impl RoadmapPhaseStatus { + pub fn as_str(&self) -> &'static str { + match self { + Self::Planned => "planned", + Self::InProgress => "in_progress", + Self::Completed => "completed", + } + } + + pub fn parse(s: &str) -> Option { + match s.to_lowercase().as_str() { + "planned" => Some(Self::Planned), + "in_progress" => Some(Self::InProgress), + "completed" => Some(Self::Completed), + _ => None, + } + } +} + +/// Overall status of the roadmap +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +#[serde(rename_all = "snake_case")] +pub enum RoadmapStatus { + /// Roadmap is in draft/initial state + #[default] + Draft, + /// Roadmap is actively being worked on + Active, + /// Roadmap is archived + Archived, +} + +impl RoadmapStatus { + pub fn as_str(&self) -> &'static str { + match self { + Self::Draft => "draft", + Self::Active => "active", + Self::Archived => "archived", + } + } + + pub fn parse(s: &str) -> Option { + match s.to_lowercase().as_str() { + "draft" => Some(Self::Draft), + "active" => Some(Self::Active), + "archived" => Some(Self::Archived), + _ => None, + } + } +} + +/// Status of roadmap generation process +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +#[serde(rename_all = "snake_case")] +pub enum RoadmapGenerationPhase { + /// No generation in progress + #[default] + Idle, + /// Analyzing project structure + Analyzing, + /// Discovering target audience and product vision + Discovering, + /// Generating features and phases + Generating, + /// Generation completed successfully + Complete, + /// Generation failed with error + Error, +} + +impl RoadmapGenerationPhase { + pub fn as_str(&self) -> &'static str { + match self { + Self::Idle => "idle", + Self::Analyzing => "analyzing", + Self::Discovering => "discovering", + Self::Generating => "generating", + Self::Complete => "complete", + Self::Error => "error", + } + } + + pub fn is_active(&self) -> bool { + matches!(self, Self::Analyzing | Self::Discovering | Self::Generating) + } + + pub fn parse(s: &str) -> Option { + match s.to_lowercase().as_str() { + "idle" => Some(Self::Idle), + "analyzing" => Some(Self::Analyzing), + "discovering" => Some(Self::Discovering), + "generating" => Some(Self::Generating), + "complete" => Some(Self::Complete), + "error" => Some(Self::Error), + _ => None, + } + } +} + +// ============================================ +// Structs +// ============================================ + +/// Target audience for the product +#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +pub struct TargetAudience { + /// Primary user persona + pub primary: String, + /// Secondary user personas + #[serde(default)] + pub secondary: Vec, + /// Pain points the target audience faces + #[serde(default)] + pub pain_points: Vec, + /// Goals the target audience wants to achieve + #[serde(default)] + pub goals: Vec, + /// Usage context (when/where/how they use the product) + #[serde(default)] + pub usage_context: Option, +} + +/// A milestone within a roadmap phase +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +pub struct RoadmapMilestone { + /// Unique identifier + pub id: String, + /// Milestone title + pub title: String, + /// Milestone description + pub description: String, + /// Feature IDs included in this milestone + #[serde(default)] + pub features: Vec, + /// Milestone status + #[serde(default)] + pub status: RoadmapPhaseStatus, +} + +/// A phase in the roadmap (e.g., Foundation, Enhancement, Scale) +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +pub struct RoadmapPhase { + /// Unique identifier + pub id: String, + /// Phase name + pub name: String, + /// Phase description + pub description: String, + /// Order in the roadmap (1-based) + pub order: u32, + /// Phase status + #[serde(default)] + pub status: RoadmapPhaseStatus, + /// Feature IDs in this phase + #[serde(default)] + pub features: Vec, + /// Milestones within this phase + #[serde(default)] + pub milestones: Vec, +} + +/// A feature in the roadmap +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +pub struct RoadmapFeature { + /// Unique identifier + pub id: String, + /// Feature title + pub title: String, + /// Feature description + pub description: String, + /// Rationale - why this feature matters + #[serde(default)] + pub rationale: String, + /// Priority (MoSCoW) + #[serde(default)] + pub priority: RoadmapPriority, + /// Complexity estimate + #[serde(default)] + pub complexity: RoadmapComplexity, + /// Impact estimate + #[serde(default)] + pub impact: RoadmapImpact, + /// Phase this feature belongs to + pub phase_id: String, + /// Feature IDs this depends on + #[serde(default)] + pub dependencies: Vec, + /// Current status + #[serde(default)] + pub status: RoadmapFeatureStatus, + /// Acceptance criteria + #[serde(default)] + pub acceptance_criteria: Vec, + /// User stories + #[serde(default)] + pub user_stories: Vec, + /// Linked task ID (when converted to task) + #[serde(default)] + pub linked_task_id: Option, +} + +/// The complete roadmap +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +pub struct Roadmap { + /// Unique identifier + pub id: String, + /// Project name + pub project_name: String, + /// Roadmap version + #[serde(default = "default_version")] + pub version: String, + /// Product vision statement + pub vision: String, + /// Target audience information + #[serde(default)] + pub target_audience: TargetAudience, + /// Roadmap phases + #[serde(default)] + pub phases: Vec, + /// All features in the roadmap + #[serde(default)] + pub features: Vec, + /// Overall roadmap status + #[serde(default)] + pub status: RoadmapStatus, + /// Creation timestamp + #[serde(default = "default_now")] + pub created_at: DateTime, + /// Last update timestamp + #[serde(default = "default_now")] + pub updated_at: DateTime, +} + +fn default_version() -> String { + "1.0".to_string() +} + +fn default_now() -> DateTime { + Utc::now() +} + +impl Roadmap { + /// Create a new empty roadmap + pub fn new(project_name: impl Into, vision: impl Into) -> Self { + let now = Utc::now(); + Self { + id: format!("roadmap-{}", now.timestamp_millis()), + project_name: project_name.into(), + version: default_version(), + vision: vision.into(), + target_audience: TargetAudience::default(), + phases: Vec::new(), + features: Vec::new(), + status: RoadmapStatus::Draft, + created_at: now, + updated_at: now, + } + } + + /// Get features by status + pub fn features_by_status(&self, status: RoadmapFeatureStatus) -> Vec<&RoadmapFeature> { + self.features + .iter() + .filter(|f| f.status == status) + .collect() + } + + /// Get features by phase + pub fn features_by_phase(&self, phase_id: &str) -> Vec<&RoadmapFeature> { + self.features + .iter() + .filter(|f| f.phase_id == phase_id) + .collect() + } + + /// Get feature by ID + pub fn feature_by_id(&self, id: &str) -> Option<&RoadmapFeature> { + self.features.iter().find(|f| f.id == id) + } + + /// Get mutable feature by ID + pub fn feature_by_id_mut(&mut self, id: &str) -> Option<&mut RoadmapFeature> { + self.features.iter_mut().find(|f| f.id == id) + } + + /// Get statistics about the roadmap + pub fn stats(&self) -> RoadmapStats { + let mut by_priority = std::collections::HashMap::new(); + let mut by_status = std::collections::HashMap::new(); + let mut by_complexity = std::collections::HashMap::new(); + + for feature in &self.features { + *by_priority.entry(feature.priority).or_insert(0) += 1; + *by_status.entry(feature.status).or_insert(0) += 1; + *by_complexity.entry(feature.complexity).or_insert(0) += 1; + } + + RoadmapStats { + total_features: self.features.len(), + total_phases: self.phases.len(), + by_priority, + by_status, + by_complexity, + } + } +} + +/// Statistics about a roadmap +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +pub struct RoadmapStats { + pub total_features: usize, + pub total_phases: usize, + #[serde(default)] + pub by_priority: std::collections::HashMap, + #[serde(default)] + pub by_status: std::collections::HashMap, + #[serde(default)] + pub by_complexity: std::collections::HashMap, +} + +/// Status of roadmap generation +#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +pub struct RoadmapGenerationStatus { + /// Current phase + #[serde(default)] + pub phase: RoadmapGenerationPhase, + /// Progress percentage (0-100) + #[serde(default)] + pub progress: u8, + /// Current message/status + #[serde(default)] + pub message: String, + /// Error message if phase is Error + #[serde(default)] + pub error: Option, +} + +impl RoadmapGenerationStatus { + pub fn idle() -> Self { + Self { + phase: RoadmapGenerationPhase::Idle, + progress: 0, + message: String::new(), + error: None, + } + } + + pub fn analyzing() -> Self { + Self { + phase: RoadmapGenerationPhase::Analyzing, + progress: 10, + message: "Analyzing project structure...".to_string(), + error: None, + } + } + + pub fn discovering() -> Self { + Self { + phase: RoadmapGenerationPhase::Discovering, + progress: 40, + message: "Discovering target audience and product vision...".to_string(), + error: None, + } + } + + pub fn generating() -> Self { + Self { + phase: RoadmapGenerationPhase::Generating, + progress: 70, + message: "Generating feature roadmap...".to_string(), + error: None, + } + } + + pub fn complete() -> Self { + Self { + phase: RoadmapGenerationPhase::Complete, + progress: 100, + message: "Roadmap generation complete!".to_string(), + error: None, + } + } + + pub fn error(message: impl Into) -> Self { + Self { + phase: RoadmapGenerationPhase::Error, + progress: 0, + message: "Generation failed".to_string(), + error: Some(message.into()), + } + } +} + +// ============================================ +// Request/Response types for API +// ============================================ + +/// Request to generate a roadmap +#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +pub struct GenerateRoadmapRequest { + /// Force regeneration even if roadmap exists + #[serde(default)] + pub force: bool, +} + +/// Request to update a feature +#[derive(Debug, Clone, Serialize, Deserialize, Default, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +pub struct UpdateFeatureRequest { + pub status: Option, + pub phase_id: Option, + pub priority: Option, + pub linked_task_id: Option, +} + +/// Response for convert feature to task +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +pub struct ConvertToTaskResponse { + pub task_id: String, + pub feature_id: String, +} + +// ============================================ +// Tests +// ============================================ + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_priority_parsing() { + assert_eq!(RoadmapPriority::parse("must"), Some(RoadmapPriority::Must)); + assert_eq!( + RoadmapPriority::parse("SHOULD"), + Some(RoadmapPriority::Should) + ); + assert_eq!(RoadmapPriority::parse("wont"), Some(RoadmapPriority::Wont)); + assert_eq!(RoadmapPriority::parse("won't"), Some(RoadmapPriority::Wont)); + assert_eq!(RoadmapPriority::parse("invalid"), None); + } + + #[test] + fn test_feature_status_parsing() { + assert_eq!( + RoadmapFeatureStatus::parse("under_review"), + Some(RoadmapFeatureStatus::UnderReview) + ); + assert_eq!( + RoadmapFeatureStatus::parse("idea"), + Some(RoadmapFeatureStatus::UnderReview) + ); + assert_eq!( + RoadmapFeatureStatus::parse("in_progress"), + Some(RoadmapFeatureStatus::InProgress) + ); + } + + #[test] + fn test_roadmap_creation() { + let roadmap = Roadmap::new("Test Project", "Build something amazing"); + + assert_eq!(roadmap.project_name, "Test Project"); + assert_eq!(roadmap.vision, "Build something amazing"); + assert_eq!(roadmap.status, RoadmapStatus::Draft); + assert!(roadmap.features.is_empty()); + assert!(roadmap.phases.is_empty()); + } + + #[test] + fn test_roadmap_stats() { + let mut roadmap = Roadmap::new("Test", "Vision"); + roadmap.features.push(RoadmapFeature { + id: "f1".to_string(), + title: "Feature 1".to_string(), + description: "Desc".to_string(), + rationale: String::new(), + priority: RoadmapPriority::Must, + complexity: RoadmapComplexity::Low, + impact: RoadmapImpact::High, + phase_id: "p1".to_string(), + dependencies: Vec::new(), + status: RoadmapFeatureStatus::Planned, + acceptance_criteria: Vec::new(), + user_stories: Vec::new(), + linked_task_id: None, + }); + roadmap.features.push(RoadmapFeature { + id: "f2".to_string(), + title: "Feature 2".to_string(), + description: "Desc".to_string(), + rationale: String::new(), + priority: RoadmapPriority::Should, + complexity: RoadmapComplexity::Medium, + impact: RoadmapImpact::Medium, + phase_id: "p1".to_string(), + dependencies: Vec::new(), + status: RoadmapFeatureStatus::UnderReview, + acceptance_criteria: Vec::new(), + user_stories: Vec::new(), + linked_task_id: None, + }); + + let stats = roadmap.stats(); + assert_eq!(stats.total_features, 2); + assert_eq!(stats.by_priority.get(&RoadmapPriority::Must), Some(&1)); + assert_eq!(stats.by_priority.get(&RoadmapPriority::Should), Some(&1)); + } + + #[test] + fn test_generation_status() { + let status = RoadmapGenerationStatus::analyzing(); + assert_eq!(status.phase, RoadmapGenerationPhase::Analyzing); + assert_eq!(status.progress, 10); + + let error = RoadmapGenerationStatus::error("Something went wrong"); + assert_eq!(error.phase, RoadmapGenerationPhase::Error); + assert_eq!(error.error, Some("Something went wrong".to_string())); + } +} diff --git a/crates/db/src/repositories/diff_viewed_repository.rs b/crates/db/src/repositories/diff_viewed_repository.rs index f69196c..1963723 100644 --- a/crates/db/src/repositories/diff_viewed_repository.rs +++ b/crates/db/src/repositories/diff_viewed_repository.rs @@ -92,12 +92,30 @@ mod tests { pool } + /// Create a task in the database for foreign key constraints + async fn create_test_task(pool: &SqlitePool, task_id: &str) { + let now = Utc::now().timestamp(); + sqlx::query( + r#" + INSERT INTO tasks (id, title, description, status, created_at, updated_at) + VALUES (?, 'Test Task', 'Test description', 'todo', ?, ?) + "#, + ) + .bind(task_id) + .bind(now) + .bind(now) + .execute(pool) + .await + .unwrap(); + } + #[tokio::test] async fn test_mark_and_get_viewed_files() { let pool = setup_test_db().await; - let repo = DiffViewedRepository::new(pool); + let repo = DiffViewedRepository::new(pool.clone()); let task_id = "test-task-123"; + create_test_task(&pool, task_id).await; // Initially no viewed files let viewed = repo.get_viewed_files(task_id).await.unwrap(); @@ -116,9 +134,10 @@ mod tests { #[tokio::test] async fn test_unmark_viewed() { let pool = setup_test_db().await; - let repo = DiffViewedRepository::new(pool); + let repo = DiffViewedRepository::new(pool.clone()); let task_id = "test-task-456"; + create_test_task(&pool, task_id).await; repo.mark_viewed(task_id, "src/main.rs").await.unwrap(); repo.mark_viewed(task_id, "src/lib.rs").await.unwrap(); @@ -133,9 +152,10 @@ mod tests { #[tokio::test] async fn test_clear_viewed_files() { let pool = setup_test_db().await; - let repo = DiffViewedRepository::new(pool); + let repo = DiffViewedRepository::new(pool.clone()); let task_id = "test-task-789"; + create_test_task(&pool, task_id).await; repo.mark_viewed(task_id, "src/main.rs").await.unwrap(); repo.mark_viewed(task_id, "src/lib.rs").await.unwrap(); @@ -149,9 +169,10 @@ mod tests { #[tokio::test] async fn test_mark_viewed_idempotent() { let pool = setup_test_db().await; - let repo = DiffViewedRepository::new(pool); + let repo = DiffViewedRepository::new(pool.clone()); let task_id = "test-task-idempotent"; + create_test_task(&pool, task_id).await; // Mark same file twice should not fail repo.mark_viewed(task_id, "src/main.rs").await.unwrap(); diff --git a/crates/db/src/repositories/review_comment_repository.rs b/crates/db/src/repositories/review_comment_repository.rs index fd8b401..afaf972 100644 --- a/crates/db/src/repositories/review_comment_repository.rs +++ b/crates/db/src/repositories/review_comment_repository.rs @@ -225,10 +225,28 @@ mod tests { pool } + async fn create_test_task(pool: &SqlitePool, task_id: &str) { + let now = Utc::now().timestamp(); + sqlx::query( + r#" + INSERT INTO tasks (id, title, description, status, created_at, updated_at) + VALUES (?, 'Test Task', 'Test description', 'todo', ?, ?) + "#, + ) + .bind(task_id) + .bind(now) + .bind(now) + .execute(pool) + .await + .unwrap(); + } + #[tokio::test] async fn test_create_and_find_comment() { let pool = setup_test_db().await; - let repo = ReviewCommentRepository::new(pool); + let repo = ReviewCommentRepository::new(pool.clone()); + + create_test_task(&pool, "task-123").await; let comment = repo .create( @@ -257,7 +275,10 @@ mod tests { #[tokio::test] async fn test_find_by_task_id() { let pool = setup_test_db().await; - let repo = ReviewCommentRepository::new(pool); + let repo = ReviewCommentRepository::new(pool.clone()); + + create_test_task(&pool, "task-1").await; + create_test_task(&pool, "task-2").await; repo.create("c1", "task-1", "src/a.rs", 1, 5, "new", "Comment 1") .await @@ -276,7 +297,9 @@ mod tests { #[tokio::test] async fn test_update_status() { let pool = setup_test_db().await; - let repo = ReviewCommentRepository::new(pool); + let repo = ReviewCommentRepository::new(pool.clone()); + + create_test_task(&pool, "task-1").await; repo.create("c1", "task-1", "src/a.rs", 1, 5, "new", "Comment") .await @@ -291,7 +314,9 @@ mod tests { #[tokio::test] async fn test_delete_comment() { let pool = setup_test_db().await; - let repo = ReviewCommentRepository::new(pool); + let repo = ReviewCommentRepository::new(pool.clone()); + + create_test_task(&pool, "task-1").await; repo.create("c1", "task-1", "src/a.rs", 1, 5, "new", "Comment") .await diff --git a/crates/events/bindings/AgentMessageData.ts b/crates/events/bindings/AgentMessageData.ts new file mode 100644 index 0000000..42d2fd3 --- /dev/null +++ b/crates/events/bindings/AgentMessageData.ts @@ -0,0 +1,15 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type AgentMessageData = { +/** + * The message content + */ +content: string, +/** + * Message role (assistant, user, system) + */ +role: string, +/** + * Whether this is a partial/streaming message + */ +is_partial: boolean, }; diff --git a/crates/events/bindings/Event.ts b/crates/events/bindings/Event.ts new file mode 100644 index 0000000..dfc5d03 --- /dev/null +++ b/crates/events/bindings/Event.ts @@ -0,0 +1,82 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AgentMessageData } from "./AgentMessageData"; +import type { ToolExecutionData } from "./ToolExecutionData"; +import type { WikiGenerationPhase } from "./WikiGenerationPhase"; + +export type Event = { "type": "task.created", task_id: string, title: string, } | { "type": "task.updated", task_id: string, } | { "type": "task.status_changed", task_id: string, from_status: string, to_status: string, } | { "type": "session.started", session_id: string, task_id: string, +/** + * Session phase (planning, implementation, review, etc.) + */ +phase: string, +/** + * Session status (pending, running, completed, failed) + */ +status: string, +/** + * OpenCode session ID (when connected) + */ +opencode_session_id: string | null, +/** + * When the session was created + */ +created_at: string, } | { "type": "session.ended", session_id: string, task_id: string, success: boolean, } | { "type": "phase.completed", task_id: string, session_id: string, +/** + * The phase number that was completed (1-indexed) + */ +phase_number: number, +/** + * Total number of phases + */ +total_phases: number, +/** + * Title of the completed phase + */ +phase_title: string, } | { "type": "phase.continuing", task_id: string, +/** + * The next phase number (1-indexed) + */ +next_phase_number: number, +/** + * Total number of phases + */ +total_phases: number, } | { "type": "agent.message", session_id: string, task_id: string, message: AgentMessageData, } | { "type": "tool.execution", session_id: string, task_id: string, tool: ToolExecutionData, } | { "type": "workspace.created", task_id: string, path: string, } | { "type": "workspace.merged", task_id: string, success: boolean, } | { "type": "workspace.deleted", task_id: string, } | { "type": "project.opened", path: string, name: string, was_initialized: boolean, } | { "type": "project.closed", path: string, } | { "type": "wiki.generation_progress", branch: string, phase: WikiGenerationPhase, current: number, total: number, current_item: string | null, message: string | null, } | { "type": "roadmap.generation_started" } | { "type": "roadmap.generation_progress", +/** + * Current phase (analyzing, discovering, generating, complete, error) + */ +phase: string, +/** + * Progress percentage (0-100) + */ +progress: number, +/** + * Status message + */ +message: string, } | { "type": "roadmap.generation_completed", +/** + * Number of features generated + */ +feature_count: number, +/** + * Number of phases generated + */ +phase_count: number, } | { "type": "roadmap.generation_failed", +/** + * Error message + */ +error: string, } | { "type": "roadmap.feature_updated", +/** + * Feature ID + */ +feature_id: string, +/** + * New status (if changed) + */ +status: string | null, } | { "type": "roadmap.feature_converted", +/** + * Feature ID + */ +feature_id: string, +/** + * Created task ID + */ +task_id: string, } | { "type": "error", message: string, context: string | null, }; diff --git a/crates/events/bindings/EventEnvelope.ts b/crates/events/bindings/EventEnvelope.ts new file mode 100644 index 0000000..2df75cf --- /dev/null +++ b/crates/events/bindings/EventEnvelope.ts @@ -0,0 +1,16 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { Event } from "./Event"; + +export type EventEnvelope = { +/** + * Unique event ID + */ +id: string, +/** + * When the event occurred + */ +timestamp: string, +/** + * The actual event + */ +event: Event, }; diff --git a/crates/events/bindings/ToolExecutionData.ts b/crates/events/bindings/ToolExecutionData.ts new file mode 100644 index 0000000..ccd63f3 --- /dev/null +++ b/crates/events/bindings/ToolExecutionData.ts @@ -0,0 +1,19 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ToolExecutionData = { +/** + * Tool name + */ +name: string, +/** + * Tool input (JSON string or summary) + */ +input: string | null, +/** + * Tool output (truncated if large) + */ +output: string | null, +/** + * Whether the tool succeeded + */ +success: boolean, }; diff --git a/crates/events/bindings/WikiGenerationPhase.ts b/crates/events/bindings/WikiGenerationPhase.ts new file mode 100644 index 0000000..03b2cd9 --- /dev/null +++ b/crates/events/bindings/WikiGenerationPhase.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type WikiGenerationPhase = "analyzing" | "planning" | "generating_pages" | "completed" | "failed"; diff --git a/crates/events/src/types.rs b/crates/events/src/types.rs index f33cba0..dfa166b 100644 --- a/crates/events/src/types.rs +++ b/crates/events/src/types.rs @@ -138,6 +138,68 @@ pub enum Event { #[serde(rename = "project.closed")] ProjectClosed { path: String }, + // Wiki events + /// Wiki generation progress update + #[serde(rename = "wiki.generation_progress")] + WikiGenerationProgress { + branch: String, + phase: WikiGenerationPhase, + current: u32, + total: u32, + current_item: Option, + message: Option, + }, + + // Roadmap events + /// Roadmap generation started + #[serde(rename = "roadmap.generation_started")] + RoadmapGenerationStarted, + + /// Roadmap generation progress update + #[serde(rename = "roadmap.generation_progress")] + RoadmapGenerationProgress { + /// Current phase (analyzing, discovering, generating, complete, error) + phase: String, + /// Progress percentage (0-100) + progress: u8, + /// Status message + message: String, + }, + + /// Roadmap generation completed + #[serde(rename = "roadmap.generation_completed")] + RoadmapGenerationCompleted { + /// Number of features generated + feature_count: usize, + /// Number of phases generated + phase_count: usize, + }, + + /// Roadmap generation failed + #[serde(rename = "roadmap.generation_failed")] + RoadmapGenerationFailed { + /// Error message + error: String, + }, + + /// Roadmap feature updated + #[serde(rename = "roadmap.feature_updated")] + RoadmapFeatureUpdated { + /// Feature ID + feature_id: String, + /// New status (if changed) + status: Option, + }, + + /// Roadmap feature converted to task + #[serde(rename = "roadmap.feature_converted")] + RoadmapFeatureConverted { + /// Feature ID + feature_id: String, + /// Created task ID + task_id: Uuid, + }, + // System events /// Generic error event #[serde(rename = "error")] @@ -147,6 +209,18 @@ pub enum Event { }, } +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] +#[cfg_attr(feature = "typescript", ts(export))] +#[serde(rename_all = "snake_case")] +pub enum WikiGenerationPhase { + Analyzing, + Planning, + GeneratingPages, + Completed, + Failed, +} + #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] #[cfg_attr(feature = "typescript", derive(ts_rs::TS))] #[cfg_attr(feature = "typescript", ts(export))] @@ -190,6 +264,13 @@ impl Event { Event::WorkspaceDeleted { task_id } => Some(*task_id), Event::ProjectOpened { .. } => None, Event::ProjectClosed { .. } => None, + Event::WikiGenerationProgress { .. } => None, + Event::RoadmapGenerationStarted => None, + Event::RoadmapGenerationProgress { .. } => None, + Event::RoadmapGenerationCompleted { .. } => None, + Event::RoadmapGenerationFailed { .. } => None, + Event::RoadmapFeatureUpdated { .. } => None, + Event::RoadmapFeatureConverted { task_id, .. } => Some(*task_id), Event::Error { .. } => None, } } diff --git a/crates/github/Cargo.toml b/crates/github/Cargo.toml index ec2a55f..2c22c91 100644 --- a/crates/github/Cargo.toml +++ b/crates/github/Cargo.toml @@ -14,6 +14,8 @@ thiserror = { workspace = true } tracing = { workspace = true } chrono = { workspace = true } async-trait = { workspace = true } +ts-rs = { workspace = true } +utoipa = { workspace = true } # GitHub API client octocrab = "0.41" diff --git a/crates/github/bindings/CheckRun.ts b/crates/github/bindings/CheckRun.ts new file mode 100644 index 0000000..38b78c2 --- /dev/null +++ b/crates/github/bindings/CheckRun.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type CheckRun = { name: string, status: string, conclusion: string | null, html_url: string | null, }; diff --git a/crates/github/bindings/CiState.ts b/crates/github/bindings/CiState.ts new file mode 100644 index 0000000..3ac9632 --- /dev/null +++ b/crates/github/bindings/CiState.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type CiState = "pending" | "success" | "failure" | "error"; diff --git a/crates/github/bindings/CiStatus.ts b/crates/github/bindings/CiStatus.ts new file mode 100644 index 0000000..d985e29 --- /dev/null +++ b/crates/github/bindings/CiStatus.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { CheckRun } from "./CheckRun"; +import type { CiState } from "./CiState"; + +export type CiStatus = { state: CiState, total_count: number, checks: Array, }; diff --git a/crates/github/bindings/DiffSide.ts b/crates/github/bindings/DiffSide.ts new file mode 100644 index 0000000..4efb44f --- /dev/null +++ b/crates/github/bindings/DiffSide.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type DiffSide = "LEFT" | "RIGHT"; diff --git a/crates/github/bindings/FileStatus.ts b/crates/github/bindings/FileStatus.ts new file mode 100644 index 0000000..dec337b --- /dev/null +++ b/crates/github/bindings/FileStatus.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type FileStatus = "added" | "removed" | "modified" | "renamed" | "copied" | "changed" | "unchanged"; diff --git a/crates/github/bindings/GitHubUser.ts b/crates/github/bindings/GitHubUser.ts new file mode 100644 index 0000000..d0c4a7e --- /dev/null +++ b/crates/github/bindings/GitHubUser.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type GitHubUser = { login: string, avatar_url: string, html_url: string, }; diff --git a/crates/github/bindings/Label.ts b/crates/github/bindings/Label.ts new file mode 100644 index 0000000..0ff08f6 --- /dev/null +++ b/crates/github/bindings/Label.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type Label = { name: string, color: string, description: string | null, }; diff --git a/crates/github/bindings/PrFile.ts b/crates/github/bindings/PrFile.ts new file mode 100644 index 0000000..0318f1c --- /dev/null +++ b/crates/github/bindings/PrFile.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { FileStatus } from "./FileStatus"; + +export type PrFile = { filename: string, status: FileStatus, additions: number, deletions: number, changes: number, patch: string | null, previous_filename: string | null, }; diff --git a/crates/github/bindings/PrIssueComment.ts b/crates/github/bindings/PrIssueComment.ts new file mode 100644 index 0000000..7750977 --- /dev/null +++ b/crates/github/bindings/PrIssueComment.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { GitHubUser } from "./GitHubUser"; +import type { Reactions } from "./Reactions"; + +export type PrIssueComment = { id: bigint, body: string, user: GitHubUser, created_at: string, updated_at: string, html_url: string, reactions: Reactions | null, }; diff --git a/crates/github/bindings/PrReview.ts b/crates/github/bindings/PrReview.ts new file mode 100644 index 0000000..63bf4d1 --- /dev/null +++ b/crates/github/bindings/PrReview.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { GitHubUser } from "./GitHubUser"; +import type { ReviewState } from "./ReviewState"; + +export type PrReview = { id: bigint, user: GitHubUser, state: ReviewState, body: string | null, submitted_at: string | null, html_url: string, }; diff --git a/crates/github/bindings/PrReviewComment.ts b/crates/github/bindings/PrReviewComment.ts new file mode 100644 index 0000000..a5f15f4 --- /dev/null +++ b/crates/github/bindings/PrReviewComment.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { DiffSide } from "./DiffSide"; +import type { GitHubUser } from "./GitHubUser"; +import type { Reactions } from "./Reactions"; + +export type PrReviewComment = { id: bigint, body: string, path: string, line: number | null, original_line: number | null, side: DiffSide, commit_id: string, user: GitHubUser, created_at: string, updated_at: string, html_url: string, in_reply_to_id: bigint | null, reactions: Reactions | null, }; diff --git a/crates/github/bindings/PrState.ts b/crates/github/bindings/PrState.ts new file mode 100644 index 0000000..a4f3931 --- /dev/null +++ b/crates/github/bindings/PrState.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type PrState = "open" | "closed" | "merged"; diff --git a/crates/github/bindings/PullRequestDetail.ts b/crates/github/bindings/PullRequestDetail.ts new file mode 100644 index 0000000..c129fa6 --- /dev/null +++ b/crates/github/bindings/PullRequestDetail.ts @@ -0,0 +1,7 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { CiStatus } from "./CiStatus"; +import type { GitHubUser } from "./GitHubUser"; +import type { Label } from "./Label"; +import type { PrState } from "./PrState"; + +export type PullRequestDetail = { number: bigint, title: string, body: string | null, state: PrState, head_branch: string, base_branch: string, html_url: string, created_at: string, updated_at: string, merged_at: string | null, ci_status: CiStatus | null, user: GitHubUser, additions: number, deletions: number, changed_files: number, mergeable: boolean | null, mergeable_state: string | null, labels: Array