Files
hapi/cli/CLAUDE.md
T
weishu 4f03f29ac3 docs: rebrand Happy to HAPI and add component documentation
This commit rebrands the project from "Happy" to "HAPI" throughout the codebase, including documentation, comments, logs, and tool references. It also adds comprehensive README files for the server and web components, clarifies the monorepo structure in AGENTS.md and root README.md, and removes the outdated roadmap.md file.

Changes include:
- Rebrand references from Happy to HAPI in CLI, server, and web components
- MCP tool names updated from mcp__happy__ to mcp__hapi__
- Process/service names updated consistently
- New server/README.md with deployment and configuration guide
- New web/README.md with stack and development instructions
- Updated root README.md with quickstart guide
- Updated AGENTS.md with cleaner structure documentation
- Removed cli/roadmap.md (now superseded by documentation)
2025-12-21 18:49:04 +08:00

8.1 KiB

HAPI CLI Codebase Overview

Project Overview

HAPI CLI (hapi) is a command-line tool that wraps Claude Code to enable remote control and session sharing via hapi-server (Telegram Bot + Mini App). It's part of a two-component system:

  1. hapi (this project) - CLI wrapper for Claude Code
  2. hapi-server - Public server (Socket.IO + REST + SQLite) + Telegram Mini App

Code Style Preferences

TypeScript Conventions

  • Strict typing: No untyped code ("I despise untyped code")
  • Clean function signatures: Explicit parameter and return types
  • As little as possible classes
  • Comprehensive JSDoc comments: Each file includes header comments explaining responsibilities.
  • Import style: Uses @/ alias for src imports, e.g., import { logger } from '@/ui/logger'
  • File extensions: Uses .ts for TypeScript files
  • Export style: Named exports preferred, with occasional default exports for main functions

DO NOT

  • Create stupid small functions / getters / setters
  • Excessive use of if statements - especially if you can avoid control flow changes with a better design
  • NEVER import modules mid-code - ALL imports must be at the top of the file

Error Handling

  • Graceful error handling with proper error messages
  • Use of try-catch blocks with specific error logging
  • Abort controllers for cancellable operations
  • Careful handling of process lifecycle and cleanup

Testing

  • Unit tests using Vitest
  • No mocking - tests make real API calls
  • Test files colocated with source files (.test.ts)
  • Descriptive test names and proper async handling

Logging

  • All debugging through file logs to avoid disturbing Claude sessions
  • Console output only for user-facing messages
  • Special handling for large JSON objects with truncation

Architecture & Key Components

1. API Module (/src/api/)

Handles bot communication (direct connect; no end-to-end encryption).

  • api.ts: Main API client class for session management
  • apiSession.ts: WebSocket-based real-time session client with RPC support
  • auth.ts: Loads CLI_API_TOKEN from env
  • encryption.ts: Base64 helpers (no encryption)
  • types.ts: Zod schemas for type-safe API communication

Key Features:

  • Socket.IO for real-time messaging
  • Optimistic concurrency control for state updates
  • RPC handler registration for remote procedure calls

2. Claude Integration (/src/claude/)

Core Claude Code integration layer.

  • loop.ts: Main control loop managing interactive/remote modes

  • types.ts: Claude message type definitions with parsers

  • claudeSdk.ts: Direct SDK integration using @anthropic-ai/claude-code

  • interactive.ts: LIKELY WILL BE DEPRECATED in favor of running through SDK PTY-based interactive Claude sessions

  • watcher.ts: File system watcher for Claude session files (for interactive mode snooping)

  • mcp/startPermissionServer.ts: MCP (Model Context Protocol) permission server

Key Features:

  • Dual mode operation: interactive (terminal) and remote (mobile control)
  • Session persistence and resumption
  • Real-time message streaming
  • Permission intercepting via MCP [Permission checking not implemented yet]

3. UI Module (/src/ui/)

User interface components.

  • logger.ts: Centralized logging system with file output
  • qrcode.ts: QR code generation for mobile authentication
  • start.ts: Main application startup and orchestration

Key Features:

  • Clean console UI with chalk styling
  • QR code display for easy mobile connection
  • Graceful mode switching between interactive and remote

4. Core Files

  • index.ts: CLI entry point with argument parsing
  • persistence.ts: Local storage for settings and keys
  • utils/time.ts: Exponential backoff utilities

Data Flow

  1. Authentication:

    • Use CLI_API_TOKEN to authenticate to hapi-server (REST + Socket.IO)
  2. Session Creation:

    • Create/load session via POST /cli/sessions → Establish Socket.IO /cli connection
  3. Message Flow:

    • Local mode: terminal/SDK → hapi CLI → hapi-server → Telegram Mini App
  4. Permission Handling:

    • Claude requests permission → hapi CLI exposes RPC handlers → Mini App calls REST → hapi-server relays RPC to hapi CLI

Key Design Decisions

  1. File-based logging: Prevents interference with Claude's terminal UI
  2. Dual Claude integration: Process spawning for interactive, SDK for remote
  3. No E2E encryption: Use HTTPS/TLS for hapi-server deployments
  4. Session persistence: Allows resuming sessions across restarts
  5. Optimistic concurrency: Handles distributed state updates gracefully

Security Considerations

  • CLI_API_TOKEN is a shared secret; treat it like a password.
  • No end-to-end encryption: use HTTPS/TLS for hapi-server deployments.
  • Session isolation through unique session IDs.

Dependencies

  • Core: Node.js, TypeScript
  • Claude: @anthropic-ai/claude-code SDK
  • Networking: Socket.IO client, Axios
  • Terminal: node-pty, chalk, qrcode-terminal
  • Validation: Zod
  • Testing: Vitest

Running the Daemon

Starting the Daemon

# From the hapi CLI directory:
hapi daemon start

# With custom bot URL (for local development):
HAPI_BOT_URL=http://localhost:3006 CLI_API_TOKEN=your_token hapi daemon start

# Stop the daemon:
hapi daemon stop

# Check daemon status:
hapi daemon status

Daemon Logs

  • Daemon logs are stored in ~/.hapi-dev/logs/ (or $HAPI_HOME_DIR/logs/)
  • Named with format: YYYY-MM-DD-HH-MM-SS-daemon.log

Session Forking claude and sdk behavior

Commands Run

Initial Session

claude --print --output-format stream-json --verbose 'list files in this directory'
  • Original Session ID: aada10c6-9299-4c45-abc4-91db9c0f935d
  • Created file: ~/.claude/projects/.../aada10c6-9299-4c45-abc4-91db9c0f935d.jsonl

Resume with --resume flag

claude --print --output-format stream-json --verbose --resume aada10c6-9299-4c45-abc4-91db9c0f935d 'what file did we just see?'
  • New Session ID: 1433467f-ff14-4292-b5b2-2aac77a808f0
  • Created file: ~/.claude/projects/.../1433467f-ff14-4292-b5b2-2aac77a808f0.jsonl

Key Findings for --resume

1. Session File Behavior

  • Creates a NEW session file with NEW session ID
  • Original session file remains unchanged
  • Two separate files exist after resumption

2. History Preservation

  • The new session file contains the COMPLETE history from the original session
  • History is prefixed at the beginning of the new file
  • Includes a summary line at the very top

3. Session ID Rewriting

  • CRITICAL FINDING: All historical messages have their sessionId field UPDATED to the new session ID
  • Original messages from session aada10c6-9299-4c45-abc4-91db9c0f935d now show sessionId: "1433467f-ff14-4292-b5b2-2aac77a808f0"
  • This creates a unified session history under the new ID

4. Message Structure in New File

Line 1: Summary of previous conversation
Lines 2-6: Complete history from original session (with updated session IDs)
Lines 7-8: New messages from current interaction

5. Context Preservation

  • Claude successfully maintains full context
  • Can answer questions about previous interactions
  • Behaves as if it's a continuous conversation

Technical Details

Original Session File Structure

  • Contains only messages from the original session
  • All messages have original session ID
  • Remains untouched after resume

New Session File Structure After Resume

{"type":"summary","summary":"Listing directory files in current location","leafUuid":"..."}
{"parentUuid":null,"sessionId":"1433467f-ff14-4292-b5b2-2aac77a808f0","message":{"role":"user","content":[{"type":"text","text":"list files in this directory"}]},...}
// ... all historical messages with NEW session ID ...
{"parentUuid":"...","sessionId":"1433467f-ff14-4292-b5b2-2aac77a808f0","message":{"role":"user","content":"what file did we just see?"},...}

Implications for handy-cli

When using --resume:

  1. Must handle new session ID in responses
  2. Original session remains as historical record
  3. All context preserved but under new session identity
  4. Session ID in stream-json output will be the new one, not the resumed one