@fizzyflow/wdoublesync_cli 1.0.2 → 1.0.5
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/README.md +45 -14
- package/SKILL.md +297 -0
- package/bin/wdoublesync.js +45 -10
- package/lib/WalrusSealClient.js +377 -0
- package/lib/commands/index.js +5 -0
- package/lib/commands/info.js +113 -0
- package/lib/commands/pull.js +63 -0
- package/lib/commands/push.js +100 -0
- package/lib/commands/rebate.js +81 -0
- package/lib/commands/shared.js +237 -0
- package/lib/commands/watch.js +181 -0
- package/lib/commands.js +49 -15
- package/package.json +3 -4
package/README.md
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# wdoublesync cli
|
|
2
2
|
|
|
3
|
-
CLI tool to sync local folders to [Walrus](https://walrus.xyz) decentralised storage on the Sui network.
|
|
3
|
+
CLI tool to sync local folders to Sui and [Walrus](https://walrus.xyz) decentralised storage on the Sui network.
|
|
4
4
|
|
|
5
5
|
Built on top of the [`wdoublesync`](https://github.com/fizzyFlow/wdoublesync) library.
|
|
6
6
|
|
|
7
|
-
Each `push` stores a versioned, gzip-compressed
|
|
7
|
+
Each `push` stores a versioned, gzip-compressed diff or shapshot inside an [EndlessVector](https://github.com/fizzyFlow/endless_vector) on-chain object. Any past version can be restored at any time with `pull`. Folders can optionally be encrypted with [Seal](https://github.com/MystenLabs/seal).
|
|
8
8
|
|
|
9
|
+
## AI Agent Skill
|
|
10
|
+
|
|
11
|
+
wdoublesync ships with a [SKILL.md](https://github.com/FizzyFlow/wdoublesync_cli/blob/main/SKILL.md) that teaches AI coding agents how to use it autonomously. Once loaded, an agent can push folders to on-chain storage, pull specific versions for inspection or rollback, watch a directory for bi-directional sync, and run rebate to compact a vector's archive — all without hand-holding on the commands. This is useful when you want an agent to persist its own working state, archive project snapshots, or coordinate versioned data across sessions. The skill also covers how to combine wdoublesync with [MemWal](https://github.com/MystenLabs/MemWal) for workflows.
|
|
9
12
|
|
|
10
13
|
## Installation
|
|
11
14
|
|
|
@@ -18,12 +21,15 @@ pnpm link --global
|
|
|
18
21
|
## Usage
|
|
19
22
|
|
|
20
23
|
```
|
|
21
|
-
wdoublesync push [vector-id] [options] Sync
|
|
22
|
-
wdoublesync pull <vector-id> [options] Restore vector contents to
|
|
23
|
-
wdoublesync info
|
|
24
|
-
wdoublesync watch <vector-id> [options] Watch folder
|
|
24
|
+
wdoublesync push [vector-id] [path] [options] Sync folder to a vector (creates one if no id given)
|
|
25
|
+
wdoublesync pull <vector-id> [path] [options] Restore vector contents to a folder
|
|
26
|
+
wdoublesync info [vector-id] [path] [options] Show chain/wallet info, or full vector metadata
|
|
27
|
+
wdoublesync watch <vector-id> [path] [options] Watch folder: auto-push on changes, auto-pull on remote updates
|
|
28
|
+
wdoublesync rebate <vector-id> [path] [options] Burn archive patches and push folder as a fresh snapshot
|
|
25
29
|
```
|
|
26
30
|
|
|
31
|
+
The `[path]` argument is optional — if omitted, the current working directory is used.
|
|
32
|
+
|
|
27
33
|
### Options
|
|
28
34
|
|
|
29
35
|
| Flag | Description |
|
|
@@ -54,11 +60,15 @@ Supply a signing key in one of three ways (checked in order):
|
|
|
54
60
|
|
|
55
61
|
## Examples
|
|
56
62
|
|
|
57
|
-
### Push
|
|
63
|
+
### Push a folder (first time)
|
|
58
64
|
|
|
59
65
|
```bash
|
|
60
|
-
|
|
66
|
+
# from current directory
|
|
61
67
|
wdoublesync push --chain testnet --key suiprivkey1...
|
|
68
|
+
|
|
69
|
+
# or pass path explicitly
|
|
70
|
+
wdoublesync push ~/my-project --chain testnet --key suiprivkey1...
|
|
71
|
+
|
|
62
72
|
# prints the new vector id, e.g.:
|
|
63
73
|
# created: 0xabc123...
|
|
64
74
|
# version 1 pushed (full snapshot, gzip compressed)
|
|
@@ -68,26 +78,32 @@ wdoublesync push --chain testnet --key suiprivkey1...
|
|
|
68
78
|
|
|
69
79
|
```bash
|
|
70
80
|
wdoublesync push 0xabc123... --chain testnet --key suiprivkey1...
|
|
71
|
-
|
|
81
|
+
|
|
82
|
+
# or with explicit path
|
|
83
|
+
wdoublesync push 0xabc123... ~/my-project --chain testnet --key suiprivkey1...
|
|
72
84
|
```
|
|
73
85
|
|
|
74
|
-
### Pull the latest version
|
|
86
|
+
### Pull the latest version
|
|
75
87
|
|
|
76
88
|
```bash
|
|
77
|
-
|
|
78
|
-
wdoublesync pull 0xabc123... --chain testnet
|
|
89
|
+
wdoublesync pull 0xabc123... ~/restored --chain testnet
|
|
79
90
|
```
|
|
80
91
|
|
|
81
92
|
### Pull a specific version
|
|
82
93
|
|
|
83
94
|
```bash
|
|
84
|
-
wdoublesync pull 0xabc123... --chain testnet --version 1
|
|
95
|
+
wdoublesync pull 0xabc123... ~/restored --chain testnet --version 1
|
|
85
96
|
```
|
|
86
97
|
|
|
87
|
-
### Inspect a vector
|
|
98
|
+
### Inspect a vector
|
|
88
99
|
|
|
89
100
|
```bash
|
|
101
|
+
# check your wallet + chain (no vector ID needed)
|
|
102
|
+
wdoublesync info
|
|
103
|
+
|
|
104
|
+
# full vector metadata + local sync status
|
|
90
105
|
wdoublesync info 0xabc123... --chain testnet
|
|
106
|
+
wdoublesync info 0xabc123... ~/my-project --chain testnet
|
|
91
107
|
```
|
|
92
108
|
|
|
93
109
|
### Fast incremental pushes with a manifest
|
|
@@ -101,6 +117,9 @@ wdoublesync push 0xabc123... --chain testnet --key suiprivkey1... --manifest
|
|
|
101
117
|
|
|
102
118
|
```bash
|
|
103
119
|
wdoublesync watch 0xabc123... --chain testnet --key suiprivkey1...
|
|
120
|
+
|
|
121
|
+
# or with explicit path
|
|
122
|
+
wdoublesync watch 0xabc123... ~/my-project --chain testnet --key suiprivkey1...
|
|
104
123
|
# pushes local changes 1 s after the last edit
|
|
105
124
|
# pulls remote updates every 2 s
|
|
106
125
|
# Ctrl-C to stop
|
|
@@ -119,6 +138,17 @@ wdoublesync watch 0xabc123... --push-only # no auto-pull
|
|
|
119
138
|
wdoublesync watch 0xabc123... --pull-only # no auto-push (read-only mirror)
|
|
120
139
|
```
|
|
121
140
|
|
|
141
|
+
### Rebate (compact archive)
|
|
142
|
+
|
|
143
|
+
After many incremental syncs, burn old archive patches and push the current folder as a fresh single snapshot. Reduces storage cost.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
wdoublesync rebate 0xabc123... --chain testnet --key suiprivkey1...
|
|
147
|
+
|
|
148
|
+
# or with explicit path
|
|
149
|
+
wdoublesync rebate 0xabc123... ~/my-project --chain testnet --key suiprivkey1...
|
|
150
|
+
```
|
|
151
|
+
|
|
122
152
|
### Repair a corrupt vector with a force snapshot
|
|
123
153
|
|
|
124
154
|
If a diff patch was pushed against a stale base (e.g. a race condition in `watch`), subsequent pulls will fail. Fix it by pushing a new full snapshot:
|
|
@@ -135,6 +165,7 @@ wdoublesync push 0xabc123... --chain testnet --key suiprivkey1... --force-snapsh
|
|
|
135
165
|
2. **pull** — reads the requested version from the EndlessVector, decrypts it if Seal-encrypted, and writes only changed files to disk. Files absent from the stored version are deleted.
|
|
136
166
|
3. **info** — reads EndlessVector metadata from the chain (version count, binary size, history) and checks whether the local folder matches any stored version.
|
|
137
167
|
4. **watch** — combines push and pull in a loop. A filesystem watcher triggers a debounced push on local changes. A poll interval checks the remote vector for new versions and pulls them if found. Push and pull never run concurrently.
|
|
168
|
+
5. **rebate** — burns all existing archive patches on-chain and pushes the current folder as a single fresh full snapshot, reducing Walrus storage costs after many incremental syncs.
|
|
138
169
|
|
|
139
170
|
### Default excludes
|
|
140
171
|
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wdoublesync
|
|
3
|
+
version: 0.1.7
|
|
4
|
+
description: Claude agent skill for decentralized file storage, versioning, and sync on Sui + Walrus + Seal. Enables agents to push local folders as on-chain vectors, pull versions, manage Walrus storage, and watch for changes.
|
|
5
|
+
keywords: [walrus, sui, storage, versioning, sync, seal-encryption, blockchain, defi]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# wdoublesync
|
|
9
|
+
|
|
10
|
+
Decentralized file storage, versioning, and sync on **Sui + Walrus + Seal**.
|
|
11
|
+
|
|
12
|
+
An abstract virtual filesystem that synchronizes folder state on-chain via Sui + Walrus using Content-Defined Chunking (CDC) to compute minimal binary diffs. Files can optionally be encrypted with Seal so only authorized addresses can decrypt them.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- **Archive and restore folder snapshots** on-chain with full version history
|
|
17
|
+
- **Efficient incremental sync** — only changed chunks uploaded, not entire files
|
|
18
|
+
- **End-to-end encrypted storage** — data encrypted with Seal before Walrus upload
|
|
19
|
+
- **Verify data integrity** — pull any version and reconstruct exact folder state
|
|
20
|
+
- **Extend storage** before Walrus epochs expire without re-uploading data
|
|
21
|
+
- **Clean archive** with rebate workflow (burn old archive, push as fresh snapshot)
|
|
22
|
+
|
|
23
|
+
## When NOT to Use
|
|
24
|
+
|
|
25
|
+
- For **semantic/vector search over text** — if you need to index and search text by meaning, use [MemWal](https://raw.githubusercontent.com/MystenLabs/MemWal/refs/heads/dev/SKILL.md) instead (vector database with embeddings)
|
|
26
|
+
|
|
27
|
+
## MemWal + WDoubleSync
|
|
28
|
+
|
|
29
|
+
Feel free to combine MemWal and WDoubleSync in your agent workflows. For example, you can use MemWal to store and search text embeddings, and WDoubleSync to store the original files or folders that correspond to those embeddings. This allows you to have both semantic search capabilities and versioned file storage in one system.
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
Check if `wdoublesync` is already installed:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
wdoublesync --help
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
if not, install via npm:
|
|
40
|
+
|
|
41
|
+
**Global npm install**
|
|
42
|
+
```bash
|
|
43
|
+
npm install -g @fizzyflow/wdoublesync_cli
|
|
44
|
+
# Now use: wdoublesync <command> (installed from npm)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
After you have access to `wdoublesync`, you can run `wdoublesync --help` to see the available commands and options. Use `wdoublesync info` to check your currently connected wallet (`your wallet` field), if there's no - wallet, you can set one with `--key` or `--phrase` flags, or by exporting `WDOUBLESYNC_KEY` environment variable. Feel free to ask user to set up a wallet if they haven't done so yet, as it's required for push operations and pull encrypted vectors.
|
|
48
|
+
|
|
49
|
+
### Set up your key (required for push and pull of encrypted vectors)
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
export WDOUBLESYNC_KEY=suiprivkey1...
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
For **read-only public vectors**, the key is not required.
|
|
56
|
+
|
|
57
|
+
### Push a folder (creates new vector if no ID provided)
|
|
58
|
+
|
|
59
|
+
Be sure to run this command from the folder you want to sync:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
cd ~/my-folder
|
|
63
|
+
wdoublesync push
|
|
64
|
+
# Creates new vector + syncs current folder
|
|
65
|
+
# Output: created: 0x1234... / syncing ./ → 0x1234...
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
This creates a new EndlessVector on-chain and pushes the current folder as a snapshot encrypted by Seal. The output will show the vector ID (e.g., `0x1234...`) which you can use for future pulls or pushes.
|
|
69
|
+
|
|
70
|
+
### Pull a vector to restore it
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
mkdir ~/restored-folder && cd ~/restored-folder
|
|
74
|
+
wdoublesync pull 0x1234...
|
|
75
|
+
# Restores vector to current directory
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### View vector metadata
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
wdoublesync info 0x1234...
|
|
82
|
+
# Output: ID, owner, version count, total size, encryption status
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Watch for changes (bi-directional sync)
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
cd ~/my-data
|
|
89
|
+
wdoublesync watch 0x1234... --poll-interval 5
|
|
90
|
+
# Monitors local folder, auto-pushes changes
|
|
91
|
+
# Checks remote every 5 seconds, auto-pulls updates
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## API Surface
|
|
95
|
+
|
|
96
|
+
All commands operate on the **current working directory** — `cd` into your folder first.
|
|
97
|
+
|
|
98
|
+
| Command | Arguments | Use Case |
|
|
99
|
+
|---------|-----------|----------|
|
|
100
|
+
| **push** | `[vectorId]` `[options]` | Sync current folder to vector; creates new vector if no ID given |
|
|
101
|
+
| **pull** | `vectorId` `[options]` | Restore vector (default: latest version) into current directory |
|
|
102
|
+
| **info** | `[vectorId]` | No ID: show chain + wallet. With ID: full vector details |
|
|
103
|
+
| **watch** | `vectorId` `[options]` | Bi-directional sync: auto-push local changes, auto-pull remote updates |
|
|
104
|
+
| **rebate** | `vectorId` | Burn archive patches, push current folder as fresh single snapshot |
|
|
105
|
+
|
|
106
|
+
### Command Examples
|
|
107
|
+
|
|
108
|
+
#### push (create new vector)
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
cd ~/my-data
|
|
112
|
+
wdoublesync push
|
|
113
|
+
# Syncs current folder as new vector
|
|
114
|
+
# Output: creating new EndlessVector on testnet...
|
|
115
|
+
# created: 0xabc123...
|
|
116
|
+
# syncing ./ → 0xabc123...
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### push (with manifest for faster change detection)
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
cd ~/my-data
|
|
123
|
+
wdoublesync push 0x1234... --manifest
|
|
124
|
+
# Writes .wdoublesync manifest; faster change detection on future pushes
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### push (full snapshot, not incremental)
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
cd ~/my-data
|
|
131
|
+
wdoublesync push 0x1234... --force-snapshot
|
|
132
|
+
# Uploads entire snapshot, useful if history is corrupted
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### pull (latest version)
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
mkdir ~/restored && cd ~/restored
|
|
139
|
+
wdoublesync pull 0x1234...
|
|
140
|
+
# Restores latest version to current directory
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### pull (specific version)
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
cd ~/restored
|
|
147
|
+
wdoublesync pull 0x1234... --version 10
|
|
148
|
+
# Restores version 10 instead of latest
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### watch (bi-directional)
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
cd ~/my-data
|
|
155
|
+
wdoublesync watch 0x1234... --poll-interval 5
|
|
156
|
+
# Monitors current folder, auto-pushes on change (debounce: 1000ms default)
|
|
157
|
+
# Checks remote every 5 seconds, auto-pulls new versions
|
|
158
|
+
# Runs indefinitely; stop with Ctrl+C
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### watch (push-only)
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
cd ~/my-data
|
|
165
|
+
wdoublesync watch 0x1234... --push-only
|
|
166
|
+
# Only auto-push on local changes, don't pull remote updates
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
#### watch (pull-only)
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
cd ~/my-data
|
|
173
|
+
wdoublesync watch 0x1234... --pull-only
|
|
174
|
+
# Only pull remote updates, don't auto-push local changes
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### rebate
|
|
178
|
+
|
|
179
|
+
When user asks to rebate, you can explain that this command is useful after many incremental syncs to reclaim on-chain storage. It burns the archive history and pushes the current folder as a fresh single snapshot. Make sure user understands that after rebate, only the latest snapshot is available, and old patches will be burned.
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
cd ~/my-data
|
|
183
|
+
wdoublesync rebate 0x1234...
|
|
184
|
+
# Burns archive history, pushes current folder as fresh single snapshot
|
|
185
|
+
# Useful after many incremental syncs to reclaim on-chain storage
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
## Configuration
|
|
190
|
+
|
|
191
|
+
### Command-line flags
|
|
192
|
+
|
|
193
|
+
| Flag | Arguments | Default | Use |
|
|
194
|
+
|------|-----------|---------|-----|
|
|
195
|
+
| `--chain` | `mainnet` \| `testnet` \| `devnet` \| `localnet` | `testnet` | Which Sui network to use |
|
|
196
|
+
| `--key` | Sui private key (`suiprivkey1...`) | — | Sign transactions (or use env vars) |
|
|
197
|
+
| `--phrase` | Mnemonic phrase | — | Alternative: derive key from mnemonic |
|
|
198
|
+
| `--no-compress` | — | — | Push: disable gzip compression |
|
|
199
|
+
| `--manifest` | — | — | Push: write/use `.wdoublesync` file for faster change detection |
|
|
200
|
+
| `--force-snapshot` | — | — | Push: full snapshot (repairs corrupt vectors) |
|
|
201
|
+
| `--version` | Number | `latest` | Pull: restore specific version instead of latest |
|
|
202
|
+
| `--exclude` | Patterns (comma-separated) | — | Extra file patterns to exclude from sync |
|
|
203
|
+
| `--poll-interval` | Seconds | `2` | Watch: check for remote updates every N seconds |
|
|
204
|
+
| `--debounce` | Milliseconds | `1000` | Watch: quiet period before pushing after local change |
|
|
205
|
+
| `--push-only` | — | — | Watch: disable auto-pull |
|
|
206
|
+
| `--pull-only` | — | — | Watch: disable auto-push |
|
|
207
|
+
|
|
208
|
+
### Environment variables
|
|
209
|
+
|
|
210
|
+
| Variable | Type | Use |
|
|
211
|
+
|----------|------|-----|
|
|
212
|
+
| `WDOUBLESYNC_KEY` | Sui private key (`suiprivkey1...`) | Sign transactions (alternative to `--key` flag) |
|
|
213
|
+
|
|
214
|
+
## Example Workflows
|
|
215
|
+
|
|
216
|
+
### Workflow 1: Create and verify
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# 1. Push a folder (creates new vector on first push)
|
|
220
|
+
cd ~/important-data
|
|
221
|
+
wdoublesync push
|
|
222
|
+
# Output: creating new EndlessVector on testnet...
|
|
223
|
+
# created: 0xabc123...
|
|
224
|
+
|
|
225
|
+
# 2. Verify by pulling to a fresh folder
|
|
226
|
+
mkdir ~/verify-tmp && cd ~/verify-tmp
|
|
227
|
+
wdoublesync pull 0xabc123...
|
|
228
|
+
|
|
229
|
+
# 3. Check file counts match
|
|
230
|
+
ls ~/important-data | wc -l
|
|
231
|
+
ls ~/verify-tmp | wc -l
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Workflow 2: Multi-version history and rollback
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
cd ~/data
|
|
238
|
+
# Push version 1
|
|
239
|
+
wdoublesync push 0xabc123...
|
|
240
|
+
|
|
241
|
+
# Make changes, push version 2
|
|
242
|
+
echo "new file" > new.txt
|
|
243
|
+
wdoublesync push 0xabc123...
|
|
244
|
+
|
|
245
|
+
# List all versions
|
|
246
|
+
wdoublesync info 0xabc123...
|
|
247
|
+
|
|
248
|
+
# Rollback to version 1
|
|
249
|
+
mkdir ~/data-v1 && cd ~/data-v1
|
|
250
|
+
wdoublesync pull 0xabc123... --version 1
|
|
251
|
+
# Folder now matches state from version 1
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Workflow 3: Rebate to compact archive
|
|
255
|
+
|
|
256
|
+
After many incremental syncs, archive grows with lots of patches. Rebate burns old data and rebuilds as single snapshot:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# Before rebate: many small patches
|
|
260
|
+
wdoublesync info 0xabc123...
|
|
261
|
+
# Output: version 87, total size 45 MB (many patches)
|
|
262
|
+
|
|
263
|
+
# Run rebate from current directory
|
|
264
|
+
cd ~/data
|
|
265
|
+
wdoublesync rebate 0xabc123...
|
|
266
|
+
# Output: Burned 86 items, pushed version 88 (3.2 MB)
|
|
267
|
+
|
|
268
|
+
# After rebate: single snapshot instead of 87 patches
|
|
269
|
+
# Much more efficient for Walrus storage
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Workflow 4: Watch for external changes
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
# Another user pushes to the same vector
|
|
276
|
+
# You want to auto-sync your local copy
|
|
277
|
+
|
|
278
|
+
cd ~/data
|
|
279
|
+
wdoublesync watch 0xabc123... --poll-interval 5
|
|
280
|
+
# Monitors local folder for changes, auto-pushes them
|
|
281
|
+
# Also checks remote every 5 seconds for updates, auto-pulls
|
|
282
|
+
# Press Ctrl+C to stop
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Troubleshooting
|
|
286
|
+
|
|
287
|
+
| Issue | Cause | Solution |
|
|
288
|
+
|-------|-------|----------|
|
|
289
|
+
| **"No signing key"** | Trying to push/pull without credentials | Export `WDOUBLESYNC_KEY=suiprivkey1...` or use `--key` / `--phrase` flag |
|
|
290
|
+
| **"vector-id is required"** | Command needs a vector ID but none provided | Pass the vector ID as the first argument: `wdoublesync pull 0x...` |
|
|
291
|
+
| **"This vector is Seal-encrypted"** | Vector is encrypted but no key provided | Provide `--key` or `--phrase`, or export `WDOUBLESYNC_KEY` |
|
|
292
|
+
| **"at() is out of range, this part of archive has been burned"** | Trying to restore a version whose archive was burned by rebate | Only the latest snapshot is available after rebate; pull without `--version` |
|
|
293
|
+
| **Connection errors** | RPC endpoint unreachable or wrong chain | You may need to try again little later |
|
|
294
|
+
|
|
295
|
+
## Links
|
|
296
|
+
|
|
297
|
+
- **Repository**: https://github.com/FizzyFlow/wdoublesync_cli
|
package/bin/wdoublesync.js
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// Intercept process.exit() calls from dependencies so they don't interrupt
|
|
4
|
+
// the top-level await before it settles. Converts them to thrown errors that
|
|
5
|
+
// our try/catch handles, then sets process.exitCode without calling exit().
|
|
6
|
+
const _realExit = process.exit.bind(process);
|
|
7
|
+
process.exit = (code) => {
|
|
8
|
+
const err = new Error(`process.exit(${code ?? 0})`);
|
|
9
|
+
err._isProcessExit = true;
|
|
10
|
+
err._exitCode = code ?? 0;
|
|
11
|
+
throw err;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
import { push, pull, info, watch, rebate } from '../lib/commands/index.js';
|
|
4
15
|
|
|
5
16
|
const USAGE = `wdoublesync — sync local folders to EndlessVector on Sui+Walrus
|
|
6
17
|
|
|
@@ -31,6 +42,7 @@ function parseArgs(argv) {
|
|
|
31
42
|
const args = {
|
|
32
43
|
command: null,
|
|
33
44
|
vectorId: null,
|
|
45
|
+
path: process.cwd(),
|
|
34
46
|
chain: 'testnet',
|
|
35
47
|
key: null,
|
|
36
48
|
phrase: null,
|
|
@@ -49,18 +61,30 @@ function parseArgs(argv) {
|
|
|
49
61
|
|
|
50
62
|
if (raw.length === 0 || raw.includes('--help')) {
|
|
51
63
|
console.log(USAGE);
|
|
52
|
-
|
|
64
|
+
_realExit(0);
|
|
53
65
|
}
|
|
54
66
|
|
|
55
67
|
args.command = raw[0];
|
|
56
68
|
|
|
57
69
|
let i = 1;
|
|
58
70
|
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
71
|
+
// Collect up to two positional args: [vectorId] [path]
|
|
72
|
+
// vectorId starts with 0x, path starts with /, ~, or .
|
|
73
|
+
const positionals = [];
|
|
74
|
+
while (i < raw.length && !raw[i].startsWith('--')) {
|
|
75
|
+
positionals.push(raw[i]);
|
|
62
76
|
i++;
|
|
63
77
|
}
|
|
78
|
+
if (positionals.length === 2) {
|
|
79
|
+
args.vectorId = positionals[0];
|
|
80
|
+
args.path = positionals[1];
|
|
81
|
+
} else if (positionals.length === 1) {
|
|
82
|
+
if (positionals[0].startsWith('0x')) {
|
|
83
|
+
args.vectorId = positionals[0];
|
|
84
|
+
} else {
|
|
85
|
+
args.path = positionals[0];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
64
88
|
|
|
65
89
|
while (i < raw.length) {
|
|
66
90
|
const flag = raw[i];
|
|
@@ -97,6 +121,12 @@ function parseArgs(argv) {
|
|
|
97
121
|
|
|
98
122
|
const args = parseArgs(process.argv);
|
|
99
123
|
|
|
124
|
+
// The Sui/Walrus SDKs use undici (Node.js fetch) which unref's its HTTP connections.
|
|
125
|
+
// With only unref'd I/O in flight, the event loop drains and Node.js exits with code 13
|
|
126
|
+
// ("Detected unsettled top-level await") before network responses arrive.
|
|
127
|
+
// A ref'd interval keeps the event loop alive for the duration of the command.
|
|
128
|
+
const keepAlive = setInterval(() => {}, 60_000);
|
|
129
|
+
|
|
100
130
|
try {
|
|
101
131
|
if (args.command === 'push') {
|
|
102
132
|
await push(args);
|
|
@@ -111,11 +141,16 @@ try {
|
|
|
111
141
|
} else {
|
|
112
142
|
console.error('Unknown command:', args.command);
|
|
113
143
|
console.log(USAGE);
|
|
114
|
-
process.
|
|
144
|
+
process.exitCode = 1;
|
|
115
145
|
}
|
|
116
|
-
process.exit(0);
|
|
117
146
|
} catch (err) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
147
|
+
if (err._isProcessExit) {
|
|
148
|
+
process.exitCode = err._exitCode;
|
|
149
|
+
} else {
|
|
150
|
+
console.error('Error:', err.message);
|
|
151
|
+
if (err.stack) console.error(err.stack);
|
|
152
|
+
process.exitCode = 1;
|
|
153
|
+
}
|
|
154
|
+
} finally {
|
|
155
|
+
clearInterval(keepAlive);
|
|
121
156
|
}
|