diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..d351922 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,44 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Essential Commands + +Build, test, and develop: +```shell +make # Full workflow: format, lint, test, clean, build +make test # Run tests only +make build # Build binary to ./dist/gmi2html +make fmt # Format code with gofumpt and gci +make lint # Run linter after formatting +make lintfix # Run linter with auto-fix +``` + +Running the tool: +```shell +./dist/gmi2html output.html +./dist/gmi2html --no-container content.html +./dist/gmi2html --replace-gmi-ext output.html +``` + +## Architecture + +This is a Go library and CLI tool that converts Gemini text format to HTML. + +**Core Components:** +- `gmi2html.go`: Main conversion logic with `Gmi2html()` function and `convertGeminiContent()` for parsing +- `templates.go`: HTML templates for each Gemini element type (headings, links, lists, etc.) +- `cmd/gmi2html/main.go`: CLI entry point that reads from stdin and writes to stdout +- `assets/main.html`: Embedded HTML template with CSS for the full page container + +**Key Architecture Patterns:** +- Uses Go's `html/template` package for safe HTML generation with automatic escaping +- Embeds the main HTML template using `//go:embed` directive +- Line-by-line parser that switches between normal and preformatted modes +- Two output modes: full HTML document or content-only for embedding +- Optional `.gmi` to `.html` link conversion for static site generation + +**Gemini Format Support:** +- Headings (#, ##, ###), links (=>), lists (*), quotes (>), preformatted blocks (```) +- Proper handling of preformatted content with mode switching +- URL parsing and validation for links \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..79e562c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,98 @@ +# CLAUDE.md + +This file provides guidance to AI Agents such as Claude Code or ChatGPT Codex when working with code in this repository. + +## General guidelines + +Use idiomatic Go as possible. Prefer simple code than complex. + +## Project Overview + +Gemserve is a simple Gemini protocol server written in Go that serves static files over TLS-encrypted connections. The Gemini protocol is a lightweight, privacy-focused alternative to HTTP designed for serving text-based content. + +### Development Commands + +```bash +# Build, test, and format everything +make + +# Run tests only +make test + +# Build binaries to ./dist/ (gemserve, gemget, gembench) +make build + +# Format code with gofumpt and gci +make fmt + +# Run golangci-lint +make lint + +# Run linter with auto-fix +make lintfix + +# Clean build artifacts +make clean + +# Run the server (after building) +./dist/gemserve + +# Generate TLS certificates for development +certs/generate.sh +``` + +### Architecture + +Core Components + +- **cmd/gemserve/gemserve.go**: Entry point with TLS server setup, signal handling, and graceful shutdown +- **cmd/gemget/**: Gemini protocol client for fetching content +- **cmd/gembench/**: Benchmarking tool for Gemini servers +- **server/**: Request processing, file serving, and Gemini protocol response handling +- **gemini/**: Gemini protocol implementation (URL parsing, status codes, path normalization) +- **config/**: CLI-based configuration system +- **lib/logging/**: Structured logging package with context-aware loggers +- **lib/apperrors/**: Application error handling (fatal vs non-fatal errors) +- **uid/**: Connection ID generation for logging (uses external vendor package) + +Key Patterns + +- **Security First**: All file operations use `filepath.IsLocal()` and path cleaning to prevent directory traversal +- **Error Handling**: Uses structured errors via `lib/apperrors` package distinguishing fatal from non-fatal errors +- **Logging**: Structured logging with configurable levels via internal logging package +- **Testing**: Table-driven tests with parallel execution, heavy focus on security edge cases + +Request Flow + +1. TLS connection established on port 1965 +2. Read up to 1KB request (Gemini spec limit) +3. Parse and normalize Gemini URL +4. Validate path security (prevent traversal) +5. Serve file or directory index with appropriate MIME type +6. Send response with proper Gemini status codes + +Configuration + +Server configured via CLI flags: +- `--listen`: Server address (default: localhost:1965) +- `--root-path`: Directory to serve files from +- `--dir-indexing`: Enable directory browsing (default: false) +- `--log-level`: Logging verbosity (debug, info, warn, error; default: info) +- `--response-timeout`: Response timeout in seconds (default: 30) +- `--tls-cert`: TLS certificate file path (default: certs/server.crt) +- `--tls-key`: TLS key file path (default: certs/server.key) +- `--max-response-size`: Maximum response size in bytes (default: 5242880) + +Testing Strategy + +- **server/server_test.go**: Path security and file serving tests +- **gemini/url_test.go**: URL parsing and normalization tests +- Focus on security edge cases (Unicode, traversal attempts, malformed URLs) +- Use parallel test execution for performance + +Security Considerations + +- All connections require TLS certificates (stored in certs/) +- Path traversal protection is critical - test thoroughly when modifying file serving logic +- Request size limited to 1KB per Gemini specification +- Input validation on all URLs and paths diff --git a/Makefile b/Makefile index 8b79493..c8a4ba3 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,6 @@ debug: @echo "GOPATH: $(shell go env GOPATH)" @which go @which gofumpt - @which gci @which golangci-lint clean: @@ -24,7 +23,6 @@ tidy: # Format code fmt: gofumpt -l -w . - gci write . # Run linter lint: fmt diff --git a/assets/main.html b/assets/main.html index 3cebd7c..b7211f4 100644 --- a/assets/main.html +++ b/assets/main.html @@ -9,18 +9,31 @@