diff --git a/README.md b/README.md index 8a7a6fb..91e933f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,295 @@ -# snippet-manager +# Snip - Local-First Code Snippet Manager -Local-first code snippet manager with SQLite, FTS5 search, encryption, and P2P sync \ No newline at end of file +![CI](https://7000pct.gitea.bloupla.net/7000pctAUTO/snippet-manager/actions/workflows/ci.yml/badge.svg) + +A powerful CLI tool for managing code snippets with local-first architecture. Store snippets in SQLite with FTS5 full-text search, optional AES encryption, and peer-to-peer sync capabilities. + +## Features + +- **CRUD Operations**: Create, read, update, delete code snippets with ease +- **Full-Text Search**: FTS5-powered search across title, description, code, and tags with ranking +- **Tag Organization**: Flexible tag-based organization with autocomplete +- **Collections**: Group snippets into named collections for better organization +- **Syntax Highlighting**: Beautiful terminal syntax highlighting using Pygments +- **Import/Export**: JSON import/export for backup, sharing, and portability +- **Encryption**: Optional AES encryption for sensitive snippets using PBKDF2 key derivation +- **P2P Sync**: Discover and sync snippets with peers on your local network via mDNS + +## Installation + +### From Source + +```bash +git clone https://7000pct.gitea.bloupla.net/7000pctAUTO/snippet-manager.git +cd snippet-manager +pip install -e . +``` + +### Dependencies + +``` +click>=8.3.0 +cryptography>=46.0.0 +pygments>=2.19.0 +rich>=13.0.0 +zeroconf>=0.148.0 +``` + +## Quick Start + +```bash +# Initialize the database +snip init + +# Add a snippet +snip add --title "Hello World" --code 'print("Hello, World!")' --language python + +# List all snippets +snip list + +# Get a snippet with syntax highlighting +snip get 1 + +# Search snippets +snip search hello + +# Add tags to organize +snip tag add 1 python basics + +# Create a collection +snip collection create "Python Snippets" + +# Export snippets for backup +snip export all --file backup.json + +# Import snippets from backup +snip import --file backup.json --strategy skip +``` + +## Commands Reference + +### Snippet Commands + +| Command | Description | +|---------|-------------| +| `snip init` | Initialize the snippet database | +| `snip add` | Add a new snippet | +| `snip get ` | Get a snippet by ID with syntax highlighting | +| `snip list` | List all snippets with pagination | +| `snip edit ` | Edit a snippet in your default editor | +| `snip delete ` | Delete a snippet (with confirmation) | +| `snip search ` | Full-text search with FTS5 | + +### Tag Commands + +| Command | Description | +|---------|-------------| +| `snip tag add ` | Add a tag to a snippet | +| `snip tag remove ` | Remove a tag from a snippet | +| `snip tag list` | List all tags in use | + +### Collection Commands + +| Command | Description | +|---------|-------------| +| `snip collection create ` | Create a new collection | +| `snip collection list` | List all collections | +| `snip collection delete ` | Delete a collection | +| `snip collection add ` | Add snippet to collection | +| `snip collection remove ` | Remove snippet from collection | + +### Import/Export Commands + +| Command | Description | +|---------|-------------| +| `snip export all --file ` | Export all snippets to JSON | +| `snip export collection --file ` | Export a specific collection | +| `snip export snippet --file ` | Export a single snippet | +| `snip import --file --strategy ` | Import snippets (strategies: skip, replace, duplicate) | + +### P2P Sync Commands + +| Command | Description | +|---------|-------------| +| `snip discover list` | Discover peers on the local network | +| `snip sync --peer-id ` | Sync snippets with a discovered peer | +| `snip peers` | List known sync peers | + +## Configuration + +### Environment Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `SNIP_DB_PATH` | `~/.snip/snippets.db` | Path to SQLite database | +| `SNIP_KEY_FILE` | `~/.snip/.key` | Path to encryption key file | +| `SNIP_SYNC_PORT` | `8765` | Port for P2P sync | +| `SNIP_PEER_CACHE` | `~/.snip/peers.json` | Path to peer cache | + +### Configuration File + +Optional configuration can be placed at `~/.snip/config.toml`: + +```toml +[database] +path = "~/.snip/snippets.db" + +[sync] +port = 8765 +auto_discover = true + +[display] +style = "monokai" +line_numbers = true +``` + +## Encryption + +Snippets can be encrypted using AES encryption with PBKDF2 key derivation (480k iterations, SHA256). + +```bash +# Add an encrypted snippet +snip add --title "API Secret" --code "API_KEY=abc123" --language python --encrypt + +# View encrypted snippet (will prompt for password) +snip get 1 + +# Encrypted snippets are stored with is_encrypted flag +# Decryption happens on-demand with password verification +``` + +### How Encryption Works + +1. User provides a password when creating an encrypted snippet +2. PBKDF2 derives a 32-byte key using SHA256 (480,000 iterations) +3. Fernet (AES-128-CBC with HMAC) encrypts the snippet content +4. Encrypted data stored in database with `is_encrypted=True` +5. On retrieval, password decrypts the content in memory + +## P2P Sync + +Snip can discover and sync snippets with other peers on your local network using mDNS/Bonjour service discovery. + +### Discovery + +```bash +# Discover available peers on the network +snip discover list + +# Output example: +# Peer: macbook-pro.local (192.168.1.100:8765) +# Last seen: 2 minutes ago +``` + +### Sync Protocol + +1. Peer discovery via `_snippets._tcp.local.` mDNS service +2. HTTP/JSON communication over TCP +3. Sync exchanges snippets updated since last sync +4. Conflict resolution: newest-wins strategy (with option to keep both) + +```bash +# Sync with a specific peer +snip sync --peer-id + +# View known peers +snip peers +``` + +## Import/Export Format + +Exported JSON follows this structure: + +```json +{ + "version": "1.0", + "exported_at": "2024-01-15T10:30:00Z", + "snippets": [ + { + "title": "Hello World", + "description": "A simple Hello World example", + "code": "print('Hello, World!')", + "language": "python", + "tags": ["basics", "example"], + "created_at": "2024-01-10T08:00:00Z", + "updated_at": "2024-01-10T08:00:00Z" + } + ] +} +``` + +### Import Strategies + +- **skip**: Skip snippets that already exist (by title match) +- **replace**: Replace existing snippets with same title +- **duplicate**: Import all as new snippets (generate new IDs) + +## Shell Completion + +Snip supports shell completion for bash and zsh. + +### Bash + +```bash +# Add to ~/.bashrc +eval "$(_SNIP_COMPLETE=bash snip)" +``` + +### Zsh + +```bash +# Add to ~/.zshrc +eval "$(_SNIP_COMPLETE=zsh snip)" +``` + +## Troubleshooting + +### Database Locked + +If you see "Database locked" errors: +- Ensure no other snip processes are running +- Check file permissions on `~/.snip/` + +### FTS Query Syntax Error + +FTS5 uses special syntax for boolean queries: +- Use quotes for phrases: `"hello world"` +- Use AND/OR for boolean: `hello AND world` +- Escape special characters with `\` + +### Decryption Failed + +- Verify you're using the correct password +- Passwords cannot be recovered if forgotten +- Encrypted snippets without the password cannot be decrypted + +### Peer Unreachable + +- Ensure both peers are on the same network +- Check firewall settings for port 8765 +- Verify mDNS/Bonjour is enabled on your system + +## Development + +```bash +# Clone repository +git clone https://7000pct.gitea.bloupla.net/7000pctAUTO/snippet-manager.git +cd snippet-manager + +# Install in development mode +pip install -e ".[dev]" + +# Run tests +pytest tests/ -v + +# Run with verbose output +pytest tests/ -v --capture=no +``` + +## License + +MIT License - see [LICENSE](LICENSE) for details. + +## Contributing + +Contributions welcome! Please open an issue or submit a pull request.