From fc0527e9e7f9477c455fe186dd67b95069c028ce Mon Sep 17 00:00:00 2001 From: Isaac Paul Date: Thu, 4 Jun 2026 21:58:31 -0400 Subject: [PATCH] chore: ignore .bkit/, add CLAUDE.md and update-service.sh --- .gitignore | 2 ++ CLAUDE.md | 88 +++++++++++++++++++++++++++++++++++++++++++++++ update-service.sh | 63 +++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 CLAUDE.md create mode 100755 update-service.sh diff --git a/.gitignore b/.gitignore index 5260ec2..7f934a2 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ tests/screenshots/ package-lock.json docs/ .server.pid + +.bkit/ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..4761df4 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,88 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +```bash +# Development (client + server with hot reload) +npm run dev + +# Server only +npm run dev:server + +# Client only +npm run dev:client + +# Production build (frontend → dist/) +npm run build + +# Run server against built dist/ +npm start +``` + +No test runner is configured. Tests in `test/mvp/` and `tests/` are standalone Node.js scripts run directly: +```bash +node test/mvp/test-e2e.js +node test/mvp/test-hooks.js +``` + +## Environment + +Required: `CLAWTAP_PASSWORD=` +Optional: `PORT` (default 3456), `OPENAI_API_KEY` (enables voice transcription) + +State stored in `~/.clawtap/` — SQLite DB, VAPID keys, push subscriptions, PID file. + +In production, the server runs as a systemd user service (`~/.config/systemd/user/clawtap.service`) with env vars loaded from `~/.clawtap/env`; use `./update-service.sh` (not `npm install -g .`) to build and redeploy. + +## Architecture + +ClawTap bridges mobile browsers to AI CLI tools running in tmux on the dev machine. + +``` +Mobile PWA (React) ◄─ WebSocket ─► Express Server ◄─ tmux sendKeys ─► claude/codex/gemini CLI +``` + +### Server (`server/`) + +- **`index.ts`** — Express app, HTTP/HTTPS server, REST routes, WS transport setup, graceful shutdown +- **`session-manager.ts`** — Bridges adapter events to WebSocket clients. Transport-agnostic. Routes all adapter events (streaming-text, tool-start/done, permission-request, etc.) to connected clients. Manages push notifications when no client is watching. +- **`adapters/`** — Plugin system for CLI backends + - **`interface.ts`** (`IAdapter`) — Abstract base class all adapters extend. Emits standardized events; see JSDoc for full event list. + - **`registry.ts`** — Registers adapters; `DEFAULT_ADAPTER` is `'claude'` + - **`shared/tmux-manager.ts`** — Core tmux primitive: create windows, send keys, paste buffers (>500 chars or multiline use paste buffer instead of sendKeys) + - **`claude/`**, **`codex/`**, **`gemini/`** — Per-adapter implementations +- **`transport/websocket-transport.ts`** — WS server; wraps raw `ws` into `ClientConnection` abstractions +- **`db.ts`** — SQLite via `better-sqlite3`; tables: `push_subscriptions`, `login_attempts`, `session_reviews`, `session_stats`, `user_preferences` +- **`push.ts`** — Web Push (VAPID) notifications +- **`auth.ts`** — Password-based auth with bcrypt + JWT; rate-limits login attempts by IP +- **`config.ts`** — Reads env vars; auto-detects HTTPS certs at `~/.clawtap/cert.pem` + `key.pem` +- **`stores/task-aggregator.ts`** — Aggregates task-tool events (TodoRead/TodoWrite/Task) into round-based groups for the mobile task panel + +### Frontend (`src/`) + +- **`App.tsx`** — Top-level view router (sessions / newchat / chat / settings). View persisted to `sessionStorage`; URL updated via `history.pushState`. +- **`lib/ws.ts`** — WebSocket singleton; reconnect logic +- **`lib/api.ts`** — Fetch wrapper with JWT auth header +- **`hooks/useChat.ts`** — Main chat hook: sends queries, handles all WS message types, manages message list and tool state +- **`hooks/useTaskState.ts`** — Consumes `TASK_STATE` WS events; surfaces round-based task groups to the FAB +- **`components/ChatView.tsx`** — Full chat screen with message list, tool cards, interactive prompt overlay, review panel +- **`components/FloatingReviewPanel.tsx`** — Multi-tab cross-AI review panel +- **`components/adapters/`** — Adapter-specific UI (models, permission modes, branding) + +### WebSocket Protocol + +All message types defined in `server/ws-types.ts` (`WS` const) and `server/types/messages.ts`. Key flows: + +- Client sends `query` → server routes to adapter → adapter emits `streaming-text` / `tool-start` / `tool-done` / `session-idle` → server broadcasts to clients +- Adapter emits `permission-request` → server sends `interactive-prompt` to client → client sends `prompt-response` → server calls `respondInteractivePrompt` +- Cross-AI review: client calls `POST /api/reviews/register` → server broadcasts `review-started` to parent session clients + +### Adding a New Adapter + +1. Create `server/adapters//index.ts` extending `IAdapter` +2. Set static `id`, `displayName`, `command` +3. Implement `setup(app)`, `startSession`, `resumeSession`, `sendMessage`, `interrupt`, `getSessions`, `getMessages` +4. Register in `server/adapters/init.ts` +5. Add frontend branding in `src/lib/adapter-brands.ts` diff --git a/update-service.sh b/update-service.sh new file mode 100755 index 0000000..3157909 --- /dev/null +++ b/update-service.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SERVICE_NAME="clawtap.service" +UNIT_DIR="$HOME/.config/systemd/user" +ENV_FILE="$HOME/.clawtap/env" +UNIT_FILE="$UNIT_DIR/$SERVICE_NAME" + +# --- Install systemd unit if missing --- +if [ ! -f "$UNIT_FILE" ]; then + echo "Installing $SERVICE_NAME..." + + if [ ! -f "$ENV_FILE" ]; then + echo "ERROR: $ENV_FILE not found." + echo "Create it with at minimum:" + echo " CLAWTAP_PASSWORD=your-password-here" + exit 1 + fi + + mkdir -p "$UNIT_DIR" + cat > "$UNIT_FILE" <