@storacha/clawracha 0.1.0 → 0.1.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.
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,qBAAqB,CAAC;AAiG7B,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,GAAG,EAAE,iBAAiB,QAoepD"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,qBAAqB,CAAC;AAiH7B,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,GAAG,EAAE,iBAAiB,QAgjBpD"}
package/dist/plugin.js CHANGED
@@ -12,7 +12,8 @@ import { SyncEngine } from "./sync.js";
12
12
  import { FileWatcher } from "./watcher.js";
13
13
  import { createStorachaClient } from "./utils/client.js";
14
14
  import { decodeDelegation, encodeDelegation, readDelegationArg, } from "./utils/delegation.js";
15
- import { resolveAgentWorkspace, getAgentIds, } from "./utils/workspace.js";
15
+ import { resolveAgentWorkspace, getAgentIds } from "./utils/workspace.js";
16
+ import { readIgnoreFile } from "./utils/ignore.js";
16
17
  const activeSyncers = new Map();
17
18
  // --- Config helpers ---
18
19
  async function loadDeviceConfig(workspace) {
@@ -66,6 +67,18 @@ async function startWorkspaceSync(workspace, agentId, pluginConfig, logger) {
66
67
  logger.info(`[${agentId}] Started syncing workspace: ${workspace}`);
67
68
  return { engine, watcher, workspace, agentId };
68
69
  }
70
+ /**
71
+ * Scan workspace for files, excluding patterns.
72
+ * Returns paths relative to workspace.
73
+ */
74
+ async function scanWorkspaceFiles(workspace, ignorePatterns) {
75
+ const { glob } = await import("glob");
76
+ return glob("**/*", {
77
+ cwd: workspace,
78
+ nodir: true,
79
+ ignore: ignorePatterns.map((p) => p.includes("/") || p.includes("*") ? p : `${p}/**`),
80
+ });
81
+ }
69
82
  // --- Plugin entry ---
70
83
  export default function plugin(api) {
71
84
  const pluginConfig = (api.pluginConfig ?? {});
@@ -99,6 +112,7 @@ export default function plugin(api) {
99
112
  },
100
113
  async stop(ctx) {
101
114
  for (const [workspace, sync] of activeSyncers) {
115
+ sync.engine.stop();
102
116
  await sync.watcher.stop();
103
117
  ctx.logger.info(`[${sync.agentId}] Stopped syncing: ${workspace}`);
104
118
  }
@@ -248,6 +262,32 @@ export default function plugin(api) {
248
262
  deviceConfig.spaceDID = spaceDID ?? undefined;
249
263
  deviceConfig.setupComplete = true;
250
264
  await saveDeviceConfig(workspace, deviceConfig);
265
+ // Initial upload: scan all existing workspace files and sync to Storacha
266
+ const storachaClient = await createStorachaClient(deviceConfig);
267
+ const engine = new SyncEngine(storachaClient, workspace);
268
+ await engine.init(deviceConfig);
269
+ const userIgnored = await readIgnoreFile(workspace);
270
+ const ignorePatterns = [
271
+ ".storacha",
272
+ "node_modules",
273
+ ".git",
274
+ "dist",
275
+ ...userIgnored,
276
+ ];
277
+ const allFiles = await scanWorkspaceFiles(workspace, ignorePatterns);
278
+ if (allFiles.length > 0) {
279
+ const changes = allFiles.map((f) => ({
280
+ type: "add",
281
+ path: f,
282
+ }));
283
+ await engine.processChanges(changes);
284
+ await engine.sync();
285
+ console.log(`Uploaded ${allFiles.length} existing files to Storacha.`);
286
+ }
287
+ // Save name archive after initial sync
288
+ const exportedArchive = await engine.exportNameArchive();
289
+ deviceConfig.nameArchive = exportedArchive;
290
+ await saveDeviceConfig(workspace, deviceConfig);
251
291
  const { Agent } = await import("@storacha/ucn/pail");
252
292
  const agent = Agent.parse(deviceConfig.agentKey);
253
293
  console.log(`🔥 Storacha workspace ready for ${agentId}!`);
@@ -433,5 +473,45 @@ export default function plugin(api) {
433
473
  process.exit(1);
434
474
  }
435
475
  });
476
+ // --- inspect ---
477
+ clawracha
478
+ .command("inspect")
479
+ .description("Inspect internal sync state for debugging")
480
+ .requiredOption("--agent <id>", "Agent ID")
481
+ .action(async (opts) => {
482
+ try {
483
+ const { agentId, workspace } = requireAgent(opts.agent);
484
+ const deviceConfig = await loadDeviceConfig(workspace);
485
+ if (!deviceConfig?.agentKey || !deviceConfig.setupComplete) {
486
+ console.log(`Not set up. Run \`openclaw clawracha init --agent ${agentId}\` first.`);
487
+ return;
488
+ }
489
+ // Spin up a temporary engine to inspect state
490
+ const storachaClient = await createStorachaClient(deviceConfig);
491
+ const engine = new SyncEngine(storachaClient, workspace);
492
+ await engine.init(deviceConfig);
493
+ const state = await engine.inspect();
494
+ console.log(`🔥 Storacha Inspect [${agentId}]`);
495
+ console.log(`Workspace: ${workspace}`);
496
+ console.log(`Running: ${state.running}`);
497
+ console.log(`Root CID: ${state.root ?? "(none)"}`);
498
+ console.log(`Revisions: ${state.revisions.length}`);
499
+ for (const r of state.revisions) {
500
+ console.log(` event: ${r.event}`);
501
+ }
502
+ console.log(`\nPail entries (${state.pailKeys.length}):`);
503
+ for (const key of state.pailKeys) {
504
+ console.log(` ${key}`);
505
+ }
506
+ console.log(`\nPending ops (${state.pendingOps.length}):`);
507
+ for (const op of state.pendingOps) {
508
+ console.log(` ${op.type} ${op.key}${op.value ? ` → ${op.value}` : ""}`);
509
+ }
510
+ }
511
+ catch (err) {
512
+ console.error(`Error: ${err.message}`);
513
+ process.exit(1);
514
+ }
515
+ });
436
516
  }, { commands: ["clawracha"] });
437
517
  }
package/dist/sync.d.ts CHANGED
@@ -46,11 +46,31 @@ export declare class SyncEngine {
46
46
  * Apply remote changes to local filesystem
47
47
  */
48
48
  private applyRemoteChanges;
49
+ /**
50
+ * Mark the engine as stopped.
51
+ */
52
+ stop(): void;
49
53
  /**
50
54
  * Pull all remote state and write to local filesystem.
51
55
  * Used by /storacha-join to overwrite local with remote before watcher starts.
52
56
  */
53
57
  pullRemote(): Promise<number>;
58
+ /**
59
+ * Inspect internal state for debugging.
60
+ */
61
+ inspect(): Promise<{
62
+ root: string | null;
63
+ revisions: {
64
+ event: string;
65
+ }[];
66
+ pailKeys: string[];
67
+ pendingOps: {
68
+ type: string;
69
+ key: string;
70
+ value?: string;
71
+ }[];
72
+ running: boolean;
73
+ }>;
54
74
  status(): Promise<SyncState>;
55
75
  exportNameArchive(): Promise<string>;
56
76
  private storeBlocks;
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EAEV,YAAY,EACb,MAAM,kBAAkB,CAAC;AAS1B,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG1C,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,IAAI,CAAyB;IACrC,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,cAAc,CAAS;gBAEnB,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAMrD;;OAEG;IACG,IAAI,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC/C;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAe1D;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkD3B;;OAEG;YACW,iBAAiB;IAc/B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;IAc5C;;OAEG;YACW,kBAAkB;IAWhC;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IA0B7B,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC;IAW5B,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;YAM5B,WAAW;CAK1B"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EAEV,YAAY,EACb,MAAM,kBAAkB,CAAC;AAS1B,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG1C,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,IAAI,CAAyB;IACrC,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,cAAc,CAAS;gBAEnB,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAMrD;;OAEG;IACG,IAAI,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAkC/C;;OAEG;IACG,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAe1D;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkD3B;;OAEG;YACW,iBAAiB;IAc/B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC;IAc5C;;OAEG;YACW,kBAAkB;IAWhC;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IA0BnC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC;QACvB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,SAAS,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QAC/B,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,UAAU,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QAC5D,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;IAiBI,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC;IAW5B,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;YAM5B,WAAW;CAK1B"}
package/dist/sync.js CHANGED
@@ -68,6 +68,7 @@ export class SyncEngine {
68
68
  throw err;
69
69
  }
70
70
  }
71
+ this.running = true;
71
72
  }
72
73
  /**
73
74
  * Process a batch of file changes
@@ -163,6 +164,12 @@ export class SyncEngine {
163
164
  current: this.current ?? undefined,
164
165
  });
165
166
  }
167
+ /**
168
+ * Mark the engine as stopped.
169
+ */
170
+ stop() {
171
+ this.running = false;
172
+ }
166
173
  /**
167
174
  * Pull all remote state and write to local filesystem.
168
175
  * Used by /storacha-join to overwrite local with remote before watcher starts.
@@ -192,6 +199,25 @@ export class SyncEngine {
192
199
  this.lastSync = Date.now();
193
200
  return entries.size;
194
201
  }
202
+ /**
203
+ * Inspect internal state for debugging.
204
+ */
205
+ async inspect() {
206
+ const entries = await this.getPailEntries();
207
+ return {
208
+ root: this.current?.root?.toString() ?? null,
209
+ revisions: this.current?.revision?.map((r) => ({
210
+ event: r.event.cid.toString(),
211
+ })) ?? [],
212
+ pailKeys: [...entries.keys()],
213
+ pendingOps: this.pendingOps.map((op) => ({
214
+ type: op.type,
215
+ key: op.key,
216
+ value: op.value?.toString(),
217
+ })),
218
+ running: this.running,
219
+ };
220
+ }
195
221
  async status() {
196
222
  const entries = await this.getPailEntries();
197
223
  return {
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Read .clawrachaignore from workspace root (gitignore-style).
3
+ * Returns parsed patterns, or empty array if file doesn't exist.
4
+ */
5
+ export declare function readIgnoreFile(workspace: string): Promise<string[]>;
6
+ //# sourceMappingURL=ignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignore.d.ts","sourceRoot":"","sources":["../../src/utils/ignore.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAYzE"}
@@ -0,0 +1,21 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ /**
4
+ * Read .clawrachaignore from workspace root (gitignore-style).
5
+ * Returns parsed patterns, or empty array if file doesn't exist.
6
+ */
7
+ export async function readIgnoreFile(workspace) {
8
+ const ignorePath = path.join(workspace, ".clawrachaignore");
9
+ try {
10
+ const content = await fs.readFile(ignorePath, "utf-8");
11
+ return content
12
+ .split("\n")
13
+ .map((line) => line.trim())
14
+ .filter((line) => line && !line.startsWith("#"));
15
+ }
16
+ catch (err) {
17
+ if (err.code === "ENOENT")
18
+ return [];
19
+ throw err;
20
+ }
21
+ }
@@ -1 +1 @@
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"}
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;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;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,27 +5,8 @@
5
5
  * before triggering sync.
6
6
  */
7
7
  import chokidar from "chokidar";
8
- import * as fs from "node:fs/promises";
8
+ import { readIgnoreFile } from "./utils/ignore.js";
9
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
- }
29
10
  export class FileWatcher {
30
11
  watcher = null;
31
12
  pendingChanges = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storacha/clawracha",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "OpenClaw plugin for Storacha workspace sync via UCN Pail",
5
5
  "type": "module",
6
6
  "files": [
@@ -36,6 +36,7 @@
36
36
  "@web3-storage/pail": "0.6.3-rc.3",
37
37
  "carstream": "^2.3.0",
38
38
  "chokidar": "^3.6.0",
39
+ "glob": "^13.0.5",
39
40
  "multiformats": "^13.0.0"
40
41
  },
41
42
  "devDependencies": {