diff --git a/apps/captain-mobile-v2/ESTADO_PROYECTO.md b/apps/captain-mobile-v2/ESTADO_PROYECTO.md index 0aa5911..9c0e6e9 100644 --- a/apps/captain-mobile-v2/ESTADO_PROYECTO.md +++ b/apps/captain-mobile-v2/ESTADO_PROYECTO.md @@ -1,164 +1,131 @@ -# Captain Claude Mobile v2 - Estado del Proyecto +# Captain Claude Mobile - Estado del Proyecto **Fecha:** 2026-01-17 -**Estado:** BACKEND ACTUALIZADO / PENDIENTE COMPILAR APK +**Versión:** v3.1 +**Estado:** FUNCIONAL --- -## Cambios Realizados (17 Ene 2026) +## Resumen -### Backend reescrito con patrón LLMChat - -Se aplicó el patrón de streaming de [LLMChat](https://github.com/c0sogi/LLMChat): - -1. **Queue para desacoplar receiver/sender** - - `asyncio.Queue` para mensajes entrantes - - `ws_receiver()` y `ws_sender()` corren en paralelo con `asyncio.gather()` - -2. **ChatBuffer** - Contexto por conexión - - Mantiene estado: `websocket`, `username`, `queue`, `done`, `conversation_id` - - `done` event para interrumpir streaming - -3. **Mensaje `init` al conectar** - - Envía lista de conversaciones al conectar - - Frontend recibe estado inicial sin llamada REST adicional - -4. **Soporte para interrumpir streaming** - - Cliente envía `{"type": "stop"}` - - Backend termina proceso Claude y envía `{"type": "interrupted"}` - -5. **Nuevos tipos de mensaje** - - `init` - Estado inicial con conversaciones - - `text_start` - Inicio de bloque de texto - - `tool_input` - Input completo del tool - - `interrupted` - Generación interrumpida - - `conversation_loaded` - Conversación cargada via WS +App móvil para chatear con Claude Code usando `claude -p --output-format stream-json`. --- -## Configuración Actual +## Arquitectura v3 -| Componente | Puerto | Notas | -|------------|--------|-------| -| **captain-api-v2** | **3030** | Backend con patrón LLMChat | +### Backend (`captain_api_v3.py`) -**Credenciales:** `admin` / `admin` -**Servicio:** `captain-api-v2.service` (systemd) +- **Puerto:** 3030 +- **Servicio systemd:** `captain-claude` +- **Método:** `claude -p --output-format stream-json` +- **Contexto:** `--resume SESSION_ID` mantiene historial de conversación +- **Auto-connect:** Al crear sesión, se conecta automáticamente +- **Almacenamiento:** Sesiones en memoria (se pierden al reiniciar) + +### Flutter App + +- **APK:** `260117_captain-claude-v3.1.apk` +- **UI:** Simplificada - botón + para nuevo chat, logout +- **Conexión:** WebSocket a `wss://captain.tzzrarchitect.me/ws/chat` --- -## Archivos Modificados +## API WebSocket + +### Mensajes del Cliente + +```json +{"token": "jwt"} // Autenticación +{"type": "create_session", "name": "Chat 1"} // Crear sesión +{"type": "message", "content": "hola"} // Enviar mensaje +{"type": "ping"} // Keep-alive +``` + +### Respuestas del Servidor + +```json +{"type": "init", "sessions": [...]} // Estado inicial +{"type": "session_created", "session_id": "x", "name": "y"} // Sesión creada +{"type": "session_connected", "session_id": "x", "name": "y"} // Conectado +{"type": "output", "content": "..."} // Respuesta de Claude +{"type": "done", "session_id": "uuid"} // Respuesta completa +{"type": "error", "message": "..."} // Error +``` + +--- + +## Archivos ``` apps/captain-mobile-v2/ ├── backend/ -│ ├── captain_api_v2.py # Backend reescrito -│ └── captain-api-v2.service # Puerto 3031 -├── flutter/lib/ -│ ├── config/api_config.dart # Puerto 3031 -│ ├── services/chat_service.dart # Nuevos eventos -│ └── providers/chat_provider.dart # Manejo de init, interrupted, etc. -└── ESTADO_PROYECTO.md # Este archivo +│ ├── captain_api_v3.py # Backend actual +│ ├── captain-claude.service # Servicio systemd +│ └── test_*.py # Tests +├── flutter/ +│ ├── lib/ +│ │ ├── screens/chat_screen.dart +│ │ ├── providers/chat_provider.dart +│ │ ├── services/chat_service.dart +│ │ └── config/api_config.dart +│ └── build/app/outputs/flutter-apk/app-release.apk +└── ESTADO_PROYECTO.md ``` --- -## Próximos Pasos +## Comandos Útiles -### 1. Instalar servicio systemd (requiere sudo) ```bash -sudo cp captain-api-v2.service /etc/systemd/system/ -sudo systemctl daemon-reload -sudo systemctl enable captain-api-v2 -sudo systemctl start captain-api-v2 -``` +# Estado del servicio +systemctl status captain-claude -### 2. Compilar APK -```bash +# Logs +journalctl -u captain-claude -f + +# Reiniciar +systemctl restart captain-claude + +# Compilar APK cd /home/architect/captain-claude/apps/captain-mobile-v2/flutter /home/architect/flutter/bin/flutter build apk --release -``` -### 3. Subir a Nextcloud -```bash -scp -i ~/.ssh/tzzr build/app/outputs/flutter-apk/app-release.apk \ - root@72.62.1.113:"/var/www/nextcloud/data/tzzrdeck/files/documentos adjuntos/captain-mobile-v2.apk" -ssh -i ~/.ssh/tzzr root@72.62.1.113 \ - "chown www-data:www-data '/var/www/nextcloud/data/tzzrdeck/files/documentos adjuntos/captain-mobile-v2.apk' && \ - cd /var/www/nextcloud && sudo -u www-data php occ files:scan tzzrdeck" +# Subir a Nextcloud +/home/architect/bin/rclone copy build/app/outputs/flutter-apk/app-release.apk nextcloud-architect:app/ ``` --- -## Probar Backend Manualmente +## Siguiente Paso: Sesiones Screen -```bash -# Health check -curl http://localhost:3031/health +### Objetivo -# Login -TOKEN=$(curl -s -X POST http://localhost:3031/auth/login \ - -H "Content-Type: application/json" \ - -d '{"username":"admin","password":"admin"}' | jq -r '.token') +Crear versión capaz de: +1. Listar sesiones screen existentes +2. Conectarse a sesiones screen en tiempo real +3. Crear nuevas sesiones screen con Claude Code +4. Enviar input a sesiones activas -# Listar conversaciones -curl -H "Authorization: Bearer $TOKEN" http://localhost:3031/conversations -``` +### Diferencia + +| v3 Actual | Screen Sessions | +|-----------|-----------------| +| `claude -p` por mensaje | Proceso persistente en screen | +| Sesiones en memoria | Sesiones reales en servidor | +| Solo texto limpio | Output completo | +| Sin acceso a otras screens | Acceso a cualquier screen | + +### Implementación + +1. Backend v4 con endpoints para screen +2. Parsing de output ANSI +3. Flutter con selector de screens --- -## Arquitectura WebSocket (LLMChat pattern) +## Historial -``` -┌─────────────────┐ WebSocket ┌─────────────────┐ -│ Flutter Client │ ◄───────────────► │ FastAPI Server │ -│ │ /ws/chat │ │ -└─────────────────┘ └────────┬────────┘ - │ - ┌──────────────────────────────────────┼──────────────────┐ - │ │ │ - ▼ ▼ ▼ - ws_receiver() ws_sender() ChatBuffer - - Recibe JSON - Procesa queue - websocket - - stop → buffer.done.set() - Llama Claude - username - - ping → pong - Stream chunks - queue - - Otros → queue.put() - Guarda en DB - done event -``` - ---- - -## Flujo de Mensajes - -### Conexión -``` -Cliente Servidor - │ │ - │──── {"token": "xxx"} ─────────►│ - │ │ - │◄─── {"type": "init", │ - │ "user": "admin", │ - │ "conversations": [...]} │ -``` - -### Chat -``` -Cliente Servidor - │ │ - │──── {"type": "message", │ - │ "content": "Hola"} ──────►│ - │ │ - │◄─── {"type": "start"} ─────────│ - │◄─── {"type": "thinking"} ──────│ - │◄─── {"type": "delta", ...} ────│ (múltiples) - │◄─── {"type": "done", ...} ─────│ -``` - -### Interrumpir -``` -Cliente Servidor - │ │ - │──── {"type": "stop"} ─────────►│ - │ │ - │◄─── {"type": "interrupted", │ - │ "content": "..."} ────────│ -``` +- **v3.1** (17/01/26): UI simplificada, auto-connect en backend +- **v3.0** (17/01/26): Cambio a `claude -p --output-format stream-json` +- **v2.x** (17/01/26): Intentos con screen+hardcopy (descartado)