openclaw-workspace-sync 1.0.0 → 1.0.2
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 +5 -5
- package/dist/dist/index.d.ts +21 -0
- package/dist/dist/index.d.ts.map +1 -0
- package/dist/dist/index.js +527 -0
- package/dist/dist/index.js.map +1 -0
- package/dist/dist/rclone.d.ts +105 -0
- package/dist/dist/rclone.d.ts.map +1 -0
- package/dist/dist/rclone.js +391 -0
- package/dist/dist/rclone.js.map +1 -0
- package/dist/dist/sync-manager.d.ts +25 -0
- package/dist/dist/sync-manager.d.ts.map +1 -0
- package/dist/dist/sync-manager.js +173 -0
- package/dist/dist/sync-manager.js.map +1 -0
- package/dist/dist/types.d.ts +40 -0
- package/dist/dist/types.d.ts.map +1 -0
- package/dist/dist/types.js +2 -0
- package/dist/dist/types.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/openclaw.plugin.json +45 -14
- package/package.json +1 -1
- package/skills/workspace-sync/SKILL.md +1 -1
- package/skills/workspace-sync/scripts/setup.sh +0 -0
- package/skills/workspace-sync/scripts/status.sh +0 -0
- package/skills/workspace-sync/scripts/sync.sh +0 -0
- /package/dist/{vitest.config.d.ts → dist/vitest.config.d.ts} +0 -0
- /package/dist/{vitest.config.d.ts.map → dist/vitest.config.d.ts.map} +0 -0
- /package/dist/{vitest.config.js → dist/vitest.config.js} +0 -0
- /package/dist/{vitest.config.js.map → dist/vitest.config.js.map} +0 -0
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ Local Machine Cloud Provider Remote Gateway
|
|
|
21
21
|
## Install
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
openclaw plugins install
|
|
24
|
+
openclaw plugins install openclaw-workspace-sync
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
Or clone into your extensions directory:
|
|
@@ -57,7 +57,7 @@ Add to your `openclaw.json`:
|
|
|
57
57
|
{
|
|
58
58
|
"plugins": {
|
|
59
59
|
"entries": {
|
|
60
|
-
"workspace-sync": {
|
|
60
|
+
"openclaw-workspace-sync": {
|
|
61
61
|
"enabled": true,
|
|
62
62
|
"config": {
|
|
63
63
|
"provider": "dropbox",
|
|
@@ -292,13 +292,13 @@ chmod -R 755 <workspace>/shared
|
|
|
292
292
|
|
|
293
293
|
```bash
|
|
294
294
|
# Install dependencies
|
|
295
|
-
|
|
295
|
+
npm install
|
|
296
296
|
|
|
297
297
|
# Run tests
|
|
298
|
-
|
|
298
|
+
npm test
|
|
299
299
|
|
|
300
300
|
# Type check
|
|
301
|
-
|
|
301
|
+
npx tsc --noEmit
|
|
302
302
|
```
|
|
303
303
|
|
|
304
304
|
## License
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw Workspace Sync Plugin
|
|
3
|
+
*
|
|
4
|
+
* Bidirectional workspace cloud sync via rclone.
|
|
5
|
+
* Supports Dropbox, Google Drive, S3, OneDrive, and 70+ providers.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - CLI commands: openclaw workspace sync/status/setup/authorize/list
|
|
9
|
+
* - Background periodic sync (pure rclone, zero LLM cost)
|
|
10
|
+
* - Session start/end hooks for automatic sync
|
|
11
|
+
* - Config-driven rclone setup (no manual rclone config needed)
|
|
12
|
+
*/
|
|
13
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
14
|
+
declare const workspaceSyncPlugin: {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
register(api: OpenClawPluginApi): void;
|
|
19
|
+
};
|
|
20
|
+
export default workspaceSyncPlugin;
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAyB7D,QAAA,MAAM,mBAAmB;;;;kBAMT,iBAAiB;CAmmBhC,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw Workspace Sync Plugin
|
|
3
|
+
*
|
|
4
|
+
* Bidirectional workspace cloud sync via rclone.
|
|
5
|
+
* Supports Dropbox, Google Drive, S3, OneDrive, and 70+ providers.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - CLI commands: openclaw workspace sync/status/setup/authorize/list
|
|
9
|
+
* - Background periodic sync (pure rclone, zero LLM cost)
|
|
10
|
+
* - Session start/end hooks for automatic sync
|
|
11
|
+
* - Config-driven rclone setup (no manual rclone config needed)
|
|
12
|
+
*/
|
|
13
|
+
import * as clack from "@clack/prompts";
|
|
14
|
+
import { setLogger, isRcloneInstalled, ensureRcloneInstalled, isRcloneConfigured, ensureRcloneConfigFromConfig, resolveSyncConfig, runBisync, runSync, checkRemote, listRemote, authorizeRclone, writeRcloneConfig, generateRcloneConfig, } from "./rclone.js";
|
|
15
|
+
import { startSyncManager, stopSyncManager, getSyncManagerStatus } from "./sync-manager.js";
|
|
16
|
+
function parsePluginConfig(raw) {
|
|
17
|
+
if (!raw)
|
|
18
|
+
return {};
|
|
19
|
+
return raw;
|
|
20
|
+
}
|
|
21
|
+
const workspaceSyncPlugin = {
|
|
22
|
+
id: "openclaw-workspace-sync",
|
|
23
|
+
name: "Workspace Cloud Sync",
|
|
24
|
+
description: "Bidirectional workspace sync with cloud storage (Dropbox, Google Drive, S3, OneDrive, 70+ providers) via rclone",
|
|
25
|
+
register(api) {
|
|
26
|
+
const syncConfig = parsePluginConfig(api.pluginConfig);
|
|
27
|
+
setLogger(api.logger);
|
|
28
|
+
api.logger.info(`workspace-sync: registered (provider: ${syncConfig.provider ?? "not configured"})`);
|
|
29
|
+
// ========================================================================
|
|
30
|
+
// CLI Commands
|
|
31
|
+
// ========================================================================
|
|
32
|
+
api.registerCli(({ program, workspaceDir }) => {
|
|
33
|
+
const workspace = program
|
|
34
|
+
.command("workspace")
|
|
35
|
+
.description("Workspace management and cloud sync");
|
|
36
|
+
// openclaw workspace sync
|
|
37
|
+
workspace
|
|
38
|
+
.command("sync")
|
|
39
|
+
.description("Sync workspace with cloud storage")
|
|
40
|
+
.option("--agent <id>", "Agent ID (default: main)")
|
|
41
|
+
.option("--resync", "Force resync (required for first sync)")
|
|
42
|
+
.option("--dry-run", "Preview changes without syncing")
|
|
43
|
+
.option("--direction <dir>", "One-way sync: pull or push")
|
|
44
|
+
.option("-v, --verbose", "Verbose output")
|
|
45
|
+
.action(async (opts) => {
|
|
46
|
+
const cfgSync = syncConfig;
|
|
47
|
+
const wsDir = workspaceDir ?? process.cwd();
|
|
48
|
+
if (!cfgSync.provider || cfgSync.provider === "off") {
|
|
49
|
+
console.error("Workspace sync not configured.");
|
|
50
|
+
console.error("Run: openclaw workspace setup");
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
const installed = await isRcloneInstalled();
|
|
54
|
+
if (!installed) {
|
|
55
|
+
console.error("rclone not installed.");
|
|
56
|
+
console.error("Run: openclaw workspace setup");
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
const resolved = resolveSyncConfig(cfgSync, wsDir);
|
|
60
|
+
ensureRcloneConfigFromConfig(cfgSync, resolved.configPath, resolved.remoteName);
|
|
61
|
+
if (!isRcloneConfigured(resolved.configPath, resolved.remoteName)) {
|
|
62
|
+
console.error(`rclone not configured for remote "${resolved.remoteName}".`);
|
|
63
|
+
console.error("Run: openclaw workspace authorize");
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
console.log(`Syncing ${resolved.remoteName}:${resolved.remotePath}`);
|
|
67
|
+
console.log(`Local: ${resolved.localPath}`);
|
|
68
|
+
let result;
|
|
69
|
+
if (opts.direction) {
|
|
70
|
+
result = await runSync({
|
|
71
|
+
configPath: resolved.configPath,
|
|
72
|
+
remoteName: resolved.remoteName,
|
|
73
|
+
remotePath: resolved.remotePath,
|
|
74
|
+
localPath: resolved.localPath,
|
|
75
|
+
direction: opts.direction,
|
|
76
|
+
exclude: resolved.exclude,
|
|
77
|
+
dryRun: opts.dryRun,
|
|
78
|
+
verbose: opts.verbose,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
result = await runBisync({
|
|
83
|
+
configPath: resolved.configPath,
|
|
84
|
+
remoteName: resolved.remoteName,
|
|
85
|
+
remotePath: resolved.remotePath,
|
|
86
|
+
localPath: resolved.localPath,
|
|
87
|
+
conflictResolve: resolved.conflictResolve,
|
|
88
|
+
exclude: resolved.exclude,
|
|
89
|
+
copySymlinks: resolved.copySymlinks,
|
|
90
|
+
resync: opts.resync,
|
|
91
|
+
dryRun: opts.dryRun,
|
|
92
|
+
verbose: opts.verbose,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (result.ok) {
|
|
96
|
+
console.log("Sync completed");
|
|
97
|
+
if (result.filesTransferred) {
|
|
98
|
+
console.log(`Files transferred: ${result.filesTransferred}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
console.error(`Sync failed: ${result.error}`);
|
|
103
|
+
if (result.error?.includes("--resync")) {
|
|
104
|
+
console.error("First sync requires --resync: openclaw workspace sync --resync");
|
|
105
|
+
}
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
// openclaw workspace status
|
|
110
|
+
workspace
|
|
111
|
+
.command("status")
|
|
112
|
+
.description("Show workspace sync status")
|
|
113
|
+
.option("--agent <id>", "Agent ID (default: main)")
|
|
114
|
+
.option("-v, --verbose", "Verbose output")
|
|
115
|
+
.action(async (opts) => {
|
|
116
|
+
const cfgSync = syncConfig;
|
|
117
|
+
const wsDir = workspaceDir ?? process.cwd();
|
|
118
|
+
console.log("Workspace Sync Status");
|
|
119
|
+
console.log("");
|
|
120
|
+
if (!cfgSync.provider || cfgSync.provider === "off") {
|
|
121
|
+
console.log("Provider: not configured");
|
|
122
|
+
console.log("Configure in openclaw.json plugins.entries.workspace-sync.config");
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const resolved = resolveSyncConfig(cfgSync, wsDir);
|
|
126
|
+
console.log(`Provider: ${cfgSync.provider}`);
|
|
127
|
+
console.log(`Remote: ${resolved.remoteName}:${resolved.remotePath}`);
|
|
128
|
+
console.log(`Local: ${resolved.localPath}`);
|
|
129
|
+
console.log(`Config: ${resolved.configPath}`);
|
|
130
|
+
console.log("");
|
|
131
|
+
const installed = await isRcloneInstalled();
|
|
132
|
+
if (!installed) {
|
|
133
|
+
console.log("rclone: NOT installed");
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
console.log("rclone: installed");
|
|
137
|
+
ensureRcloneConfigFromConfig(cfgSync, resolved.configPath, resolved.remoteName);
|
|
138
|
+
const configured = isRcloneConfigured(resolved.configPath, resolved.remoteName);
|
|
139
|
+
if (!configured) {
|
|
140
|
+
console.log("rclone config: NOT configured");
|
|
141
|
+
console.log("Run: openclaw workspace authorize");
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
console.log("rclone config: OK");
|
|
145
|
+
const check = await checkRemote({
|
|
146
|
+
configPath: resolved.configPath,
|
|
147
|
+
remoteName: resolved.remoteName,
|
|
148
|
+
});
|
|
149
|
+
if (!check.ok) {
|
|
150
|
+
console.log(`Connection: FAILED (${check.error})`);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
console.log("Connection: OK");
|
|
154
|
+
const list = await listRemote({
|
|
155
|
+
configPath: resolved.configPath,
|
|
156
|
+
remoteName: resolved.remoteName,
|
|
157
|
+
remotePath: resolved.remotePath,
|
|
158
|
+
});
|
|
159
|
+
if (list.ok) {
|
|
160
|
+
console.log("");
|
|
161
|
+
console.log(`Remote files: ${list.files.length}`);
|
|
162
|
+
if (opts.verbose && list.files.length > 0) {
|
|
163
|
+
for (const file of list.files.slice(0, 10)) {
|
|
164
|
+
console.log(` ${file}`);
|
|
165
|
+
}
|
|
166
|
+
if (list.files.length > 10) {
|
|
167
|
+
console.log(` ... and ${list.files.length - 10} more`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Background sync manager status
|
|
172
|
+
const mgrStatus = getSyncManagerStatus();
|
|
173
|
+
console.log("");
|
|
174
|
+
console.log("Background sync:");
|
|
175
|
+
console.log(` Running: ${mgrStatus.running ? "yes" : "no"}`);
|
|
176
|
+
console.log(` On session start: ${resolved.onSessionStart ? "yes" : "no"}`);
|
|
177
|
+
console.log(` On session end: ${resolved.onSessionEnd ? "yes" : "no"}`);
|
|
178
|
+
if (resolved.interval > 0) {
|
|
179
|
+
console.log(` Interval: ${resolved.interval}s (pure rclone, zero LLM cost)`);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
console.log(" Interval: disabled");
|
|
183
|
+
}
|
|
184
|
+
if (mgrStatus.lastSyncAt) {
|
|
185
|
+
console.log(` Last sync: ${mgrStatus.lastSyncAt.toISOString()}`);
|
|
186
|
+
console.log(` Last sync OK: ${mgrStatus.lastSyncOk}`);
|
|
187
|
+
console.log(` Total syncs: ${mgrStatus.syncCount}`);
|
|
188
|
+
console.log(` Errors: ${mgrStatus.errorCount}`);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
// openclaw workspace setup — interactive wizard
|
|
192
|
+
workspace
|
|
193
|
+
.command("setup")
|
|
194
|
+
.description("Interactive setup wizard for cloud sync")
|
|
195
|
+
.action(async () => {
|
|
196
|
+
clack.intro("Workspace Cloud Sync Setup");
|
|
197
|
+
const rcloneInstalled = await isRcloneInstalled();
|
|
198
|
+
if (!rcloneInstalled) {
|
|
199
|
+
const installed = await ensureRcloneInstalled(async (message, defaultValue) => {
|
|
200
|
+
const result = await clack.confirm({ message, initialValue: defaultValue });
|
|
201
|
+
return !clack.isCancel(result) && result;
|
|
202
|
+
});
|
|
203
|
+
if (!installed) {
|
|
204
|
+
clack.note("Install rclone manually:\n\n" +
|
|
205
|
+
" macOS: brew install rclone\n" +
|
|
206
|
+
" Linux: curl -s https://rclone.org/install.sh | sudo bash\n" +
|
|
207
|
+
" Docker: Add to Dockerfile: RUN curl -s https://rclone.org/install.sh | bash", "Installation required");
|
|
208
|
+
clack.outro("Install rclone and run this command again.");
|
|
209
|
+
process.exit(1);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
clack.log.success("rclone is installed");
|
|
214
|
+
const provider = (await clack.select({
|
|
215
|
+
message: "Select cloud provider",
|
|
216
|
+
options: [
|
|
217
|
+
{ value: "dropbox", label: "Dropbox", hint: "Recommended - easy setup" },
|
|
218
|
+
{ value: "gdrive", label: "Google Drive", hint: "Requires service account" },
|
|
219
|
+
{ value: "onedrive", label: "OneDrive", hint: "Microsoft 365" },
|
|
220
|
+
{ value: "s3", label: "S3 / R2 / Minio", hint: "Access key authentication" },
|
|
221
|
+
],
|
|
222
|
+
}));
|
|
223
|
+
if (clack.isCancel(provider)) {
|
|
224
|
+
clack.cancel("Setup cancelled.");
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const remotePath = (await clack.text({
|
|
228
|
+
message: "Remote folder name",
|
|
229
|
+
placeholder: "openclaw-share",
|
|
230
|
+
initialValue: "openclaw-share",
|
|
231
|
+
validate: (value = "") => {
|
|
232
|
+
if (!value.trim())
|
|
233
|
+
return "Folder name is required";
|
|
234
|
+
if (value.includes("/"))
|
|
235
|
+
return "Use a simple folder name, not a path";
|
|
236
|
+
return undefined;
|
|
237
|
+
},
|
|
238
|
+
}));
|
|
239
|
+
if (clack.isCancel(remotePath)) {
|
|
240
|
+
clack.cancel("Setup cancelled.");
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
let appKey;
|
|
244
|
+
let appSecret;
|
|
245
|
+
if (provider === "dropbox") {
|
|
246
|
+
const accessType = (await clack.select({
|
|
247
|
+
message: "Dropbox access type",
|
|
248
|
+
options: [
|
|
249
|
+
{ value: "full", label: "Full Dropbox", hint: "Simpler setup" },
|
|
250
|
+
{ value: "app", label: "App Folder only", hint: "More secure" },
|
|
251
|
+
],
|
|
252
|
+
}));
|
|
253
|
+
if (clack.isCancel(accessType)) {
|
|
254
|
+
clack.cancel("Setup cancelled.");
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (accessType === "app") {
|
|
258
|
+
clack.note("1. Go to https://www.dropbox.com/developers/apps\n" +
|
|
259
|
+
"2. Create app: Scoped access > App folder\n" +
|
|
260
|
+
"3. Enable: files.metadata.read/write, files.content.read/write\n" +
|
|
261
|
+
"4. Copy App key and App secret", "Create Dropbox App");
|
|
262
|
+
appKey = (await clack.text({
|
|
263
|
+
message: "Dropbox App key",
|
|
264
|
+
placeholder: "your-app-key",
|
|
265
|
+
}));
|
|
266
|
+
if (clack.isCancel(appKey)) {
|
|
267
|
+
clack.cancel("Setup cancelled.");
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
appSecret = (await clack.text({
|
|
271
|
+
message: "Dropbox App secret",
|
|
272
|
+
placeholder: "your-app-secret",
|
|
273
|
+
}));
|
|
274
|
+
if (clack.isCancel(appSecret)) {
|
|
275
|
+
clack.cancel("Setup cancelled.");
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const intervalChoice = (await clack.select({
|
|
281
|
+
message: "Background sync interval",
|
|
282
|
+
options: [
|
|
283
|
+
{ value: "0", label: "Manual only", hint: "Run 'openclaw workspace sync' when needed" },
|
|
284
|
+
{ value: "300", label: "Every 5 minutes", hint: "Recommended" },
|
|
285
|
+
{ value: "600", label: "Every 10 minutes" },
|
|
286
|
+
{ value: "1800", label: "Every 30 minutes" },
|
|
287
|
+
{ value: "3600", label: "Every hour" },
|
|
288
|
+
],
|
|
289
|
+
}));
|
|
290
|
+
if (clack.isCancel(intervalChoice)) {
|
|
291
|
+
clack.cancel("Setup cancelled.");
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const interval = parseInt(intervalChoice, 10);
|
|
295
|
+
const onSessionStart = (await clack.confirm({
|
|
296
|
+
message: "Sync when session starts?",
|
|
297
|
+
initialValue: true,
|
|
298
|
+
}));
|
|
299
|
+
if (clack.isCancel(onSessionStart)) {
|
|
300
|
+
clack.cancel("Setup cancelled.");
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
// OAuth authorization
|
|
304
|
+
clack.log.info("Starting OAuth authorization...");
|
|
305
|
+
clack.note("A browser window will open.\nLog in and authorize access, then return here.", "Authorization");
|
|
306
|
+
const authResult = await authorizeRclone(provider, appKey, appSecret);
|
|
307
|
+
if (!authResult.ok) {
|
|
308
|
+
clack.log.error(`Authorization failed: ${authResult.error}`);
|
|
309
|
+
clack.outro("Fix the error and run 'openclaw workspace setup' again.");
|
|
310
|
+
process.exit(1);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
clack.log.success("Authorization successful");
|
|
314
|
+
// Save rclone config
|
|
315
|
+
const stateDir = process.env.OPENCLAW_STATE_DIR ?? `${process.env.HOME}/.openclaw`;
|
|
316
|
+
const configPath = `${stateDir}/.config/rclone/rclone.conf`;
|
|
317
|
+
const remoteName = "cloud";
|
|
318
|
+
const configContent = generateRcloneConfig(provider, remoteName, authResult.token, {
|
|
319
|
+
dropbox: appKey ? { appKey, appSecret } : undefined,
|
|
320
|
+
});
|
|
321
|
+
writeRcloneConfig(configPath, configContent);
|
|
322
|
+
clack.log.success(`rclone config saved to ${configPath}`);
|
|
323
|
+
// Print config snippet for user to add to openclaw.json
|
|
324
|
+
clack.note(`Add to your openclaw.json:\n\n` +
|
|
325
|
+
`"plugins": {\n` +
|
|
326
|
+
` "entries": {\n` +
|
|
327
|
+
` "workspace-sync": {\n` +
|
|
328
|
+
` "enabled": true,\n` +
|
|
329
|
+
` "config": {\n` +
|
|
330
|
+
` "provider": "${provider}",\n` +
|
|
331
|
+
` "remotePath": "${remotePath.trim()}",\n` +
|
|
332
|
+
` "interval": ${interval},\n` +
|
|
333
|
+
` "onSessionStart": ${onSessionStart}\n` +
|
|
334
|
+
` }\n` +
|
|
335
|
+
` }\n` +
|
|
336
|
+
` }\n` +
|
|
337
|
+
`}`, "Plugin Configuration");
|
|
338
|
+
clack.outro("Workspace sync configured! Run: openclaw workspace sync --resync");
|
|
339
|
+
});
|
|
340
|
+
// openclaw workspace authorize
|
|
341
|
+
workspace
|
|
342
|
+
.command("authorize")
|
|
343
|
+
.description("Authorize rclone with cloud provider")
|
|
344
|
+
.option("--provider <name>", "Provider: dropbox, gdrive, onedrive, s3")
|
|
345
|
+
.option("--app-key <key>", "Dropbox app key")
|
|
346
|
+
.option("--app-secret <secret>", "Dropbox app secret")
|
|
347
|
+
.action(async (opts) => {
|
|
348
|
+
const provider = opts.provider ||
|
|
349
|
+
syncConfig.provider ||
|
|
350
|
+
"dropbox";
|
|
351
|
+
if (provider === "off" || provider === "custom") {
|
|
352
|
+
console.error("Please specify a provider: --provider dropbox");
|
|
353
|
+
process.exit(1);
|
|
354
|
+
}
|
|
355
|
+
const installed = await isRcloneInstalled();
|
|
356
|
+
if (!installed) {
|
|
357
|
+
console.error("rclone not installed.");
|
|
358
|
+
console.error("Install: curl -s https://rclone.org/install.sh | bash");
|
|
359
|
+
process.exit(1);
|
|
360
|
+
}
|
|
361
|
+
console.log(`Authorizing with ${provider}...`);
|
|
362
|
+
console.log("A browser window will open for authentication.");
|
|
363
|
+
console.log("");
|
|
364
|
+
const result = await authorizeRclone(provider, opts.appKey || syncConfig.dropbox?.appKey, opts.appSecret || syncConfig.dropbox?.appSecret);
|
|
365
|
+
if (!result.ok) {
|
|
366
|
+
console.error(`Authorization failed: ${result.error}`);
|
|
367
|
+
process.exit(1);
|
|
368
|
+
}
|
|
369
|
+
console.log("Authorization successful");
|
|
370
|
+
const stateDir = process.env.OPENCLAW_STATE_DIR ?? `${process.env.HOME}/.openclaw`;
|
|
371
|
+
const remoteName = syncConfig.remoteName || "cloud";
|
|
372
|
+
const configPath = syncConfig.configPath || `${stateDir}/.config/rclone/rclone.conf`;
|
|
373
|
+
const configContent = generateRcloneConfig(provider, remoteName, result.token, {
|
|
374
|
+
dropbox: syncConfig.dropbox,
|
|
375
|
+
s3: syncConfig.s3,
|
|
376
|
+
});
|
|
377
|
+
writeRcloneConfig(configPath, configContent);
|
|
378
|
+
console.log(`Config saved to: ${configPath}`);
|
|
379
|
+
console.log("");
|
|
380
|
+
console.log("Next: openclaw workspace sync --resync");
|
|
381
|
+
});
|
|
382
|
+
// openclaw workspace list
|
|
383
|
+
workspace
|
|
384
|
+
.command("list")
|
|
385
|
+
.description("List files in remote storage")
|
|
386
|
+
.option("--agent <id>", "Agent ID (default: main)")
|
|
387
|
+
.action(async (opts) => {
|
|
388
|
+
const cfgSync = syncConfig;
|
|
389
|
+
const wsDir = workspaceDir ?? process.cwd();
|
|
390
|
+
if (!cfgSync.provider || cfgSync.provider === "off") {
|
|
391
|
+
console.error("Workspace sync not configured.");
|
|
392
|
+
process.exit(1);
|
|
393
|
+
}
|
|
394
|
+
const resolved = resolveSyncConfig(cfgSync, wsDir);
|
|
395
|
+
ensureRcloneConfigFromConfig(cfgSync, resolved.configPath, resolved.remoteName);
|
|
396
|
+
if (!isRcloneConfigured(resolved.configPath, resolved.remoteName)) {
|
|
397
|
+
console.error("rclone not configured.");
|
|
398
|
+
console.error("Run: openclaw workspace authorize");
|
|
399
|
+
process.exit(1);
|
|
400
|
+
}
|
|
401
|
+
const result = await listRemote({
|
|
402
|
+
configPath: resolved.configPath,
|
|
403
|
+
remoteName: resolved.remoteName,
|
|
404
|
+
remotePath: resolved.remotePath,
|
|
405
|
+
});
|
|
406
|
+
if (!result.ok) {
|
|
407
|
+
console.error(`Failed to list: ${result.error}`);
|
|
408
|
+
process.exit(1);
|
|
409
|
+
}
|
|
410
|
+
if (result.files.length === 0) {
|
|
411
|
+
console.log("No files in remote.");
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
console.log(`${resolved.remoteName}:${resolved.remotePath}/`);
|
|
415
|
+
for (const file of result.files) {
|
|
416
|
+
console.log(` ${file}`);
|
|
417
|
+
}
|
|
418
|
+
console.log(`\n${result.files.length} files`);
|
|
419
|
+
});
|
|
420
|
+
}, { commands: ["workspace"] });
|
|
421
|
+
// ========================================================================
|
|
422
|
+
// Session Hooks
|
|
423
|
+
// ========================================================================
|
|
424
|
+
if (syncConfig.onSessionStart) {
|
|
425
|
+
api.on("session_start", async (_event, ctx) => {
|
|
426
|
+
if (!syncConfig.provider || syncConfig.provider === "off")
|
|
427
|
+
return;
|
|
428
|
+
api.logger.info("[workspace-sync] triggered on session start");
|
|
429
|
+
try {
|
|
430
|
+
const installed = await isRcloneInstalled();
|
|
431
|
+
if (!installed) {
|
|
432
|
+
api.logger.warn("[workspace-sync] rclone not installed, skipping sync");
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
const wsDir = ctx.agentId
|
|
436
|
+
? api.resolvePath(`agents/${ctx.agentId}/workspace`)
|
|
437
|
+
: api.resolvePath("workspace");
|
|
438
|
+
const resolved = resolveSyncConfig(syncConfig, wsDir);
|
|
439
|
+
ensureRcloneConfigFromConfig(syncConfig, resolved.configPath, resolved.remoteName);
|
|
440
|
+
if (!isRcloneConfigured(resolved.configPath, resolved.remoteName)) {
|
|
441
|
+
api.logger.warn(`[workspace-sync] rclone not configured for "${resolved.remoteName}", skipping`);
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
api.logger.info(`[workspace-sync] syncing ${resolved.remoteName}:${resolved.remotePath} <-> ${resolved.localPath}`);
|
|
445
|
+
const result = await runBisync({
|
|
446
|
+
configPath: resolved.configPath,
|
|
447
|
+
remoteName: resolved.remoteName,
|
|
448
|
+
remotePath: resolved.remotePath,
|
|
449
|
+
localPath: resolved.localPath,
|
|
450
|
+
conflictResolve: resolved.conflictResolve,
|
|
451
|
+
exclude: resolved.exclude,
|
|
452
|
+
copySymlinks: resolved.copySymlinks,
|
|
453
|
+
});
|
|
454
|
+
if (result.ok) {
|
|
455
|
+
api.logger.info("[workspace-sync] session start sync completed");
|
|
456
|
+
}
|
|
457
|
+
else if (result.error?.includes("--resync")) {
|
|
458
|
+
api.logger.warn("[workspace-sync] first sync requires manual --resync. Run: openclaw workspace sync --resync");
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
api.logger.error(`[workspace-sync] sync failed: ${result.error}`);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
catch (err) {
|
|
465
|
+
api.logger.error(`[workspace-sync] error: ${err instanceof Error ? err.message : String(err)}`);
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
if (syncConfig.onSessionEnd) {
|
|
470
|
+
api.on("session_end", async (_event, ctx) => {
|
|
471
|
+
if (!syncConfig.provider || syncConfig.provider === "off")
|
|
472
|
+
return;
|
|
473
|
+
api.logger.info("[workspace-sync] triggered on session end");
|
|
474
|
+
try {
|
|
475
|
+
const installed = await isRcloneInstalled();
|
|
476
|
+
if (!installed)
|
|
477
|
+
return;
|
|
478
|
+
const wsDir = ctx.agentId
|
|
479
|
+
? api.resolvePath(`agents/${ctx.agentId}/workspace`)
|
|
480
|
+
: api.resolvePath("workspace");
|
|
481
|
+
const resolved = resolveSyncConfig(syncConfig, wsDir);
|
|
482
|
+
ensureRcloneConfigFromConfig(syncConfig, resolved.configPath, resolved.remoteName);
|
|
483
|
+
if (!isRcloneConfigured(resolved.configPath, resolved.remoteName))
|
|
484
|
+
return;
|
|
485
|
+
const result = await runBisync({
|
|
486
|
+
configPath: resolved.configPath,
|
|
487
|
+
remoteName: resolved.remoteName,
|
|
488
|
+
remotePath: resolved.remotePath,
|
|
489
|
+
localPath: resolved.localPath,
|
|
490
|
+
conflictResolve: resolved.conflictResolve,
|
|
491
|
+
exclude: resolved.exclude,
|
|
492
|
+
copySymlinks: resolved.copySymlinks,
|
|
493
|
+
});
|
|
494
|
+
if (result.ok) {
|
|
495
|
+
api.logger.info("[workspace-sync] session end sync completed");
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
api.logger.error(`[workspace-sync] sync failed: ${result.error}`);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
catch (err) {
|
|
502
|
+
api.logger.error(`[workspace-sync] error: ${err instanceof Error ? err.message : String(err)}`);
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
// ========================================================================
|
|
507
|
+
// Background Sync Service
|
|
508
|
+
// ========================================================================
|
|
509
|
+
api.registerService({
|
|
510
|
+
id: "openclaw-workspace-sync",
|
|
511
|
+
start: (ctx) => {
|
|
512
|
+
if (!syncConfig.provider || syncConfig.provider === "off") {
|
|
513
|
+
api.logger.info("[workspace-sync] service: sync not configured, idle");
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const wsDir = ctx.workspaceDir ?? api.resolvePath("workspace");
|
|
517
|
+
startSyncManager(syncConfig, wsDir, ctx.stateDir, ctx.logger);
|
|
518
|
+
},
|
|
519
|
+
stop: () => {
|
|
520
|
+
stopSyncManager();
|
|
521
|
+
api.logger.info("[workspace-sync] service stopped");
|
|
522
|
+
},
|
|
523
|
+
});
|
|
524
|
+
},
|
|
525
|
+
};
|
|
526
|
+
export default workspaceSyncPlugin;
|
|
527
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|