@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.
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +81 -1
- package/dist/sync.d.ts +20 -0
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +26 -0
- package/dist/utils/ignore.d.ts +6 -0
- package/dist/utils/ignore.d.ts.map +1 -0
- package/dist/utils/ignore.js +21 -0
- package/dist/watcher.d.ts.map +1 -1
- package/dist/watcher.js +1 -20
- package/package.json +2 -1
package/dist/plugin.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
|
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;
|
package/dist/sync.d.ts.map
CHANGED
|
@@ -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;
|
|
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 @@
|
|
|
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
|
+
}
|
package/dist/watcher.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
|
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.
|
|
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": {
|