aethel
v1.2.1
Published
Git-style Google Drive sync CLI with interactive TUI
Downloads
429
Maintainers
Readme
Aethel
Git-style Google Drive sync from your terminal.
Aethel brings a snapshot → diff → stage → commit workflow to Google Drive. Track changes on both sides, resolve conflicts explicitly, and keep a full sync history — all without leaving the command line. It also ships with a dual-pane TUI for hands-on file management.
Install
npm install -g aethelgit clone https://github.com/CCJ-0617/Aethel.git
cd Aethel
npm install
npm run install:cli # symlinks `aethel` into ~/.local/bin
npm run install:debug # symlinks `debug_aethel` without replacing `aethel`Requires Node.js >= 18
Setup

1. Get Google OAuth Credentials
- Go to Google Cloud Console
- Create a project (or select an existing one)
- Enable the Google Drive API (APIs & Services → Library)
- Go to APIs & Services → Credentials
- Click Create Credentials → OAuth 2.0 Client ID
- Application type: Desktop application
- Download the JSON file
2. Save Credentials
Save the downloaded JSON as ~/.config/aethel/credentials.json:
mkdir -p ~/.config/aethel
mv ~/Downloads/client_secret_*.json ~/.config/aethel/credentials.jsonYou can also place credentials.json in the current directory, or pass a custom path with --credentials.
3. Authenticate
aethel auth # opens browser, saves token.json4. Initialize a Workspace

aethel init --local-path ./my-drive # sync entire My Drive
aethel init --local-path ./workspace --drive-folder <folder-id> # sync specific folder
aethel pull --all -m "initial pull" # hydrate local files from the current remote tree
credentials.jsonandtoken.jsonare local secrets — never commit them.
Usage

aethel status # local vs remote changes at a glance
aethel diff --side all # detailed file-level diff
aethel add --all # stage default suggested actions
aethel commit -m "sync" # execute staged operations
aethel pull -m "pull" # fetch remote changes and apply
aethel pull --all # download the full remote tree to local
aethel push -m "push" # push local changes to Drive
aethel verify # verify local files against the last snapshotpull applies remote changes relative to the latest snapshot. Use pull --all for the first full download or to rehydrate a local workspace from the current remote tree.
Conflict Resolution
When both local and remote change the same path:
aethel status # identify conflicts
aethel resolve <path> --keep local # or: remote, both
aethel commit -m "resolve"Deduplication
Multi-device conflicts can leave duplicate folders on Drive:
aethel dedupe-folders # dry run — report only
aethel dedupe-folders --execute # merge duplicates, trash emptiesProcesses deepest-first for single-pass convergence, caches child state to minimize API calls, and runs independent merge groups in parallel.
Commands
| Command | Description |
| ------------------ | ------------------------------------------------------------------- |
| auth | OAuth flow — creates token.json, verifies Drive access |
| init | Initialize a local sync workspace |
| status | Show local vs remote changes |
| diff | Detailed file differences |
| add | Stage changes |
| reset | Unstage changes |
| commit | Execute staged sync operations |
| pull | Fetch and apply remote changes (--all for full remote download) |
| push | Push local changes to Drive |
| log | Sync history |
| fetch | Refresh remote state without applying |
| resolve | Resolve conflicts (local / remote / both) |
| ignore | Manage .aethelignore patterns |
| show | Inspect a saved snapshot |
| restore | Restore files from the last snapshot |
| rm | Remove local files and stage remote deletion |
| mv | Move or rename local files |
| verify | Verify local and optional remote integrity against the last snapshot |
| clean | List and optionally trash/delete Drive files |
| dedupe-folders | Detect and merge duplicate remote folders |
| tui | Launch interactive terminal UI |
Integrity Verification
aethel verify # check snapshot checksum and local file hashes
aethel verify --remote # also compare Drive file hashesverify compares the latest snapshot with the workspace on disk and exits non-zero when files are missing or modified. Add --remote when you also want to verify Drive state before a release, migration, or restore.
TUI
aethel tuiDual-pane file browser — local filesystem on the left, Google Drive on the right.
| Key | Action |
| -------------------- | -------------------------------------------------- |
| Tab | Switch panes |
| Left / Right | Navigate up / into directories |
| u | Upload selected local file or folder to Drive |
| s | Batch sync local folder to current Drive directory |
| U | Upload from a manually entered path |
| n | Rename selected local item |
| x | Delete selected local item |
| Space | Toggle selection in Drive pane |
| t / d | Trash / permanently delete selected Drive items |
| / | Filter by name |
| f | Open the commands page and choose a TUI action |
| : | Run any Aethel CLI command inside the TUI |
Directory Packing
Large directories with many small files (e.g., node_modules, vendor) can be slow to sync. Aethel can pack these into compressed archives for faster transfers.
Enable Packing
Create .aethelconfig in your workspace root:
packing:
enabled: true
compression:
default:
algorithm: gzip # gzip, brotli, zstd, xz, or none
level: 6
rules:
- path: node_modules
strategy: full
- path: vendor
strategy: fullHow It Works
- Tree Hash: Directories are fingerprinted using mtime+size (30x faster than MD5)
- Pack Detection:
aethel statusshows pack states (P+, PL, PR, P=, P!) - Compression: Archives use gzip/brotli (built-in) or zstd/xz (if installed)
Pack Status Codes
| Code | Meaning |
|------|---------|
| P+ | New pack (not yet synced) |
| PL | Pack changed locally |
| PR | Pack changed on Drive |
| P= | Pack up to date |
| P! | Pack conflict |
Use aethel status --verbose to show synced packs.
Ignore Patterns
Create .aethelignore (gitignore syntax) in your workspace root — or run aethel init to generate a default one.
.venv/
node_modules/
__pycache__/
.idea/
dist/
build/Environment Variables
| Variable | Default | Description |
| --------------------------------- | ------------------------------------- | --------------------------------- |
| GOOGLE_DRIVE_CREDENTIALS_PATH | ~/.config/aethel/credentials.json | Path to OAuth credentials |
| GOOGLE_DRIVE_TOKEN_PATH | ~/.config/aethel/token.json | Path to cached OAuth token |
| AETHEL_DRIVE_CONCURRENCY | 40 | Max concurrent Drive API requests |
Architecture
Aethel uses a Repository pattern — a single Repository class (src/core/repository.js) wraps all core modules and serves as the unified data-access layer for both the CLI and the TUI.
src/
├── cli.js CLI entry — all handlers use Repository
├── core/
│ ├── repository.js Unified data-access layer
│ ├── auth.js OAuth authentication
│ ├── config.js Workspace config & state persistence
│ ├── diff.js Change detection between states
│ ├── drive-api.js Google Drive API wrapper
│ ├── local-fs.js Local filesystem operations
│ ├── remote-cache.js Short-lived remote file cache
│ ├── snapshot.js Local scanning & snapshot creation
│ ├── staging.js Stage/unstage operations
│ ├── sync.js Execute staged changes
│ ├── ignore.js .aethelignore pattern matching
│ ├── compress.js Multi-algorithm compression (gzip, brotli, zstd, xz)
│ ├── pack.js Tar archive operations & tree hash
│ └── pack-manifest.js Pack manifest CRUD operations
└── tui/
├── app.js React (Ink) dual-pane component
├── index.js TUI entry
├── commands.js CLI command parser for TUI
└── command-catalog.js Available TUI commandsSee docs/ARCHITECTURE.md for detailed module structure and data flow.
Contributing
See CONTRIBUTING.md for development setup and guidelines.
