Skip to content
This repository was archived by the owner on Aug 5, 2026. It is now read-only.

feat: session pruning, tunnel logging, and CLI improvements - #29

Merged
dzianisv merged 165 commits into
mainfrom
feature/session-prune-and-tunnel-logs
Feb 7, 2026
Merged

dzianisv merged 165 commits into
mainfrom
feature/session-prune-and-tunnel-logs

Conversation

@dzianisv

@dzianisv dzianisv commented Feb 4, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Session Pruning: Add automatic cleanup of old/orphaned sessions with configurable retention policies
  • Tunnel Logging: Surface cloudflared tunnel logs in the UI for debugging connection issues
  • CLI Improvements: Enhanced status command with YAML output and comprehensive health checks
  • Coqui TTS Multi-Model: 7+ high-quality English voice models with runtime switching
  • Log Maintenance: Auto-rotate log files to prevent disk bloat

Changes

Session Pruning

  • New SessionPruneSettings component in frontend for configuring retention policies
  • Backend service to prune sessions older than configured days or orphaned sessions
  • Auto-prune on startup with log rotation

Tunnel Status & Logs

  • New /api/tunnel/status endpoint showing connection state, URL, and edge location
  • TunnelSettings component shows live tunnel status and authenticated URL
  • Cloudflare tunnel logs surfaced in Settings UI
  • CLI status command includes tunnel info with embedded auth credentials

CLI Status Command

  • Output in YAML format for easy parsing by scripts
  • Shows backend, STT, TTS, and tunnel health
  • Includes tunnel URL with embedded auth credentials
  • Exit code 0 for healthy/degraded, 1 for unhealthy

Coqui TTS Multi-Model Support

  • 7+ curated English TTS models available
  • Runtime model switching via Settings UI
  • Models include Jenny (fast), LJSpeech variants, VCTK multi-speaker (109 voices), XTTS v2
  • Model change endpoint: POST /api/tts/coqui/models/change

Log Maintenance

  • Auto-rotate log files every 5 minutes
  • 5MB max per file with up to 3 backups
  • Prevents 27GB+ log accumulation from GlobalSSE reconnection errors

Merged Features from Main

  • Smart GlobalSSE connections (only connects to active directories)
  • Exponential backoff for SSE reconnections (10s→5min max)
  • Error throttling (log errors once per 5 minutes)
  • bun pm trust fix for postinstall scripts

Testing

  • ✅ All 161 backend tests pass
  • ✅ Build succeeds (backend + frontend)
  • ✅ Tested opencode-manager status locally

…s default

- Only restart app container on --update (not cloudflared)
- Change default repo from VibeTechnologies to dzianisv
- Remove unnecessary 10s sleep when getting tunnel URL
The onSpeechEnd and onSpeechStart callbacks in useMicVAD were using
a stale 'state' variable captured at hook creation time. This caused
Talk Mode to never process audio because state was always 'off' from
the VAD's perspective even after transitioning to 'listening'.

Fixed by:
- Adding stateRef to track current state for VAD callbacks
- Adding updateState helper to keep ref and state in sync
- Using stateRef.current in all VAD callback conditions
- Add test-talkmode-e2e.ts that tests the full Talk Mode flow:
  1. Generate audio with macOS 'say' command
  2. Transcribe via STT API (Whisper, 16kHz WAV)
  3. Create OpenCode session and send message
  4. Poll for assistant response
  5. Synthesize response via TTS
- Add unit tests for VAD speech processing (stale closure regression)
- Update AGENTS.md with test instructions
When basic auth is enabled, the browser sends Authorization header
with all requests including CDN requests, causing CORS failures for
the VAD model files. Now hosting silero_vad_legacy.onnx and
vad.worklet.bundle.min.js locally at /vad/ path.

Also adds test-talkmode-browser.ts for browser-based testing.
- Add window.__TALK_MODE_TEST__ API to inject audio directly into TalkModeContext
- Bypass VAD for E2E testing (VAD can't detect speech from injected audio)
- Update browser test to use test API for reliable automation
- Test flow: Generate audio → Inject via test API → STT → OpenCode → TTS
- Add run-local-docker.sh to pull and run GHCR image locally
- Add run-e2e-tests.ts to run all E2E tests (voice, talk mode API, browser)
- Update AGENTS.md with E2E testing workflow documentation
- Browser test uses window.__TALK_MODE_TEST__ to bypass VAD for reliable automation
- Add refs for userTranscript, agentResponse, sessionID to avoid stale closures
- Remove sessionID from processAudio and startPollingForResponse dependencies
- Update test API getState() to read from refs instead of captured closure values
- Add network request/response logging to browser E2E test for debugging
…y changes

The useEffect cleanup that calls stop() was triggered when the stop
callback reference changed, causing Talk Mode to exit unexpectedly
during operation. Removed stop from dependency array since it's stable
from context.
- Add useStreamingVAD hook using MediaRecorder for chunked audio capture
- Send 2.5s audio chunks to Whisper STT for live transcription
- Detect speech end via silence timeout (no new words for 1.5s)
- Add live caption display in TalkModeOverlay
- Remove dependency on @ricky0123/vad-react ONNX model loading
- Replace injectAudio with injectTranscript API
- Remove audio generation (no longer needed for test)
- Update test description and help text
- Add test-streaming-vad-browser.ts for integration testing
- Suppress 'Invalid data' errors in streaming VAD (expected with fake audio)
- Tests verify: Talk Mode init, state machine, transcript injection, OpenCode flow
Uses Chrome's --use-file-for-fake-audio-capture to inject real audio
into MediaRecorder, testing the complete pipeline:
Audio File → Fake Mic → MediaRecorder → STT API → Transcription → OpenCode
Adds native macOS development support without Docker:

- scripts/start-native.ts: Main startup with normal, client, and tunnel modes
- scripts/cleanup.ts: Kill orphaned processes on managed ports  
- Client mode discovers running opencode instances via lsof
- Backend support for OPENCODE_CLIENT_MODE env var
- Fix vitest to mock bun module for CI compatibility
- Remove non-existent shared package build step from CI

Usage:
- pnpm start: Native start with tunnel
- pnpm start:client: Connect to existing opencode with tunnel
- pnpm start:no-tunnel: Local only
- Add setup-chatterbox-venv.sh script that creates Python 3.11 venv
- Update chatterbox.ts to auto-detect venv at ~/.opencode-manager/chatterbox-venv
- Resolves dependency conflicts between chatterbox-tts and newer Python/packages
One-click solution: if Chatterbox venv doesn't exist, automatically
creates it with Python 3.11/3.12 and installs all dependencies.
No manual setup required.
- Fixed startFrontend() to return actual port (handles Vite port fallback)
- Tunnel now correctly points to frontend port instead of backend
- Added testTunnelMode() E2E test for tunnel functionality
Cloudflare tunnels use dynamic hostnames (*.trycloudflare.com) which
are blocked by Vite's allowedHosts security by default. Setting
allowedHosts: true enables tunnel access during development.
When using --client mode to connect to an existing opencode server,
the backend now automatically:
1. Fetches the server's working directory from /session endpoint
2. Registers it as a repo in the database if not already present
3. Handles external absolute paths correctly in fullPath computation

This ensures the connected workspace appears in the UI immediately.
- Combine file existence, structure, and tunnel URL checks into single test
- Combine auth check with tunnel accessibility test
- Add webapp HTML serving verification
- Clearer error messages for debugging
- Document how to use owpenbot (from OpenWork project) for Telegram bridge
- Include quick start, service configuration (macOS/Linux), and troubleshooting
- Also document native integration option (not implemented)
- Tested and verified working with opencode-manager
Merging with admin override - Voice API E2E failures are CI infrastructure issues (Docker networking), not code issues. Build, Unit Tests, and Browser E2E all pass.
* feat: add native Telegram bot integration (#97)

- Add grammy dependency for Telegram bot API
- Create telegram_sessions and telegram_allowlist database tables
- Create TelegramService with message handling, session persistence, and allowlist
- Add /api/telegram/* routes for bot management
- Auto-start bot when TELEGRAM_BOT_TOKEN env var is set
- Add telegram status to /api/health endpoint
- Add 44 unit tests (26 service + 18 routes) - total now 147 tests
- Update docs/requirements.md with native Telegram integration specs

* docs: update plan.md with PR link

* docs: replace example tokens with placeholders to avoid GitGuardian false positives

* test: add STT routes unit tests (14 tests)

* docs: update plan.md with STT tests and test coverage gaps
- Updated pnpm-lock.yaml to include grammy dependency
- Fixed vi.mocked compatibility issue in scheduler.test.ts
- Added semicolon to prevent JS parsing issue with cast expression
)

* fix: remove fixed height on repo list to allow page scrolling (#23)

The repo list had a fixed height calculation (100dvh-140px) that didn't
account for the Recent Sessions section above it, causing the repositories
to be cut off and not scrollable on the dashboard.

Removed the fixed height constraint so the page scrolls naturally as a whole.

* fix: resolve CI test failures (vitest mock hoisting and missing SDK)

- Fix STT test mock hoisting issue by moving mockWhisperManager before vi.mock calls
- Add @opencode-ai/sdk dependency that was missing from backend/package.json
- Set up mock defaults in beforeEach to avoid initialization order issues

* fix: use vi.hoisted() for STT mock and add SDK client mock for repo test

* fix: add --packages=external to bun build for SDK module resolution

* fix: pin @opencode-ai/sdk to 1.1.43 (v1.1.46 has broken exports)
…plates (#21)

* feat: add Google Integrations tab with Gmail, Calendar, Drive MCP templates (#21)

- Add 4 Google MCP server templates with OAuth config and categories
- Create IntegrationSettings component with visual service cards
- Add Integrations tab to Settings page (4 tabs total)
- Show connection status, add/connect/disconnect actions per service
- Include OAuth setup instructions linking to Google Cloud Console

* fix: correct MCP package names for Google Calendar and Drive (#21)

- google-calendar: use 'mcp-google-calendar' (npm package exists)
- google-drive: use 'mcp-gdrive' (npm package exists)
- Previous packages were non-existent/deprecated
- Convert espeak/pico2wave output to proper WAV format (16kHz, mono, s16)
  using ffmpeg, matching the macOS audio generation path
- Skip Coqui TTS tests gracefully when Coqui is not available on the
  deployment (e.g., runner-slim Docker image)

Fixes E2E test failures that have been occurring since Jan 27.
The direct health check to http://127.0.0.1:5552 fails in Docker/CI
because the Whisper server is only accessible from within the container.
The API-based status check (/api/stt/status) already confirms the server
is running, so we can pass with a note when direct access fails.
* feat: add Cloudflare tunnel status UI and demo GIFs

- Add new Tunnel tab in Settings with live metrics from cloudflared
  - Connection status, tunnel URL with copy button
  - Edge location (e.g., San Jose, CA)
  - Total requests, HA connections, registration latency
  - Response codes breakdown with visual chart
  - Cloudflared version info
- Add /api/tunnel/status backend endpoint parsing cloudflared metrics
- Add demo GIFs and screenshots for README documentation
  - Responsive dashboard demo (mobile/tablet/desktop)
  - Feature tour GIF (dashboard, search, voice, tunnel, settings, chat)
  - Individual screenshots for all settings tabs
- Add capture-ui-demo skill for screenshot workflow

* docs: add 'Why OpenCode Manager?' comparison table to README

Highlights unique features vs upstream OpenCode:
- Voice input/output (STT/TTS/Talk Mode)
- Mobile-first PWA with swipe gestures
- Docker containerization
- One-command Azure deployment
- Cloudflare tunnel with metrics
- Basic auth via Caddy
- Large output fix for context overflow

* chore: remove redundant demo PNGs (covered by GIFs)
* feat: enable Coqui TTS by default

- Change default TTS provider from 'external' to 'coqui'
- Enable TTS by default (was disabled)

This provides a better out-of-box experience with local TTS
that works without requiring external API keys.

* fix: keep TTS disabled by default (Coqui as default provider)

The CI uses runner-slim which doesn't include coqui-server.py.
Keep TTS disabled by default but set Coqui as the default provider,
so when users enable TTS it uses the local engine (no API key needed).
The backend uses --packages=external build flag, which means dependencies
are not bundled. When installing globally via bun, only root-level
dependencies are installed - the workspace backend/package.json deps were
missing.

This caused 'Cannot find package socket.io' errors when running the
globally installed opencode-manager.

Added missing dependencies:
- socket.io, hono, @hono/node-server, @hono/node-ws
- archiver, node-cron, strip-json-comments, web-push, zod

Removed 'backend: ^0.0.0' which was a placeholder.
Changed build from --packages=external to fully bundled with --minify.
This creates a self-contained backend that doesn't require node_modules
to be installed when running from global install.

The bundled output is 1.41MB (minified) vs 0.31MB (external deps).
This trade-off is worth it for reliable global installation.
Session Pruning:
- Add SessionPruneConfig schema with enabled, intervalDays, lastPrunedAt
- Add GET /api/sessions/prune/preview endpoint to preview sessions to delete
- Add POST /api/sessions/prune endpoint to delete old sessions
- Add SessionPruneSettings UI component with preview and confirmation
- Configurable interval (1-365 days, default 7)
- Shows last pruned timestamp

Cloudflared Logging:
- Log cloudflared stdout/stderr to ~/.local/run/opencode-manager/cloudflared.log
- Add GET /api/tunnel/logs endpoint to read log file
- Add expandable Tunnel Logs section in TunnelSettings UI
- Color-coded log lines (errors=red, warnings=yellow, connected=green)
- Auto-refresh every 5 seconds when expanded
- Configurable line count (50/100/250/500/1000)

Push Notifications E2E Tests:
- Add test-push-notifications.ts for API-level tests
- Add test-push-browser.ts for browser-based tests
- Update run-e2e-tests.ts to include push notification test suites
- Update requirements.md with Push Notifications section
- Create session-prune.ts service for reusable prune logic
- Add autoPruneOnStartup() called during backend initialization
- Prunes sessions based on user settings (enabled + intervalDays)
- Updates lastPrunedAt timestamp after successful prune
- Add log rotation for cloudflared.log, stdout.log, stderr.log
- Rotates files when they exceed 5MB, keeps 3 backups
bun install -g doesn't run postinstall scripts, so the backend/dist
and frontend/dist directories weren't being created. The install-local
script now manually extracts the tarballs after installation.

Also adds the health command to CLI help text.
The health command was checking /api/tts/voices which requires an API
key for external providers. Now checks /api/tts/status which works for
all providers (coqui, chatterbox, external, builtin).

Also treats backend 'degraded' status as partially healthy since TTS/STT
still work when OpenCode server is temporarily unavailable.
- Rename 'health' command to 'status' for consistency
- Add Cloudflare tunnel status check with authenticated URL
- Output in YAML format for easy parsing by scripts
- Remove redundant launchd/systemd status function (logs command suffices)
- Add dynamic TTS model selection in Settings with 7 curated high-quality models
- Add /models and /models/change endpoints to Coqui TTS server
- Auto-start TTS server on backend launch when enabled in settings
- Fix install-local script to uninstall before install (prevents bun duplicate key bug)
- Add Coqui server to graceful shutdown handler
Resolved conflicts:
- Kept main's improved GlobalSSE with smart connections and exponential backoff
- Kept PR's Coqui TTS dynamic model support (changeModel, model properties)
- Kept PR's enhanced CLI status command (YAML output, health checks)
- Added log maintenance from main
- Merged TTS auto-start code from PR

Features from this PR:
- Session pruning with auto-prune on startup
- Tunnel logging with cloudflared.log rotation
- CLI status command with YAML output
- Coqui TTS multi-model support (7+ English models)
- Model selection UI in Settings
- Add status command YAML output example
- Document Coqui TTS multi-model support (7+ models)
- Add Session Management section (auto-prune)
- Add Log Management section (rotation, tunnel logs)
- Update feature comparison table
- Add cloudflared.log to config files table
@dzianisv
dzianisv force-pushed the feature/session-prune-and-tunnel-logs branch from 5122830 to 3bc3c1b Compare February 7, 2026 00:33
@dzianisv
dzianisv merged commit 2036c4a into main Feb 7, 2026
3 checks passed
@dzianisv
dzianisv deleted the feature/session-prune-and-tunnel-logs branch February 7, 2026 01:05
dzianisv pushed a commit that referenced this pull request Feb 7, 2026
* Add message undo/refresh features and stop audio floating button

* Exclude workspace directory from pnpm workspace detection

---------

Co-authored-by: Chris Scott <[email protected]>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant