clawon 0.1.11 → 0.1.13

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.
Files changed (3) hide show
  1. package/README.md +22 -4
  2. package/dist/index.js +162 -3
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -56,9 +56,27 @@ npx clawon schedule off
56
56
  npx clawon schedule status
57
57
  ```
58
58
 
59
+ ### Workspaces
60
+
61
+ Workspaces organize your cloud snapshots by machine or environment — like GitHub repos for your backups. A default workspace is created automatically on login.
62
+
63
+ ```bash
64
+ # List your workspaces
65
+ npx clawon workspaces list
66
+
67
+ # Create a new workspace
68
+ npx clawon workspaces create "Work Server"
69
+
70
+ # Switch active workspace (affects backup/restore/list)
71
+ npx clawon workspaces switch work-server
72
+
73
+ # Show current workspace info
74
+ npx clawon workspaces info
75
+ ```
76
+
59
77
  ### Cloud Backups (requires account)
60
78
 
61
- Cloud backups sync your workspace to Clawon's servers for cross-machine access.
79
+ Cloud backups sync your workspace to Clawon's servers for cross-machine access. Snapshots are scoped to your current workspace.
62
80
 
63
81
  ```bash
64
82
  # Authenticate (env var recommended to avoid shell history)
@@ -72,7 +90,7 @@ npx clawon login --api-key <your-key>
72
90
  npx clawon backup
73
91
  npx clawon backup --tag "stable config"
74
92
  npx clawon backup --dry-run # Preview without uploading
75
- npx clawon backup --include-memory-db # Requires Pro account
93
+ npx clawon backup --include-memory-db # Requires Hobby or Pro
76
94
  npx clawon backup --include-sessions # Requires Hobby or Pro
77
95
 
78
96
  # List cloud backups
@@ -97,7 +115,7 @@ npx clawon discover # Show exactly which files would be backed up
97
115
  npx clawon discover --include-memory-db # Include SQLite memory index
98
116
  npx clawon discover --include-sessions # Include chat history
99
117
  npx clawon schedule status # Show active schedules
100
- npx clawon status # Connection status and file count
118
+ npx clawon status # Connection status, workspace, and file count
101
119
  npx clawon logout # Remove local credentials
102
120
  ```
103
121
 
@@ -169,7 +187,7 @@ Each archive contains:
169
187
 
170
188
  ## Configuration
171
189
 
172
- Config is stored at `~/.clawon/config.json` after running `clawon login`. Contains your API key, profile ID, and API URL. Run `clawon logout` to remove it.
190
+ Config is stored at `~/.clawon/config.json` after running `clawon login`. Contains your API key, profile ID, workspace, and API URL. Run `clawon logout` to remove it.
173
191
 
174
192
  ## Telemetry
175
193
 
package/dist/index.js CHANGED
@@ -255,12 +255,20 @@ program.command("login").description("Connect to Clawon with your API key").opti
255
255
  writeConfig({
256
256
  apiKey,
257
257
  profileId: connectJson.profileId,
258
+ workspaceId: connectJson.workspaceId || void 0,
259
+ workspaceSlug: connectJson.workspaceSlug || void 0,
258
260
  apiBaseUrl: opts.apiUrl,
259
261
  connectedAt: (/* @__PURE__ */ new Date()).toISOString()
260
262
  });
261
263
  console.log("\u2713 Logged in");
262
264
  console.log(` Profile ID: ${connectJson.profileId}`);
263
- trackCliEvent(connectJson.profileId, "cli_login");
265
+ if (connectJson.workspaceSlug) {
266
+ console.log(` Workspace: ${connectJson.workspaceSlug}`);
267
+ }
268
+ trackCliEvent(connectJson.profileId, "cli_login", {
269
+ workspace_slug: connectJson.workspaceSlug,
270
+ workspace_count: connectJson.workspaceCount ?? 1
271
+ });
264
272
  } catch (e) {
265
273
  console.error(`\u2717 Login failed: ${e.message}`);
266
274
  process.exit(1);
@@ -268,7 +276,7 @@ program.command("login").description("Connect to Clawon with your API key").opti
268
276
  });
269
277
  program.command("backup").description("Backup your OpenClaw workspace to the cloud").option("--dry-run", "Show what would be backed up without uploading").option("--tag <label>", "Add a label to this backup").option("--include-memory-db", "Include SQLite memory index").option("--include-sessions", "Include chat history (sessions)").option("--scheduled", "Internal: triggered by cron (suppresses interactive output)").action(async (opts) => {
270
278
  if (opts.includeMemoryDb) {
271
- console.error("\u2717 Memory DB cloud backup requires a Pro account. Use `clawon local backup --include-memory-db` for local backups.");
279
+ console.error("\u2717 Memory DB cloud backup requires a Hobby or Pro account. Use `clawon local backup --include-memory-db` for local backups.");
272
280
  process.exit(1);
273
281
  }
274
282
  if (opts.includeSessions) {
@@ -280,6 +288,11 @@ program.command("backup").description("Backup your OpenClaw workspace to the clo
280
288
  console.error("\u2717 Not logged in. Run: clawon login --api-key <key>");
281
289
  process.exit(1);
282
290
  }
291
+ if (!cfg.workspaceId) {
292
+ console.error("\u2717 No workspace selected. Run: clawon workspaces switch <slug>");
293
+ console.error(" Or re-login: clawon login --api-key <key>");
294
+ process.exit(1);
295
+ }
283
296
  if (!fs.existsSync(OPENCLAW_DIR)) {
284
297
  console.error(`\u2717 OpenClaw directory not found: ${OPENCLAW_DIR}`);
285
298
  process.exit(1);
@@ -314,6 +327,7 @@ program.command("backup").description("Backup your OpenClaw workspace to the clo
314
327
  cfg.apiKey,
315
328
  {
316
329
  profileId: cfg.profileId,
330
+ workspaceId: cfg.workspaceId,
317
331
  files: files.map((f) => ({ path: f.path, size: f.size })),
318
332
  ...opts.tag ? { tag: opts.tag } : {}
319
333
  }
@@ -350,6 +364,7 @@ program.command("backup").description("Backup your OpenClaw workspace to the clo
350
364
  include_memory_db: !!opts.includeMemoryDb,
351
365
  include_sessions: !!opts.includeSessions,
352
366
  type: "cloud",
367
+ workspace_slug: cfg.workspaceSlug,
353
368
  trigger: opts.scheduled ? "scheduled" : "manual"
354
369
  });
355
370
  } catch (e) {
@@ -434,9 +449,10 @@ program.command("list").description("List your backups").option("--limit <n>", "
434
449
  process.exit(1);
435
450
  }
436
451
  try {
452
+ const wsParam = cfg.workspaceId ? `&workspaceId=${cfg.workspaceId}` : "";
437
453
  const { snapshots } = await api(
438
454
  cfg.apiBaseUrl,
439
- `/api/v1/snapshots/list?profileId=${cfg.profileId}&limit=${opts.limit}`,
455
+ `/api/v1/snapshots/list?profileId=${cfg.profileId}&limit=${opts.limit}${wsParam}`,
440
456
  "GET",
441
457
  cfg.apiKey
442
458
  );
@@ -444,6 +460,10 @@ program.command("list").description("List your backups").option("--limit <n>", "
444
460
  console.log("No backups yet. Run: clawon backup");
445
461
  return;
446
462
  }
463
+ if (cfg.workspaceSlug) {
464
+ console.log(`Workspace: ${cfg.workspaceSlug}
465
+ `);
466
+ }
447
467
  console.log("Your backups:\n");
448
468
  console.log("ID | Date | Files | Size | Tag");
449
469
  console.log("\u2500".repeat(100));
@@ -916,12 +936,151 @@ local.command("restore").description("Restore from a local backup").option("--fi
916
936
  process.exit(1);
917
937
  }
918
938
  });
939
+ var workspaces = program.command("workspaces").description("Manage workspaces");
940
+ workspaces.command("list").description("List your workspaces").action(async () => {
941
+ const cfg = readConfig();
942
+ if (!cfg) {
943
+ console.error("\u2717 Not logged in. Run: clawon login --api-key <key>");
944
+ process.exit(1);
945
+ }
946
+ try {
947
+ const { workspaces: wsList } = await api(
948
+ cfg.apiBaseUrl,
949
+ `/api/v1/workspaces/list?profileId=${cfg.profileId}`,
950
+ "GET",
951
+ cfg.apiKey
952
+ );
953
+ if (!wsList?.length) {
954
+ console.log("No workspaces yet.");
955
+ return;
956
+ }
957
+ console.log("Your workspaces:\n");
958
+ console.log("Name | Slug | Snapshots | Last Backup");
959
+ console.log("\u2500".repeat(80));
960
+ for (const ws of wsList) {
961
+ const lastBackup = ws.lastBackupAt ? new Date(ws.lastBackupAt).toLocaleString() : "Never";
962
+ const current = ws.id === cfg.workspaceId ? " \u2190 current" : "";
963
+ console.log(
964
+ `${ws.name.padEnd(20)} | ${ws.slug.padEnd(20)} | ${String(ws.snapshotCount).padEnd(9)} | ${lastBackup}${current}`
965
+ );
966
+ }
967
+ console.log(`
968
+ Total: ${wsList.length} workspace(s)`);
969
+ trackCliEvent(cfg.profileId, "cli_workspaces_listed", { count: wsList.length });
970
+ } catch (e) {
971
+ console.error(`\u2717 Failed to list workspaces: ${e.message}`);
972
+ process.exit(1);
973
+ }
974
+ });
975
+ workspaces.command("create <name>").description("Create a new workspace").option("--description <desc>", "Workspace description").action(async (name, opts) => {
976
+ const cfg = readConfig();
977
+ if (!cfg) {
978
+ console.error("\u2717 Not logged in. Run: clawon login --api-key <key>");
979
+ process.exit(1);
980
+ }
981
+ try {
982
+ const { workspace } = await api(
983
+ cfg.apiBaseUrl,
984
+ "/api/v1/workspaces/create",
985
+ "POST",
986
+ cfg.apiKey,
987
+ {
988
+ profileId: cfg.profileId,
989
+ name,
990
+ ...opts.description ? { description: opts.description } : {}
991
+ }
992
+ );
993
+ console.log(`\u2713 Workspace created`);
994
+ console.log(` Name: ${workspace.name}`);
995
+ console.log(` Slug: ${workspace.slug}`);
996
+ console.log(`
997
+ Switch to it: clawon workspaces switch ${workspace.slug}`);
998
+ trackCliEvent(cfg.profileId, "workspace_created", { name, slug: workspace.slug });
999
+ } catch (e) {
1000
+ console.error(`\u2717 Failed to create workspace: ${e.message}`);
1001
+ process.exit(1);
1002
+ }
1003
+ });
1004
+ workspaces.command("switch <slug>").description("Switch to a different workspace").action(async (slug) => {
1005
+ const cfg = readConfig();
1006
+ if (!cfg) {
1007
+ console.error("\u2717 Not logged in. Run: clawon login --api-key <key>");
1008
+ process.exit(1);
1009
+ }
1010
+ try {
1011
+ const { workspaces: wsList } = await api(
1012
+ cfg.apiBaseUrl,
1013
+ `/api/v1/workspaces/list?profileId=${cfg.profileId}`,
1014
+ "GET",
1015
+ cfg.apiKey
1016
+ );
1017
+ const target = (wsList || []).find((w) => w.slug === slug);
1018
+ if (!target) {
1019
+ console.error(`\u2717 Workspace "${slug}" not found.`);
1020
+ console.error(" Available workspaces:");
1021
+ for (const ws of wsList || []) {
1022
+ console.error(` \u2022 ${ws.slug}`);
1023
+ }
1024
+ process.exit(1);
1025
+ }
1026
+ const previousSlug = cfg.workspaceSlug;
1027
+ updateConfig({ workspaceId: target.id, workspaceSlug: target.slug });
1028
+ console.log(`\u2713 Switched to workspace: ${target.name} (${target.slug})`);
1029
+ trackCliEvent(cfg.profileId, "workspace_switched", {
1030
+ from_slug: previousSlug,
1031
+ to_slug: target.slug
1032
+ });
1033
+ } catch (e) {
1034
+ console.error(`\u2717 Failed to switch workspace: ${e.message}`);
1035
+ process.exit(1);
1036
+ }
1037
+ });
1038
+ workspaces.command("info").description("Show current workspace info").action(async () => {
1039
+ const cfg = readConfig();
1040
+ if (!cfg) {
1041
+ console.error("\u2717 Not logged in. Run: clawon login --api-key <key>");
1042
+ process.exit(1);
1043
+ }
1044
+ if (!cfg.workspaceId) {
1045
+ console.log("No workspace selected. Run: clawon workspaces switch <slug>");
1046
+ return;
1047
+ }
1048
+ try {
1049
+ const { workspaces: wsList } = await api(
1050
+ cfg.apiBaseUrl,
1051
+ `/api/v1/workspaces/list?profileId=${cfg.profileId}`,
1052
+ "GET",
1053
+ cfg.apiKey
1054
+ );
1055
+ const current = (wsList || []).find((w) => w.id === cfg.workspaceId);
1056
+ if (!current) {
1057
+ console.log("Current workspace not found on server. It may have been deleted.");
1058
+ return;
1059
+ }
1060
+ console.log("Current Workspace\n");
1061
+ console.log(` Name: ${current.name}`);
1062
+ console.log(` Slug: ${current.slug}`);
1063
+ console.log(` Snapshots: ${current.snapshotCount}`);
1064
+ if (current.lastBackupAt) {
1065
+ console.log(` Last backup: ${new Date(current.lastBackupAt).toLocaleString()}`);
1066
+ }
1067
+ if (current.description) {
1068
+ console.log(` Description: ${current.description}`);
1069
+ }
1070
+ } catch (e) {
1071
+ console.error(`\u2717 Failed to get workspace info: ${e.message}`);
1072
+ process.exit(1);
1073
+ }
1074
+ });
919
1075
  program.command("status").description("Show current status").action(async () => {
920
1076
  const cfg = readConfig();
921
1077
  console.log("Clawon Status\n");
922
1078
  if (cfg) {
923
1079
  console.log(`\u2713 Logged in`);
924
1080
  console.log(` Profile ID: ${cfg.profileId}`);
1081
+ if (cfg.workspaceSlug) {
1082
+ console.log(` Workspace: ${cfg.workspaceSlug}`);
1083
+ }
925
1084
  console.log(` API: ${cfg.apiBaseUrl}`);
926
1085
  } else {
927
1086
  console.log(`\u2717 Not logged in`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawon",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Backup and restore your OpenClaw workspace",
5
5
  "type": "module",
6
6
  "bin": {