Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Latest commit

 

History

History
163 lines (129 loc) · 11.1 KB

File metadata and controls

163 lines (129 loc) · 11.1 KB

Project Overview

Freshell is a self-hosted, browser-accessible terminal multiplexer and session organizer. It provides multi-tab terminal management with support for terminals and coding CLI's like Claude Code and Codex. Key features include session history browsing, AI-powered summaries (via Google Gemini), and remote access over LAN/VPN with token-based authentication.

Development Philosophy

  • We are working on an infinite schedule with infinite tokens. This is unusual! We do not have time pressure, and can do things correctly.
  • We use Red-Green-Refactor TDD for all changes but the most trivial (e.g. doc changes). We never skip the tests, and never skip the refactor.
  • We ensure both unit test & e2e coverage of everything.
  • Before starting anything, think - what's the most idiomatic solution for the technology we're using?
  • We prefer clean architecture and correctness over small patches.
  • We fix the system over the symptom.

Repo Rules

  • Always work in a worktree (in .worktrees)
  • Before creating a new worktree, ensure the repo-supported test suite is green on the intended base. If the suite is not green, pause before creating the worktree and notify the user with the failing command and failure summary.
  • New behavior changes start on a worktree branch from origin/main and are submitted as PRs to origin/main; local dev only consumes PR heads.
  • Many agents may be working in the worktree at the same time. If you see activity from other agents (for example test runs or file changes), respect it.
  • Specific user instructions override ALL other instructions, including the above, and including superpowers or skills
  • Server uses NodeNext/ESM; relative imports must include .js extensions
  • Always consider checking logs for debugging; server logs (including client console logs) are in the server process stdout/stderr (e.g., npm run dev/npm start).
  • Debug logging toggle (UI Settings → Debugging → Debug logging) enables debug-level logs and perf logging; keep OFF outside perf investigations.
  • When adding new user-facing features or making significant UI changes, update docs/index.html to reflect them. It's a nonfunctional mock of the default experience, so only major changes need to be added.

Test Coordination

  • Broad repo-supported test runs wait for the shared coordinator gate; if another agent holds it, wait rather than kill a foreign holder.
  • Set FRESHELL_TEST_SUMMARY when you want holder/status output to show a human-meaningful reason for a broad run.
  • Use npm run test:status to inspect the current holder, recent results, and any advisory reusable baseline.
  • Use npm run test:vitest -- ... for a repo-owned direct Vitest path. Raw npx vitest is not a coordinated workflow.
  • test:unit is the exact default-config test/unit workload, test:integration is the exact server-config test/server workload, and test:server stays watch-capable unless you pass an explicit broad --run.

Branch Model And Self-Hosting (CRITICAL - Read This)

This checkout is self-hosted from local dev, not local main.

  • Local main is a mirror of origin/main; do not commit to it, merge into it, or self-host from it.
  • Local dev is the self-hosted integration branch. It is rebuilt from origin/main plus pending PR heads.
  • The repo root normally remains on local main; use .worktrees/dev as the self-hosted integration checkout and create separate worktrees for authored changes.
  • Do not edit production behavior directly on dev.
  • If a change is needed on dev, create or update a PR against origin/main, then apply that PR head to dev.
  • If applying a PR to dev needs semantic conflict resolution, stop and fix the PR branch or create a replacement PR. Do not hide behavior changes in a local-only dev merge commit.
  • Never run git merge directly on main.
  • Never reset, force-push, or fast-forward local main during ordinary work. If the user explicitly asks to refresh the mirror, first verify Freshell is self-hosting from dev and local main has no work to preserve.
  • We cannot approve our own PRs. dev may contain unapproved pending work, but origin/main changes still require independent review.

Process Safety (CRITICAL)

  • Never use broad kill patterns (for example pkill -f "tsx watch server/index.ts", pkill -f vite, pkill node).
  • Start manual worktree servers on a unique port and record their PID, then stop only that PID.
  • Dev mode example (source + Vite): PORT=3344 npm run dev:server > /tmp/freshell-3344.log 2>&1 & echo $! > /tmp/freshell-3344.pid
  • Production mode example (built dist): PORT=3344 npm start > /tmp/freshell-3344.log 2>&1 & echo $! > /tmp/freshell-3344.pid
    • NEVER run node dist/server/index.js directly — use npm start which sets NODE_ENV=production; without it the server prints the Vite port (5173) in the startup URL even though Vite isn't running
  • Example stop: kill "$(cat /tmp/freshell-3344.pid)" && rm -f /tmp/freshell-3344.pid
  • Before stopping any process, verify it belongs to the worktree (ps -fp <pid> and confirm cwd/path includes .worktrees/...).
  • The self-hosted dev server must never be restarted without explicit user approval (the word "APPROVED"). Building is fine; deploying (stop + start) is not. The user's current Freshell session depends on it, and an unapproved restart will disconnect them mid-operation.

Codex Agent in CMD Instructions (Codex agents only; only when running in CMD on windows; all other agents must ignore)

  • Prefer bash/WSL over PowerShell; Windows paths map like D:\... -> /mnt/d/....
  • Use bash -lc "<cmd>" for non-interactive commands; avoid interactive shells so commands return control.
  • Apply_patch expects Windows-style paths.
  • If a bash command produces no visible output, rerun with tty: true to force output.
  • PowerShell may hang for dozens of seconds before starting in this tool; stick to bash unless explicitly required.
  • Don't make silly mistakes like installing Linux binaries in node_modules when we're on windows

Commands

Development

npm run dev                 # Run client + server concurrently with hot reload
npm run dev:client          # Vite dev server only (port 5173)
npm run dev:server          # Node with tsx watch for server auto-reload

Building

npm run build               # Full build (client + server)
npm run build:client        # Vite build → dist/client
npm run build:server        # TypeScript compile → dist/server
npm run serve               # Build and run production server
# Note: `npm run build` is guarded — it will refuse to overwrite dist/
# if a production server is detected on the configured PORT. Use
# `npm run check` for safe verification, or build from a worktree.

Testing

npm test                    # Coordinated full suite (default + server configs)
npm run check               # Typecheck, then coordinated full suite
npm run verify              # Build, then coordinated full suite
npm run test:coverage       # Coordinated default-config coverage run
npm run test:status         # Show active holder, latest results, and advisory baseline info
npm run test:vitest -- ...  # Repo-owned direct Vitest path for focused passthrough work

Architecture

Tech Stack

  • Frontend: React 18, Redux Toolkit, Vite, Tailwind CSS, shadcn/ui, xterm.js, Zod
  • Backend: Node.js/Express, node-pty, WebSocket (ws), Chokidar, Vercel AI SDK + Google Generative AI
  • Testing: Vitest, Testing Library, supertest, superwstest

Directory Structure

  • src/ - React frontend application
    • components/ - UI components (TabBar, Sidebar, TerminalView, HistoryView, etc.)
    • store/ - Redux slices (tabs, connection, sessions, settings, claude)
    • lib/ - Utilities (api.ts, claude-types.ts)
  • server/ - Node.js/Express backend
    • index.ts - HTTP/REST routes and server entry
    • ws-handler.ts - WebSocket protocol handler
    • terminal-registry.ts - PTY lifecycle management
    • claude-session.ts - Claude session discovery & indexing
    • claude-indexer.ts - File watcher for ~/.claude directory
  • test/ - Test suites organized by unit/integration and client/server

Key Architectural Patterns

WebSocket Protocol: Schema-validated messages using Zod. Handshake flow: client sends hello with token → server validates → sends ready. Message types include terminal.create/input/resize/detach/attach and broadcasts like sessions.updated.

PTY Lifecycle: Each terminal has a unique ID. Server maintains 64KB scrollback buffer. On attach, client receives buffer snapshot then streams new output. On detach, process continues running (background session). Configurable idle timeout (180 mins default).

Claude Session Discovery: Watches ~/.claude/projects/*/sessions/*.jsonl for new files. Parses JSONL streams to extract messages, groups by project path.

Redux State Management: Slices for tabs, panes, connection, sessions, settings, claude. Persist middleware saves tabs and panes to localStorage. Async thunks for API calls.

Configuration Persistence: User config stored at ~/.freshell/config.json. Atomic writes with temp file + rename. Settings changes POST to /api/settings and broadcast via WebSocket.

Pane System: Tabs contain pane layouts (tree structure of splits). Each pane owns its terminal lifecycle via createRequestId and terminalId. When splitting panes, each new pane gets its own createRequestId, ensuring independent backend terminals. Pane content types: terminal (with mode, shell, status) and browser (with URL, devtools state).

Data Flow

  1. Browser loads → fetches settings from /api/settings and sessions from /api/sessions
  2. WebSocket connects → client sends hello with auth token → server sends ready
  3. Terminal creation → Pane content has createRequestId → UI sends terminal.create WS message with that ID → server spawns PTY → sends back terminal.created with terminalId → pane content updated
  4. Terminal I/O → terminal.input WS messages write to PTY stdin → stdout/stderr streams to attached clients

Accessibility (A11y) Requirements

All components must be accessible for browser-use automation and WCAG compliance:

Semantic HTML:

  • Use <button>, <a>, <input>, <label> for interactive elements (not div with onClick)
  • Use semantic headers (<h1>-<h6>), nav, main, aside
  • Use proper form structure with labels associated to controls

ARIA & Labels:

  • Icon-only buttons: aria-label="Description" or <span className="sr-only">
  • Clickable cards/tiles: role="button" + aria-label
  • Custom components: appropriate roles and ARIA props
  • Complex widgets: aria-expanded, aria-pressed, aria-selected where applicable

Browser-use Requirements:

  • All interactive elements must be indexable (semantic HTML or proper roles)
  • All interactive elements must be identifiable (visible text or aria-label)
  • Never rely on selectors for automation; fix accessibility instead

Linting:

  • Run npm run lint to check a11y violations (eslint-plugin-jsx-a11y)
  • Fix with npm run lint:fix for auto-fixable issues
  • A11y linting is CI requirement before merging

Path Aliases

  • @/src/
  • @test/test/