@storacha/clawracha 0.0.1 → 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 +34 -7
- package/dist/handlers/apply.d.ts +18 -0
- package/dist/handlers/apply.d.ts.map +1 -0
- package/dist/handlers/apply.js +50 -0
- package/dist/handlers/process.d.ts +15 -0
- package/dist/handlers/process.d.ts.map +1 -0
- package/dist/handlers/process.js +82 -0
- package/dist/handlers/remote.d.ts +15 -0
- package/dist/handlers/remote.d.ts.map +1 -0
- package/dist/handlers/remote.js +48 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/mdsync/index.d.ts +45 -0
- package/dist/mdsync/index.d.ts.map +1 -0
- package/dist/mdsync/index.js +365 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +233 -29
- package/dist/sync.d.ts +12 -5
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +82 -157
- package/dist/types/index.d.ts +58 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/utils/client.d.ts +14 -0
- package/dist/utils/client.d.ts.map +1 -0
- package/dist/utils/client.js +38 -0
- package/dist/utils/differ.d.ts +29 -0
- package/dist/utils/differ.d.ts.map +1 -0
- package/dist/utils/differ.js +47 -0
- package/dist/utils/encoder.d.ts +16 -0
- package/dist/utils/encoder.d.ts.map +1 -0
- package/dist/utils/encoder.js +51 -0
- package/dist/utils/tempcar.d.ts +22 -0
- package/dist/utils/tempcar.d.ts.map +1 -0
- package/dist/utils/tempcar.js +44 -0
- package/dist/watcher.d.ts +2 -2
- package/dist/watcher.d.ts.map +1 -1
- package/dist/watcher.js +24 -1
- package/openclaw.plugin.json +2 -2
- package/package.json +1 -1
- package/src/plugin.ts +12 -4
- package/src/watcher.ts +24 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import { createReadStream, createWriteStream } from "node:fs";
|
|
3
|
+
import * as os from "node:os";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import * as stream from "node:stream";
|
|
6
|
+
import { CarWriter } from "@ipld/car/writer";
|
|
7
|
+
export const makeTempCar = async () => {
|
|
8
|
+
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "sync-clawracha-"));
|
|
9
|
+
const cleanup = async () => await fs.rm(dir, { recursive: true });
|
|
10
|
+
const file = path.join(dir, "blocks.car");
|
|
11
|
+
// CarWriter.createAppender() creates a headerless/rootless CAR
|
|
12
|
+
// which is fine for uploadCAR (the client handles it)
|
|
13
|
+
const { writer, out } = CarWriter.createAppender();
|
|
14
|
+
// Pipe the output to a file
|
|
15
|
+
const fsWriteStream = createWriteStream(file);
|
|
16
|
+
const pipePromise = stream.promises.pipeline(stream.Readable.from(out), fsWriteStream);
|
|
17
|
+
let didWrite = false;
|
|
18
|
+
const put = async (block) => {
|
|
19
|
+
didWrite = true;
|
|
20
|
+
await writer.put({ cid: block.cid, bytes: block.bytes });
|
|
21
|
+
};
|
|
22
|
+
const switchToReadable = async () => {
|
|
23
|
+
try {
|
|
24
|
+
await writer.close();
|
|
25
|
+
await pipePromise;
|
|
26
|
+
if (!didWrite) {
|
|
27
|
+
await cleanup();
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
readable: {
|
|
32
|
+
stream: () => stream.Readable.toWeb(createReadStream(file)),
|
|
33
|
+
},
|
|
34
|
+
cleanup,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
console.error("Error switching to readable:", err);
|
|
39
|
+
await cleanup();
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
return { put, switchToReadable, cleanup };
|
|
44
|
+
};
|
package/dist/watcher.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Uses chokidar to watch for file changes and batches them
|
|
5
5
|
* before triggering sync.
|
|
6
6
|
*/
|
|
7
|
-
import type { FileChange, SyncPluginConfig } from "./types.js";
|
|
7
|
+
import type { FileChange, SyncPluginConfig } from "./types/index.js";
|
|
8
8
|
export interface WatcherOptions {
|
|
9
9
|
workspace: string;
|
|
10
10
|
config: SyncPluginConfig;
|
|
@@ -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
|
*/
|
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;
|
|
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, {
|
package/openclaw.plugin.json
CHANGED
|
@@ -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
|
-
"
|
|
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": ["
|
|
19
|
+
"default": ["**/*"],
|
|
20
20
|
"description": "Glob patterns to watch for sync"
|
|
21
21
|
},
|
|
22
22
|
"ignorePatterns": {
|
package/package.json
CHANGED
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
|
|