# clipcp

Transfer files and folders between machines via a shared clipboard — no network configuration, no open ports, no SSH. Works anywhere your clipboard is shared (e.g. a remote desktop session, a VM with clipboard integration, or a KVM switch).

## Install

```bash
pip install clipcp
```

## Usage

### Manual mode (ENTER-driven)

**Sender:**
```bash
clipcp <file_or_folder>
```

**Receiver:**
```bash
clipcp
```

You copy each chunk to clipboard and press ENTER to advance. Works with any shared clipboard.

### Auto mode (fully hands-free)

Both sides poll the clipboard and handshake automatically — no interaction needed once started.

**Receiver** (start first):
```bash
clipcp --auto [--dest DIR] [--timeout S]
```

**Sender:**
```bash
clipcp <file_or_folder> --auto [--chunk-size KB] [--timeout S]
```

### Git sync mode

Synchronise a git repository between two machines. Only the missing commits are transferred (as an encrypted git bundle). Merging is done on the server side.

**Server** (the authoritative repo):
```bash
clipcp . --git [--yes]
```

**Client** (the repo to sync into):
```bash
clipcp --git [--dest DIR]
```

Both sides run simultaneously. The handshake proceeds automatically:

1. Server announces its HEAD hash.
2. Client replies with its HEAD hash.
3. If server is ahead — server sends a bundle of missing commits to client.
4. If client is ahead or histories diverged — server negotiates a common base with the client, then the client sends a bundle to the server which merges it in.

#### Merge conflicts

If both sides modified the same files, the merge is aborted and the conflicting ref is left at `refs/clipcp/incoming`. Resolve manually on the server:

```bash
git merge refs/clipcp/incoming
# edit conflicting files, remove <<<<<<< markers
git add <resolved files>
git commit
```

Or take one side entirely:
```bash
git merge -X ours refs/clipcp/incoming    # keep server version
git merge -X theirs refs/clipcp/incoming  # keep incoming version
```

#### Options

| Flag | Description |
|---|---|
| `--yes` / `-y` | Skip the confirmation prompt before sending chunks |

---

## Options

| Flag | Default | Description |
|---|---|---|
| `--auto` | on | Auto handshake mode (`--no-auto` for manual ENTER-driven) |
| `--git` | off | Git sync mode |
| `--chunk-size KB` | 64 | Max size of each clipboard chunk |
| `--dest DIR` | `.` | Destination directory (receiver / git client) |
| `--timeout S` | 60 | Seconds to wait for each step |
| `--skip PATTERN` | — | Skip files matching pattern (e.g. `--skip .git *.pyc`) |
| `--yes` / `-y` | off | Skip confirmation prompt (git mode) |
| `--resume [ID]` | — | Resume an interrupted transfer |
| `--extract [ID]` | — | Extract a fully-received transfer from saved state |
| `--clear [ID\|all]` | — | Clear saved transfer state |
| `--list` | — | List all saved transfers |

## Password / Encryption

All data is AES-256-GCM encrypted. You will be prompted for a password on both sides, or set it via environment variable to skip the prompt:

```bash
export CLIPCP_PASSWORD=mysecretpassword
```

## How it works

`clipcp` compresses the target (tar.gz), encrypts it (AES-256-GCM with PBKDF2 key derivation), base64-encodes the result, and splits it into clipboard-sized chunks.

In **auto mode**, the receiver writes a `CLIPCP_READY` signal to the clipboard. The sender detects it, writes chunk 1, and the receiver ACKs each chunk until all are received and a `CLIPCP_DONE` signal is written. The sender then exits.

In **git mode**, instead of a tar archive a `git bundle` is transferred — only the commits the other side is missing. Both sides first exchange HEAD hashes to determine direction and negotiate a common base. The bundle is encrypted the same way as regular transfers.

## Requirements

- Python 3.10+
- A shared clipboard between sender and receiver (e.g. RDP, VNC, VM clipboard integration)
