@storacha/clawracha 0.1.23 ā 0.2.1
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/commands.d.ts +42 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +185 -0
- package/dist/mdsync/index.d.ts.map +1 -1
- package/dist/mdsync/index.js +19 -8
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +93 -165
- package/dist/prompts.d.ts +8 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +49 -0
- package/package.json +2 -2
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracted command logic for Storacha workspace sync.
|
|
3
|
+
*
|
|
4
|
+
* Shared by CLI commands (thin wrappers in plugin.ts) and the
|
|
5
|
+
* interactive `onboard` command.
|
|
6
|
+
*/
|
|
7
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
|
8
|
+
import type { DeviceConfig, SyncPluginConfig } from "./types/index.js";
|
|
9
|
+
import { SyncEngine } from "./sync.js";
|
|
10
|
+
import { FileWatcher } from "./watcher.js";
|
|
11
|
+
export interface WorkspaceSync {
|
|
12
|
+
engine: SyncEngine;
|
|
13
|
+
watcher: FileWatcher;
|
|
14
|
+
workspace: string;
|
|
15
|
+
agentId: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function loadDeviceConfig(workspace: string): Promise<DeviceConfig | null>;
|
|
18
|
+
export declare function saveDeviceConfig(workspace: string, config: DeviceConfig): Promise<void>;
|
|
19
|
+
export declare function requestWorkspaceUpdate(workspace: string, agentId: string, gatewayConfig: NonNullable<OpenClawConfig["gateway"]>): Promise<void>;
|
|
20
|
+
export declare function startWorkspaceSync(workspace: string, agentId: string, pluginConfig: Partial<SyncPluginConfig>, initialAdd: boolean, logger: {
|
|
21
|
+
info: (msg: string) => void;
|
|
22
|
+
warn: (msg: string) => void;
|
|
23
|
+
}): Promise<WorkspaceSync | null>;
|
|
24
|
+
export interface InitResult {
|
|
25
|
+
alreadyInitialized: boolean;
|
|
26
|
+
setupComplete: boolean;
|
|
27
|
+
agentDID: string;
|
|
28
|
+
agentKey: string;
|
|
29
|
+
}
|
|
30
|
+
export interface SetupResult {
|
|
31
|
+
agentDID: string;
|
|
32
|
+
spaceDID: string | undefined;
|
|
33
|
+
}
|
|
34
|
+
export interface JoinResult {
|
|
35
|
+
agentDID: string;
|
|
36
|
+
spaceDID: string | undefined;
|
|
37
|
+
pullCount: number;
|
|
38
|
+
}
|
|
39
|
+
export declare function doInit(workspace: string): Promise<InitResult>;
|
|
40
|
+
export declare function doSetup(workspace: string, agentId: string, delegationArg: string, pluginConfig: Partial<SyncPluginConfig>, gatewayConfig?: NonNullable<OpenClawConfig["gateway"]>): Promise<SetupResult>;
|
|
41
|
+
export declare function doJoin(workspace: string, agentId: string, uploadDelegationArg: string, nameDelegationArg: string, pluginConfig: Partial<SyncPluginConfig>, gatewayConfig?: NonNullable<OpenClawConfig["gateway"]>): Promise<JoinResult>;
|
|
42
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAS3C,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAS9B;AAED,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,WAAW,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,GACpD,OAAO,CAAC,IAAI,CAAC,CAqCf;AAID,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,OAAO,CAAC,gBAAgB,CAAC,EACvC,UAAU,EAAE,OAAO,EACnB,MAAM,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACnE,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAmC/B;AAID,MAAM,WAAW,UAAU;IACzB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,wBAAsB,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAsBnE;AAED,wBAAsB,OAAO,CAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,OAAO,CAAC,gBAAgB,CAAC,EACvC,aAAa,CAAC,EAAE,WAAW,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,GACrD,OAAO,CAAC,WAAW,CAAC,CA0CtB;AAED,wBAAsB,MAAM,CAC1B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,mBAAmB,EAAE,MAAM,EAC3B,iBAAiB,EAAE,MAAM,EACzB,YAAY,EAAE,OAAO,CAAC,gBAAgB,CAAC,EACvC,aAAa,CAAC,EAAE,WAAW,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,GACrD,OAAO,CAAC,UAAU,CAAC,CA8CrB"}
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracted command logic for Storacha workspace sync.
|
|
3
|
+
*
|
|
4
|
+
* Shared by CLI commands (thin wrappers in plugin.ts) and the
|
|
5
|
+
* interactive `onboard` command.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "node:fs/promises";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { SyncEngine } from "./sync.js";
|
|
10
|
+
import { FileWatcher } from "./watcher.js";
|
|
11
|
+
import { encodeDelegation, readDelegationArg, } from "./utils/delegation.js";
|
|
12
|
+
import { Agent } from "@storacha/ucn/pail";
|
|
13
|
+
// --- Config helpers ---
|
|
14
|
+
export async function loadDeviceConfig(workspace) {
|
|
15
|
+
const configPath = path.join(workspace, ".storacha", "config.json");
|
|
16
|
+
try {
|
|
17
|
+
const content = await fs.readFile(configPath, "utf-8");
|
|
18
|
+
return JSON.parse(content);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
if (err.code === "ENOENT")
|
|
22
|
+
return null;
|
|
23
|
+
throw err;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export async function saveDeviceConfig(workspace, config) {
|
|
27
|
+
const configDir = path.join(workspace, ".storacha");
|
|
28
|
+
await fs.mkdir(configDir, { recursive: true });
|
|
29
|
+
const configPath = path.join(configDir, "config.json");
|
|
30
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
31
|
+
}
|
|
32
|
+
export async function requestWorkspaceUpdate(workspace, agentId, gatewayConfig) {
|
|
33
|
+
const DEFAULT_GATEWAY_PORT = 18789;
|
|
34
|
+
let port = DEFAULT_GATEWAY_PORT;
|
|
35
|
+
if (typeof gatewayConfig.port === "number" &&
|
|
36
|
+
Number.isFinite(gatewayConfig.port) &&
|
|
37
|
+
gatewayConfig.port > 0) {
|
|
38
|
+
port = gatewayConfig.port;
|
|
39
|
+
}
|
|
40
|
+
const url = `http://127.0.0.1:${port}/api/channels/clawracha/workspace-update`;
|
|
41
|
+
const headers = {
|
|
42
|
+
"Content-Type": "application/json",
|
|
43
|
+
};
|
|
44
|
+
const token = gatewayConfig.auth?.token ?? gatewayConfig.auth?.password;
|
|
45
|
+
if (token) {
|
|
46
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const res = await fetch(url, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers,
|
|
52
|
+
body: JSON.stringify({ agentId, workspace }),
|
|
53
|
+
});
|
|
54
|
+
if (!res.ok) {
|
|
55
|
+
console.warn(`Warning: Failed to notify gateway (${res.status}). Restart the gateway to pick up changes.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
console.warn(`Warning: Could not reach gateway at ${url}: ${err.message}. Restart the gateway to pick up changes.`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// --- Sync lifecycle ---
|
|
63
|
+
export async function startWorkspaceSync(workspace, agentId, pluginConfig, initialAdd, logger) {
|
|
64
|
+
const deviceConfig = await loadDeviceConfig(workspace);
|
|
65
|
+
if (!deviceConfig || !deviceConfig.setupComplete) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const engine = new SyncEngine(workspace);
|
|
69
|
+
await engine.init(deviceConfig);
|
|
70
|
+
const watcher = new FileWatcher({
|
|
71
|
+
workspace,
|
|
72
|
+
config: {
|
|
73
|
+
enabled: true,
|
|
74
|
+
watchPatterns: pluginConfig.watchPatterns ?? ["**/*"],
|
|
75
|
+
ignorePatterns: pluginConfig.ignorePatterns ?? [
|
|
76
|
+
".storacha/**",
|
|
77
|
+
"node_modules/**",
|
|
78
|
+
".git/**",
|
|
79
|
+
"dist/**",
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
onChanges: async (changes) => {
|
|
83
|
+
await engine.processChanges(changes);
|
|
84
|
+
await engine.sync();
|
|
85
|
+
const nameArchive = await engine.exportNameArchive();
|
|
86
|
+
const updatedConfig = { ...deviceConfig, nameArchive };
|
|
87
|
+
await saveDeviceConfig(workspace, updatedConfig);
|
|
88
|
+
},
|
|
89
|
+
initialAdd,
|
|
90
|
+
});
|
|
91
|
+
await watcher.start();
|
|
92
|
+
logger.info(`[${agentId}] Started syncing workspace: ${workspace}`);
|
|
93
|
+
return { engine, watcher, workspace, agentId };
|
|
94
|
+
}
|
|
95
|
+
// --- Core command logic ---
|
|
96
|
+
export async function doInit(workspace) {
|
|
97
|
+
const existing = await loadDeviceConfig(workspace);
|
|
98
|
+
if (existing?.agentKey) {
|
|
99
|
+
const agent = Agent.parse(existing.agentKey);
|
|
100
|
+
return {
|
|
101
|
+
alreadyInitialized: true,
|
|
102
|
+
setupComplete: !!existing.setupComplete,
|
|
103
|
+
agentDID: agent.did(),
|
|
104
|
+
agentKey: existing.agentKey,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const agent = await Agent.generate();
|
|
108
|
+
const agentKey = Agent.format(agent);
|
|
109
|
+
await saveDeviceConfig(workspace, { agentKey });
|
|
110
|
+
return {
|
|
111
|
+
alreadyInitialized: false,
|
|
112
|
+
setupComplete: false,
|
|
113
|
+
agentDID: agent.did(),
|
|
114
|
+
agentKey,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
export async function doSetup(workspace, agentId, delegationArg, pluginConfig, gatewayConfig) {
|
|
118
|
+
const deviceConfig = await loadDeviceConfig(workspace);
|
|
119
|
+
if (!deviceConfig?.agentKey) {
|
|
120
|
+
throw new Error("Not initialized. Run init first.");
|
|
121
|
+
}
|
|
122
|
+
if (deviceConfig.setupComplete) {
|
|
123
|
+
const agent = Agent.parse(deviceConfig.agentKey);
|
|
124
|
+
return { agentDID: agent.did(), spaceDID: deviceConfig.spaceDID };
|
|
125
|
+
}
|
|
126
|
+
const delegation = await readDelegationArg(delegationArg);
|
|
127
|
+
const spaceDID = delegation.capabilities[0]?.with;
|
|
128
|
+
const { ok: archiveBytes } = await delegation.archive();
|
|
129
|
+
if (!archiveBytes)
|
|
130
|
+
throw new Error("Failed to archive delegation");
|
|
131
|
+
deviceConfig.uploadDelegation = encodeDelegation(archiveBytes);
|
|
132
|
+
deviceConfig.spaceDID = spaceDID ?? undefined;
|
|
133
|
+
deviceConfig.setupComplete = true;
|
|
134
|
+
await saveDeviceConfig(workspace, deviceConfig);
|
|
135
|
+
// One-shot sync: scan existing files, upload, stop
|
|
136
|
+
const sync = await startWorkspaceSync(workspace, agentId, pluginConfig, true, console);
|
|
137
|
+
if (!sync)
|
|
138
|
+
throw new Error("Failed to start sync engine");
|
|
139
|
+
await sync.watcher.waitForReady();
|
|
140
|
+
await sync.watcher.stop();
|
|
141
|
+
await sync.watcher.forceFlush();
|
|
142
|
+
await sync.engine.stop();
|
|
143
|
+
if (gatewayConfig) {
|
|
144
|
+
await requestWorkspaceUpdate(workspace, agentId, gatewayConfig);
|
|
145
|
+
}
|
|
146
|
+
const agent = Agent.parse(deviceConfig.agentKey);
|
|
147
|
+
return { agentDID: agent.did(), spaceDID: spaceDID ?? undefined };
|
|
148
|
+
}
|
|
149
|
+
export async function doJoin(workspace, agentId, uploadDelegationArg, nameDelegationArg, pluginConfig, gatewayConfig) {
|
|
150
|
+
const deviceConfig = await loadDeviceConfig(workspace);
|
|
151
|
+
if (!deviceConfig?.agentKey) {
|
|
152
|
+
throw new Error("Not initialized. Run init first.");
|
|
153
|
+
}
|
|
154
|
+
if (deviceConfig.setupComplete) {
|
|
155
|
+
const agent = Agent.parse(deviceConfig.agentKey);
|
|
156
|
+
return { agentDID: agent.did(), spaceDID: deviceConfig.spaceDID, pullCount: 0 };
|
|
157
|
+
}
|
|
158
|
+
const uploadDelegation = await readDelegationArg(uploadDelegationArg);
|
|
159
|
+
const nameDelegation = await readDelegationArg(nameDelegationArg);
|
|
160
|
+
const spaceDID = uploadDelegation.capabilities[0]?.with;
|
|
161
|
+
const { ok: uploadArchive } = await uploadDelegation.archive();
|
|
162
|
+
if (!uploadArchive)
|
|
163
|
+
throw new Error("Failed to archive upload delegation");
|
|
164
|
+
const { ok: nameArchiveBytes } = await nameDelegation.archive();
|
|
165
|
+
if (!nameArchiveBytes)
|
|
166
|
+
throw new Error("Failed to archive name delegation");
|
|
167
|
+
deviceConfig.uploadDelegation = encodeDelegation(uploadArchive);
|
|
168
|
+
deviceConfig.nameDelegation = encodeDelegation(nameArchiveBytes);
|
|
169
|
+
deviceConfig.spaceDID = spaceDID ?? undefined;
|
|
170
|
+
deviceConfig.setupComplete = true;
|
|
171
|
+
await saveDeviceConfig(workspace, deviceConfig);
|
|
172
|
+
// One-shot sync: pull remote, stop
|
|
173
|
+
const sync = await startWorkspaceSync(workspace, agentId, pluginConfig, false, console);
|
|
174
|
+
if (!sync)
|
|
175
|
+
throw new Error("Failed to start sync engine");
|
|
176
|
+
const pullCount = await sync.engine.pullRemote();
|
|
177
|
+
await sync.watcher.stop();
|
|
178
|
+
await sync.watcher.forceFlush();
|
|
179
|
+
await sync.engine.stop();
|
|
180
|
+
if (gatewayConfig) {
|
|
181
|
+
await requestWorkspaceUpdate(workspace, agentId, gatewayConfig);
|
|
182
|
+
}
|
|
183
|
+
const agent = Agent.parse(deviceConfig.agentKey);
|
|
184
|
+
return { agentDID: agent.did(), spaceDID: spaceDID ?? undefined, pullCount };
|
|
185
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mdsync/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EACL,YAAY,EAGZ,SAAS,EACV,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mdsync/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EACL,YAAY,EAGZ,SAAS,EACV,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAuJ1C,UAAU,cAAc;IACtB,UAAU,EAAE,GAAG,CAAC;IAChB,SAAS,EAAE,KAAK,EAAE,CAAC;CACpB;AAyBD;;;;GAIG;AACH,eAAO,MAAM,KAAK,GAAU,aAAa,MAAM,KAAG,OAAO,CAAC,cAAc,CAEvE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,GAAG,GACd,QAAQ,YAAY,EACpB,SAAS,SAAS,EAClB,KAAK,MAAM,EACX,aAAa,MAAM,KAClB,OAAO,CAAC,cAAc,GAAG,IAAI,CAkC/B,CAAC;AAkSF;;;GAGG;AACH,eAAO,MAAM,GAAG,GACd,QAAQ,YAAY,EACpB,SAAS,SAAS,EAClB,KAAK,MAAM,KACV,OAAO,CAAC,MAAM,GAAG,SAAS,CAM5B,CAAC"}
|
package/dist/mdsync/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { MemoryBlockstore, withCache } from "@storacha/ucn/block";
|
|
|
16
16
|
import * as CRDT from "@web3-storage/pail/crdt";
|
|
17
17
|
import { CID } from "multiformats";
|
|
18
18
|
import * as cbor from "@ipld/dag-cbor";
|
|
19
|
-
import { fromMarkdown, encodeTree, encodeRGA, RGA, decodeRGA, decodeTree, computeChangeSet, applyRGAChangeSet, encodeChangeSet, decodeChangeSet, toMarkdown, } from "@storacha/md-merge";
|
|
19
|
+
import { fromMarkdown, encodeTree, encodeRGA, RGA, decodeRGA, decodeTree, computeChangeSet, applyRGAChangeSet, encodeChangeSet, decodeChangeSet, toMarkdown, mergeRGATrees, } from "@storacha/md-merge";
|
|
20
20
|
import * as Pail from "@web3-storage/pail";
|
|
21
21
|
import { decode, encode } from "multiformats/block";
|
|
22
22
|
import { sha256 } from "multiformats/hashes/sha2";
|
|
@@ -318,15 +318,26 @@ const resolveValue = async (blocks, current, key) => {
|
|
|
318
318
|
const newMDEntry = await getMarkdownEntry(blocks, mdEntryCid);
|
|
319
319
|
if (newMDEntry.type === "initial") {
|
|
320
320
|
// First write for this key ā bootstrap from the stored entry.
|
|
321
|
+
const newEventRGA = await getEventRGAFromCID(blocks, newMDEntry.events);
|
|
322
|
+
const newRoot = await getRGATreeFromRootCID(blocks, newMDEntry.root, newEventRGA);
|
|
321
323
|
if (mdEntry) {
|
|
322
|
-
|
|
324
|
+
// Concurrent initial ā two branches independently created this key.
|
|
325
|
+
// Merge event histories and merge the two RGA trees.
|
|
326
|
+
mdEntry.events.merge(newEventRGA);
|
|
327
|
+
const comparator = makeComparator(mdEntry.events);
|
|
328
|
+
mdEntry = {
|
|
329
|
+
type: "initial",
|
|
330
|
+
events: mdEntry.events,
|
|
331
|
+
root: mergeRGATrees(mdEntry.root, newRoot, comparator),
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
mdEntry = {
|
|
336
|
+
type: "initial",
|
|
337
|
+
events: newEventRGA,
|
|
338
|
+
root: newRoot,
|
|
339
|
+
};
|
|
323
340
|
}
|
|
324
|
-
const eventRGA = await getEventRGAFromCID(blocks, newMDEntry.events);
|
|
325
|
-
mdEntry = {
|
|
326
|
-
type: "initial",
|
|
327
|
-
events: eventRGA,
|
|
328
|
-
root: await getRGATreeFromRootCID(blocks, newMDEntry.root, eventRGA),
|
|
329
|
-
};
|
|
330
341
|
}
|
|
331
342
|
else {
|
|
332
343
|
// Update ā merge event histories, then apply the changeset.
|
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;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,qBAAqB,CAAC;AAkC7B,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,GAAG,EAAE,iBAAiB,QAspBpD"}
|
package/dist/plugin.js
CHANGED
|
@@ -6,107 +6,22 @@
|
|
|
6
6
|
* - CLI commands for setup and management (openclaw clawracha ...)
|
|
7
7
|
* - Agent tools for manual sync control
|
|
8
8
|
*/
|
|
9
|
-
import * as fs from "node:fs/promises";
|
|
10
|
-
import * as path from "node:path";
|
|
11
9
|
import { json as consumeJson } from "stream/consumers";
|
|
12
10
|
import { SyncEngine } from "./sync.js";
|
|
13
|
-
import { FileWatcher } from "./watcher.js";
|
|
14
11
|
import { createStorachaClient } from "./utils/client.js";
|
|
15
|
-
import { decodeDelegation, encodeDelegation,
|
|
12
|
+
import { decodeDelegation, encodeDelegation, } from "./utils/delegation.js";
|
|
16
13
|
import { resolveAgentWorkspace, getAgentIds } from "./utils/workspace.js";
|
|
17
14
|
import { Agent, Name } from "@storacha/ucn/pail";
|
|
18
15
|
import { extract } from "@storacha/client/delegation";
|
|
19
16
|
import * as z from "zod";
|
|
20
17
|
import { spaceAccess } from "@storacha/client/capability/access";
|
|
18
|
+
import { loadDeviceConfig, startWorkspaceSync, doInit, doSetup, doJoin, } from "./commands.js";
|
|
21
19
|
const activeSyncers = new Map();
|
|
22
20
|
// --- Config helpers ---
|
|
23
21
|
const UpdateParams = z.object({
|
|
24
22
|
agentId: z.string(),
|
|
25
23
|
workspace: z.string(),
|
|
26
24
|
});
|
|
27
|
-
async function loadDeviceConfig(workspace) {
|
|
28
|
-
const configPath = path.join(workspace, ".storacha", "config.json");
|
|
29
|
-
try {
|
|
30
|
-
const content = await fs.readFile(configPath, "utf-8");
|
|
31
|
-
return JSON.parse(content);
|
|
32
|
-
}
|
|
33
|
-
catch (err) {
|
|
34
|
-
if (err.code === "ENOENT")
|
|
35
|
-
return null;
|
|
36
|
-
throw err;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
async function requestWorkspaceUpdate(workspace, agentId, gatewayConfig) {
|
|
40
|
-
// Mirror resolveGatewayPort from openclaw core
|
|
41
|
-
const DEFAULT_GATEWAY_PORT = 18789;
|
|
42
|
-
let port = DEFAULT_GATEWAY_PORT;
|
|
43
|
-
if (typeof gatewayConfig.port === "number" &&
|
|
44
|
-
Number.isFinite(gatewayConfig.port) &&
|
|
45
|
-
gatewayConfig.port > 0) {
|
|
46
|
-
port = gatewayConfig.port;
|
|
47
|
-
}
|
|
48
|
-
const url = `http://127.0.0.1:${port}/api/channels/clawracha/workspace-update`;
|
|
49
|
-
const headers = {
|
|
50
|
-
"Content-Type": "application/json",
|
|
51
|
-
};
|
|
52
|
-
// Auth: /api/channels/ routes get gateway auth middleware
|
|
53
|
-
const token = gatewayConfig.auth?.token ?? gatewayConfig.auth?.password;
|
|
54
|
-
if (token) {
|
|
55
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
56
|
-
}
|
|
57
|
-
try {
|
|
58
|
-
const res = await fetch(url, {
|
|
59
|
-
method: "POST",
|
|
60
|
-
headers,
|
|
61
|
-
body: JSON.stringify({ agentId, workspace }),
|
|
62
|
-
});
|
|
63
|
-
if (!res.ok) {
|
|
64
|
-
console.warn(`Warning: Failed to notify gateway (${res.status}). Restart the gateway to pick up changes.`);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
catch (err) {
|
|
68
|
-
console.warn(`Warning: Could not reach gateway at ${url}: ${err.message}. Restart the gateway to pick up changes.`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
async function saveDeviceConfig(workspace, config) {
|
|
72
|
-
const configDir = path.join(workspace, ".storacha");
|
|
73
|
-
await fs.mkdir(configDir, { recursive: true });
|
|
74
|
-
const configPath = path.join(configDir, "config.json");
|
|
75
|
-
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
76
|
-
}
|
|
77
|
-
// --- Service helpers ---
|
|
78
|
-
async function startWorkspaceSync(workspace, agentId, pluginConfig, initialAdd, logger) {
|
|
79
|
-
const deviceConfig = await loadDeviceConfig(workspace);
|
|
80
|
-
if (!deviceConfig || !deviceConfig.setupComplete) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
const engine = new SyncEngine(workspace);
|
|
84
|
-
await engine.init(deviceConfig);
|
|
85
|
-
const watcher = new FileWatcher({
|
|
86
|
-
workspace,
|
|
87
|
-
config: {
|
|
88
|
-
enabled: true,
|
|
89
|
-
watchPatterns: pluginConfig.watchPatterns ?? ["**/*"],
|
|
90
|
-
ignorePatterns: pluginConfig.ignorePatterns ?? [
|
|
91
|
-
".storacha/**",
|
|
92
|
-
"node_modules/**",
|
|
93
|
-
".git/**",
|
|
94
|
-
"dist/**",
|
|
95
|
-
],
|
|
96
|
-
},
|
|
97
|
-
onChanges: async (changes) => {
|
|
98
|
-
await engine.processChanges(changes);
|
|
99
|
-
await engine.sync();
|
|
100
|
-
const nameArchive = await engine.exportNameArchive();
|
|
101
|
-
const updatedConfig = { ...deviceConfig, nameArchive };
|
|
102
|
-
await saveDeviceConfig(workspace, updatedConfig);
|
|
103
|
-
},
|
|
104
|
-
initialAdd,
|
|
105
|
-
});
|
|
106
|
-
await watcher.start();
|
|
107
|
-
logger.info(`[${agentId}] Started syncing workspace: ${workspace}`);
|
|
108
|
-
return { engine, watcher, workspace, agentId };
|
|
109
|
-
}
|
|
110
25
|
// --- Plugin entry ---
|
|
111
26
|
export default function plugin(api) {
|
|
112
27
|
const pluginConfig = (api.pluginConfig ?? {});
|
|
@@ -271,12 +186,11 @@ export default function plugin(api) {
|
|
|
271
186
|
.action(async (opts) => {
|
|
272
187
|
try {
|
|
273
188
|
const { agentId, workspace } = requireAgent(opts.agent);
|
|
274
|
-
const
|
|
275
|
-
if (
|
|
276
|
-
const agent = Agent.parse(existing.agentKey);
|
|
189
|
+
const result = await doInit(workspace);
|
|
190
|
+
if (result.alreadyInitialized) {
|
|
277
191
|
console.log(`Agent already initialized for ${agentId}.`);
|
|
278
|
-
console.log(`Agent DID: ${
|
|
279
|
-
if (
|
|
192
|
+
console.log(`Agent DID: ${result.agentDID}`);
|
|
193
|
+
if (result.setupComplete) {
|
|
280
194
|
console.log(`\nSetup is complete. Use \`openclaw clawracha status --agent ${agentId}\` to check sync state.`);
|
|
281
195
|
}
|
|
282
196
|
else {
|
|
@@ -286,11 +200,8 @@ export default function plugin(api) {
|
|
|
286
200
|
}
|
|
287
201
|
return;
|
|
288
202
|
}
|
|
289
|
-
const agent = await Agent.generate();
|
|
290
|
-
const agentKey = Agent.format(agent);
|
|
291
|
-
await saveDeviceConfig(workspace, { agentKey });
|
|
292
203
|
console.log(`š„ Agent initialized for ${agentId}!`);
|
|
293
|
-
console.log(`Agent DID: ${
|
|
204
|
+
console.log(`Agent DID: ${result.agentDID}`);
|
|
294
205
|
console.log("\nNext step ā choose one:");
|
|
295
206
|
console.log(` New workspace: openclaw clawracha setup <delegation> --agent ${agentId}`);
|
|
296
207
|
console.log(` Join existing: openclaw clawracha join <upload> <name> --agent ${agentId}`);
|
|
@@ -315,40 +226,10 @@ export default function plugin(api) {
|
|
|
315
226
|
console.error(`Run \`openclaw clawracha init --agent ${agentId}\` first.`);
|
|
316
227
|
process.exit(1);
|
|
317
228
|
}
|
|
318
|
-
|
|
319
|
-
console.log("Setup already complete.");
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
const delegation = await readDelegationArg(delegationArg);
|
|
323
|
-
const spaceDID = delegation.capabilities[0]?.with;
|
|
324
|
-
const { ok: archiveBytes } = await delegation.archive();
|
|
325
|
-
if (!archiveBytes) {
|
|
326
|
-
throw new Error("Failed to archive delegation");
|
|
327
|
-
}
|
|
328
|
-
deviceConfig.uploadDelegation = encodeDelegation(archiveBytes);
|
|
329
|
-
deviceConfig.spaceDID = spaceDID ?? undefined;
|
|
330
|
-
deviceConfig.setupComplete = true;
|
|
331
|
-
await saveDeviceConfig(workspace, deviceConfig);
|
|
332
|
-
// Initial upload: scan all existing workspace files and sync to Storacha
|
|
333
|
-
const sync = await startWorkspaceSync(workspace, agentId, pluginConfig, true, console);
|
|
334
|
-
if (!sync) {
|
|
335
|
-
throw new Error("Failed to start sync engine");
|
|
336
|
-
}
|
|
337
|
-
// Wait for initial files to flush through, then stop the watcher
|
|
338
|
-
await sync.watcher.waitForReady();
|
|
339
|
-
await sync.watcher.stop();
|
|
340
|
-
// force out changes then stop the engine, which will wait for last
|
|
341
|
-
// sync to complete
|
|
342
|
-
await sync.watcher.forceFlush();
|
|
343
|
-
await sync.engine.stop();
|
|
344
|
-
// post to the endpoint to tell the service to start syncing this space
|
|
345
|
-
if (config.gateway) {
|
|
346
|
-
await requestWorkspaceUpdate(workspace, agentId, config.gateway);
|
|
347
|
-
}
|
|
348
|
-
const agent = Agent.parse(deviceConfig.agentKey);
|
|
229
|
+
const result = await doSetup(workspace, agentId, delegationArg, pluginConfig, config.gateway);
|
|
349
230
|
console.log(`š„ Storacha workspace ready for ${agentId}!`);
|
|
350
|
-
console.log(`Agent DID: ${
|
|
351
|
-
console.log(`Space: ${spaceDID ?? "unknown"}`);
|
|
231
|
+
console.log(`Agent DID: ${result.agentDID}`);
|
|
232
|
+
console.log(`Space: ${result.spaceDID ?? "unknown"}`);
|
|
352
233
|
console.log(`\nTo add another device, run \`openclaw clawracha grant <their-DID> --agent ${agentId}\` here,`);
|
|
353
234
|
console.log(`then \`openclaw clawracha join <upload> <name> --agent <id>\` on the other device.`);
|
|
354
235
|
console.log("\nSync is now active (no gateway restart needed).");
|
|
@@ -375,43 +256,11 @@ export default function plugin(api) {
|
|
|
375
256
|
console.error(`Run \`openclaw clawracha init --agent ${agentId}\` first.`);
|
|
376
257
|
process.exit(1);
|
|
377
258
|
}
|
|
378
|
-
|
|
379
|
-
console.log("Setup already complete.");
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
const uploadDelegation = await readDelegationArg(uploadArg);
|
|
383
|
-
const nameDelegation = await readDelegationArg(nameArg);
|
|
384
|
-
const spaceDID = uploadDelegation.capabilities[0]?.with;
|
|
385
|
-
const { ok: uploadArchive } = await uploadDelegation.archive();
|
|
386
|
-
if (!uploadArchive)
|
|
387
|
-
throw new Error("Failed to archive upload delegation");
|
|
388
|
-
const { ok: nameArchiveBytes } = await nameDelegation.archive();
|
|
389
|
-
if (!nameArchiveBytes)
|
|
390
|
-
throw new Error("Failed to archive name delegation");
|
|
391
|
-
deviceConfig.uploadDelegation = encodeDelegation(uploadArchive);
|
|
392
|
-
deviceConfig.nameDelegation = encodeDelegation(nameArchiveBytes);
|
|
393
|
-
deviceConfig.spaceDID = spaceDID ?? undefined;
|
|
394
|
-
deviceConfig.setupComplete = true;
|
|
395
|
-
await saveDeviceConfig(workspace, deviceConfig);
|
|
396
|
-
// Pull remote state before watcher starts
|
|
397
|
-
const sync = await startWorkspaceSync(workspace, agentId, pluginConfig, false, console);
|
|
398
|
-
let pullCount = 0;
|
|
399
|
-
if (!sync) {
|
|
400
|
-
throw new Error("Failed to start sync engine");
|
|
401
|
-
}
|
|
402
|
-
pullCount = await sync.engine.pullRemote();
|
|
403
|
-
await sync.watcher.stop();
|
|
404
|
-
await sync.watcher.forceFlush();
|
|
405
|
-
await sync.engine.stop();
|
|
406
|
-
// post to the endpoint to tell the service to start syncing this space
|
|
407
|
-
if (config.gateway) {
|
|
408
|
-
await requestWorkspaceUpdate(workspace, agentId, config.gateway);
|
|
409
|
-
}
|
|
410
|
-
const agent = Agent.parse(deviceConfig.agentKey);
|
|
259
|
+
const result = await doJoin(workspace, agentId, uploadArg, nameArg, pluginConfig, config.gateway);
|
|
411
260
|
console.log(`š„ Joined existing Storacha workspace for ${agentId}!`);
|
|
412
|
-
console.log(`Agent DID: ${
|
|
413
|
-
console.log(`Space: ${spaceDID ?? "unknown"}`);
|
|
414
|
-
console.log(`Pulled ${pullCount} files from remote.`);
|
|
261
|
+
console.log(`Agent DID: ${result.agentDID}`);
|
|
262
|
+
console.log(`Space: ${result.spaceDID ?? "unknown"}`);
|
|
263
|
+
console.log(`Pulled ${result.pullCount} files from remote.`);
|
|
415
264
|
console.log("\nSync is now active (no gateway restart needed).");
|
|
416
265
|
}
|
|
417
266
|
catch (err) {
|
|
@@ -584,5 +433,84 @@ export default function plugin(api) {
|
|
|
584
433
|
process.exit(1);
|
|
585
434
|
}
|
|
586
435
|
});
|
|
436
|
+
// --- onboard ---
|
|
437
|
+
clawracha
|
|
438
|
+
.command("onboard")
|
|
439
|
+
.description("Interactive guided setup for Storacha workspace sync")
|
|
440
|
+
.requiredOption("--agent <id>", "Agent ID")
|
|
441
|
+
.action(async (opts) => {
|
|
442
|
+
const { promptMultiline, choose } = await import("./prompts.js");
|
|
443
|
+
try {
|
|
444
|
+
const { agentId, workspace } = requireAgent(opts.agent);
|
|
445
|
+
console.log("š„ Welcome to Clawracha ā Storacha workspace sync!\n");
|
|
446
|
+
// Step 1: Init
|
|
447
|
+
console.log("Step 1: Agent Identity");
|
|
448
|
+
const initResult = await doInit(workspace);
|
|
449
|
+
if (initResult.alreadyInitialized) {
|
|
450
|
+
console.log(" Agent already initialized.");
|
|
451
|
+
if (initResult.setupComplete) {
|
|
452
|
+
console.log(` Setup is already complete! Use \`openclaw clawracha status --agent ${agentId}\` to check sync.\n`);
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
console.log(" ā
Agent identity generated!");
|
|
458
|
+
}
|
|
459
|
+
console.log(` Agent DID: ${initResult.agentDID}\n`);
|
|
460
|
+
// Step 2: Path choice
|
|
461
|
+
const choice = await choose("Are you setting up a NEW workspace or JOINING an existing one?", ["NEW workspace", "JOIN existing"]);
|
|
462
|
+
if (choice === "NEW workspace") {
|
|
463
|
+
// --- Setup path ---
|
|
464
|
+
console.log("\nš¦ New Workspace Setup\n");
|
|
465
|
+
console.log("You need a Storacha upload delegation for this agent.");
|
|
466
|
+
console.log("On a machine with the Storacha CLI, run:\n");
|
|
467
|
+
console.log(` storacha delegation create ${initResult.agentDID} --base64\n`);
|
|
468
|
+
const delegationInput = await promptMultiline("Paste your upload delegation here:");
|
|
469
|
+
if (!delegationInput) {
|
|
470
|
+
console.error("No delegation provided. Aborting.");
|
|
471
|
+
process.exit(1);
|
|
472
|
+
}
|
|
473
|
+
console.log("\nā³ Setting up workspace...");
|
|
474
|
+
const result = await doSetup(workspace, agentId, delegationInput, pluginConfig, config.gateway);
|
|
475
|
+
console.log(`\nš„ Storacha workspace ready for ${agentId}!`);
|
|
476
|
+
console.log(` Agent DID: ${result.agentDID}`);
|
|
477
|
+
console.log(` Space: ${result.spaceDID ?? "unknown"}`);
|
|
478
|
+
console.log("\nTo add another device, run:");
|
|
479
|
+
console.log(` openclaw clawracha grant <their-DID> --agent ${agentId}`);
|
|
480
|
+
console.log("\nSync is now active! š");
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
// --- Join path ---
|
|
484
|
+
console.log("\nš¤ Join Existing Workspace\n");
|
|
485
|
+
console.log("You need someone with access to grant you delegations.");
|
|
486
|
+
console.log("Ask them to run:\n");
|
|
487
|
+
console.log(` openclaw clawracha grant ${initResult.agentDID} --agent <their-agent-id>\n`);
|
|
488
|
+
console.log("They'll get two delegations to share with you.\n");
|
|
489
|
+
const uploadInput = await promptMultiline("Paste the upload delegation here:");
|
|
490
|
+
if (!uploadInput) {
|
|
491
|
+
console.error("No upload delegation provided. Aborting.");
|
|
492
|
+
process.exit(1);
|
|
493
|
+
}
|
|
494
|
+
const nameInput = await promptMultiline("Paste the name delegation here:");
|
|
495
|
+
if (!nameInput) {
|
|
496
|
+
console.error("No name delegation provided. Aborting.");
|
|
497
|
+
process.exit(1);
|
|
498
|
+
}
|
|
499
|
+
console.log("\nā³ Joining workspace...");
|
|
500
|
+
const result = await doJoin(workspace, agentId, uploadInput, nameInput, pluginConfig, config.gateway);
|
|
501
|
+
console.log(`\nš„ Joined Storacha workspace for ${agentId}!`);
|
|
502
|
+
console.log(` Agent DID: ${result.agentDID}`);
|
|
503
|
+
console.log(` Space: ${result.spaceDID ?? "unknown"}`);
|
|
504
|
+
console.log(` Pulled ${result.pullCount} files from remote.`);
|
|
505
|
+
console.log("\nSync is now active! š");
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
catch (err) {
|
|
509
|
+
console.error(`\nā Error: ${err.message}`);
|
|
510
|
+
if (err.stack)
|
|
511
|
+
console.error(err.stack);
|
|
512
|
+
process.exit(1);
|
|
513
|
+
}
|
|
514
|
+
});
|
|
587
515
|
}, { commands: ["clawracha"] });
|
|
588
516
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive prompt helpers using Node.js built-in readline/promises.
|
|
3
|
+
* Zero external dependencies.
|
|
4
|
+
*/
|
|
5
|
+
export declare function prompt(question: string): Promise<string>;
|
|
6
|
+
export declare function promptMultiline(question: string): Promise<string>;
|
|
7
|
+
export declare function choose(question: string, options: string[]): Promise<string>;
|
|
8
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,wBAAsB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ9D;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUvE;AAED,wBAAsB,MAAM,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
|
package/dist/prompts.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive prompt helpers using Node.js built-in readline/promises.
|
|
3
|
+
* Zero external dependencies.
|
|
4
|
+
*/
|
|
5
|
+
import * as readline from "node:readline/promises";
|
|
6
|
+
import { stdin, stdout } from "node:process";
|
|
7
|
+
export async function prompt(question) {
|
|
8
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
9
|
+
try {
|
|
10
|
+
const answer = await rl.question(question);
|
|
11
|
+
return answer.trim();
|
|
12
|
+
}
|
|
13
|
+
finally {
|
|
14
|
+
rl.close();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export async function promptMultiline(question) {
|
|
18
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
19
|
+
try {
|
|
20
|
+
console.log(question);
|
|
21
|
+
console.log("(Paste the value and press Enter)");
|
|
22
|
+
const answer = await rl.question("> ");
|
|
23
|
+
return answer.trim();
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
rl.close();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export async function choose(question, options) {
|
|
30
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
31
|
+
try {
|
|
32
|
+
console.log(question);
|
|
33
|
+
options.forEach((opt, i) => console.log(` ${i + 1}) ${opt}`));
|
|
34
|
+
while (true) {
|
|
35
|
+
const answer = await rl.question("Choice: ");
|
|
36
|
+
const num = parseInt(answer.trim(), 10);
|
|
37
|
+
if (num >= 1 && num <= options.length) {
|
|
38
|
+
return options[num - 1];
|
|
39
|
+
}
|
|
40
|
+
const match = options.find((o) => o.toLowerCase() === answer.trim().toLowerCase());
|
|
41
|
+
if (match)
|
|
42
|
+
return match;
|
|
43
|
+
console.log(`Please enter 1-${options.length}.`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
rl.close();
|
|
48
|
+
}
|
|
49
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storacha/clawracha",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "OpenClaw plugin for Storacha workspace sync via UCN Pail",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@ipld/car": "^5.2.0",
|
|
30
30
|
"@ipld/dag-cbor": "^9.2.5",
|
|
31
31
|
"@storacha/client": "^2.0.4",
|
|
32
|
-
"@storacha/md-merge": "0.
|
|
32
|
+
"@storacha/md-merge": "0.7.0",
|
|
33
33
|
"@storacha/ucn": "1.1.1-rc.3",
|
|
34
34
|
"@storacha/upload-client": "^1.3.9",
|
|
35
35
|
"@ucanto/interface": "^11.0.1",
|