Metadata-Version: 2.4
Name: cloudscope
Version: 0.3.0
Summary: TUI for browsing and syncing files across S3, GCS, and Google Drive
Requires-Python: >=3.11
Requires-Dist: aiofiles>=23.0.0
Requires-Dist: boto3>=1.28.0
Requires-Dist: google-api-python-client>=2.90.0
Requires-Dist: google-auth-httplib2>=0.1.0
Requires-Dist: google-auth-oauthlib>=1.0.0
Requires-Dist: google-cloud-storage>=2.10.0
Requires-Dist: humanize>=4.0.0
Requires-Dist: platformdirs>=3.0.0
Requires-Dist: textual>=1.0.0
Provides-Extra: dev
Requires-Dist: moto>=4.0; extra == 'dev'
Requires-Dist: mypy>=1.5; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Requires-Dist: textual-dev>=1.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# CloudScope

A terminal UI for browsing, downloading, uploading, and bi-directionally syncing files across **AWS S3**, **Google Cloud Storage**, and **Google Drive**.

Built with [Textual](https://textual.textualize.io/) for a keyboard-driven, Linear.app-inspired dark interface.

## Features

- **Multi-backend browsing** — Switch between S3, GCS, and Google Drive with a single keypress (`1`, `2`, `3`)
- **Lazy-loading tree sidebar** — Expand buckets/drives on demand without loading everything upfront
- **Sortable file table** — Click column headers to sort by name, size, modified date, or type
- **File preview** — Metadata panel appears when a file is highlighted (size, modified date, ETag, content type)
- **Downloads and uploads** — File picker dialogs for selecting local paths
- **Folder creation** — Create new folders/prefixes directly from the TUI
- **Bi-directional sync** — Three-way diff engine with conflict resolution (newer wins, local wins, remote wins, keep both, or ask)
- **Command palette** — Press `Ctrl+K` to search and run any command
- **Settings screen** — Configure default backend, AWS profile/region, GCP project, Drive OAuth credentials
- **Auth setup** — Guided authentication testing for each backend

## Requirements

- Python 3.11+
- AWS credentials (for S3) — environment variables, `~/.aws/credentials`, or IAM role
- GCP credentials (for GCS) — Application Default Credentials (`gcloud auth application-default login`)
- OAuth2 client secrets (for Google Drive) — `client_secrets.json` placed in config directory

## Installation

### From source

```bash
git clone https://github.com/your-username/cloudscope.git
cd cloudscope
pip install -e .
```

### With dev dependencies

```bash
pip install -e ".[dev]"
```

### Run

```bash
cloudscope
```

Or via module:

```bash
python -m cloudscope
```

## Authentication Setup

### AWS S3

CloudScope uses standard boto3 credential resolution. Any of the following will work:

- Environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`)
- Shared credentials file (`~/.aws/credentials`)
- AWS config file (`~/.aws/config`) with named profiles
- IAM instance role (on EC2)

Configure a specific profile in Settings (`,`) or pass it through the config file at `~/.config/cloudscope/config.toml`.

### Google Cloud Storage

Uses [Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials):

```bash
gcloud auth application-default login
```

Or point to a service account key in Settings.

### Google Drive

Requires OAuth2 consent flow:

1. Create OAuth credentials in the [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
2. Download the client secrets JSON
3. Place it at `~/.config/cloudscope/drive_client_secrets.json` (or configure the path in Settings)
4. Press `a` in CloudScope to run the auth flow — a browser window will open for consent

The token is persisted at `~/.config/cloudscope/drive_token.json` and refreshed automatically.

## Keyboard Shortcuts

### Browsing

| Key | Action |
|---|---|
| `1` | Switch to S3 |
| `2` | Switch to GCS |
| `3` | Switch to Google Drive |
| `d` | Download selected file |
| `u` | Upload a file |
| `n` | Create new folder |
| `Delete` | Delete selected file |
| `r` | Refresh current view |
| `Tab` | Focus next panel |
| `Shift+Tab` | Focus previous panel |
| `Ctrl+K` | Open command palette |
| `s` | Open sync configuration |
| `,` | Open settings |
| `a` | Open auth setup |
| `?` | Show help |
| `q` | Quit |

### In file table

| Key | Action |
|---|---|
| `Up`/`Down` | Navigate files |
| `Enter` | Open folder or select file |
| Click column header | Sort by that column |

## Configuration

Settings are stored at `~/.config/cloudscope/config.toml`:

```toml
default_backend = "s3"
max_concurrent_transfers = 3

[backends.s3]
profile = "default"
region = "us-east-1"

[backends.gcs]
project = "my-project-id"

[backends.drive]
client_secrets_path = "/path/to/client_secrets.json"
```

All settings can also be edited from the TUI via the Settings screen (`,`).

## Project Structure

```
src/cloudscope/
├── app.py                  # Main Textual application
├── config.py               # TOML config management
├── __main__.py             # CLI entry point
├── auth/
│   ├── aws.py              # AWS profile listing and client creation
│   ├── gcp.py              # GCS client creation (ADC or service account)
│   └── drive_oauth.py      # Google Drive OAuth2 flow
├── backends/
│   ├── base.py             # CloudBackend Protocol and error hierarchy
│   ├── registry.py         # Backend factory (register/get/list)
│   ├── s3.py               # AWS S3 backend (boto3)
│   ├── gcs.py              # Google Cloud Storage backend
│   └── drive.py            # Google Drive backend (path-to-ID cache, export)
├── models/
│   ├── cloud_file.py       # CloudFile, CloudFileType, CloudLocation
│   ├── transfer.py         # TransferJob, TransferDirection, TransferStatus
│   └── sync_state.py       # SyncRecord, SyncConflict, SyncPlan, etc.
├── sync/
│   ├── state.py            # SQLite-backed sync state persistence
│   ├── differ.py           # Three-way diff algorithm
│   ├── resolver.py         # Conflict resolution strategies
│   ├── plan.py             # Converts SyncDiff to executable SyncPlan
│   └── engine.py           # Sync orchestrator (diff → plan → execute)
├── transfer/
│   ├── manager.py          # Concurrent transfer queue (asyncio.Semaphore)
│   └── progress.py         # Progress adapter for SDK callbacks
└── tui/
    ├── commands.py          # Command palette provider (Ctrl+K)
    ├── screens/
    │   ├── browse.py        # Main browsing screen
    │   ├── settings.py      # Settings form
    │   ├── sync_config.py   # Sync configuration and execution
    │   └── auth_setup.py    # Guided auth testing
    ├── modals/
    │   ├── confirm_dialog.py
    │   ├── download_dialog.py
    │   ├── upload_dialog.py
    │   ├── new_folder.py
    │   └── sync_dialog.py   # Sync conflict resolution
    ├── widgets/
    │   ├── status_bar.py    # AppHeader (slim 1-line header)
    │   ├── app_footer.py    # Context-sensitive keybind hints
    │   ├── cloud_tree.py    # Lazy-loading tree sidebar
    │   ├── file_table.py    # Sortable file listing (DataTable)
    │   ├── breadcrumb.py    # Path breadcrumb with › separators
    │   ├── preview_panel.py # File metadata display
    │   └── transfer_panel.py# Transfer progress bar
    └── styles/
        └── cloudscope.tcss  # Linear-inspired dark theme
```

## Development

```bash
# Install with dev dependencies
pip install -e ".[dev]"

# Lint
ruff check src/

# Type check
mypy src/cloudscope/

# Test
pytest

# Run with Textual dev tools (live CSS reloading, etc.)
textual run --dev cloudscope.app:CloudScopeApp
```

## License

MIT
