aethel 0.2.4 → 0.2.6
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 +8 -0
- package/README.md +63 -105
- package/package.json +1 -1
- package/src/core/drive-api.js +2 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.6 (2026-04-05)
|
|
4
|
+
|
|
5
|
+
- Rewrite README with clearer structure and usage examples
|
|
6
|
+
|
|
7
|
+
## 0.2.5 (2026-04-05)
|
|
8
|
+
|
|
9
|
+
- Fix Node.js v25 Proxy invariant violation in withDriveRetry
|
|
10
|
+
|
|
3
11
|
## 0.2.4 (2026-04-05)
|
|
4
12
|
|
|
5
13
|
- Fix npm publish authentication in CI workflow
|
package/README.md
CHANGED
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
[](https://nodejs.org)
|
|
7
7
|
|
|
8
|
-
**Git-style Google Drive sync
|
|
8
|
+
**Git-style Google Drive sync from your terminal.**
|
|
9
9
|
|
|
10
|
-
Aethel
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
across local and remote directories.
|
|
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
|
+
|
|
12
|
+
---
|
|
14
13
|
|
|
15
14
|
## Install
|
|
16
15
|
|
|
@@ -18,96 +17,89 @@ across local and remote directories.
|
|
|
18
17
|
npm install -g aethel
|
|
19
18
|
```
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
<details>
|
|
21
|
+
<summary>Install from source</summary>
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
git clone https://github.com/
|
|
25
|
-
cd
|
|
24
|
+
git clone https://github.com/CCJ-0617/Aethel.git
|
|
25
|
+
cd Aethel
|
|
26
26
|
npm install
|
|
27
27
|
npm run install:cli # symlinks `aethel` into ~/.local/bin
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
</details>
|
|
31
|
+
|
|
32
|
+
**Requires Node.js >= 18**
|
|
33
|
+
|
|
34
|
+
## Setup
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
1. Create a project in the [Google Cloud Console](https://console.cloud.google.com/)
|
|
37
|
+
2. Enable the **Google Drive API**
|
|
38
|
+
3. Create an **OAuth 2.0 Client ID** (Desktop application)
|
|
39
|
+
4. Download the credentials JSON and save it as `credentials.json` in your project root
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
```bash
|
|
42
|
+
aethel auth # opens browser, saves token.json
|
|
43
|
+
aethel init --local-path ./workspace --drive-folder <folder-id>
|
|
44
|
+
```
|
|
38
45
|
|
|
39
|
-
|
|
46
|
+
> `credentials.json` and `token.json` are local secrets — never commit them.
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
- `Version & Release`: bumps the version, updates the changelog, creates a GitHub Release, publishes to npm, and publishes to GitHub Packages
|
|
43
|
-
- `Publish GitHub Packages (manual)`: manually publishes the package to GitHub Packages only
|
|
44
|
-
- `Dependabot`: opens weekly dependency update PRs for npm packages and GitHub Actions
|
|
48
|
+
## Usage
|
|
45
49
|
|
|
46
|
-
|
|
50
|
+
```bash
|
|
51
|
+
aethel status # local vs remote changes at a glance
|
|
52
|
+
aethel diff --side all # detailed file-level diff
|
|
53
|
+
aethel add --all # stage default suggested actions
|
|
54
|
+
aethel commit -m "sync" # execute staged operations
|
|
47
55
|
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
|
|
51
|
-
- workflow filename: `version.yml`
|
|
56
|
+
aethel pull -m "pull" # fetch remote changes and apply
|
|
57
|
+
aethel push -m "push" # push local changes to Drive
|
|
58
|
+
```
|
|
52
59
|
|
|
53
|
-
|
|
60
|
+
### Conflict Resolution
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
When both local and remote change the same path:
|
|
56
63
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
```bash
|
|
65
|
+
aethel status # identify conflicts
|
|
66
|
+
aethel resolve <path> --keep local # or: remote, both
|
|
67
|
+
aethel commit -m "resolve"
|
|
68
|
+
```
|
|
62
69
|
|
|
63
|
-
|
|
70
|
+
### Deduplication
|
|
64
71
|
|
|
65
|
-
|
|
72
|
+
Multi-device conflicts can leave duplicate folders on Drive:
|
|
66
73
|
|
|
67
74
|
```bash
|
|
68
|
-
#
|
|
69
|
-
aethel
|
|
70
|
-
|
|
71
|
-
# Initialize a sync workspace
|
|
72
|
-
aethel init --local-path ./workspace
|
|
73
|
-
|
|
74
|
-
# Optional: target a specific Drive folder
|
|
75
|
-
aethel init --local-path ./workspace \
|
|
76
|
-
--drive-folder <folder-id> \
|
|
77
|
-
--drive-folder-name "My Project"
|
|
78
|
-
|
|
79
|
-
# Check status and sync
|
|
80
|
-
aethel status
|
|
81
|
-
aethel diff --side all
|
|
82
|
-
aethel add --all
|
|
83
|
-
aethel commit -m "initial sync"
|
|
84
|
-
aethel pull -m "pull"
|
|
85
|
-
aethel push -m "push"
|
|
86
|
-
aethel log -n 10
|
|
75
|
+
aethel dedupe-folders # dry run — report only
|
|
76
|
+
aethel dedupe-folders --execute # merge duplicates, trash empties
|
|
87
77
|
```
|
|
88
78
|
|
|
79
|
+
Processes deepest-first for single-pass convergence, caches child state to minimize API calls, and runs independent merge groups in parallel.
|
|
80
|
+
|
|
89
81
|
## Commands
|
|
90
82
|
|
|
91
83
|
| Command | Description |
|
|
92
84
|
|---------|-------------|
|
|
93
|
-
| `auth` |
|
|
85
|
+
| `auth` | OAuth flow — creates `token.json`, verifies Drive access |
|
|
94
86
|
| `init` | Initialize a local sync workspace |
|
|
95
|
-
| `status` | Show
|
|
96
|
-
| `diff` |
|
|
97
|
-
| `add` | Stage changes
|
|
87
|
+
| `status` | Show local vs remote changes |
|
|
88
|
+
| `diff` | Detailed file differences |
|
|
89
|
+
| `add` | Stage changes |
|
|
98
90
|
| `reset` | Unstage changes |
|
|
99
91
|
| `commit` | Execute staged sync operations |
|
|
100
|
-
| `pull` | Fetch remote changes
|
|
101
|
-
| `push` |
|
|
102
|
-
| `log` |
|
|
103
|
-
| `fetch` | Refresh remote state without applying
|
|
104
|
-
| `resolve` | Resolve conflicts
|
|
105
|
-
| `ignore` |
|
|
106
|
-
| `show` |
|
|
92
|
+
| `pull` | Fetch and apply remote changes |
|
|
93
|
+
| `push` | Push local changes to Drive |
|
|
94
|
+
| `log` | Sync history |
|
|
95
|
+
| `fetch` | Refresh remote state without applying |
|
|
96
|
+
| `resolve` | Resolve conflicts (local / remote / both) |
|
|
97
|
+
| `ignore` | Manage `.aethelignore` patterns |
|
|
98
|
+
| `show` | Inspect a saved snapshot |
|
|
107
99
|
| `restore` | Restore files from the last snapshot |
|
|
108
100
|
| `rm` | Remove local files and stage remote deletion |
|
|
109
101
|
| `mv` | Move or rename local files |
|
|
110
|
-
| `clean` | List and optionally trash/delete
|
|
102
|
+
| `clean` | List and optionally trash/delete Drive files |
|
|
111
103
|
| `dedupe-folders` | Detect and merge duplicate remote folders |
|
|
112
104
|
| `tui` | Launch interactive terminal UI |
|
|
113
105
|
|
|
@@ -117,56 +109,34 @@ aethel log -n 10
|
|
|
117
109
|
aethel tui
|
|
118
110
|
```
|
|
119
111
|
|
|
120
|
-
Dual-pane file browser
|
|
121
|
-
the right.
|
|
112
|
+
Dual-pane file browser — local filesystem on the left, Google Drive on the right.
|
|
122
113
|
|
|
123
114
|
| Key | Action |
|
|
124
115
|
|-----|--------|
|
|
125
|
-
| `Tab` | Switch
|
|
116
|
+
| `Tab` | Switch panes |
|
|
126
117
|
| `Left` / `Right` | Navigate up / into directories |
|
|
127
|
-
| `u` | Upload selected local file or folder to
|
|
128
|
-
| `s` | Batch sync local folder
|
|
129
|
-
| `U` | Upload from a manually entered
|
|
118
|
+
| `u` | Upload selected local file or folder to Drive |
|
|
119
|
+
| `s` | Batch sync local folder to current Drive directory |
|
|
120
|
+
| `U` | Upload from a manually entered path |
|
|
130
121
|
| `n` | Rename selected local item |
|
|
131
122
|
| `x` | Delete selected local item |
|
|
132
123
|
| `Space` | Toggle selection in Drive pane |
|
|
133
124
|
| `t` / `d` | Trash / permanently delete selected Drive items |
|
|
134
125
|
| `/` | Filter by name |
|
|
135
126
|
|
|
136
|
-
## Deduplication
|
|
137
|
-
|
|
138
|
-
When duplicate folders accumulate from multi-device conflicts, run:
|
|
139
|
-
|
|
140
|
-
```bash
|
|
141
|
-
# Dry run — report duplicates without changing anything
|
|
142
|
-
aethel dedupe-folders
|
|
143
|
-
|
|
144
|
-
# Execute — merge duplicates and trash empty losers
|
|
145
|
-
aethel dedupe-folders --execute
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
The deduplication engine processes folders deepest-first to guarantee
|
|
149
|
-
single-pass convergence, caches child state in memory to minimize API calls,
|
|
150
|
-
and runs independent merge groups in parallel. Paths matching `.aethelignore`
|
|
151
|
-
are excluded automatically.
|
|
152
|
-
|
|
153
127
|
## Ignore Patterns
|
|
154
128
|
|
|
155
|
-
Create
|
|
156
|
-
exclude paths from sync and deduplication:
|
|
129
|
+
Create `.aethelignore` (gitignore syntax) in your workspace root — or run `aethel init` to generate a default one.
|
|
157
130
|
|
|
158
131
|
```gitignore
|
|
159
132
|
.venv/
|
|
160
133
|
node_modules/
|
|
161
134
|
__pycache__/
|
|
162
135
|
.idea/
|
|
163
|
-
.vscode/
|
|
164
136
|
dist/
|
|
165
137
|
build/
|
|
166
138
|
```
|
|
167
139
|
|
|
168
|
-
A default `.aethelignore` is created on `init`.
|
|
169
|
-
|
|
170
140
|
## Environment Variables
|
|
171
141
|
|
|
172
142
|
| Variable | Default | Description |
|
|
@@ -177,19 +147,7 @@ A default `.aethelignore` is created on `init`.
|
|
|
177
147
|
|
|
178
148
|
## Architecture
|
|
179
149
|
|
|
180
|
-
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for module structure and data
|
|
181
|
-
flow.
|
|
182
|
-
|
|
183
|
-
## Publishing
|
|
184
|
-
|
|
185
|
-
```bash
|
|
186
|
-
npm test
|
|
187
|
-
npm run pack:check
|
|
188
|
-
npm publish
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
For a GitHub release, push the tagged version and create a release that matches
|
|
192
|
-
the published npm version.
|
|
150
|
+
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for module structure and data flow.
|
|
193
151
|
|
|
194
152
|
## Contributing
|
|
195
153
|
|
package/package.json
CHANGED
package/src/core/drive-api.js
CHANGED
|
@@ -71,11 +71,8 @@ export function withDriveRetry(drive) {
|
|
|
71
71
|
return (...args) => withRetry(() => value.apply(target, args));
|
|
72
72
|
},
|
|
73
73
|
});
|
|
74
|
-
return
|
|
75
|
-
|
|
76
|
-
if (prop === "files") return filesProxy;
|
|
77
|
-
return Reflect.get(target, prop, receiver);
|
|
78
|
-
},
|
|
74
|
+
return Object.create(drive, {
|
|
75
|
+
files: { value: filesProxy, configurable: true, enumerable: true },
|
|
79
76
|
});
|
|
80
77
|
}
|
|
81
78
|
|