aethel 0.4.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.0 (2026-04-15)
4
+
5
+ - Add Packing modules
6
+
7
+ ## 1.1.0 (2026-04-15)
8
+
9
+ ### Added
10
+ - **Directory Packing**: Pack large directories (e.g., `node_modules`) into compressed archives for faster sync
11
+ - Multi-algorithm compression support: gzip, brotli (built-in), zstd, xz (optional)
12
+ - Tree hash algorithm for fast directory fingerprinting (~30x faster than MD5)
13
+ - Pack-aware scanning that skips packed directories
14
+ - Pack change detection: PACK_NEW, PACK_LOCAL_MODIFIED, PACK_REMOTE_MODIFIED, PACK_SYNCED, PACK_CONFLICT
15
+ - `aethel status --verbose` shows synced packs
16
+ - `.aethelconfig` YAML file for packing configuration
17
+
18
+ ### Changed
19
+ - Upgraded ink from 6.8.0 to 7.0.0
20
+ - Upgraded react from 19.2.4 to 19.2.5
21
+
22
+ ## 1.0.0 (2026-04-06)
23
+
24
+ - release: 1.0.0
25
+
3
26
  ## 0.4.0 (2026-04-06)
4
27
 
5
28
  - Add pull --all for full remote download
package/README.md CHANGED
@@ -9,8 +9,6 @@
9
9
 
10
10
  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.
11
11
 
12
- ---
13
-
14
12
  ## Install
15
13
 
16
14
  ```bash
@@ -33,6 +31,8 @@ npm run install:cli # symlinks `aethel` into ~/.local/bin
33
31
 
34
32
  ## Setup
35
33
 
34
+ ![Aethel setup flow](docs/setup.gif)
35
+
36
36
  ### 1. Get Google OAuth Credentials
37
37
 
38
38
  1. Go to [Google Cloud Console](https://console.cloud.google.com/)
@@ -62,15 +62,20 @@ aethel auth # opens browser, saves token.json
62
62
 
63
63
  ### 4. Initialize a Workspace
64
64
 
65
+ ![Aethel init flow](docs/init.gif)
66
+
65
67
  ```bash
66
68
  aethel init --local-path ./my-drive # sync entire My Drive
67
69
  aethel init --local-path ./workspace --drive-folder <folder-id> # sync specific folder
70
+ aethel pull --all -m "initial pull" # hydrate local files from the current remote tree
68
71
  ```
69
72
 
70
73
  > `credentials.json` and `token.json` are local secrets — never commit them.
71
74
 
72
75
  ## Usage
73
76
 
77
+ ![Aethel usage flow](docs/usage.gif)
78
+
74
79
  ```bash
75
80
  aethel status # local vs remote changes at a glance
76
81
  aethel diff --side all # detailed file-level diff
@@ -82,6 +87,8 @@ aethel pull --all # download the full remote tree to local
82
87
  aethel push -m "push" # push local changes to Drive
83
88
  ```
84
89
 
90
+ `pull` 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.
91
+
85
92
  ### Conflict Resolution
86
93
 
87
94
  When both local and remote change the same path:
@@ -105,28 +112,28 @@ Processes deepest-first for single-pass convergence, caches child state to minim
105
112
 
106
113
  ## Commands
107
114
 
108
- | Command | Description |
109
- |---------|-------------|
110
- | `auth` | OAuth flow — creates `token.json`, verifies Drive access |
111
- | `init` | Initialize a local sync workspace |
112
- | `status` | Show local vs remote changes |
113
- | `diff` | Detailed file differences |
114
- | `add` | Stage changes |
115
- | `reset` | Unstage changes |
116
- | `commit` | Execute staged sync operations |
117
- | `pull` | Fetch and apply remote changes |
118
- | `push` | Push local changes to Drive |
119
- | `log` | Sync history |
120
- | `fetch` | Refresh remote state without applying |
121
- | `resolve` | Resolve conflicts (local / remote / both) |
122
- | `ignore` | Manage `.aethelignore` patterns |
123
- | `show` | Inspect a saved snapshot |
124
- | `restore` | Restore files from the last snapshot |
125
- | `rm` | Remove local files and stage remote deletion |
126
- | `mv` | Move or rename local files |
127
- | `clean` | List and optionally trash/delete Drive files |
128
- | `dedupe-folders` | Detect and merge duplicate remote folders |
129
- | `tui` | Launch interactive terminal UI |
115
+ | Command | Description |
116
+ | ------------------ | ------------------------------------------------------------------- |
117
+ | `auth` | OAuth flow — creates `token.json`, verifies Drive access |
118
+ | `init` | Initialize a local sync workspace |
119
+ | `status` | Show local vs remote changes |
120
+ | `diff` | Detailed file differences |
121
+ | `add` | Stage changes |
122
+ | `reset` | Unstage changes |
123
+ | `commit` | Execute staged sync operations |
124
+ | `pull` | Fetch and apply remote changes (`--all` for full remote download) |
125
+ | `push` | Push local changes to Drive |
126
+ | `log` | Sync history |
127
+ | `fetch` | Refresh remote state without applying |
128
+ | `resolve` | Resolve conflicts (local / remote / both) |
129
+ | `ignore` | Manage `.aethelignore` patterns |
130
+ | `show` | Inspect a saved snapshot |
131
+ | `restore` | Restore files from the last snapshot |
132
+ | `rm` | Remove local files and stage remote deletion |
133
+ | `mv` | Move or rename local files |
134
+ | `clean` | List and optionally trash/delete Drive files |
135
+ | `dedupe-folders` | Detect and merge duplicate remote folders |
136
+ | `tui` | Launch interactive terminal UI |
130
137
 
131
138
  ## TUI
132
139
 
@@ -136,20 +143,60 @@ aethel tui
136
143
 
137
144
  Dual-pane file browser — local filesystem on the left, Google Drive on the right.
138
145
 
139
- | Key | Action |
140
- |-----|--------|
141
- | `Tab` | Switch panes |
142
- | `Left` / `Right` | Navigate up / into directories |
143
- | `u` | Upload selected local file or folder to Drive |
144
- | `s` | Batch sync local folder to current Drive directory |
145
- | `U` | Upload from a manually entered path |
146
- | `n` | Rename selected local item |
147
- | `x` | Delete selected local item |
148
- | `Space` | Toggle selection in Drive pane |
149
- | `t` / `d` | Trash / permanently delete selected Drive items |
150
- | `/` | Filter by name |
151
- | `f` | Open the commands page and choose a TUI action |
152
- | `:` | Run any Aethel CLI command inside the TUI |
146
+ | Key | Action |
147
+ | -------------------- | -------------------------------------------------- |
148
+ | `Tab` | Switch panes |
149
+ | `Left` / `Right` | Navigate up / into directories |
150
+ | `u` | Upload selected local file or folder to Drive |
151
+ | `s` | Batch sync local folder to current Drive directory |
152
+ | `U` | Upload from a manually entered path |
153
+ | `n` | Rename selected local item |
154
+ | `x` | Delete selected local item |
155
+ | `Space` | Toggle selection in Drive pane |
156
+ | `t` / `d` | Trash / permanently delete selected Drive items |
157
+ | `/` | Filter by name |
158
+ | `f` | Open the commands page and choose a TUI action |
159
+ | `:` | Run any Aethel CLI command inside the TUI |
160
+
161
+ ## Directory Packing
162
+
163
+ 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.
164
+
165
+ ### Enable Packing
166
+
167
+ Create `.aethelconfig` in your workspace root:
168
+
169
+ ```yaml
170
+ packing:
171
+ enabled: true
172
+ compression:
173
+ default:
174
+ algorithm: gzip # gzip, brotli, zstd, xz, or none
175
+ level: 6
176
+ rules:
177
+ - path: node_modules
178
+ strategy: full
179
+ - path: vendor
180
+ strategy: full
181
+ ```
182
+
183
+ ### How It Works
184
+
185
+ 1. **Tree Hash**: Directories are fingerprinted using mtime+size (30x faster than MD5)
186
+ 2. **Pack Detection**: `aethel status` shows pack states (P+, PL, PR, P=, P!)
187
+ 3. **Compression**: Archives use gzip/brotli (built-in) or zstd/xz (if installed)
188
+
189
+ ### Pack Status Codes
190
+
191
+ | Code | Meaning |
192
+ |------|---------|
193
+ | `P+` | New pack (not yet synced) |
194
+ | `PL` | Pack changed locally |
195
+ | `PR` | Pack changed on Drive |
196
+ | `P=` | Pack up to date |
197
+ | `P!` | Pack conflict |
198
+
199
+ Use `aethel status --verbose` to show synced packs.
153
200
 
154
201
  ## Ignore Patterns
155
202
 
@@ -166,11 +213,11 @@ build/
166
213
 
167
214
  ## Environment Variables
168
215
 
169
- | Variable | Default | Description |
170
- |----------|---------|-------------|
171
- | `GOOGLE_DRIVE_CREDENTIALS_PATH` | `~/.config/aethel/credentials.json` | Path to OAuth credentials |
172
- | `GOOGLE_DRIVE_TOKEN_PATH` | `~/.config/aethel/token.json` | Path to cached OAuth token |
173
- | `AETHEL_DRIVE_CONCURRENCY` | `40` | Max concurrent Drive API requests |
216
+ | Variable | Default | Description |
217
+ | --------------------------------- | ------------------------------------- | --------------------------------- |
218
+ | `GOOGLE_DRIVE_CREDENTIALS_PATH` | `~/.config/aethel/credentials.json` | Path to OAuth credentials |
219
+ | `GOOGLE_DRIVE_TOKEN_PATH` | `~/.config/aethel/token.json` | Path to cached OAuth token |
220
+ | `AETHEL_DRIVE_CONCURRENCY` | `40` | Max concurrent Drive API requests |
174
221
 
175
222
  ## Architecture
176
223
 
@@ -187,10 +234,13 @@ src/
187
234
  │ ├── drive-api.js Google Drive API wrapper
188
235
  │ ├── local-fs.js Local filesystem operations
189
236
  │ ├── remote-cache.js Short-lived remote file cache
190
- │ ├── snapshot.js Local scanning & snapshot creation
237
+ │ ├── snapshot.js Local scanning & snapshot creation
191
238
  │ ├── staging.js Stage/unstage operations
192
239
  │ ├── sync.js Execute staged changes
193
- └── ignore.js .aethelignore pattern matching
240
+ ├── ignore.js .aethelignore pattern matching
241
+ │ ├── compress.js Multi-algorithm compression (gzip, brotli, zstd, xz)
242
+ │ ├── pack.js Tar archive operations & tree hash
243
+ │ └── pack-manifest.js Pack manifest CRUD operations
194
244
  └── tui/
195
245
  ├── app.js React (Ink) dual-pane component
196
246
  ├── index.js TUI entry
@@ -45,6 +45,15 @@ The core design is not a live mirror between local storage and Drive. Instead, s
45
45
  - Manages `.aethelignore`
46
46
  - `src/core/remote-cache.js`
47
47
  - Short-lived cache for remote listings
48
+ - `src/core/compress.js`
49
+ - Multi-algorithm compression (gzip, brotli, zstd, xz)
50
+ - Compression profiles and algorithm detection
51
+ - `src/core/pack.js`
52
+ - Tar archive creation and extraction
53
+ - Tree hash algorithm for fast directory fingerprinting
54
+ - `src/core/pack-manifest.js`
55
+ - CRUD operations for pack manifest
56
+ - Tracks packed directories and their sync state
48
57
 
49
58
  ### 2.3 State Storage Layer
50
59
 
@@ -55,16 +64,20 @@ After workspace initialization, the project root contains:
55
64
  config.json
56
65
  index.json
57
66
  .hash-cache.json
67
+ pack-manifest.json
58
68
  snapshots/
59
69
  latest.json
60
70
  history/
71
+ .aethelconfig
61
72
  ```
62
73
 
63
74
  - `config.json`: sync root configuration
64
75
  - `index.json`: currently staged operations
65
76
  - `.hash-cache.json`: local file hash cache
77
+ - `pack-manifest.json`: tracks packed directories and their sync state
66
78
  - `snapshots/latest.json`: baseline state after the most recent successful sync
67
79
  - `snapshots/history/`: archived older snapshots
80
+ - `.aethelconfig` (workspace root): YAML configuration for directory packing
68
81
 
69
82
  ## 3. Core Data Flow
70
83
 
@@ -124,6 +137,7 @@ That means the system does not compare only "local vs remote". It also asks:
124
137
 
125
138
  `src/core/diff.js` classifies changes as:
126
139
 
140
+ **File changes:**
127
141
  - `remote_added`
128
142
  - `remote_modified`
129
143
  - `remote_deleted`
@@ -132,6 +146,13 @@ That means the system does not compare only "local vs remote". It also asks:
132
146
  - `local_deleted`
133
147
  - `conflict`
134
148
 
149
+ **Pack changes (for packed directories):**
150
+ - `pack_new` - directory newly configured for packing
151
+ - `pack_local_modified` - packed directory changed locally
152
+ - `pack_remote_modified` - packed directory changed on Drive
153
+ - `pack_synced` - packed directory up to date
154
+ - `pack_conflict` - both sides changed the packed directory
155
+
135
156
  It also provides default suggested actions for each category:
136
157
 
137
158
  - Drive added/modified -> `download`
@@ -139,6 +160,9 @@ It also provides default suggested actions for each category:
139
160
  - Local added/modified -> `upload`
140
161
  - Local deleted -> `delete_remote`
141
162
  - Both sides changed the same path -> `conflict`
163
+ - Pack new/local modified -> `push_pack`
164
+ - Pack remote modified -> `pull_pack`
165
+ - Pack conflict -> `resolve_pack`
142
166
 
143
167
  ### 4.3 Execution Model
144
168
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aethel",
3
- "version": "0.4.0",
3
+ "version": "1.2.0",
4
4
  "description": "Git-style Google Drive sync CLI with interactive TUI",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -26,6 +26,11 @@
26
26
  },
27
27
  "files": [
28
28
  "src/",
29
+ "scripts/demo.js",
30
+ "scripts/render-demo-gif.py",
31
+ "scripts/render-demo-screenshot.js",
32
+ "docs/demo.gif",
33
+ "docs/demo-screenshot.svg",
29
34
  "LICENSE",
30
35
  "README.md",
31
36
  "CHANGELOG.md",
@@ -33,6 +38,12 @@
33
38
  ".env.example"
34
39
  ],
35
40
  "scripts": {
41
+ "demo": "node scripts/demo.js",
42
+ "demo:gif": "python3 scripts/render-demo-gif.py",
43
+ "demo:screenshot": "node scripts/render-demo-screenshot.js",
44
+ "demo:setup": "python3 scripts/generate-cast.py && agg docs/setup.cast docs/setup.gif --font-size 32 --theme dracula",
45
+ "demo:init": "python3 scripts/generate-init-cast.py && agg docs/init.cast docs/init.gif --font-size 32 --theme dracula",
46
+ "demo:usage": "python3 scripts/generate-usage-cast.py && agg docs/usage.cast docs/usage.gif --font-size 32 --theme dracula",
36
47
  "start": "node src/cli.js",
37
48
  "auth": "node src/cli.js auth",
38
49
  "clean": "node src/cli.js clean",
@@ -48,12 +59,14 @@
48
59
  "commander": "^14.0.3",
49
60
  "googleapis": "^171.4.0",
50
61
  "ignore": "^7.0.5",
51
- "ink": "^6.8.0",
62
+ "ink": "^7.0.0",
52
63
  "ink-select-input": "^6.0.0",
53
64
  "ink-spinner": "^5.0.0",
54
65
  "ink-text-input": "^6.0.0",
55
66
  "open": "^11.0.0",
56
- "react": "^19.2.4"
67
+ "react": "^19.2.4",
68
+ "tar": "^7.5.13",
69
+ "yaml": "^2.8.3"
57
70
  },
58
71
  "engines": {
59
72
  "node": ">=18"