clawon 0.1.11 → 0.1.12

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 +161 -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,19 @@ 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
+ });
264
271
  } catch (e) {
265
272
  console.error(`\u2717 Login failed: ${e.message}`);
266
273
  process.exit(1);
@@ -268,7 +275,7 @@ program.command("login").description("Connect to Clawon with your API key").opti
268
275
  });
269
276
  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
277
  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.");
278
+ console.error("\u2717 Memory DB cloud backup requires a Hobby or Pro account. Use `clawon local backup --include-memory-db` for local backups.");
272
279
  process.exit(1);
273
280
  }
274
281
  if (opts.includeSessions) {
@@ -280,6 +287,11 @@ program.command("backup").description("Backup your OpenClaw workspace to the clo
280
287
  console.error("\u2717 Not logged in. Run: clawon login --api-key <key>");
281
288
  process.exit(1);
282
289
  }
290
+ if (!cfg.workspaceId) {
291
+ console.error("\u2717 No workspace selected. Run: clawon workspaces switch <slug>");
292
+ console.error(" Or re-login: clawon login --api-key <key>");
293
+ process.exit(1);
294
+ }
283
295
  if (!fs.existsSync(OPENCLAW_DIR)) {
284
296
  console.error(`\u2717 OpenClaw directory not found: ${OPENCLAW_DIR}`);
285
297
  process.exit(1);
@@ -314,6 +326,7 @@ program.command("backup").description("Backup your OpenClaw workspace to the clo
314
326
  cfg.apiKey,
315
327
  {
316
328
  profileId: cfg.profileId,
329
+ workspaceId: cfg.workspaceId,
317
330
  files: files.map((f) => ({ path: f.path, size: f.size })),
318
331
  ...opts.tag ? { tag: opts.tag } : {}
319
332
  }
@@ -350,6 +363,7 @@ program.command("backup").description("Backup your OpenClaw workspace to the clo
350
363
  include_memory_db: !!opts.includeMemoryDb,
351
364
  include_sessions: !!opts.includeSessions,
352
365
  type: "cloud",
366
+ workspace_slug: cfg.workspaceSlug,
353
367
  trigger: opts.scheduled ? "scheduled" : "manual"
354
368
  });
355
369
  } catch (e) {
@@ -434,9 +448,10 @@ program.command("list").description("List your backups").option("--limit <n>", "
434
448
  process.exit(1);
435
449
  }
436
450
  try {
451
+ const wsParam = cfg.workspaceId ? `&workspaceId=${cfg.workspaceId}` : "";
437
452
  const { snapshots } = await api(
438
453
  cfg.apiBaseUrl,
439
- `/api/v1/snapshots/list?profileId=${cfg.profileId}&limit=${opts.limit}`,
454
+ `/api/v1/snapshots/list?profileId=${cfg.profileId}&limit=${opts.limit}${wsParam}`,
440
455
  "GET",
441
456
  cfg.apiKey
442
457
  );
@@ -444,6 +459,10 @@ program.command("list").description("List your backups").option("--limit <n>", "
444
459
  console.log("No backups yet. Run: clawon backup");
445
460
  return;
446
461
  }
462
+ if (cfg.workspaceSlug) {
463
+ console.log(`Workspace: ${cfg.workspaceSlug}
464
+ `);
465
+ }
447
466
  console.log("Your backups:\n");
448
467
  console.log("ID | Date | Files | Size | Tag");
449
468
  console.log("\u2500".repeat(100));
@@ -916,12 +935,151 @@ local.command("restore").description("Restore from a local backup").option("--fi
916
935
  process.exit(1);
917
936
  }
918
937
  });
938
+ var workspaces = program.command("workspaces").description("Manage workspaces");
939
+ workspaces.command("list").description("List your workspaces").action(async () => {
940
+ const cfg = readConfig();
941
+ if (!cfg) {
942
+ console.error("\u2717 Not logged in. Run: clawon login --api-key <key>");
943
+ process.exit(1);
944
+ }
945
+ try {
946
+ const { workspaces: wsList } = await api(
947
+ cfg.apiBaseUrl,
948
+ `/api/v1/workspaces/list?profileId=${cfg.profileId}`,
949
+ "GET",
950
+ cfg.apiKey
951
+ );
952
+ if (!wsList?.length) {
953
+ console.log("No workspaces yet.");
954
+ return;
955
+ }
956
+ console.log("Your workspaces:\n");
957
+ console.log("Name | Slug | Snapshots | Last Backup");
958
+ console.log("\u2500".repeat(80));
959
+ for (const ws of wsList) {
960
+ const lastBackup = ws.lastBackupAt ? new Date(ws.lastBackupAt).toLocaleString() : "Never";
961
+ const current = ws.id === cfg.workspaceId ? " \u2190 current" : "";
962
+ console.log(
963
+ `${ws.name.padEnd(20)} | ${ws.slug.padEnd(20)} | ${String(ws.snapshotCount).padEnd(9)} | ${lastBackup}${current}`
964
+ );
965
+ }
966
+ console.log(`
967
+ Total: ${wsList.length} workspace(s)`);
968
+ trackCliEvent(cfg.profileId, "cli_workspaces_listed", { count: wsList.length });
969
+ } catch (e) {
970
+ console.error(`\u2717 Failed to list workspaces: ${e.message}`);
971
+ process.exit(1);
972
+ }
973
+ });
974
+ workspaces.command("create <name>").description("Create a new workspace").option("--description <desc>", "Workspace description").action(async (name, opts) => {
975
+ const cfg = readConfig();
976
+ if (!cfg) {
977
+ console.error("\u2717 Not logged in. Run: clawon login --api-key <key>");
978
+ process.exit(1);
979
+ }
980
+ try {
981
+ const { workspace } = await api(
982
+ cfg.apiBaseUrl,
983
+ "/api/v1/workspaces/create",
984
+ "POST",
985
+ cfg.apiKey,
986
+ {
987
+ profileId: cfg.profileId,
988
+ name,
989
+ ...opts.description ? { description: opts.description } : {}
990
+ }
991
+ );
992
+ console.log(`\u2713 Workspace created`);
993
+ console.log(` Name: ${workspace.name}`);
994
+ console.log(` Slug: ${workspace.slug}`);
995
+ console.log(`
996
+ Switch to it: clawon workspaces switch ${workspace.slug}`);
997
+ trackCliEvent(cfg.profileId, "workspace_created", { name, slug: workspace.slug });
998
+ } catch (e) {
999
+ console.error(`\u2717 Failed to create workspace: ${e.message}`);
1000
+ process.exit(1);
1001
+ }
1002
+ });
1003
+ workspaces.command("switch <slug>").description("Switch to a different workspace").action(async (slug) => {
1004
+ const cfg = readConfig();
1005
+ if (!cfg) {
1006
+ console.error("\u2717 Not logged in. Run: clawon login --api-key <key>");
1007
+ process.exit(1);
1008
+ }
1009
+ try {
1010
+ const { workspaces: wsList } = await api(
1011
+ cfg.apiBaseUrl,
1012
+ `/api/v1/workspaces/list?profileId=${cfg.profileId}`,
1013
+ "GET",
1014
+ cfg.apiKey
1015
+ );
1016
+ const target = (wsList || []).find((w) => w.slug === slug);
1017
+ if (!target) {
1018
+ console.error(`\u2717 Workspace "${slug}" not found.`);
1019
+ console.error(" Available workspaces:");
1020
+ for (const ws of wsList || []) {
1021
+ console.error(` \u2022 ${ws.slug}`);
1022
+ }
1023
+ process.exit(1);
1024
+ }
1025
+ const previousSlug = cfg.workspaceSlug;
1026
+ updateConfig({ workspaceId: target.id, workspaceSlug: target.slug });
1027
+ console.log(`\u2713 Switched to workspace: ${target.name} (${target.slug})`);
1028
+ trackCliEvent(cfg.profileId, "workspace_switched", {
1029
+ from_slug: previousSlug,
1030
+ to_slug: target.slug
1031
+ });
1032
+ } catch (e) {
1033
+ console.error(`\u2717 Failed to switch workspace: ${e.message}`);
1034
+ process.exit(1);
1035
+ }
1036
+ });
1037
+ workspaces.command("info").description("Show current workspace info").action(async () => {
1038
+ const cfg = readConfig();
1039
+ if (!cfg) {
1040
+ console.error("\u2717 Not logged in. Run: clawon login --api-key <key>");
1041
+ process.exit(1);
1042
+ }
1043
+ if (!cfg.workspaceId) {
1044
+ console.log("No workspace selected. Run: clawon workspaces switch <slug>");
1045
+ return;
1046
+ }
1047
+ try {
1048
+ const { workspaces: wsList } = await api(
1049
+ cfg.apiBaseUrl,
1050
+ `/api/v1/workspaces/list?profileId=${cfg.profileId}`,
1051
+ "GET",
1052
+ cfg.apiKey
1053
+ );
1054
+ const current = (wsList || []).find((w) => w.id === cfg.workspaceId);
1055
+ if (!current) {
1056
+ console.log("Current workspace not found on server. It may have been deleted.");
1057
+ return;
1058
+ }
1059
+ console.log("Current Workspace\n");
1060
+ console.log(` Name: ${current.name}`);
1061
+ console.log(` Slug: ${current.slug}`);
1062
+ console.log(` Snapshots: ${current.snapshotCount}`);
1063
+ if (current.lastBackupAt) {
1064
+ console.log(` Last backup: ${new Date(current.lastBackupAt).toLocaleString()}`);
1065
+ }
1066
+ if (current.description) {
1067
+ console.log(` Description: ${current.description}`);
1068
+ }
1069
+ } catch (e) {
1070
+ console.error(`\u2717 Failed to get workspace info: ${e.message}`);
1071
+ process.exit(1);
1072
+ }
1073
+ });
919
1074
  program.command("status").description("Show current status").action(async () => {
920
1075
  const cfg = readConfig();
921
1076
  console.log("Clawon Status\n");
922
1077
  if (cfg) {
923
1078
  console.log(`\u2713 Logged in`);
924
1079
  console.log(` Profile ID: ${cfg.profileId}`);
1080
+ if (cfg.workspaceSlug) {
1081
+ console.log(` Workspace: ${cfg.workspaceSlug}`);
1082
+ }
925
1083
  console.log(` API: ${cfg.apiBaseUrl}`);
926
1084
  } else {
927
1085
  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.12",
4
4
  "description": "Backup and restore your OpenClaw workspace",
5
5
  "type": "module",
6
6
  "bin": {