Files
paseo/packages/server
paseo-bot[bot]andAlexander Adam 0ed57187a9 Keep fork owners in Gitea and Forgejo checkout names (#6829)
* fix(gitea): prefix fork PR branches with the owner

Two forks with the same branch name (say patch-1) ended up on the same
local branch. The gitea service had no buildPrLocalBranchName or
defaultCheckoutRefs, github has both.

getPullRequestCheckoutTarget also fell back to refs/heads/<name> on
origin for fork PRs. Thats the base repo's branch, not the fork's, so
a failed refs/pull fetch checked out the wrong branch without an error.

fixes #3515

* refactor(forge): share fork branch naming with github

moved the owner normalizer and the branch name builder to
utils/change-request-checkout.ts, gitea and github both use it.

github changes a bit: a fork PR with an unknown or unusable owner (eg
deleted fork) now gets pr-N/<branch> instead of the bare branch name,
which could collide with a local branch the same way #3515 did.

* fix(gitea): PRs from a deleted fork are still cross repo

the API drops head.repo once the fork is gone, we read that as a same
repo PR and fetched refs/heads/<name> from origin

* fix(gitea): handle AGit PRs and deleted head branches

neither has a branch on origin. forgejo reports refs/pull/N/head as
head.ref for both, so skip the refs/heads fallback and dont track
origin.

also try refs/pull/N/head on upstream for clones where origin is your
fork, like github does. that list lives in the shared util now.

* test: resolver harness uses the real branch helper

plus deleted forks and same repo PRs without an origin branch

* fix(gitea): collapse pull-ref-only heads to pr-N in local branch names

buildForkLocalBranchName still used the raw headRef even when it was
just the pull ref (refs/pull/N/head), which agit prs and deleted head
branches report as their headRefName. that gave local branches literal
names like refs/heads/refs/pull/3/head.

* fix(gitea): surface hasHeadBranch on the pr checkout target

resolveForkCheckoutFacts already knew whether a pr had a real head
branch (agit flow, or head.ref == the pull ref both mean no). now that
signal reaches buildPrLocalBranchName so worktree names and local
branches stop being named after the raw pull ref.

covers same-repo, fork with owner known, and deleted fork all with no
real head branch. added an end to end gitea-service test plus resolver
cases since the worktree slug follows localBranchName too.

* refactor(forge): one head ref kind on the checkout target

hasOriginHeadBranch and hasHeadBranch could describe contradictory
states (cross-repo checkout claiming an origin head branch). collapse
both into headRefKind: "branch" | "pull-ref" and derive origin
tracking in the resolver instead of storing it separately.

Co-authored-by: Alexander Adam <alexander.adam@vade.io>

* fix(worktrees): avoid branch namespace conflicts in fork checkouts

Fork owner prefixes can name an existing branch as a parent, which Git rejects even when the full proposed name is unused. Allocate names against parent and child refs, suffixing the conflicting segment while preserving existing branches and fetched commits.

* test(worktrees): make fork fixture line endings deterministic

Windows Git converts the fixture checkout to CRLF when core.autocrlf is enabled. Set the repository fixture to preserve its written LF bytes so the content assertion checks the fetched patch on every platform. Reproduced the failure locally with inherited core.autocrlf=true and verified the corrected setup against that same configuration.

---------

Co-authored-by: Alexander Adam <alexander.adam@vade.io>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-15 10:10:54 +02:00
..
2026-04-23 21:44:48 +07:00

Voice Assistant

A voice-controlled terminal assistant that runs as a single local service.

Quick Start

# Install dependencies
npm install

# Copy environment variables
cp .env.example .env
# Edit .env and add your API keys (OpenAI, Deepgram)

# Run development servers
npm run dev

# Open browser to http://localhost:5173

Architecture

  • Express Server (port 3000) - Serves API and built UI in production
  • Vite Dev Server (port 5173) - Hot-reload React UI in development
  • WebSocket (/ws) - Real-time bidirectional communication
  • Agent - STT → LLM → TTS pipeline with terminal control
  • Daemon - tmux-based terminal management (in-process)

Development

# Run both servers (recommended)
npm run dev

# Or run separately:
npm run dev:server  # Express on port 3000
npm run dev:ui      # Vite on port 5173

# Type checking
npm run typecheck

# Build for production
npm run build

# Start production server
npm start

Project Status

✅ Completed (Phases 1-2):

  • Package setup and configuration
  • Express server with WebSocket
  • React UI with Vite
  • WebSocket client with ping/pong testing

⏳ In Progress (Phase 3):

  • Terminal control (tmux integration)

📋 Planned (Phases 4-9):

  • LLM integration (OpenAI GPT-4)
  • Agent orchestrator
  • Speech-to-Text (Deepgram)
  • Text-to-Speech (OpenAI)
  • Audio streaming
  • UI polish

See IMPLEMENTATION_PLAN.md for complete details.

Environment Variables

OPENAI_API_KEY=your-openai-key-here      # GPT-4 and TTS
DEEPGRAM_API_KEY=your-deepgram-key-here  # Streaming STT
STT_MODEL=whisper-1        # Optional: override to gpt-4o-transcribe, etc.
STT_CONFIDENCE_THRESHOLD=-3.0  # Optional: reject low-confidence clips
STT_DEBUG_AUDIO_DIR=.stt-debug # Optional: persist raw dictation audio for debugging
PASEO_HOME=~/.paseo        # Runtime state directory (agents/, etc.)
PASEO_LISTEN=127.0.0.1:6767  # Listen address (host:port or /path/to/socket)

PASEO_HOME defaults to ~/.paseo and isolates runtime artifacts like agents/. PASEO_LISTEN controls the daemon listen address. For blue/green testing you can run a parallel server without touching production state:

PASEO_HOME=~/.paseo-blue PASEO_LISTEN=127.0.0.1:7777 npm run dev

Tech Stack

  • Server: Express, TypeScript, ws (WebSocket)
  • Client: React 18, Vite, TypeScript
  • Terminal: tmux (via child_process)
  • AI: OpenAI (LLM + TTS), Deepgram (STT)

Testing

Currently manual testing via:

  1. Start servers: npm run dev
  2. Open http://localhost:5173
  3. Test WebSocket connection (green status indicator)
  4. Click "Send Ping" button to test communication

More testing guidance as features are implemented.

License

MIT