@storacha/clawracha 0.0.2 → 0.0.3

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 CHANGED
@@ -21,14 +21,41 @@ openclaw plugins install @storacha/clawracha
21
21
 
22
22
  ## Setup
23
23
 
24
- ```bash
25
- # Initialize sync for this workspace
26
- openclaw storacha init
24
+ Setup is done via slash commands in your chat session with the agent (not CLI commands).
25
+
26
+ ### New workspace (first device)
27
+
28
+ ```
29
+ /storacha-init <upload-delegation-b64>
30
+ ```
31
+
32
+ Creates a fresh workspace with a new UCN Name. You'll need an upload delegation from a Storacha space owner.
33
+
34
+ ### Join an existing workspace (additional devices)
35
+
36
+ ```
37
+ /storacha-join <upload-delegation-b64> <name-delegation-b64>
38
+ ```
39
+
40
+ Joins an existing workspace from another device. Both delegations are required — get them by running `/storacha-grant` on the existing device. The join command pulls all remote files before the watcher starts, so your local workspace is fully synced from the start.
27
41
 
28
- # Import a delegation from a space owner
29
- openclaw storacha delegate <base64-delegation>
42
+ ### Grant access to another device
30
43
 
31
- # Restart gateway to start syncing
44
+ ```
45
+ /storacha-grant <target-agent-DID>
46
+ ```
47
+
48
+ Generates upload and name delegations for the target device. The target device uses these with `/storacha-join`.
49
+
50
+ ### Check status
51
+
52
+ ```
53
+ /storacha-status
54
+ ```
55
+
56
+ After setup, restart the gateway to start syncing:
57
+
58
+ ```bash
32
59
  openclaw gateway restart
33
60
  ```
34
61
 
@@ -108,7 +135,7 @@ The plugin provides tools for manual sync control:
108
135
 
109
136
  The plugin stores data in `.storacha/` within the workspace:
110
137
 
111
- - `config.json` - Agent key, delegation, name archive (NOT synced)
138
+ - `config.json` - Agent key, delegations, name archive (NOT synced)
112
139
  - `blocks/` - Local block cache (NOT synced)
113
140
 
114
141
  Add `.storacha/` to your `.gitignore`.
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,qBAAqB,CAAC;AAwC7B;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,GAAG,EAAE,iBAAiB,QAqapD"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,qBAAqB,CAAC;AAwC7B;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,GAAG,EAAE,iBAAiB,QA6apD"}
package/dist/plugin.js CHANGED
@@ -44,10 +44,16 @@ async function saveDeviceConfig(workspace, config) {
44
44
  * Plugin entry — called by OpenClaw when the plugin is loaded.
45
45
  */
46
46
  export default function plugin(api) {
47
+ // Capture plugin-specific config at registration time
48
+ const pluginConfig = (api.pluginConfig ?? {});
47
49
  // Register background service
48
50
  api.registerService({
49
51
  id: "storacha-sync",
50
52
  async start(ctx) {
53
+ if (pluginConfig.enabled === false) {
54
+ ctx.logger.info("Storacha sync disabled via config.");
55
+ return;
56
+ }
51
57
  workspaceDir = ctx.workspaceDir;
52
58
  const workspace = workspaceDir;
53
59
  if (!workspace) {
@@ -66,8 +72,8 @@ export default function plugin(api) {
66
72
  workspace,
67
73
  config: {
68
74
  enabled: true,
69
- watchPatterns: ["**/*"],
70
- ignorePatterns: [
75
+ watchPatterns: pluginConfig.watchPatterns ?? ["**/*"],
76
+ ignorePatterns: pluginConfig.ignorePatterns ?? [
71
77
  ".storacha/**",
72
78
  "node_modules/**",
73
79
  ".git/**",
@@ -84,7 +90,7 @@ export default function plugin(api) {
84
90
  await saveDeviceConfig(workspace, updatedConfig);
85
91
  },
86
92
  });
87
- fileWatcher.start();
93
+ await fileWatcher.start();
88
94
  ctx.logger.info("Started watching workspace");
89
95
  },
90
96
  async stop(ctx) {
package/dist/watcher.d.ts CHANGED
@@ -21,7 +21,7 @@ export declare class FileWatcher {
21
21
  /**
22
22
  * Start watching the workspace
23
23
  */
24
- start(): void;
24
+ start(): Promise<void>;
25
25
  /**
26
26
  * Stop watching
27
27
  */
@@ -1 +1 @@
1
- {"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAErE,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,gBAAgB,CAAC;IACzB,SAAS,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,EAAE,cAAc;IAKnC;;OAEG;IACH,KAAK,IAAI,IAAI;IA+Bb;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;YACW,KAAK;IAanB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAOlC"}
1
+ {"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAErE,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,gBAAgB,CAAC;IACzB,SAAS,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAoBD,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,EAAE,cAAc;IAKnC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmC5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;YACW,KAAK;IAanB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAOlC"}
package/dist/watcher.js CHANGED
@@ -5,7 +5,27 @@
5
5
  * before triggering sync.
6
6
  */
7
7
  import chokidar from "chokidar";
8
+ import * as fs from "node:fs/promises";
8
9
  import * as path from "node:path";
10
+ /**
11
+ * Read .clawrachaignore from workspace root (gitignore-style).
12
+ * Returns parsed patterns, or empty array if file doesn't exist.
13
+ */
14
+ async function readIgnoreFile(workspace) {
15
+ const ignorePath = path.join(workspace, ".clawrachaignore");
16
+ try {
17
+ const content = await fs.readFile(ignorePath, "utf-8");
18
+ return content
19
+ .split("\n")
20
+ .map((line) => line.trim())
21
+ .filter((line) => line && !line.startsWith("#"));
22
+ }
23
+ catch (err) {
24
+ if (err.code === "ENOENT")
25
+ return [];
26
+ throw err;
27
+ }
28
+ }
9
29
  export class FileWatcher {
10
30
  watcher = null;
11
31
  pendingChanges = new Map();
@@ -19,15 +39,18 @@ export class FileWatcher {
19
39
  /**
20
40
  * Start watching the workspace
21
41
  */
22
- start() {
42
+ async start() {
23
43
  if (this.watcher)
24
44
  return;
25
45
  const { workspace, config } = this.options;
46
+ // Read workspace-level ignore file
47
+ const userIgnored = await readIgnoreFile(workspace);
26
48
  // Build watch patterns
27
49
  const watchPaths = config.watchPatterns.map((p) => path.join(workspace, p));
28
50
  // Build ignore patterns
29
51
  const ignored = [
30
52
  ...config.ignorePatterns,
53
+ ...userIgnored,
31
54
  ".storacha/**", // Always ignore our own data
32
55
  ];
33
56
  this.watcher = chokidar.watch(watchPaths, {
@@ -5,7 +5,7 @@
5
5
  "description": "Sync OpenClaw workspaces to Storacha via UCN Pail",
6
6
  "entry": "./src/plugin.ts",
7
7
  "skills": [],
8
- "config": {
8
+ "configSchema": {
9
9
  "type": "object",
10
10
  "properties": {
11
11
  "enabled": {
@@ -16,7 +16,7 @@
16
16
  "watchPatterns": {
17
17
  "type": "array",
18
18
  "items": { "type": "string" },
19
- "default": ["**/*.md"],
19
+ "default": ["**/*"],
20
20
  "description": "Glob patterns to watch for sync"
21
21
  },
22
22
  "ignorePatterns": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storacha/clawracha",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "OpenClaw plugin for Storacha workspace sync via UCN Pail",
5
5
  "type": "module",
6
6
  "main": "dist/plugin.js",
package/src/plugin.ts CHANGED
@@ -15,7 +15,7 @@ import type {
15
15
  OpenClawPluginServiceContext,
16
16
  AnyAgentTool,
17
17
  } from "openclaw/plugin-sdk";
18
- import type { DeviceConfig } from "./types/index.js";
18
+ import type { DeviceConfig, SyncPluginConfig } from "./types/index.js";
19
19
  import { SyncEngine } from "./sync.js";
20
20
  import { FileWatcher } from "./watcher.js";
21
21
  import { createStorachaClient } from "./utils/client.js";
@@ -58,10 +58,18 @@ async function saveDeviceConfig(
58
58
  * Plugin entry — called by OpenClaw when the plugin is loaded.
59
59
  */
60
60
  export default function plugin(api: OpenClawPluginApi) {
61
+ // Capture plugin-specific config at registration time
62
+ const pluginConfig = (api.pluginConfig ?? {}) as Partial<SyncPluginConfig>;
63
+
61
64
  // Register background service
62
65
  api.registerService({
63
66
  id: "storacha-sync",
64
67
  async start(ctx: OpenClawPluginServiceContext) {
68
+ if (pluginConfig.enabled === false) {
69
+ ctx.logger.info("Storacha sync disabled via config.");
70
+ return;
71
+ }
72
+
65
73
  workspaceDir = ctx.workspaceDir;
66
74
  const workspace = workspaceDir;
67
75
  if (!workspace) {
@@ -85,8 +93,8 @@ export default function plugin(api: OpenClawPluginApi) {
85
93
  workspace,
86
94
  config: {
87
95
  enabled: true,
88
- watchPatterns: ["**/*"],
89
- ignorePatterns: [
96
+ watchPatterns: pluginConfig.watchPatterns ?? ["**/*"],
97
+ ignorePatterns: pluginConfig.ignorePatterns ?? [
90
98
  ".storacha/**",
91
99
  "node_modules/**",
92
100
  ".git/**",
@@ -104,7 +112,7 @@ export default function plugin(api: OpenClawPluginApi) {
104
112
  },
105
113
  });
106
114
 
107
- fileWatcher.start();
115
+ await fileWatcher.start();
108
116
  ctx.logger.info("Started watching workspace");
109
117
  },
110
118
 
package/src/watcher.ts CHANGED
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import chokidar from "chokidar";
9
+ import * as fs from "node:fs/promises";
9
10
  import * as path from "node:path";
10
11
  import type { FileChange, SyncPluginConfig } from "./types/index.js";
11
12
 
@@ -16,6 +17,24 @@ export interface WatcherOptions {
16
17
  debounceMs?: number;
17
18
  }
18
19
 
20
+ /**
21
+ * Read .clawrachaignore from workspace root (gitignore-style).
22
+ * Returns parsed patterns, or empty array if file doesn't exist.
23
+ */
24
+ async function readIgnoreFile(workspace: string): Promise<string[]> {
25
+ const ignorePath = path.join(workspace, ".clawrachaignore");
26
+ try {
27
+ const content = await fs.readFile(ignorePath, "utf-8");
28
+ return content
29
+ .split("\n")
30
+ .map((line) => line.trim())
31
+ .filter((line) => line && !line.startsWith("#"));
32
+ } catch (err: any) {
33
+ if (err.code === "ENOENT") return [];
34
+ throw err;
35
+ }
36
+ }
37
+
19
38
  export class FileWatcher {
20
39
  private watcher: chokidar.FSWatcher | null = null;
21
40
  private pendingChanges: Map<string, FileChange> = new Map();
@@ -31,17 +50,21 @@ export class FileWatcher {
31
50
  /**
32
51
  * Start watching the workspace
33
52
  */
34
- start(): void {
53
+ async start(): Promise<void> {
35
54
  if (this.watcher) return;
36
55
 
37
56
  const { workspace, config } = this.options;
38
57
 
58
+ // Read workspace-level ignore file
59
+ const userIgnored = await readIgnoreFile(workspace);
60
+
39
61
  // Build watch patterns
40
62
  const watchPaths = config.watchPatterns.map((p) => path.join(workspace, p));
41
63
 
42
64
  // Build ignore patterns
43
65
  const ignored = [
44
66
  ...config.ignorePatterns,
67
+ ...userIgnored,
45
68
  ".storacha/**", // Always ignore our own data
46
69
  ];
47
70