chore: ignore .bkit/, add CLAUDE.md and update-service.sh

This commit is contained in:
2026-06-04 21:58:31 -04:00
parent 35b4519b94
commit fc0527e9e7
3 changed files with 153 additions and 0 deletions
+2
View File
@@ -9,3 +9,5 @@ tests/screenshots/
package-lock.json package-lock.json
docs/ docs/
.server.pid .server.pid
.bkit/
+88
View File
@@ -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=<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/<name>/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`
+63
View File
@@ -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" <<EOF
[Unit]
Description=ClawTap — mobile UI for AI coding sessions
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=$REPO_DIR
Environment=HOME=$HOME
Environment=PATH=/usr/local/bin:/usr/bin:/bin
EnvironmentFile=$ENV_FILE
ExecStart=$REPO_DIR/node_modules/.bin/tsx $REPO_DIR/server/index.ts
Restart=on-failure
RestartSec=5
StandardOutput=append:$HOME/.clawtap/server.log
StandardError=append:$HOME/.clawtap/server.log
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable "$SERVICE_NAME"
echo "Service installed and enabled."
fi
# --- Build frontend ---
echo "Building frontend..."
cd "$REPO_DIR"
npm run build
# --- Install CLI binary ---
echo "Installing CLI binary..."
sudo cp "$REPO_DIR/bin/clawtap" /usr/bin/clawtap
# --- Restart ---
echo "Restarting $SERVICE_NAME..."
systemctl --user restart "$SERVICE_NAME"
echo "Status:"
systemctl --user status "$SERVICE_NAME" --no-pager