openclaw-workspace-sync 2.1.2 → 2.1.4
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 +42 -0
- package/README.src.md +600 -0
- package/TROUBLESHOOTING.md +203 -0
- package/docs/diagrams/mode-0.svg +42 -1
- package/docs/diagrams/mode-1.svg +42 -1
- package/docs/diagrams/mode-2.svg +42 -1
- package/openclaw.plugin.json +24 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -110,6 +110,46 @@ Use this only if you understand the trade-offs:
|
|
|
110
110
|
|
|
111
111
|
If you are running on a container platform, `mailbox` mode is strongly recommended.
|
|
112
112
|
|
|
113
|
+
## Before your first sync
|
|
114
|
+
|
|
115
|
+
Getting the initial state right prevents data loss. Each mode has different requirements:
|
|
116
|
+
|
|
117
|
+
### `mailbox` mode — starting state
|
|
118
|
+
|
|
119
|
+
The first sync **pushes** your local workspace to the cloud. This means rclone makes cloud match local exactly — any files on cloud that don't exist locally will be **deleted**.
|
|
120
|
+
|
|
121
|
+
**Recommended starting state:** Local workspace is the source of truth (the agent has been writing here), or local and remote are already identical.
|
|
122
|
+
|
|
123
|
+
**If remote is the source of truth** (e.g. you've been syncing manually or switching from another mode), pull first:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
rclone sync <remote>:<path> /data/workspace/ --config <config-path> \
|
|
127
|
+
--exclude '**/.DS_Store' --exclude '**/.git/**' \
|
|
128
|
+
--exclude '**/__pycache__/**' --exclude '**/node_modules/**' \
|
|
129
|
+
--verbose
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Then verify local matches remote before enabling the plugin.
|
|
133
|
+
|
|
134
|
+
### `mirror` mode — starting state
|
|
135
|
+
|
|
136
|
+
The first sync **pulls** from cloud to local. Local can be empty, stale, or corrupted — the pull simply overwrites it. **No preparation needed.**
|
|
137
|
+
|
|
138
|
+
### `bisync` mode — starting state
|
|
139
|
+
|
|
140
|
+
The first sync requires `--resync`, which copies everything from both sides to the other. Any stale or unwanted files on either side will propagate.
|
|
141
|
+
|
|
142
|
+
**Recommended starting state:** Both sides are identical, or one side is empty and the other has the data you want. Verify both before running `--resync`.
|
|
143
|
+
|
|
144
|
+
### General first-sync checklist
|
|
145
|
+
|
|
146
|
+
1. Run a `--dry-run` first to see what would happen: `openclaw workspace-sync sync --dry-run`
|
|
147
|
+
2. Check the output for unexpected deletions
|
|
148
|
+
3. If everything looks right, run the actual sync
|
|
149
|
+
4. Only then enable periodic sync (`interval` in config)
|
|
150
|
+
|
|
151
|
+
> For maintenance, recovery, and common problems, see [TROUBLESHOOTING.md](./TROUBLESHOOTING.md).
|
|
152
|
+
|
|
113
153
|
## Setup sequence
|
|
114
154
|
|
|
115
155
|
Getting sync right depends on doing things in the right order. Follow these steps:
|
|
@@ -425,6 +465,8 @@ Cloud sync involves two copies of your data. When things go wrong, one side can
|
|
|
425
465
|
|
|
426
466
|
**If in doubt, use `mailbox` mode.** It gives you a live local mirror of the workspace and a clean way to send files to the agent, with no risk of data loss.
|
|
427
467
|
|
|
468
|
+
> For recovery procedures, mode switching, and maintenance tips, see [TROUBLESHOOTING.md](./TROUBLESHOOTING.md).
|
|
469
|
+
|
|
428
470
|
## Important: `--resync` is destructive (bisync only)
|
|
429
471
|
|
|
430
472
|
**Never use `--resync` unless you know exactly what it does.** The `--resync` flag tells rclone to throw away its knowledge of what has changed and do a full reconciliation — it copies every file that exists on either side to the other side. This means:
|
package/README.src.md
ADDED
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
# OpenClaw Workspace Cloud Sync Plugin
|
|
2
|
+
|
|
3
|
+
Sync your OpenClaw agent workspace with cloud storage via [rclone](https://rclone.org/).
|
|
4
|
+
|
|
5
|
+
Supports **Dropbox, Google Drive, OneDrive, S3/R2/Minio**, and [70+ cloud providers](https://rclone.org/overview/).
|
|
6
|
+
|
|
7
|
+
## How it works
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<img src="https://raw.githubusercontent.com/ashbrener/openclaw-workspace-sync/main/docs/how-it-works.png" alt="How it works — Local Machine syncs to Cloud Provider syncs to Remote Gateway" width="600" />
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
The remote gateway workspace is the **source of truth**. Changes made by the agent flow down to your local machine through cloud storage. You can send files to the agent through an optional inbox.
|
|
14
|
+
|
|
15
|
+
**Zero LLM cost.** All sync operations are pure rclone file operations — they never wake the bot or trigger LLM calls.
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img src="https://raw.githubusercontent.com/ashbrener/openclaw-workspace-sync/main/docs/architecture.png" alt="Plugin architecture — CLI, Hooks, and Sync Manager feed into rclone wrapper" width="600" />
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
## Sync modes (breaking change in v2.0)
|
|
24
|
+
|
|
25
|
+
**`mode` is now required.** Previous versions used bidirectional bisync implicitly. Starting with v2.0, you must explicitly set `"mode"` in your config. The plugin will refuse to start and log an error until `mode` is set. This prevents accidental data loss from an unexpected sync direction.
|
|
26
|
+
|
|
27
|
+
The plugin supports three sync modes. Choose the one that fits your workflow:
|
|
28
|
+
|
|
29
|
+
| Mode | Direction | Description |
|
|
30
|
+
|------|-----------|-------------|
|
|
31
|
+
| `mailbox` | Push + inbox/outbox | Workspace pushes to cloud; users drop files in `_outbox` to send them to the agent. **Safest.** |
|
|
32
|
+
| `mirror` | Remote → Local | One-way sync: workspace mirrors down to local. Safe — local can never overwrite remote. |
|
|
33
|
+
| `bisync` | Bidirectional | Full two-way sync. Powerful but requires careful setup. |
|
|
34
|
+
|
|
35
|
+
**Upgrading from a previous version?** If you were using bisync before, add `"mode": "bisync"` to your config to preserve the existing behavior. For the safest option, use `"mode": "mailbox"`.
|
|
36
|
+
|
|
37
|
+
### `mailbox` mode (recommended)
|
|
38
|
+
|
|
39
|
+
The agent workspace is the source of truth. Each sync cycle:
|
|
40
|
+
|
|
41
|
+
1. **Push**: `rclone sync` pushes the workspace to the cloud (excluding `_inbox/` and `_outbox/`)
|
|
42
|
+
2. **Drain**: `rclone move` pulls files from the cloud `_outbox/` into the workspace `_inbox/`, deleting them from the cloud after transfer
|
|
43
|
+
|
|
44
|
+
```mermaid
|
|
45
|
+
flowchart LR
|
|
46
|
+
subgraph GW["Gateway (source of truth)"]
|
|
47
|
+
WS["/workspace"]
|
|
48
|
+
INBOX["_inbox/"]
|
|
49
|
+
end
|
|
50
|
+
subgraph CLOUD["Cloud Provider"]
|
|
51
|
+
CF["workspace files"]
|
|
52
|
+
OUTBOX_C["_outbox/"]
|
|
53
|
+
end
|
|
54
|
+
subgraph LOCAL["Your Machine"]
|
|
55
|
+
LM["local mirror"]
|
|
56
|
+
OUTBOX_L["_outbox/ (drop files here)"]
|
|
57
|
+
end
|
|
58
|
+
WS -- "1. rclone sync (push)" --> CF
|
|
59
|
+
CF -. "desktop app (auto)" .-> LM
|
|
60
|
+
OUTBOX_L -. "desktop app (auto)" .-> OUTBOX_C
|
|
61
|
+
OUTBOX_C -- "2. rclone move (drain)" --> INBOX
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This creates a clean separation:
|
|
65
|
+
|
|
66
|
+
- **Your local machine** gets a live mirror of the workspace via your cloud provider's desktop app (e.g., Dropbox). You also see an `_outbox/` folder — drop files there to send them to the agent.
|
|
67
|
+
- **The agent workspace** has an `_inbox/` folder where incoming files land. The agent (or a skill) can process them from there.
|
|
68
|
+
|
|
69
|
+
On startup, the plugin bootstraps both directories:
|
|
70
|
+
- `rclone mkdir cloud:_outbox` — ensures the cloud `_outbox` exists so your desktop app creates the local folder
|
|
71
|
+
- `mkdir -p <workspace>/_inbox` — ensures the agent's landing zone exists
|
|
72
|
+
|
|
73
|
+
Because the push explicitly excludes `_inbox/**` and `_outbox/**`, there is no risk of sync loops or accidental overwrites. Files only flow in one direction through each channel.
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"mode": "mailbox",
|
|
78
|
+
"provider": "dropbox",
|
|
79
|
+
"remotePath": "",
|
|
80
|
+
"localPath": "/",
|
|
81
|
+
"interval": 60
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### `mirror` mode
|
|
86
|
+
|
|
87
|
+
The agent workspace is the source of truth. Every sync cycle copies the latest workspace state down to your local folder. Local files outside the workspace are never sent up.
|
|
88
|
+
|
|
89
|
+
```mermaid
|
|
90
|
+
flowchart LR
|
|
91
|
+
subgraph CLOUD["Cloud Provider"]
|
|
92
|
+
CF["workspace files"]
|
|
93
|
+
end
|
|
94
|
+
subgraph LOCAL["Your Machine"]
|
|
95
|
+
LM["local copy (read-only)"]
|
|
96
|
+
end
|
|
97
|
+
subgraph GW["Gateway (source of truth)"]
|
|
98
|
+
WS["/workspace"]
|
|
99
|
+
NOTE["agent writes here"]
|
|
100
|
+
end
|
|
101
|
+
CF -- "rclone sync (pull)" --> LM
|
|
102
|
+
WS -. "rclone sync (push)" .-> CF
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
This is safe: even if something goes wrong, only your local copy is affected — the workspace stays untouched.
|
|
106
|
+
|
|
107
|
+
### `ingest` option (mirror mode only)
|
|
108
|
+
|
|
109
|
+
Want to send files to the agent while using mirror mode? Enable the `ingest` option. This creates a local `inbox/` folder (sibling to the sync folder) that syncs one-way **up** to the workspace. Drop a file in the inbox — it appears on the remote workspace. The inbox is separate from the mirror, so there is no risk of overwriting workspace files.
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"mode": "mirror",
|
|
114
|
+
"ingest": true,
|
|
115
|
+
"ingestPath": "inbox"
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
When enabled, a local `inbox/` folder syncs its contents to `<remotePath>/inbox/` on the workspace. This is additive only — files are copied up, never deleted from the remote side.
|
|
120
|
+
|
|
121
|
+
> For a more robust file-exchange pattern, consider `mailbox` mode instead. Mailbox uses `rclone move` to drain files (deleting from the source after transfer), which prevents duplicates and is easier to reason about.
|
|
122
|
+
|
|
123
|
+
### `bisync` mode (advanced)
|
|
124
|
+
|
|
125
|
+
Full bidirectional sync using rclone bisync. Changes on either side propagate to the other.
|
|
126
|
+
|
|
127
|
+
```mermaid
|
|
128
|
+
flowchart LR
|
|
129
|
+
subgraph GW["Gateway"]
|
|
130
|
+
WS["/workspace"]
|
|
131
|
+
end
|
|
132
|
+
subgraph CLOUD["Cloud Provider"]
|
|
133
|
+
CF["workspace files"]
|
|
134
|
+
end
|
|
135
|
+
subgraph LOCAL["Your Machine"]
|
|
136
|
+
LM["local copy"]
|
|
137
|
+
end
|
|
138
|
+
WS -- "rclone bisync" --> CF
|
|
139
|
+
CF -- "rclone bisync" --> WS
|
|
140
|
+
CF -. "desktop app" .-> LM
|
|
141
|
+
LM -. "desktop app" .-> CF
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Use this only if you understand the trade-offs:
|
|
145
|
+
|
|
146
|
+
- Both sides must be in a known-good state before starting
|
|
147
|
+
- A `--resync` is required once to establish the baseline — and it copies **everything**
|
|
148
|
+
- If bisync state is lost (e.g., after a deploy that wipes ephemeral storage), you must `--resync` again
|
|
149
|
+
- Deleted files can reappear if the other side still has them during a resync
|
|
150
|
+
- On container platforms (Fly.io, Railway), bisync state lives in ephemeral storage and is lost on every deploy
|
|
151
|
+
|
|
152
|
+
If you are running on a container platform, `mailbox` mode is strongly recommended.
|
|
153
|
+
|
|
154
|
+
## Before your first sync
|
|
155
|
+
|
|
156
|
+
Getting the initial state right prevents data loss. Each mode has different requirements:
|
|
157
|
+
|
|
158
|
+
### `mailbox` mode — starting state
|
|
159
|
+
|
|
160
|
+
The first sync **pushes** your local workspace to the cloud. This means rclone makes cloud match local exactly — any files on cloud that don't exist locally will be **deleted**.
|
|
161
|
+
|
|
162
|
+
**Recommended starting state:** Local workspace is the source of truth (the agent has been writing here), or local and remote are already identical.
|
|
163
|
+
|
|
164
|
+
**If remote is the source of truth** (e.g. you've been syncing manually or switching from another mode), pull first:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
rclone sync <remote>:<path> /data/workspace/ --config <config-path> \
|
|
168
|
+
--exclude '**/.DS_Store' --exclude '**/.git/**' \
|
|
169
|
+
--exclude '**/__pycache__/**' --exclude '**/node_modules/**' \
|
|
170
|
+
--verbose
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Then verify local matches remote before enabling the plugin.
|
|
174
|
+
|
|
175
|
+
### `mirror` mode — starting state
|
|
176
|
+
|
|
177
|
+
The first sync **pulls** from cloud to local. Local can be empty, stale, or corrupted — the pull simply overwrites it. **No preparation needed.**
|
|
178
|
+
|
|
179
|
+
### `bisync` mode — starting state
|
|
180
|
+
|
|
181
|
+
The first sync requires `--resync`, which copies everything from both sides to the other. Any stale or unwanted files on either side will propagate.
|
|
182
|
+
|
|
183
|
+
**Recommended starting state:** Both sides are identical, or one side is empty and the other has the data you want. Verify both before running `--resync`.
|
|
184
|
+
|
|
185
|
+
### General first-sync checklist
|
|
186
|
+
|
|
187
|
+
1. Run a `--dry-run` first to see what would happen: `openclaw workspace-sync sync --dry-run`
|
|
188
|
+
2. Check the output for unexpected deletions
|
|
189
|
+
3. If everything looks right, run the actual sync
|
|
190
|
+
4. Only then enable periodic sync (`interval` in config)
|
|
191
|
+
|
|
192
|
+
> For maintenance, recovery, and common problems, see [TROUBLESHOOTING.md](./TROUBLESHOOTING.md).
|
|
193
|
+
|
|
194
|
+
## Setup sequence
|
|
195
|
+
|
|
196
|
+
Getting sync right depends on doing things in the right order. Follow these steps:
|
|
197
|
+
|
|
198
|
+
1. **Configure the plugin** in `openclaw.json` with your provider credentials and `mode`
|
|
199
|
+
2. **Verify the remote** is accessible: `openclaw workspace-sync status`
|
|
200
|
+
3. **Run a dry-run first** to see what would happen: `openclaw workspace-sync sync --dry-run`
|
|
201
|
+
4. **Run the first sync**: `openclaw workspace-sync sync`
|
|
202
|
+
- In `mailbox` mode, this pushes the workspace and drains the `_outbox`
|
|
203
|
+
- In `mirror` mode, this pulls the current workspace down
|
|
204
|
+
- In `bisync` mode, this requires `--resync` to establish the baseline
|
|
205
|
+
5. **Enable periodic sync** by setting `interval` in your config
|
|
206
|
+
|
|
207
|
+
Take care when changing config (switching `remotePath`, `localPath`, or `mode`) — always disable periodic sync first, verify the new paths, then re-enable.
|
|
208
|
+
|
|
209
|
+
## Install
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
openclaw plugins install openclaw-workspace-sync
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Or clone into your extensions directory:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
cd ~/.openclaw/extensions
|
|
219
|
+
git clone https://github.com/ashbrener/openclaw-workspace-sync workspace-sync
|
|
220
|
+
cd workspace-sync && npm install --omit=dev
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Quick start
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
# Interactive setup wizard (recommended)
|
|
227
|
+
openclaw workspace-sync setup
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
The setup wizard guides you through:
|
|
231
|
+
1. Checking/installing rclone
|
|
232
|
+
2. Selecting cloud provider
|
|
233
|
+
3. Choosing sync mode
|
|
234
|
+
4. Dropbox app folder option (for scoped access)
|
|
235
|
+
5. Background sync interval
|
|
236
|
+
6. OAuth authorization
|
|
237
|
+
7. First sync
|
|
238
|
+
|
|
239
|
+
Or configure manually — see [Configuration](#configuration) below.
|
|
240
|
+
|
|
241
|
+
## Configuration
|
|
242
|
+
|
|
243
|
+
Add to your `openclaw.json`:
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
{
|
|
247
|
+
"plugins": {
|
|
248
|
+
"entries": {
|
|
249
|
+
"openclaw-workspace-sync": {
|
|
250
|
+
"enabled": true,
|
|
251
|
+
"config": {
|
|
252
|
+
"provider": "dropbox",
|
|
253
|
+
"mode": "mailbox",
|
|
254
|
+
"remotePath": "",
|
|
255
|
+
"localPath": "/",
|
|
256
|
+
"interval": 60,
|
|
257
|
+
"timeout": 1800,
|
|
258
|
+
"onSessionStart": true,
|
|
259
|
+
"onSessionEnd": false,
|
|
260
|
+
"exclude": [".git/**", "node_modules/**", "*.log"]
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Config reference
|
|
269
|
+
|
|
270
|
+
| Key | Type | Default | Description |
|
|
271
|
+
|-----|------|---------|-------------|
|
|
272
|
+
| `provider` | string | `"off"` | `dropbox` \| `gdrive` \| `onedrive` \| `s3` \| `custom` \| `off` |
|
|
273
|
+
| `mode` | string | **required** | `mailbox` \| `mirror` \| `bisync` — see [Sync modes](#sync-modes-breaking-change-in-v20) |
|
|
274
|
+
| `ingest` | boolean | `false` | Enable local inbox for sending files to the agent (mirror mode only) |
|
|
275
|
+
| `ingestPath` | string | `"inbox"` | Local subfolder name for ingestion (relative to `localPath`) |
|
|
276
|
+
| `remotePath` | string | `"openclaw-share"` | Folder name in cloud storage |
|
|
277
|
+
| `localPath` | string | `"shared"` | Subfolder within workspace to sync |
|
|
278
|
+
| `interval` | number | `0` | Background sync interval in seconds (0 = manual only, min 60) |
|
|
279
|
+
| `timeout` | number | `1800` | Max seconds for a single rclone sync operation (min 60) |
|
|
280
|
+
| `onSessionStart` | boolean | `false` | Sync when an agent session begins |
|
|
281
|
+
| `onSessionEnd` | boolean | `false` | Sync when an agent session ends |
|
|
282
|
+
| `remoteName` | string | `"cloud"` | rclone remote name |
|
|
283
|
+
| `configPath` | string | auto | Path to rclone.conf |
|
|
284
|
+
| `conflictResolve` | string | `"newer"` | `newer` \| `local` \| `remote` (bisync only) |
|
|
285
|
+
| `exclude` | string[] | see below | Glob patterns to exclude |
|
|
286
|
+
| `copySymlinks` | boolean | `false` | Follow symlinks during sync |
|
|
287
|
+
|
|
288
|
+
Default excludes: `**/.DS_Store`
|
|
289
|
+
|
|
290
|
+
### Provider-specific options
|
|
291
|
+
|
|
292
|
+
**Dropbox with app folder (recommended for security):**
|
|
293
|
+
|
|
294
|
+
```json
|
|
295
|
+
{
|
|
296
|
+
"provider": "dropbox",
|
|
297
|
+
"remotePath": "",
|
|
298
|
+
"dropbox": {
|
|
299
|
+
"appFolder": true,
|
|
300
|
+
"appKey": "your-app-key",
|
|
301
|
+
"appSecret": "your-app-secret",
|
|
302
|
+
"token": "{\"access_token\":\"...\"}"
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
With `appFolder: true`, set `remotePath` to `""`. The app folder root is your sync root — do not repeat the app folder name in `remotePath` or rclone will fail with "directory not found."
|
|
308
|
+
|
|
309
|
+
**Google Drive:**
|
|
310
|
+
|
|
311
|
+
```json
|
|
312
|
+
{
|
|
313
|
+
"provider": "gdrive",
|
|
314
|
+
"remotePath": "openclaw-sync",
|
|
315
|
+
"gdrive": {
|
|
316
|
+
"token": "{\"access_token\":\"...\"}",
|
|
317
|
+
"teamDrive": "0ABcDeFgHiJ",
|
|
318
|
+
"rootFolderId": "folder-id"
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
`teamDrive` and `rootFolderId` are optional — omit them for personal Google Drive.
|
|
324
|
+
|
|
325
|
+
**OneDrive:**
|
|
326
|
+
|
|
327
|
+
```json
|
|
328
|
+
{
|
|
329
|
+
"provider": "onedrive",
|
|
330
|
+
"remotePath": "openclaw-sync",
|
|
331
|
+
"onedrive": {
|
|
332
|
+
"token": "{\"access_token\":\"...\"}",
|
|
333
|
+
"driveId": "drive-id",
|
|
334
|
+
"driveType": "business"
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
`driveType` can be `personal`, `business`, or `sharepoint`. Both fields are optional.
|
|
340
|
+
|
|
341
|
+
**S3 / Cloudflare R2 / Minio:**
|
|
342
|
+
|
|
343
|
+
```json
|
|
344
|
+
{
|
|
345
|
+
"provider": "s3",
|
|
346
|
+
"remotePath": "openclaw-sync",
|
|
347
|
+
"s3": {
|
|
348
|
+
"endpoint": "https://s3.us-east-1.amazonaws.com",
|
|
349
|
+
"bucket": "your-bucket",
|
|
350
|
+
"region": "us-east-1",
|
|
351
|
+
"accessKeyId": "AKID...",
|
|
352
|
+
"secretAccessKey": "SECRET..."
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**Any rclone backend (SFTP, B2, Mega, pCloud, etc.):**
|
|
358
|
+
|
|
359
|
+
```json
|
|
360
|
+
{
|
|
361
|
+
"provider": "custom",
|
|
362
|
+
"remotePath": "openclaw-sync",
|
|
363
|
+
"custom": {
|
|
364
|
+
"rcloneType": "sftp",
|
|
365
|
+
"rcloneOptions": {
|
|
366
|
+
"host": "example.com",
|
|
367
|
+
"user": "deploy",
|
|
368
|
+
"key_file": "/path/to/key"
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
The `custom` provider accepts any [rclone backend type](https://rclone.org/overview/) and passes `rcloneOptions` directly to the rclone config. This gives you config-driven access to all 70+ providers without manually editing `rclone.conf`.
|
|
375
|
+
|
|
376
|
+
## CLI commands
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
# Interactive setup wizard
|
|
380
|
+
openclaw workspace-sync setup
|
|
381
|
+
|
|
382
|
+
# Check sync status
|
|
383
|
+
openclaw workspace-sync status
|
|
384
|
+
|
|
385
|
+
# Sync (behavior depends on mode)
|
|
386
|
+
openclaw workspace-sync sync
|
|
387
|
+
|
|
388
|
+
# Preview changes without syncing
|
|
389
|
+
openclaw workspace-sync sync --dry-run
|
|
390
|
+
|
|
391
|
+
# One-way sync (explicit, overrides mode for this run)
|
|
392
|
+
openclaw workspace-sync sync --direction pull # remote -> local
|
|
393
|
+
openclaw workspace-sync sync --direction push # local -> remote
|
|
394
|
+
|
|
395
|
+
# Force re-establish bisync baseline (bisync mode only)
|
|
396
|
+
openclaw workspace-sync sync --resync
|
|
397
|
+
|
|
398
|
+
# Authorize with cloud provider
|
|
399
|
+
openclaw workspace-sync authorize
|
|
400
|
+
openclaw workspace-sync authorize --provider gdrive
|
|
401
|
+
|
|
402
|
+
# List remote files
|
|
403
|
+
openclaw workspace-sync list
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## Auto-sync
|
|
407
|
+
|
|
408
|
+
### Session hooks
|
|
409
|
+
|
|
410
|
+
Sync automatically when sessions start or end. These run during existing agent activity and incur zero LLM cost:
|
|
411
|
+
|
|
412
|
+
```json
|
|
413
|
+
{
|
|
414
|
+
"onSessionStart": true,
|
|
415
|
+
"onSessionEnd": false
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Periodic background sync
|
|
420
|
+
|
|
421
|
+
Set `interval` to enable automatic background sync (in seconds):
|
|
422
|
+
|
|
423
|
+
```json
|
|
424
|
+
{
|
|
425
|
+
"interval": 300,
|
|
426
|
+
"timeout": 3600
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
The gateway runs sync in the background at this interval. Minimum interval is 60 seconds. The `timeout` controls how long each sync operation is allowed to run (default: 1800s / 30 min). Increase this for large workspaces or slow connections.
|
|
431
|
+
|
|
432
|
+
In `mailbox` mode, periodic sync pushes the workspace to the cloud and drains the `_outbox`. In `mirror` mode, periodic sync pulls the latest workspace state down to local. In `bisync` mode, it runs a full bidirectional sync.
|
|
433
|
+
|
|
434
|
+
### External cron (alternative)
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
# Add to crontab (crontab -e)
|
|
438
|
+
*/5 * * * * openclaw workspace-sync sync >> /var/log/openclaw-sync.log 2>&1
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
## Supported providers
|
|
442
|
+
|
|
443
|
+
| Provider | Config value | Auth method | Config-driven |
|
|
444
|
+
|----------|-------------|-------------|---------------|
|
|
445
|
+
| Dropbox | `dropbox` | OAuth token | Full (token, appKey, appSecret, appFolder) |
|
|
446
|
+
| Google Drive | `gdrive` | OAuth token | Full (token, teamDrive, rootFolderId) |
|
|
447
|
+
| OneDrive | `onedrive` | OAuth token | Full (token, driveId, driveType) |
|
|
448
|
+
| S3/R2/Minio | `s3` | Access keys | Full (endpoint, bucket, region, credentials) |
|
|
449
|
+
| Any rclone backend | `custom` | Varies | Full (rcloneType + rcloneOptions) |
|
|
450
|
+
|
|
451
|
+
All providers are fully config-driven — no manual `rclone.conf` editing needed. The `custom` provider gives access to all [70+ rclone backends](https://rclone.org/overview/) (SFTP, B2, Mega, pCloud, Azure Blob, etc.).
|
|
452
|
+
|
|
453
|
+
## Manual setup (without wizard)
|
|
454
|
+
|
|
455
|
+
If you prefer to skip the interactive wizard, configure the plugin in `openclaw.json` and use the CLI:
|
|
456
|
+
|
|
457
|
+
```bash
|
|
458
|
+
# 1. Authorize with your cloud provider
|
|
459
|
+
openclaw workspace-sync authorize --provider dropbox
|
|
460
|
+
|
|
461
|
+
# 2. Run a dry-run to preview what will sync
|
|
462
|
+
openclaw workspace-sync sync --dry-run
|
|
463
|
+
|
|
464
|
+
# 3. Run the first sync
|
|
465
|
+
openclaw workspace-sync sync
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
The plugin handles rclone installation, config generation, and token storage automatically based on your `openclaw.json` settings.
|
|
469
|
+
|
|
470
|
+
## Dropbox app folder access (recommended)
|
|
471
|
+
|
|
472
|
+
For better security, create a scoped Dropbox app that only accesses a single folder:
|
|
473
|
+
|
|
474
|
+
1. Go to [Dropbox App Console](https://www.dropbox.com/developers/apps)
|
|
475
|
+
2. Click **Create app** > **Scoped access** > **App folder**
|
|
476
|
+
3. Name it (e.g., `openclaw-sync`)
|
|
477
|
+
4. In **Settings** tab, add a **Redirect URI**: `http://localhost:53682/`
|
|
478
|
+
- This is required for rclone's OAuth flow to work. Without it, Dropbox returns "Invalid redirect_uri" during authorization.
|
|
479
|
+
5. In **Permissions** tab, enable:
|
|
480
|
+
- `files.metadata.read` / `files.metadata.write`
|
|
481
|
+
- `files.content.read` / `files.content.write`
|
|
482
|
+
6. Copy **App key** and **App secret** from Settings
|
|
483
|
+
|
|
484
|
+
> **Important:** When using an app folder scoped app, set `"remotePath": ""` (empty string) in your config. The app folder **is** the root — rclone sees it as `/`. If you set `remotePath` to your app folder name (e.g., `"openclaw-sync"`), rclone will look for a subfolder *inside* the app folder with that name and fail with "directory not found."
|
|
485
|
+
|
|
486
|
+
Benefits:
|
|
487
|
+
- Token only accesses one folder, not your entire Dropbox
|
|
488
|
+
- If token is compromised, blast radius is limited
|
|
489
|
+
- Clean separation — sync folder lives under `Apps/<your-app-name>/`
|
|
490
|
+
|
|
491
|
+
## Understanding sync safety
|
|
492
|
+
|
|
493
|
+
Cloud sync involves two copies of your data. When things go wrong, one side can overwrite the other. Here is what to keep in mind:
|
|
494
|
+
|
|
495
|
+
**Mailbox mode is the safest.** The workspace pushes to the cloud; users send files via `_outbox`. The two streams never overlap. Even if your local folder is wiped, the next push re-creates everything. Even if the `_outbox` has stale files, they just land in `_inbox` for the agent to handle.
|
|
496
|
+
|
|
497
|
+
**Mirror mode is safe by design.** The remote workspace is the authority. Local is a read-only copy. Even if your local folder is empty, stale, or corrupted, the next sync just re-downloads the workspace. The agent's work is never affected by local state.
|
|
498
|
+
|
|
499
|
+
**Bisync requires both sides to agree.** Bisync tracks what changed since the last sync. If that tracking state is lost (deploy, disk wipe, moving to a new machine), rclone does not know what changed and requires a `--resync`. A resync copies everything from both sides — if one side has stale or unwanted files, they propagate to the other.
|
|
500
|
+
|
|
501
|
+
**Common pitfalls to avoid:**
|
|
502
|
+
- Changing `remotePath` or `localPath` while periodic sync is enabled
|
|
503
|
+
- Running `--resync` without checking both sides first
|
|
504
|
+
- Using `bisync` on container platforms where state is ephemeral
|
|
505
|
+
- Syncing very large directories (use `exclude` patterns liberally)
|
|
506
|
+
|
|
507
|
+
**If in doubt, use `mailbox` mode.** It gives you a live local mirror of the workspace and a clean way to send files to the agent, with no risk of data loss.
|
|
508
|
+
|
|
509
|
+
> For recovery procedures, mode switching, and maintenance tips, see [TROUBLESHOOTING.md](./TROUBLESHOOTING.md).
|
|
510
|
+
|
|
511
|
+
## Important: `--resync` is destructive (bisync only)
|
|
512
|
+
|
|
513
|
+
**Never use `--resync` unless you know exactly what it does.** The `--resync` flag tells rclone to throw away its knowledge of what has changed and do a full reconciliation — it copies every file that exists on either side to the other side. This means:
|
|
514
|
+
|
|
515
|
+
- Files you deleted remotely will come back from local (and vice versa)
|
|
516
|
+
- It transfers your **entire** sync scope, not just recent changes
|
|
517
|
+
- On a large Dropbox, this can take 30+ minutes and fill your disk
|
|
518
|
+
|
|
519
|
+
Normal bisync (without `--resync`) only transfers files that changed since the last sync. The plugin **never** auto-resyncs. If bisync's internal state gets corrupted, it will log a message telling you to run `--resync` manually — but only do this after confirming both sides are in the state you want.
|
|
520
|
+
|
|
521
|
+
```bash
|
|
522
|
+
# Only when you explicitly need to re-establish the baseline:
|
|
523
|
+
openclaw workspace-sync sync --resync
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
## Troubleshooting
|
|
527
|
+
|
|
528
|
+
### Token expired
|
|
529
|
+
|
|
530
|
+
```bash
|
|
531
|
+
openclaw workspace-sync authorize
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Conflicts (bisync only)
|
|
535
|
+
|
|
536
|
+
Files modified on both sides get a `.conflict` suffix. The winner is determined by `conflictResolve` (default: `newer`). To find conflict files:
|
|
537
|
+
|
|
538
|
+
```bash
|
|
539
|
+
find <workspace>/shared -name "*.conflict"
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### Stale lock files
|
|
543
|
+
|
|
544
|
+
The plugin automatically handles stale rclone lock files. If a sync is interrupted (timeout, crash, kill), the next run detects the stale lock, clears it, and retries. Lock files older than 15 minutes are treated as expired by rclone's `--max-lock` flag.
|
|
545
|
+
|
|
546
|
+
If you still see lock errors, you can manually clear them:
|
|
547
|
+
|
|
548
|
+
```bash
|
|
549
|
+
rclone deletefile ~/.cache/rclone/bisync/<lockfile>.lck
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### Sync times out
|
|
553
|
+
|
|
554
|
+
Increase the `timeout` config (in seconds). The default is 1800 (30 min). For large workspaces:
|
|
555
|
+
|
|
556
|
+
```json
|
|
557
|
+
{
|
|
558
|
+
"timeout": 3600
|
|
559
|
+
}
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### Permission errors
|
|
563
|
+
|
|
564
|
+
```bash
|
|
565
|
+
chmod -R 755 <workspace>/shared
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
## Deployment recommendations
|
|
569
|
+
|
|
570
|
+
If you are running OpenClaw on a cloud container (Fly.io, Railway, Render) or a VPS:
|
|
571
|
+
|
|
572
|
+
- **Use a separate persistent volume for the workspace.** Container root filesystems are ephemeral — a redeploy wipes everything. Mount a dedicated volume (e.g., Fly.io volumes, EBS, DigitalOcean block storage) at your workspace path so data survives deploys and restarts.
|
|
573
|
+
- **Enable daily volume snapshots.** Most cloud providers offer automated snapshots (Fly.io does this by default with 5-day retention). If something goes wrong — a bad sync, accidental deletion, or a failed reorganization — a recent snapshot lets you restore in minutes instead of rebuilding from scratch.
|
|
574
|
+
- **Test your restore process.** A backup you have never restored is a backup you do not have. Create a volume from a snapshot at least once to confirm the process works and you know the steps.
|
|
575
|
+
|
|
576
|
+
These recommendations apply regardless of whether you use this plugin. Cloud sync adds convenience but is not a substitute for proper backups.
|
|
577
|
+
|
|
578
|
+
## Security notes
|
|
579
|
+
|
|
580
|
+
- **Token storage**: rclone tokens are stored in `rclone.conf` with `0600` permissions
|
|
581
|
+
- **Sensitive files**: Don't sync secrets, API keys, or credentials
|
|
582
|
+
- **Encryption**: Consider [rclone crypt](https://rclone.org/crypt/) for sensitive data
|
|
583
|
+
- **App folder**: Use Dropbox app folder access for minimal permissions
|
|
584
|
+
|
|
585
|
+
## Development
|
|
586
|
+
|
|
587
|
+
```bash
|
|
588
|
+
# Install dependencies
|
|
589
|
+
npm install
|
|
590
|
+
|
|
591
|
+
# Run tests
|
|
592
|
+
npm test
|
|
593
|
+
|
|
594
|
+
# Type check
|
|
595
|
+
npx tsc --noEmit
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
## License
|
|
599
|
+
|
|
600
|
+
MIT
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Troubleshooting & Maintenance
|
|
2
|
+
|
|
3
|
+
Common problems, recovery procedures, and maintenance tips for `openclaw-workspace-sync`.
|
|
4
|
+
|
|
5
|
+
## Quick diagnostics
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Check plugin status and remote connectivity
|
|
9
|
+
openclaw workspace-sync status
|
|
10
|
+
|
|
11
|
+
# See what a sync would do without changing anything
|
|
12
|
+
openclaw workspace-sync sync --dry-run
|
|
13
|
+
|
|
14
|
+
# Compare local and remote without making changes
|
|
15
|
+
rclone check <remote>:<path> /data/workspace/ --config <config-path>
|
|
16
|
+
|
|
17
|
+
# List remote contents
|
|
18
|
+
rclone ls <remote>:<path> --config <config-path> --max-depth 1
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Common problems
|
|
22
|
+
|
|
23
|
+
### Files deleted unexpectedly after enabling mailbox mode
|
|
24
|
+
|
|
25
|
+
**Cause:** Mailbox mode pushes local → cloud on every sync cycle. If local was empty or stale when you enabled it, the push made cloud match local — deleting cloud files that weren't present locally.
|
|
26
|
+
|
|
27
|
+
**Prevention:** Always align local with remote before enabling mailbox mode. See [Before your first sync](./README.md#before-your-first-sync).
|
|
28
|
+
|
|
29
|
+
**Recovery:**
|
|
30
|
+
1. Disable the plugin immediately (`"enabled": false` in `openclaw.json`, restart gateway)
|
|
31
|
+
2. Check your cloud provider's trash/version history (Dropbox keeps deleted files for 30 days)
|
|
32
|
+
3. Restore from cloud trash or a backup
|
|
33
|
+
4. Re-pull from cloud to align local:
|
|
34
|
+
```bash
|
|
35
|
+
rclone sync <remote>:<path> /data/workspace/ --config <config-path> --verbose
|
|
36
|
+
```
|
|
37
|
+
5. Verify local matches remote, then re-enable the plugin
|
|
38
|
+
|
|
39
|
+
### Duplicate folders from case-sensitivity mismatch
|
|
40
|
+
|
|
41
|
+
**Cause:** macOS and Dropbox are case-insensitive (`code` = `CODE`), but Linux is case-sensitive. Renaming a folder on your Mac (e.g. `code` → `CODE`) propagates to Dropbox, but when rclone pulls to Linux, it may create both `code` and `CODE` as separate directories.
|
|
42
|
+
|
|
43
|
+
**Symptoms:** You see `code`, `CODE`, and/or intermediate names like `code1` on the server.
|
|
44
|
+
|
|
45
|
+
**Fix:**
|
|
46
|
+
1. Check which folder has the most complete contents:
|
|
47
|
+
```bash
|
|
48
|
+
ls /data/workspace/code/ | wc -l
|
|
49
|
+
ls /data/workspace/CODE/ | wc -l
|
|
50
|
+
```
|
|
51
|
+
2. Keep the most complete one, delete the others:
|
|
52
|
+
```bash
|
|
53
|
+
rm -rf /data/workspace/CODE /data/workspace/code1
|
|
54
|
+
```
|
|
55
|
+
3. Re-pull from cloud to fill in anything missing:
|
|
56
|
+
```bash
|
|
57
|
+
rclone sync <remote>:<path> /data/workspace/ --config <config-path> --verbose
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Prevention:** Avoid renaming top-level folders on macOS when syncing to a Linux server via Dropbox. If you need uppercase names, rename on the server side and let it sync down.
|
|
61
|
+
|
|
62
|
+
### "directory not found" errors during sync
|
|
63
|
+
|
|
64
|
+
**Cause:** Ghost directory entries on the cloud provider — the directory name exists but the contents are gone. Common after case-sensitivity renames or interrupted uploads.
|
|
65
|
+
|
|
66
|
+
**Impact:** Harmless. rclone skips these entries and continues. Your sync still works.
|
|
67
|
+
|
|
68
|
+
**Fix:** If the errors bother you, clean up the ghost entries via your cloud provider's web UI (e.g. dropbox.com). You can also run `rclone check` to confirm actual files are in sync despite the errors.
|
|
69
|
+
|
|
70
|
+
### Sync interrupted / incomplete
|
|
71
|
+
|
|
72
|
+
**Cause:** Network timeout, process killed, SSH disconnection, container restart.
|
|
73
|
+
|
|
74
|
+
**Impact:** The sync was partial — some files were transferred, others weren't. No data corruption, but local and remote may be out of sync.
|
|
75
|
+
|
|
76
|
+
**Fix:** Re-run the sync. rclone is idempotent — it only transfers files that differ:
|
|
77
|
+
```bash
|
|
78
|
+
rclone sync <remote>:<path> /data/workspace/ --config <config-path> --verbose
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Tip:** For long syncs over SSH, use `tmux` or `screen` so the sync survives disconnections:
|
|
82
|
+
```bash
|
|
83
|
+
tmux new -s sync
|
|
84
|
+
rclone sync <remote>:<path> /data/workspace/ --config <config-path> --verbose
|
|
85
|
+
# Ctrl+B, D to detach; tmux attach -t sync to reconnect
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### "directory not found" with Dropbox app folder
|
|
89
|
+
|
|
90
|
+
**Cause:** Your `remotePath` is set to the app folder name (e.g. `"openclaw-sync"`) instead of `""`. With Dropbox app folders, the app folder IS the root — rclone sees it as `/`.
|
|
91
|
+
|
|
92
|
+
**Fix:** Set `"remotePath": ""` in your config.
|
|
93
|
+
|
|
94
|
+
### OAuth token expired
|
|
95
|
+
|
|
96
|
+
**Cause:** Dropbox tokens expire if unused for 90+ days or if the app's permissions change.
|
|
97
|
+
|
|
98
|
+
**Symptoms:** Sync fails with 401/403 errors or "token expired" messages.
|
|
99
|
+
|
|
100
|
+
**Fix:**
|
|
101
|
+
```bash
|
|
102
|
+
openclaw workspace-sync setup
|
|
103
|
+
# Re-run OAuth authorization step
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Or manually re-authorize rclone:
|
|
107
|
+
```bash
|
|
108
|
+
rclone config reconnect <remote>: --config <config-path>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Switching modes
|
|
112
|
+
|
|
113
|
+
Changing sync mode requires care. Follow this procedure:
|
|
114
|
+
|
|
115
|
+
1. **Disable periodic sync** — set `"enabled": false` or remove `interval` from config, restart gateway
|
|
116
|
+
2. **Align local and remote** — run `rclone check` to verify, or pull/push to align
|
|
117
|
+
3. **Change the mode** in `openclaw.json`
|
|
118
|
+
4. **Run a dry-run** — `openclaw workspace-sync sync --dry-run` to verify behavior
|
|
119
|
+
5. **Run the first sync** under the new mode
|
|
120
|
+
6. **Re-enable periodic sync**
|
|
121
|
+
|
|
122
|
+
### Switching to `mailbox` from `mirror` or `bisync`
|
|
123
|
+
|
|
124
|
+
Mirror pulls from cloud; mailbox pushes to cloud. Before switching:
|
|
125
|
+
- Ensure local is up to date (run one last mirror pull)
|
|
126
|
+
- Then switch to mailbox — the first push should be a no-op if both sides match
|
|
127
|
+
|
|
128
|
+
### Switching to `mirror` from `mailbox` or `bisync`
|
|
129
|
+
|
|
130
|
+
Safe — mirror only pulls. Just switch the mode. The first sync downloads the workspace.
|
|
131
|
+
|
|
132
|
+
### Switching to `bisync` from another mode
|
|
133
|
+
|
|
134
|
+
Requires `--resync` to establish the baseline. Verify both sides are aligned first.
|
|
135
|
+
|
|
136
|
+
## Maintenance
|
|
137
|
+
|
|
138
|
+
### Periodic health checks
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Compare local and remote (no changes)
|
|
142
|
+
rclone check <remote>:<path> /data/workspace/ --config <config-path>
|
|
143
|
+
|
|
144
|
+
# Check disk usage
|
|
145
|
+
du -sh /data/workspace/
|
|
146
|
+
|
|
147
|
+
# Check rclone version
|
|
148
|
+
rclone version
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Backup recommendations
|
|
152
|
+
|
|
153
|
+
- **Container platforms (Fly.io, Railway):** Use a separate persistent volume for the workspace. Volumes can be snapshotted for backup.
|
|
154
|
+
- **VPS:** Schedule daily backups of the workspace directory (cron + tar, or your provider's snapshot feature).
|
|
155
|
+
- **Cloud provider:** Most providers (Dropbox, Google Drive, OneDrive) have built-in version history and trash. Verify these are enabled.
|
|
156
|
+
|
|
157
|
+
### Keeping excludes clean
|
|
158
|
+
|
|
159
|
+
Large or frequently-changing directories waste sync bandwidth. Review your `exclude` patterns periodically:
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
"exclude": [
|
|
163
|
+
"**/.DS_Store",
|
|
164
|
+
"**/.git/**",
|
|
165
|
+
"**/__pycache__/**",
|
|
166
|
+
"**/.venv/**",
|
|
167
|
+
"**/venv/**",
|
|
168
|
+
"**/node_modules/**",
|
|
169
|
+
"*.log",
|
|
170
|
+
"DUPLICATES/**"
|
|
171
|
+
]
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Common additions:
|
|
175
|
+
- `"**/dist/**"` — build output
|
|
176
|
+
- `"**/.cache/**"` — tool caches
|
|
177
|
+
- `"**/tmp/**"` — temporary files
|
|
178
|
+
- `"**/*.pyc"` — compiled Python
|
|
179
|
+
|
|
180
|
+
### Updating the plugin
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
openclaw plugins install openclaw-workspace-sync
|
|
184
|
+
# or
|
|
185
|
+
cd ~/.openclaw/extensions/workspace-sync && git pull && npm install --omit=dev
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
After updating, restart the gateway to pick up the new version.
|
|
189
|
+
|
|
190
|
+
## Emergency: stop all syncing
|
|
191
|
+
|
|
192
|
+
If something is going wrong and you need to stop immediately:
|
|
193
|
+
|
|
194
|
+
1. **Disable the plugin:**
|
|
195
|
+
```json
|
|
196
|
+
"openclaw-workspace-sync": {
|
|
197
|
+
"enabled": false
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
2. **Restart the gateway**
|
|
201
|
+
3. **Assess the damage** — compare local and remote with `rclone check`
|
|
202
|
+
4. **Recover** — use cloud provider trash/version history if needed
|
|
203
|
+
5. **Fix the root cause** before re-enabling
|
package/docs/diagrams/mode-0.svg
CHANGED
|
@@ -1 +1,42 @@
|
|
|
1
|
-
<svg id="my-svg" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="flowchart" style="max-width: 1088.31px; background-color: transparent;" viewBox="0 0 1088.3125 532" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#000000;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:#552222;}#my-svg .error-text{fill:#552222;stroke:#552222;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#666;stroke:#666;}#my-svg .marker.cross{stroke:#666;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#my-svg p{margin:0;}#my-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#000000;}#my-svg .cluster-label text{fill:#333;}#my-svg .cluster-label span{color:#333;}#my-svg .cluster-label span p{background-color:transparent;}#my-svg .label text,#my-svg span{fill:#000000;color:#000000;}#my-svg .node rect,#my-svg .node circle,#my-svg .node ellipse,#my-svg .node polygon,#my-svg .node path{fill:#eee;stroke:#999;stroke-width:1px;}#my-svg .rough-node .label text,#my-svg .node .label text,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-anchor:middle;}#my-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#my-svg .rough-node .label,#my-svg .node .label,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-align:center;}#my-svg .node.clickable{cursor:pointer;}#my-svg .root .anchor path{fill:#666!important;stroke-width:0;stroke:#666;}#my-svg .arrowheadPath{fill:#333333;}#my-svg .edgePath .path{stroke:#666;stroke-width:2.0px;}#my-svg .flowchart-link{stroke:#666;fill:none;}#my-svg .edgeLabel{background-color:white;text-align:center;}#my-svg .edgeLabel p{background-color:white;}#my-svg .edgeLabel rect{opacity:0.5;background-color:white;fill:white;}#my-svg .labelBkg{background-color:rgba(255, 255, 255, 0.5);}#my-svg .cluster rect{fill:hsl(0, 0%, 98.9215686275%);stroke:#707070;stroke-width:1px;}#my-svg .cluster text{fill:#333;}#my-svg .cluster span{color:#333;}#my-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(-160, 0%, 93.3333333333%);border:1px solid #707070;border-radius:2px;pointer-events:none;z-index:100;}#my-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#000000;}#my-svg rect.text{fill:none;stroke-width:0;}#my-svg .icon-shape,#my-svg .image-shape{background-color:white;text-align:center;}#my-svg .icon-shape p,#my-svg .image-shape p{background-color:white;padding:2px;}#my-svg .icon-shape rect,#my-svg .image-shape rect{opacity:0.5;background-color:white;fill:white;}#my-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#my-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="my-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><g class="root"><g class="clusters"><g class="cluster" id="LOCAL" data-look="classic"><rect style="" x="8" y="8" width="1072.3125" height="124"/><g class="cluster-label" transform="translate(497.1015625, 8)"><foreignObject width="94.109375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Your Machine</p></span></div></foreignObject></g></g><g class="cluster" id="CLOUD" data-look="classic"><rect style="" x="479.921875" y="152" width="220.453125" height="228"/><g class="cluster-label" transform="translate(537.8515625, 152)"><foreignObject width="104.59375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Cloud Provider</p></span></div></foreignObject></g></g><g class="cluster" id="GW" data-look="classic"><rect style="" x="8" y="400" width="1072.3125" height="124"/><g class="cluster-label" transform="translate(451.015625, 400)"><foreignObject width="186.28125" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Gateway (source of truth)</p></span></div></foreignObject></g></g></g><g class="edgePaths"><path d="M228.625,462L253.9,462C279.174,462,329.724,462,371.607,462C413.49,462,446.706,462,479.414,425.776C512.122,389.552,544.323,317.103,560.423,280.879L576.523,244.655" id="L_WS_CF_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_WS_CF_0" data-points="W3sieCI6MjI4LjYyNSwieSI6NDYyfSx7IngiOjM4MC4yNzM0Mzc1LCJ5Ijo0NjJ9LHsieCI6NDc5LjkyMTg3NSwieSI6NDYyfSx7IngiOjU3OC4xNDc5NjQ5Njk3NTgsInkiOjI0MX1d" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M675.375,214L679.542,214C683.708,214,692.042,214,713.764,190C735.487,166,770.599,118,805.044,94C839.49,70,873.268,70,890.158,70L907.047,70" id="L_CF_LM_0" class="edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_CF_LM_0" data-points="W3sieCI6Njc1LjM3NSwieSI6MjE0fSx7IngiOjcwMC4zNzUsInkiOjIxNH0seyJ4Ijo4MDUuNzEwOTM3NSwieSI6NzB9LHsieCI6OTExLjA0Njg3NSwieSI6NzB9XQ==" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M280.625,70L297.233,70C313.841,70,347.057,70,380.273,70C413.49,70,446.706,70,479.414,106.224C512.122,142.448,544.323,214.897,560.423,251.121L576.523,287.345" id="L_OUTBOX_L_OUTBOX_C_0" class="edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_OUTBOX_L_OUTBOX_C_0" data-points="W3sieCI6MjgwLjYyNSwieSI6NzB9LHsieCI6MzgwLjI3MzQzNzUsInkiOjcwfSx7IngiOjQ3OS45MjE4NzUsInkiOjcwfSx7IngiOjU3OC4xNDc5NjQ5Njk3NTgsInkiOjI5MX1d" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M653.133,318L661.007,318C668.88,318,684.628,318,710.057,342C735.487,366,770.599,414,807.432,438C844.266,462,882.82,462,902.098,462L921.375,462" id="L_OUTBOX_C_INBOX_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_OUTBOX_C_INBOX_0" data-points="W3sieCI6NjUzLjEzMjgxMjUsInkiOjMxOH0seyJ4Ijo3MDAuMzc1LCJ5IjozMTh9LHsieCI6ODA1LjcxMDkzNzUsInkiOjQ2Mn0seyJ4Ijo5MjUuMzc1LCJ5Ijo0NjJ9XQ==" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(380.2734375, 462)"><g class="label" data-id="L_WS_CF_0" transform="translate(-74.6484375, -12)"><foreignObject width="149.296875" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel">1. rclone sync (push)</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(805.7109375, 70)"><g class="label" data-id="L_CF_LM_0" transform="translate(-67.8671875, -12)"><foreignObject width="135.734375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>desktop app (auto)</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(380.2734375, 70)"><g class="label" data-id="L_OUTBOX_L_OUTBOX_C_0" transform="translate(-67.8671875, -12)"><foreignObject width="135.734375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>desktop app (auto)</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(805.7109375, 462)"><g class="label" data-id="L_OUTBOX_C_INBOX_0" transform="translate(-80.3359375, -12)"><foreignObject width="160.671875" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel">2. rclone move (drain)</span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="flowchart-WS-0" transform="translate(156.8125, 462)"><rect class="basic label-container" style="" x="-71.8125" y="-27" width="143.625" height="54"/><g class="label" style="" transform="translate(-41.8125, -12)"><rect/><foreignObject width="83.625" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>/workspace</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-INBOX-1" transform="translate(983.1796875, 462)"><rect class="basic label-container" style="" x="-57.8046875" y="-27" width="115.609375" height="54"/><g class="label" style="" transform="translate(-27.8046875, -12)"><rect/><foreignObject width="55.609375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>_inbox/</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-CF-2" transform="translate(590.1484375, 214)"><rect class="basic label-container" style="" x="-85.2265625" y="-27" width="170.453125" height="54"/><g class="label" style="" transform="translate(-55.2265625, -12)"><rect/><foreignObject width="110.453125" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>workspace files</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-OUTBOX_C-3" transform="translate(590.1484375, 318)"><rect class="basic label-container" style="" x="-62.984375" y="-27" width="125.96875" height="54"/><g class="label" style="" transform="translate(-32.984375, -12)"><rect/><foreignObject width="65.96875" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>_outbox/</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-LM-4" transform="translate(983.1796875, 70)"><rect class="basic label-container" style="" x="-72.1328125" y="-27" width="144.265625" height="54"/><g class="label" style="" transform="translate(-42.1328125, -12)"><rect/><foreignObject width="84.265625" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>local mirror</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-OUTBOX_L-5" transform="translate(156.8125, 70)"><rect class="basic label-container" style="" x="-123.8125" y="-27" width="247.625" height="54"/><g class="label" style="" transform="translate(-93.8125, -12)"><rect/><foreignObject width="187.625" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>_outbox/ (drop files here)</p></span></div></foreignObject></g></g></g></g></g></svg>
|
|
1
|
+
<svg id="my-svg" width="1141.78125" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="flowchart" height="600" viewBox="0 0 1141.78125 600" role="graphics-document document" aria-roledescription="flowchart-v2" style="background-color: white;"><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:14px;fill:#333333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:#50C878;}#my-svg .error-text{fill:#ffffff;stroke:#ffffff;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#5C6B77;stroke:#5C6B77;}#my-svg .marker.cross{stroke:#5C6B77;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:14px;}#my-svg p{margin:0;}#my-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ffffff;}#my-svg .cluster-label text{fill:#333333;}#my-svg .cluster-label span{color:#333333;}#my-svg .cluster-label span p{background-color:transparent;}#my-svg .label text,#my-svg span{fill:#ffffff;color:#ffffff;}#my-svg .node rect,#my-svg .node circle,#my-svg .node ellipse,#my-svg .node polygon,#my-svg .node path{fill:#4A90D9;stroke:#2E6EB5;stroke-width:1px;}#my-svg .rough-node .label text,#my-svg .node .label text,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-anchor:middle;}#my-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#my-svg .rough-node .label,#my-svg .node .label,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-align:center;}#my-svg .node.clickable{cursor:pointer;}#my-svg .root .anchor path{fill:#5C6B77!important;stroke-width:0;stroke:#5C6B77;}#my-svg .arrowheadPath{fill:#0b0b0b;}#my-svg .edgePath .path{stroke:#5C6B77;stroke-width:2.0px;}#my-svg .flowchart-link{stroke:#5C6B77;fill:none;}#my-svg .edgeLabel{background-color:#ffffff;text-align:center;}#my-svg .edgeLabel p{background-color:#ffffff;}#my-svg .edgeLabel rect{opacity:0.5;background-color:#ffffff;fill:#ffffff;}#my-svg .labelBkg{background-color:rgba(255, 255, 255, 0.5);}#my-svg .cluster rect{fill:#F0F4F8;stroke:#94B8D9;stroke-width:1px;}#my-svg .cluster text{fill:#333333;}#my-svg .cluster span{color:#333333;}#my-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:#50C878;border:1px solid #3BA35C;border-radius:2px;pointer-events:none;z-index:100;}#my-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333333;}#my-svg rect.text{fill:none;stroke-width:0;}#my-svg .icon-shape,#my-svg .image-shape{background-color:#ffffff;text-align:center;}#my-svg .icon-shape p,#my-svg .image-shape p{background-color:#ffffff;padding:2px;}#my-svg .icon-shape rect,#my-svg .image-shape rect{opacity:0.5;background-color:#ffffff;fill:#ffffff;}#my-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#my-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="my-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><g class="root"><g class="clusters"><g class="cluster" id="LOCAL" data-look="classic"><rect style="" x="8" y="8" width="1125.78125" height="141"/><g class="cluster-label" transform="translate(529.7109375, 8)"><foreignObject width="82.359375" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Your Machine</p></span></div></foreignObject></g></g><g class="cluster" id="CLOUD" data-look="classic"><rect style="" x="487.8125" y="169" width="246.640625" height="262"/><g class="cluster-label" transform="translate(565.375, 169)"><foreignObject width="91.515625" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Cloud Provider</p></span></div></foreignObject></g></g><g class="cluster" id="GW" data-look="classic"><rect style="" x="8" y="451" width="1125.78125" height="141"/><g class="cluster-label" transform="translate(489.390625, 451)"><foreignObject width="163" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Gateway (source of truth)</p></span></div></foreignObject></g></g></g><g class="edgePaths"><path d="M241.672,521.5L265.975,521.5C290.279,521.5,338.885,521.5,379.909,521.5C420.932,521.5,454.372,521.5,489.156,480.194C523.939,438.888,560.066,356.277,578.129,314.971L596.192,273.665" id="L_WS_CF_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_WS_CF_0" data-points="W3sieCI6MjQxLjY3MTg3NSwieSI6NTIxLjV9LHsieCI6Mzg3LjQ5MjE4NzUsInkiOjUyMS41fSx7IngiOjQ4Ny44MTI1LCJ5Ijo1MjEuNX0seyJ4Ijo1OTcuNzk0OTc3MjgyODAxNCwieSI6MjcwfV0=" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M699.453,239.5L705.286,239.5C711.12,239.5,722.786,239.5,746.169,212.667C769.552,185.833,804.651,132.167,839.083,105.333C873.516,78.5,907.281,78.5,924.164,78.5L941.047,78.5" id="L_CF_LM_0" class="edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_CF_LM_0" data-points="W3sieCI6Njk5LjQ1MzEyNSwieSI6MjM5LjV9LHsieCI6NzM0LjQ1MzEyNSwieSI6MjM5LjV9LHsieCI6ODM5Ljc1LCJ5Ijo3OC41fSx7IngiOjk0NS4wNDY4NzUsInkiOjc4LjV9XQ==" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M287.172,78.5L303.892,78.5C320.612,78.5,354.052,78.5,387.492,78.5C420.932,78.5,454.372,78.5,489.156,119.806C523.939,161.112,560.066,243.723,578.129,285.029L596.192,326.335" id="L_OUTBOX_L_OUTBOX_C_0" class="edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_OUTBOX_L_OUTBOX_C_0" data-points="W3sieCI6Mjg3LjE3MTg3NSwieSI6NzguNX0seyJ4IjozODcuNDkyMTg3NSwieSI6NzguNX0seyJ4Ijo0ODcuODEyNSwieSI6NzguNX0seyJ4Ijo1OTcuNzk0OTc3MjgyODAxNCwieSI6MzMwfV0=" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M680,360.5L689.076,360.5C698.151,360.5,716.302,360.5,742.927,387.333C769.552,414.167,804.651,467.833,841.173,494.667C877.695,521.5,915.641,521.5,934.613,521.5L953.586,521.5" id="L_OUTBOX_C_INBOX_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_OUTBOX_C_INBOX_0" data-points="W3sieCI6NjgwLCJ5IjozNjAuNX0seyJ4Ijo3MzQuNDUzMTI1LCJ5IjozNjAuNX0seyJ4Ijo4MzkuNzUsInkiOjUyMS41fSx7IngiOjk1Ny41ODU5Mzc1LCJ5Ijo1MjEuNX1d" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(387.4921875, 521.5)"><g class="label" data-id="L_WS_CF_0" transform="translate(-65.3203125, -10.5)"><foreignObject width="130.640625" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel">1. rclone sync (push)</span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(839.75, 78.5)"><g class="label" data-id="L_CF_LM_0" transform="translate(-59.390625, -10.5)"><foreignObject width="118.78125" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>desktop app (auto)</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(387.4921875, 78.5)"><g class="label" data-id="L_OUTBOX_L_OUTBOX_C_0" transform="translate(-59.390625, -10.5)"><foreignObject width="118.78125" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>desktop app (auto)</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(839.75, 521.5)"><g class="label" data-id="L_OUTBOX_C_INBOX_0" transform="translate(-70.296875, -10.5)"><foreignObject width="140.59375" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel">2. rclone move (drain)</span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="flowchart-WS-0" transform="translate(165.0859375, 521.5)"><rect class="basic label-container" style="" x="-76.5859375" y="-30.5" width="153.171875" height="61"/><g class="label" style="" transform="translate(-36.5859375, -10.5)"><rect/><foreignObject width="73.171875" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>/workspace</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-INBOX-1" transform="translate(1021.9140625, 521.5)"><rect class="basic label-container" style="" x="-64.328125" y="-30.5" width="128.65625" height="61"/><g class="label" style="" transform="translate(-24.328125, -10.5)"><rect/><foreignObject width="48.65625" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>_inbox/</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-CF-2" transform="translate(611.1328125, 239.5)"><rect class="basic label-container" style="" x="-88.3203125" y="-30.5" width="176.640625" height="61"/><g class="label" style="" transform="translate(-48.3203125, -10.5)"><rect/><foreignObject width="96.640625" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>workspace files</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-OUTBOX_C-3" transform="translate(611.1328125, 360.5)"><rect class="basic label-container" style="" x="-68.8671875" y="-30.5" width="137.734375" height="61"/><g class="label" style="" transform="translate(-28.8671875, -10.5)"><rect/><foreignObject width="57.734375" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>_outbox/</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-LM-4" transform="translate(1021.9140625, 78.5)"><rect class="basic label-container" style="" x="-76.8671875" y="-30.5" width="153.734375" height="61"/><g class="label" style="" transform="translate(-36.8671875, -10.5)"><rect/><foreignObject width="73.734375" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>local mirror</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-OUTBOX_L-5" transform="translate(165.0859375, 78.5)"><rect class="basic label-container" style="" x="-122.0859375" y="-30.5" width="244.171875" height="61"/><g class="label" style="" transform="translate(-82.0859375, -10.5)"><rect/><foreignObject width="164.171875" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>_outbox/ (drop files here)</p></span></div></foreignObject></g></g></g></g></g><style>.edgeLabel {
|
|
2
|
+
color: #333333 !important;
|
|
3
|
+
background-color: #ffffff !important;
|
|
4
|
+
}
|
|
5
|
+
.edgeLabel span {
|
|
6
|
+
color: #333333 !important;
|
|
7
|
+
fill: #333333 !important;
|
|
8
|
+
}
|
|
9
|
+
.edgeLabel p {
|
|
10
|
+
color: #333333 !important;
|
|
11
|
+
}
|
|
12
|
+
.labelBkg {
|
|
13
|
+
background-color: #ffffff !important;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Gateway subgraph — green tint */
|
|
17
|
+
#GW rect {
|
|
18
|
+
fill: #E8F5E9 !important;
|
|
19
|
+
stroke: #66BB6A !important;
|
|
20
|
+
}
|
|
21
|
+
#GW .cluster-label span {
|
|
22
|
+
color: #2E7D32 !important;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Cloud subgraph — amber tint */
|
|
26
|
+
#CLOUD rect {
|
|
27
|
+
fill: #FFF8E1 !important;
|
|
28
|
+
stroke: #FFB74D !important;
|
|
29
|
+
}
|
|
30
|
+
#CLOUD .cluster-label span {
|
|
31
|
+
color: #E65100 !important;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Local subgraph — blue tint */
|
|
35
|
+
#LOCAL rect {
|
|
36
|
+
fill: #E3F2FD !important;
|
|
37
|
+
stroke: #64B5F6 !important;
|
|
38
|
+
}
|
|
39
|
+
#LOCAL .cluster-label span {
|
|
40
|
+
color: #1565C0 !important;
|
|
41
|
+
}
|
|
42
|
+
</style></svg>
|
package/docs/diagrams/mode-1.svg
CHANGED
|
@@ -1 +1,42 @@
|
|
|
1
|
-
<svg id="my-svg" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="flowchart" style="max-width: 751.07px; background-color: transparent;" viewBox="0 0 751.0703125 478.20001220703125" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#000000;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:#552222;}#my-svg .error-text{fill:#552222;stroke:#552222;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#666;stroke:#666;}#my-svg .marker.cross{stroke:#666;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#my-svg p{margin:0;}#my-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#000000;}#my-svg .cluster-label text{fill:#333;}#my-svg .cluster-label span{color:#333;}#my-svg .cluster-label span p{background-color:transparent;}#my-svg .label text,#my-svg span{fill:#000000;color:#000000;}#my-svg .node rect,#my-svg .node circle,#my-svg .node ellipse,#my-svg .node polygon,#my-svg .node path{fill:#eee;stroke:#999;stroke-width:1px;}#my-svg .rough-node .label text,#my-svg .node .label text,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-anchor:middle;}#my-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#my-svg .rough-node .label,#my-svg .node .label,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-align:center;}#my-svg .node.clickable{cursor:pointer;}#my-svg .root .anchor path{fill:#666!important;stroke-width:0;stroke:#666;}#my-svg .arrowheadPath{fill:#333333;}#my-svg .edgePath .path{stroke:#666;stroke-width:2.0px;}#my-svg .flowchart-link{stroke:#666;fill:none;}#my-svg .edgeLabel{background-color:white;text-align:center;}#my-svg .edgeLabel p{background-color:white;}#my-svg .edgeLabel rect{opacity:0.5;background-color:white;fill:white;}#my-svg .labelBkg{background-color:rgba(255, 255, 255, 0.5);}#my-svg .cluster rect{fill:hsl(0, 0%, 98.9215686275%);stroke:#707070;stroke-width:1px;}#my-svg .cluster text{fill:#333;}#my-svg .cluster span{color:#333;}#my-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(-160, 0%, 93.3333333333%);border:1px solid #707070;border-radius:2px;pointer-events:none;z-index:100;}#my-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#000000;}#my-svg rect.text{fill:none;stroke-width:0;}#my-svg .icon-shape,#my-svg .image-shape{background-color:white;text-align:center;}#my-svg .icon-shape p,#my-svg .image-shape p{background-color:white;padding:2px;}#my-svg .icon-shape rect,#my-svg .image-shape rect{opacity:0.5;background-color:white;fill:white;}#my-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#my-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="my-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><g class="root"><g class="clusters"><g class="cluster" id="LOCAL" data-look="classic"><rect style="" x="475.9296875" y="8" width="267.140625" height="124"/><g class="cluster-label" transform="translate(562.4453125, 8)"><foreignObject width="94.109375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Your Machine</p></span></div></foreignObject></g></g><g class="cluster" id="CLOUD" data-look="classic"><rect style="" x="8" y="8" width="293.4921875" height="124"/><g class="cluster-label" transform="translate(102.44921875, 8)"><foreignObject width="104.59375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Cloud Provider</p></span></div></foreignObject></g></g></g><g class="edgePaths"><path d="M239.973,70L250.226,70C260.479,70,280.986,70,305.775,70C330.565,70,359.638,70,388.711,70C417.784,70,446.857,70,464.893,70C482.93,70,489.93,70,493.43,70L496.93,70" id="L_CF_LM_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_CF_LM_0" data-points="W3sieCI6MjM5Ljk3MjY1NjI1LCJ5Ijo3MH0seyJ4IjozMDEuNDkyMTg3NSwieSI6NzB9LHsieCI6Mzg4LjcxMDkzNzUsInkiOjcwfSx7IngiOjQ3NS45Mjk2ODc1LCJ5Ijo3MH0seyJ4Ijo1MDAuOTI5Njg3NSwieSI6NzB9XQ==" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(388.7109375, 70)"><g class="label" data-id="L_CF_LM_0" transform="translate(-62.21875, -12)"><foreignObject width="124.4375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>rclone sync (pull)</p></span></div></foreignObject></g></g></g><g class="nodes"><g class="root" transform="translate(25, 159)"><g class="clusters"><g class="cluster" id="GW" data-look="classic"><rect style="" x="8" y="8" width="243.4921875" height="303.20000000298023"/><g class="cluster-label" transform="translate(36.60546875, 8)"><foreignObject width="186.28125" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Gateway (source of truth)</p></span></div></foreignObject></g></g></g><g class="edgePaths"><path d="M127.25,99.5L123.216,105.75C119.181,112,111.112,124.5,107.078,137C103.043,149.5,103.043,162,103.043,168.25L103.043,174.5" id="WS-cyclic-special-1" class="edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="WS-cyclic-special-1" data-points="W3sieCI6MTI3LjI1MDM2MzM3MjA5MzAyLCJ5Ijo5OS41fSx7IngiOjEwMy4wNDI5Njg3NSwieSI6MTM3fSx7IngiOjEwMy4wNDI5Njg3NSwieSI6MTc0LjV9XQ=="/><path d="M103.043,174.6L103.043,182.85C103.043,191.1,103.043,207.6,109.975,224.1C116.908,240.6,130.773,257.1,137.705,265.35L144.638,273.6" id="WS-cyclic-special-mid" class="edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="WS-cyclic-special-mid" data-points="W3sieCI6MTAzLjA0Mjk2ODc1LCJ5IjoxNzQuNjAwMDAwMDAxNDkwMTJ9LHsieCI6MTAzLjA0Mjk2ODc1LCJ5IjoyMjQuMTAwMDAwMDAxNDkwMTJ9LHsieCI6MTQ0LjYzNzY3MjY0Njk1Mjc4LCJ5IjoyNzMuNjAwMDAwMDAxNDkwMX1d"/><path d="M144.723,273.6L151.951,265.35C159.178,257.1,173.632,240.6,180.859,224.092C188.086,207.583,188.086,191.067,188.086,176.55C188.086,162.033,188.086,149.517,184.252,137.561C180.418,125.606,172.751,114.212,168.917,108.515L165.083,102.819" id="WS-cyclic-special-2" class="edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="WS-cyclic-special-2" data-points="W3sieCI6MTQ0LjcyMzQ4Nzk1NDczODgsInkiOjI3My42MDAwMDAwMDE0OTAxfSx7IngiOjE4OC4wODU5Mzc1LCJ5IjoyMjQuMTAwMDAwMDAxNDkwMTJ9LHsieCI6MTg4LjA4NTkzNzUsInkiOjE3NC41NTAwMDAwMDA3NDUwNn0seyJ4IjoxODguMDg1OTM3NSwieSI6MTM3fSx7IngiOjE2Mi44NDk3NDU2Mzk1MzQ5LCJ5Ijo5OS41fV0=" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/></g><g class="edgeLabels"><g class="edgeLabel"><g class="label" data-id="WS-cyclic-special-1" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(103.04296875, 224.10000000149012)"><g class="label" data-id="WS-cyclic-special-mid" transform="translate(-63.2734375, -12)"><foreignObject width="126.546875" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>agent writes here</p></span></div></foreignObject></g></g><g class="edgeLabel"><g class="label" data-id="WS-cyclic-special-2" transform="translate(0, 0)"><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="flowchart-WS-0" transform="translate(144.6796875, 72.5)"><rect class="basic label-container" style="" x="-71.8125" y="-27" width="143.625" height="54"/><g class="label" style="" transform="translate(-41.8125, -12)"><rect/><foreignObject width="83.625" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>/workspace</p></span></div></foreignObject></g></g><g class="label edgeLabel" id="WS---WS---1" transform="translate(103.04296875, 174.55000000074506)"><rect width="0.1" height="0.1"/><g class="label" style="" transform="translate(0, 0)"><rect/><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 10px; text-align: center;"><span class="nodeLabel"></span></div></foreignObject></g></g><g class="label edgeLabel" id="WS---WS---2" transform="translate(144.6796875, 273.6500000022352)"><rect width="0.1" height="0.1"/><g class="label" style="" transform="translate(0, 0)"><rect/><foreignObject width="0" height="0"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 10px; text-align: center;"><span class="nodeLabel"></span></div></foreignObject></g></g></g></g><g class="node default" id="flowchart-CF-1" transform="translate(154.74609375, 70)"><rect class="basic label-container" style="" x="-85.2265625" y="-27" width="170.453125" height="54"/><g class="label" style="" transform="translate(-55.2265625, -12)"><rect/><foreignObject width="110.453125" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>workspace files</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-LM-2" transform="translate(609.5, 70)"><rect class="basic label-container" style="" x="-108.5703125" y="-27" width="217.140625" height="54"/><g class="label" style="" transform="translate(-78.5703125, -12)"><rect/><foreignObject width="157.140625" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>local copy (read-only)</p></span></div></foreignObject></g></g></g></g></g></svg>
|
|
1
|
+
<svg id="my-svg" width="1173.703125" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="flowchart" height="278" viewBox="0 0 1173.703125 278" role="graphics-document document" aria-roledescription="flowchart-v2" style="background-color: white;"><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:14px;fill:#333333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:#50C878;}#my-svg .error-text{fill:#ffffff;stroke:#ffffff;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#5C6B77;stroke:#5C6B77;}#my-svg .marker.cross{stroke:#5C6B77;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:14px;}#my-svg p{margin:0;}#my-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ffffff;}#my-svg .cluster-label text{fill:#333333;}#my-svg .cluster-label span{color:#333333;}#my-svg .cluster-label span p{background-color:transparent;}#my-svg .label text,#my-svg span{fill:#ffffff;color:#ffffff;}#my-svg .node rect,#my-svg .node circle,#my-svg .node ellipse,#my-svg .node polygon,#my-svg .node path{fill:#4A90D9;stroke:#2E6EB5;stroke-width:1px;}#my-svg .rough-node .label text,#my-svg .node .label text,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-anchor:middle;}#my-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#my-svg .rough-node .label,#my-svg .node .label,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-align:center;}#my-svg .node.clickable{cursor:pointer;}#my-svg .root .anchor path{fill:#5C6B77!important;stroke-width:0;stroke:#5C6B77;}#my-svg .arrowheadPath{fill:#0b0b0b;}#my-svg .edgePath .path{stroke:#5C6B77;stroke-width:2.0px;}#my-svg .flowchart-link{stroke:#5C6B77;fill:none;}#my-svg .edgeLabel{background-color:#ffffff;text-align:center;}#my-svg .edgeLabel p{background-color:#ffffff;}#my-svg .edgeLabel rect{opacity:0.5;background-color:#ffffff;fill:#ffffff;}#my-svg .labelBkg{background-color:rgba(255, 255, 255, 0.5);}#my-svg .cluster rect{fill:#F0F4F8;stroke:#94B8D9;stroke-width:1px;}#my-svg .cluster text{fill:#333333;}#my-svg .cluster span{color:#333333;}#my-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:#50C878;border:1px solid #3BA35C;border-radius:2px;pointer-events:none;z-index:100;}#my-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333333;}#my-svg rect.text{fill:none;stroke-width:0;}#my-svg .icon-shape,#my-svg .image-shape{background-color:#ffffff;text-align:center;}#my-svg .icon-shape p,#my-svg .image-shape p{background-color:#ffffff;padding:2px;}#my-svg .icon-shape rect,#my-svg .image-shape rect{opacity:0.5;background-color:#ffffff;fill:#ffffff;}#my-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#my-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="my-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><g class="root"><g class="clusters"><g class="cluster" id="GW" data-look="classic"><rect style="" x="8" y="8" width="260.734375" height="262"/><g class="cluster-label" transform="translate(56.8671875, 8)"><foreignObject width="163" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Gateway (source of truth)</p></span></div></foreignObject></g></g><g class="cluster" id="LOCAL" data-look="classic"><rect style="" x="878.203125" y="8" width="287.5" height="141"/><g class="cluster-label" transform="translate(980.7734375, 8)"><foreignObject width="82.359375" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Your Machine</p></span></div></foreignObject></g></g><g class="cluster" id="CLOUD" data-look="classic"><rect style="" x="452.671875" y="8" width="246.640625" height="141"/><g class="cluster-label" transform="translate(530.234375, 8)"><foreignObject width="91.515625" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Cloud Provider</p></span></div></foreignObject></g></g></g><g class="edgePaths"><path d="M664.313,78.5L670.146,78.5C675.979,78.5,687.646,78.5,708.387,78.5C729.128,78.5,758.943,78.5,788.758,78.5C818.573,78.5,848.388,78.5,868.462,78.5C888.536,78.5,898.87,78.5,904.036,78.5L909.203,78.5" id="L_CF_LM_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_CF_LM_0" data-points="W3sieCI6NjY0LjMxMjUsInkiOjc4LjV9LHsieCI6Njk5LjMxMjUsInkiOjc4LjV9LHsieCI6Nzg4Ljc1NzgxMjUsInkiOjc4LjV9LHsieCI6ODc4LjIwMzEyNSwieSI6NzguNX0seyJ4Ijo5MTMuMjAzMTI1LCJ5Ijo3OC41fV0=" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M214.953,78.5L223.917,78.5C232.88,78.5,250.807,78.5,275.099,78.5C299.391,78.5,330.047,78.5,360.703,78.5C391.359,78.5,422.016,78.5,442.51,78.5C463.005,78.5,473.339,78.5,478.505,78.5L483.672,78.5" id="L_WS_CF_0" class="edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_WS_CF_0" data-points="W3sieCI6MjE0Ljk1MzEyNSwieSI6NzguNX0seyJ4IjoyNjguNzM0Mzc1LCJ5Ijo3OC41fSx7IngiOjM2MC43MDMxMjUsInkiOjc4LjV9LHsieCI6NDUyLjY3MTg3NSwieSI6NzguNX0seyJ4Ijo0ODcuNjcxODc1LCJ5Ijo3OC41fV0=" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(788.7578125, 78.5)"><g class="label" data-id="L_CF_LM_0" transform="translate(-54.4453125, -10.5)"><foreignObject width="108.890625" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>rclone sync (pull)</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(360.703125, 78.5)"><g class="label" data-id="L_WS_CF_0" transform="translate(-56.96875, -10.5)"><foreignObject width="113.9375" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>rclone sync (push)</p></span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="flowchart-CF-0" transform="translate(575.9921875, 78.5)"><rect class="basic label-container" style="" x="-88.3203125" y="-30.5" width="176.640625" height="61"/><g class="label" style="" transform="translate(-48.3203125, -10.5)"><rect/><foreignObject width="96.640625" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>workspace files</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-LM-1" transform="translate(1021.953125, 78.5)"><rect class="basic label-container" style="" x="-108.75" y="-30.5" width="217.5" height="61"/><g class="label" style="" transform="translate(-68.75, -10.5)"><rect/><foreignObject width="137.5" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>local copy (read-only)</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-WS-2" transform="translate(138.3671875, 78.5)"><rect class="basic label-container" style="" x="-76.5859375" y="-30.5" width="153.171875" height="61"/><g class="label" style="" transform="translate(-36.5859375, -10.5)"><rect/><foreignObject width="73.171875" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>/workspace</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-NOTE-3" transform="translate(138.3671875, 199.5)"><rect class="basic label-container" style="" x="-95.3671875" y="-30.5" width="190.734375" height="61"/><g class="label" style="" transform="translate(-55.3671875, -10.5)"><rect/><foreignObject width="110.734375" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>agent writes here</p></span></div></foreignObject></g></g></g></g></g><style>.edgeLabel {
|
|
2
|
+
color: #333333 !important;
|
|
3
|
+
background-color: #ffffff !important;
|
|
4
|
+
}
|
|
5
|
+
.edgeLabel span {
|
|
6
|
+
color: #333333 !important;
|
|
7
|
+
fill: #333333 !important;
|
|
8
|
+
}
|
|
9
|
+
.edgeLabel p {
|
|
10
|
+
color: #333333 !important;
|
|
11
|
+
}
|
|
12
|
+
.labelBkg {
|
|
13
|
+
background-color: #ffffff !important;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Gateway subgraph — green tint */
|
|
17
|
+
#GW rect {
|
|
18
|
+
fill: #E8F5E9 !important;
|
|
19
|
+
stroke: #66BB6A !important;
|
|
20
|
+
}
|
|
21
|
+
#GW .cluster-label span {
|
|
22
|
+
color: #2E7D32 !important;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Cloud subgraph — amber tint */
|
|
26
|
+
#CLOUD rect {
|
|
27
|
+
fill: #FFF8E1 !important;
|
|
28
|
+
stroke: #FFB74D !important;
|
|
29
|
+
}
|
|
30
|
+
#CLOUD .cluster-label span {
|
|
31
|
+
color: #E65100 !important;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Local subgraph — blue tint */
|
|
35
|
+
#LOCAL rect {
|
|
36
|
+
fill: #E3F2FD !important;
|
|
37
|
+
stroke: #64B5F6 !important;
|
|
38
|
+
}
|
|
39
|
+
#LOCAL .cluster-label span {
|
|
40
|
+
color: #1565C0 !important;
|
|
41
|
+
}
|
|
42
|
+
</style></svg>
|
package/docs/diagrams/mode-2.svg
CHANGED
|
@@ -1 +1,42 @@
|
|
|
1
|
-
<svg id="my-svg" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="flowchart" style="max-width: 893.906px; background-color: transparent;" viewBox="0 0 893.90625 152" role="graphics-document document" aria-roledescription="flowchart-v2"><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#000000;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:#552222;}#my-svg .error-text{fill:#552222;stroke:#552222;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#666;stroke:#666;}#my-svg .marker.cross{stroke:#666;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#my-svg p{margin:0;}#my-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#000000;}#my-svg .cluster-label text{fill:#333;}#my-svg .cluster-label span{color:#333;}#my-svg .cluster-label span p{background-color:transparent;}#my-svg .label text,#my-svg span{fill:#000000;color:#000000;}#my-svg .node rect,#my-svg .node circle,#my-svg .node ellipse,#my-svg .node polygon,#my-svg .node path{fill:#eee;stroke:#999;stroke-width:1px;}#my-svg .rough-node .label text,#my-svg .node .label text,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-anchor:middle;}#my-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#my-svg .rough-node .label,#my-svg .node .label,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-align:center;}#my-svg .node.clickable{cursor:pointer;}#my-svg .root .anchor path{fill:#666!important;stroke-width:0;stroke:#666;}#my-svg .arrowheadPath{fill:#333333;}#my-svg .edgePath .path{stroke:#666;stroke-width:2.0px;}#my-svg .flowchart-link{stroke:#666;fill:none;}#my-svg .edgeLabel{background-color:white;text-align:center;}#my-svg .edgeLabel p{background-color:white;}#my-svg .edgeLabel rect{opacity:0.5;background-color:white;fill:white;}#my-svg .labelBkg{background-color:rgba(255, 255, 255, 0.5);}#my-svg .cluster rect{fill:hsl(0, 0%, 98.9215686275%);stroke:#707070;stroke-width:1px;}#my-svg .cluster text{fill:#333;}#my-svg .cluster span{color:#333;}#my-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(-160, 0%, 93.3333333333%);border:1px solid #707070;border-radius:2px;pointer-events:none;z-index:100;}#my-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#000000;}#my-svg rect.text{fill:none;stroke-width:0;}#my-svg .icon-shape,#my-svg .image-shape{background-color:white;text-align:center;}#my-svg .icon-shape p,#my-svg .image-shape p{background-color:white;padding:2px;}#my-svg .icon-shape rect,#my-svg .image-shape rect{opacity:0.5;background-color:white;fill:white;}#my-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#my-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="my-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><g class="root"><g class="clusters"><g class="cluster" id="LOCAL" data-look="classic"><rect style="" x="703.421875" y="8" width="182.484375" height="136"/><g class="cluster-label" transform="translate(747.609375, 8)"><foreignObject width="94.109375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Your Machine</p></span></div></foreignObject></g></g><g class="cluster" id="CLOUD" data-look="classic"><rect style="" x="345.875" y="8" width="220.453125" height="136"/><g class="cluster-label" transform="translate(403.8046875, 8)"><foreignObject width="104.59375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Cloud Provider</p></span></div></foreignObject></g></g><g class="cluster" id="GW" data-look="classic"><rect style="" x="8" y="8" width="193.625" height="136"/><g class="cluster-label" transform="translate(73.5625, 8)"><foreignObject width="62.5" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Gateway</p></span></div></foreignObject></g></g></g><g class="edgePaths"><path d="M176.625,64.681L180.792,63.734C184.958,62.787,193.292,60.894,209.479,59.947C225.667,59,249.708,59,273.75,59C297.792,59,321.833,59,337.367,59.701C352.901,60.402,359.927,61.805,363.439,62.506L366.952,63.207" id="L_WS_CF_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_WS_CF_0" data-points="W3sieCI6MTc2LjYyNSwieSI6NjQuNjgxMDg0NTcwNjkwNzd9LHsieCI6MjAxLjYyNSwieSI6NTl9LHsieCI6MjczLjc1LCJ5Ijo1OX0seyJ4IjozNDUuODc1LCJ5Ijo1OX0seyJ4IjozNzAuODc1LCJ5Ijo2My45ODk3MjI4NzE5MjU3Mn1d" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M370.875,98.01L366.708,98.842C362.542,99.674,354.208,101.337,338.021,102.168C321.833,103,297.792,103,273.75,103C249.708,103,225.667,103,210.129,102.201C194.592,101.402,187.559,99.804,184.042,99.004L180.526,98.205" id="L_CF_WS_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_CF_WS_0" data-points="W3sieCI6MzcwLjg3NSwieSI6OTguMDEwMjc3MTI4MDc0Mjh9LHsieCI6MzQ1Ljg3NSwieSI6MTAzfSx7IngiOjI3My43NSwieSI6MTAzfSx7IngiOjIwMS42MjUsInkiOjEwM30seyJ4IjoxNzYuNjI1LCJ5Ijo5Ny4zMTg5MTU0MjkzMDkyM31d" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M541.328,63.99L545.495,63.158C549.661,62.326,557.995,60.663,573.586,59.832C589.177,59,612.026,59,634.875,59C657.724,59,680.573,59,695.516,59.848C710.459,60.697,717.496,62.394,721.015,63.242L724.533,64.09" id="L_CF_LM_0" class="edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_CF_LM_0" data-points="W3sieCI6NTQxLjMyODEyNSwieSI6NjMuOTg5NzIyODcxOTI1NzJ9LHsieCI6NTY2LjMyODEyNSwieSI6NTl9LHsieCI6NjM0Ljg3NSwieSI6NTl9LHsieCI6NzAzLjQyMTg3NSwieSI6NTl9LHsieCI6NzI4LjQyMTg3NSwieSI6NjUuMDI3OTEzMzQ4NzQ1NjF9XQ==" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M728.422,96.972L724.255,97.977C720.089,98.981,711.755,100.991,696.164,101.995C680.573,103,657.724,103,634.875,103C612.026,103,589.177,103,574.24,102.299C559.302,101.598,552.277,100.195,548.764,99.494L545.251,98.793" id="L_LM_CF_0" class="edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_LM_CF_0" data-points="W3sieCI6NzI4LjQyMTg3NSwieSI6OTYuOTcyMDg2NjUxMjU0Mzl9LHsieCI6NzAzLjQyMTg3NSwieSI6MTAzfSx7IngiOjYzNC44NzUsInkiOjEwM30seyJ4Ijo1NjYuMzI4MTI1LCJ5IjoxMDN9LHsieCI6NTQxLjMyODEyNSwieSI6OTguMDEwMjc3MTI4MDc0Mjh9XQ==" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(273.75, 59)"><g class="label" data-id="L_WS_CF_0" transform="translate(-47.125, -12)"><foreignObject width="94.25" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>rclone bisync</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(273.75, 103)"><g class="label" data-id="L_CF_WS_0" transform="translate(-47.125, -12)"><foreignObject width="94.25" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>rclone bisync</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(634.875, 59)"><g class="label" data-id="L_CF_LM_0" transform="translate(-43.546875, -12)"><foreignObject width="87.09375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>desktop app</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(634.875, 103)"><g class="label" data-id="L_LM_CF_0" transform="translate(-43.546875, -12)"><foreignObject width="87.09375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>desktop app</p></span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="flowchart-WS-0" transform="translate(104.8125, 81)"><rect class="basic label-container" style="" x="-71.8125" y="-27" width="143.625" height="54"/><g class="label" style="" transform="translate(-41.8125, -12)"><rect/><foreignObject width="83.625" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>/workspace</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-CF-1" transform="translate(456.1015625, 81)"><rect class="basic label-container" style="" x="-85.2265625" y="-27" width="170.453125" height="54"/><g class="label" style="" transform="translate(-55.2265625, -12)"><rect/><foreignObject width="110.453125" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>workspace files</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-LM-2" transform="translate(794.6640625, 81)"><rect class="basic label-container" style="" x="-66.2421875" y="-27" width="132.484375" height="54"/><g class="label" style="" transform="translate(-36.2421875, -12)"><rect/><foreignObject width="72.484375" height="24"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>local copy</p></span></div></foreignObject></g></g></g></g></g></svg>
|
|
1
|
+
<svg id="my-svg" width="997.921875" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="flowchart" height="162.25" viewBox="0 0 997.921875 162.25" role="graphics-document document" aria-roledescription="flowchart-v2" style="background-color: white;"><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:14px;fill:#333333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:#50C878;}#my-svg .error-text{fill:#ffffff;stroke:#ffffff;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#5C6B77;stroke:#5C6B77;}#my-svg .marker.cross{stroke:#5C6B77;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:14px;}#my-svg p{margin:0;}#my-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#ffffff;}#my-svg .cluster-label text{fill:#333333;}#my-svg .cluster-label span{color:#333333;}#my-svg .cluster-label span p{background-color:transparent;}#my-svg .label text,#my-svg span{fill:#ffffff;color:#ffffff;}#my-svg .node rect,#my-svg .node circle,#my-svg .node ellipse,#my-svg .node polygon,#my-svg .node path{fill:#4A90D9;stroke:#2E6EB5;stroke-width:1px;}#my-svg .rough-node .label text,#my-svg .node .label text,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-anchor:middle;}#my-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#my-svg .rough-node .label,#my-svg .node .label,#my-svg .image-shape .label,#my-svg .icon-shape .label{text-align:center;}#my-svg .node.clickable{cursor:pointer;}#my-svg .root .anchor path{fill:#5C6B77!important;stroke-width:0;stroke:#5C6B77;}#my-svg .arrowheadPath{fill:#0b0b0b;}#my-svg .edgePath .path{stroke:#5C6B77;stroke-width:2.0px;}#my-svg .flowchart-link{stroke:#5C6B77;fill:none;}#my-svg .edgeLabel{background-color:#ffffff;text-align:center;}#my-svg .edgeLabel p{background-color:#ffffff;}#my-svg .edgeLabel rect{opacity:0.5;background-color:#ffffff;fill:#ffffff;}#my-svg .labelBkg{background-color:rgba(255, 255, 255, 0.5);}#my-svg .cluster rect{fill:#F0F4F8;stroke:#94B8D9;stroke-width:1px;}#my-svg .cluster text{fill:#333333;}#my-svg .cluster span{color:#333333;}#my-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:#50C878;border:1px solid #3BA35C;border-radius:2px;pointer-events:none;z-index:100;}#my-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333333;}#my-svg rect.text{fill:none;stroke-width:0;}#my-svg .icon-shape,#my-svg .image-shape{background-color:#ffffff;text-align:center;}#my-svg .icon-shape p,#my-svg .image-shape p{background-color:#ffffff;padding:2px;}#my-svg .icon-shape rect,#my-svg .image-shape rect{opacity:0.5;background-color:#ffffff;fill:#ffffff;}#my-svg .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#my-svg .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker id="my-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="11" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-circleStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="-1" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><circle cx="5" cy="5" r="5" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossEnd" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="12" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><marker id="my-svg_flowchart-v2-crossStart" class="marker cross flowchart-v2" viewBox="0 0 11 11" refX="-1" refY="5.2" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 1,1 l 9,9 M 10,1 l -9,9" class="arrowMarkerPath" style="stroke-width: 2; stroke-dasharray: 1, 0;"/></marker><g class="root"><g class="clusters"><g class="cluster" id="LOCAL" data-look="classic"><rect style="" x="776.484375" y="8" width="213.4375" height="146.25"/><g class="cluster-label" transform="translate(842.0234375, 8)"><foreignObject width="82.359375" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Your Machine</p></span></div></foreignObject></g></g><g class="cluster" id="CLOUD" data-look="classic"><rect style="" x="383.640625" y="8" width="246.640625" height="146.25"/><g class="cluster-label" transform="translate(461.203125, 8)"><foreignObject width="91.515625" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Cloud Provider</p></span></div></foreignObject></g></g><g class="cluster" id="GW" data-look="classic"><rect style="" x="8" y="8" width="223.171875" height="146.25"/><g class="cluster-label" transform="translate(92.2421875, 8)"><foreignObject width="54.6875" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>Gateway</p></span></div></foreignObject></g></g></g><g class="edgePaths"><path d="M196.172,69.68L202.005,68.608C207.839,67.537,219.505,65.393,238.044,64.322C256.583,63.25,281.995,63.25,307.406,63.25C332.818,63.25,358.229,63.25,376.111,64.11C393.992,64.971,404.343,66.691,409.519,67.552L414.695,68.412" id="L_WS_CF_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_WS_CF_0" data-points="W3sieCI6MTk2LjE3MTg3NSwieSI6NjkuNjgwMDIxNzA0MTIzNzl9LHsieCI6MjMxLjE3MTg3NSwieSI6NjMuMjV9LHsieCI6MzA3LjQwNjI1LCJ5Ijo2My4yNX0seyJ4IjozODMuNjQwNjI1LCJ5Ijo2My4yNX0seyJ4Ijo0MTguNjQwNjI1LCJ5Ijo2OS4wNjgxODE4MTgxODE4MX1d" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M418.641,101.834L412.807,103.028C406.974,104.222,395.307,106.611,376.768,107.806C358.229,109,332.818,109,307.406,109C281.995,109,256.583,109,238.694,107.827C220.806,106.654,210.439,104.309,205.256,103.136L200.073,101.963" id="L_CF_WS_0" class="edge-thickness-normal edge-pattern-solid edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_CF_WS_0" data-points="W3sieCI6NDE4LjY0MDYyNSwieSI6MTAxLjgzMzcwMjg4MjQ4MzM3fSx7IngiOjM4My42NDA2MjUsInkiOjEwOX0seyJ4IjozMDcuNDA2MjUsInkiOjEwOX0seyJ4IjoyMzEuMTcxODc1LCJ5IjoxMDl9LHsieCI6MTk2LjE3MTg3NSwieSI6MTAxLjA4MDA5NTIxODA5MTQzfV0=" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M595.281,69.068L601.115,68.098C606.948,67.129,618.615,65.189,636.632,64.22C654.648,63.25,679.016,63.25,703.383,63.25C727.75,63.25,752.117,63.25,769.479,64.245C786.842,65.24,797.199,67.229,802.378,68.224L807.556,69.219" id="L_CF_LM_0" class="edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_CF_LM_0" data-points="W3sieCI6NTk1LjI4MTI1LCJ5Ijo2OS4wNjgxODE4MTgxODE4MX0seyJ4Ijo2MzAuMjgxMjUsInkiOjYzLjI1fSx7IngiOjcwMy4zODI4MTI1LCJ5Ijo2My4yNX0seyJ4Ijo3NzYuNDg0Mzc1LCJ5Ijo2My4yNX0seyJ4Ijo4MTEuNDg0Mzc1LCJ5Ijo2OS45NzMyNzk2NDg2MDkwOH1d" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/><path d="M811.484,100.719L805.651,102.099C799.818,103.479,788.151,106.24,770.134,107.62C752.117,109,727.75,109,703.383,109C679.016,109,654.648,109,637.285,107.939C619.921,106.879,609.56,104.757,604.38,103.697L599.2,102.636" id="L_LM_CF_0" class="edge-thickness-normal edge-pattern-dotted edge-thickness-normal edge-pattern-solid flowchart-link" style=";" data-edge="true" data-et="edge" data-id="L_LM_CF_0" data-points="W3sieCI6ODExLjQ4NDM3NSwieSI6MTAwLjcxODg4NzI2MjA3OTA2fSx7IngiOjc3Ni40ODQzNzUsInkiOjEwOX0seyJ4Ijo3MDMuMzgyODEyNSwieSI6MTA5fSx7IngiOjYzMC4yODEyNSwieSI6MTA5fSx7IngiOjU5NS4yODEyNSwieSI6MTAxLjgzMzcwMjg4MjQ4MzM3fV0=" marker-end="url(#my-svg_flowchart-v2-pointEnd)"/></g><g class="edgeLabels"><g class="edgeLabel" transform="translate(307.40625, 63.25)"><g class="label" data-id="L_WS_CF_0" transform="translate(-41.234375, -10.5)"><foreignObject width="82.46875" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>rclone bisync</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(307.40625, 109)"><g class="label" data-id="L_CF_WS_0" transform="translate(-41.234375, -10.5)"><foreignObject width="82.46875" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>rclone bisync</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(703.3828125, 63.25)"><g class="label" data-id="L_CF_LM_0" transform="translate(-38.1015625, -10.5)"><foreignObject width="76.203125" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>desktop app</p></span></div></foreignObject></g></g><g class="edgeLabel" transform="translate(703.3828125, 109)"><g class="label" data-id="L_LM_CF_0" transform="translate(-38.1015625, -10.5)"><foreignObject width="76.203125" height="21"><div xmlns="http://www.w3.org/1999/xhtml" class="labelBkg" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="edgeLabel"><p>desktop app</p></span></div></foreignObject></g></g></g><g class="nodes"><g class="node default" id="flowchart-WS-0" transform="translate(119.5859375, 83.75)"><rect class="basic label-container" style="" x="-76.5859375" y="-30.5" width="153.171875" height="61"/><g class="label" style="" transform="translate(-36.5859375, -10.5)"><rect/><foreignObject width="73.171875" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>/workspace</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-CF-1" transform="translate(506.9609375, 83.75)"><rect class="basic label-container" style="" x="-88.3203125" y="-30.5" width="176.640625" height="61"/><g class="label" style="" transform="translate(-48.3203125, -10.5)"><rect/><foreignObject width="96.640625" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>workspace files</p></span></div></foreignObject></g></g><g class="node default" id="flowchart-LM-2" transform="translate(883.203125, 83.75)"><rect class="basic label-container" style="" x="-71.71875" y="-30.5" width="143.4375" height="61"/><g class="label" style="" transform="translate(-31.71875, -10.5)"><rect/><foreignObject width="63.4375" height="21"><div xmlns="http://www.w3.org/1999/xhtml" style="display: table-cell; white-space: nowrap; line-height: 1.5; max-width: 200px; text-align: center;"><span class="nodeLabel"><p>local copy</p></span></div></foreignObject></g></g></g></g></g><style>.edgeLabel {
|
|
2
|
+
color: #333333 !important;
|
|
3
|
+
background-color: #ffffff !important;
|
|
4
|
+
}
|
|
5
|
+
.edgeLabel span {
|
|
6
|
+
color: #333333 !important;
|
|
7
|
+
fill: #333333 !important;
|
|
8
|
+
}
|
|
9
|
+
.edgeLabel p {
|
|
10
|
+
color: #333333 !important;
|
|
11
|
+
}
|
|
12
|
+
.labelBkg {
|
|
13
|
+
background-color: #ffffff !important;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Gateway subgraph — green tint */
|
|
17
|
+
#GW rect {
|
|
18
|
+
fill: #E8F5E9 !important;
|
|
19
|
+
stroke: #66BB6A !important;
|
|
20
|
+
}
|
|
21
|
+
#GW .cluster-label span {
|
|
22
|
+
color: #2E7D32 !important;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Cloud subgraph — amber tint */
|
|
26
|
+
#CLOUD rect {
|
|
27
|
+
fill: #FFF8E1 !important;
|
|
28
|
+
stroke: #FFB74D !important;
|
|
29
|
+
}
|
|
30
|
+
#CLOUD .cluster-label span {
|
|
31
|
+
color: #E65100 !important;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Local subgraph — blue tint */
|
|
35
|
+
#LOCAL rect {
|
|
36
|
+
fill: #E3F2FD !important;
|
|
37
|
+
stroke: #64B5F6 !important;
|
|
38
|
+
}
|
|
39
|
+
#LOCAL .cluster-label span {
|
|
40
|
+
color: #1565C0 !important;
|
|
41
|
+
}
|
|
42
|
+
</style></svg>
|
package/openclaw.plugin.json
CHANGED
|
@@ -5,6 +5,20 @@
|
|
|
5
5
|
"label": "Cloud Provider",
|
|
6
6
|
"help": "Cloud storage provider for workspace sync"
|
|
7
7
|
},
|
|
8
|
+
"mode": {
|
|
9
|
+
"label": "Sync Mode",
|
|
10
|
+
"help": "mailbox (safest, inbox/outbox), mirror (remote→local), or bisync (bidirectional)"
|
|
11
|
+
},
|
|
12
|
+
"ingest": {
|
|
13
|
+
"label": "Enable Ingest",
|
|
14
|
+
"help": "Create a local inbox folder that syncs one-way up to the workspace (mirror mode only)"
|
|
15
|
+
},
|
|
16
|
+
"ingestPath": {
|
|
17
|
+
"label": "Ingest Path",
|
|
18
|
+
"placeholder": "inbox",
|
|
19
|
+
"help": "Local subfolder name for ingestion (default: inbox). Mirror mode only.",
|
|
20
|
+
"advanced": true
|
|
21
|
+
},
|
|
8
22
|
"remotePath": {
|
|
9
23
|
"label": "Remote Path",
|
|
10
24
|
"placeholder": "openclaw-share",
|
|
@@ -122,6 +136,16 @@
|
|
|
122
136
|
"custom"
|
|
123
137
|
]
|
|
124
138
|
},
|
|
139
|
+
"mode": {
|
|
140
|
+
"type": "string",
|
|
141
|
+
"enum": ["mirror", "mailbox", "bisync"]
|
|
142
|
+
},
|
|
143
|
+
"ingest": {
|
|
144
|
+
"type": "boolean"
|
|
145
|
+
},
|
|
146
|
+
"ingestPath": {
|
|
147
|
+
"type": "string"
|
|
148
|
+
},
|
|
125
149
|
"remotePath": {
|
|
126
150
|
"type": "string"
|
|
127
151
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-workspace-sync",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.4",
|
|
4
4
|
"description": "Workspace cloud sync via rclone — mailbox (inbox/outbox), mirror, or bisync (Dropbox, Google Drive, S3, OneDrive, 70+ providers)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"skills",
|
|
30
30
|
"openclaw.plugin.json",
|
|
31
31
|
"README.md",
|
|
32
|
+
"TROUBLESHOOTING.md",
|
|
32
33
|
"LICENSE"
|
|
33
34
|
],
|
|
34
35
|
"dependencies": {
|
|
@@ -47,8 +48,8 @@
|
|
|
47
48
|
},
|
|
48
49
|
"scripts": {
|
|
49
50
|
"build": "tsc",
|
|
50
|
-
"prepublishOnly": "
|
|
51
|
-
"
|
|
51
|
+
"prepublishOnly": "npm run build",
|
|
52
|
+
"render-readme": "node scripts/render-mermaid.js",
|
|
52
53
|
"test": "vitest run",
|
|
53
54
|
"test:watch": "vitest"
|
|
54
55
|
}
|