@alfe.ai/openclaw-sync 0.0.6 → 0.0.7

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.
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env node
2
+ require("../ignore.cjs");
3
+ const require_sync_engine = require("../sync-engine.cjs");
4
+ let node_fs_promises = require("node:fs/promises");
5
+ let node_path = require("node:path");
6
+ //#region src/cli/index.ts
7
+ /**
8
+ * AlfeSync CLI — alfesync command-line interface.
9
+ *
10
+ * Commands:
11
+ * init - Initialize AlfeSync in a workspace
12
+ * push - Push local changes to remote
13
+ * pull - Pull remote changes to local
14
+ * status - Show sync status and pending changes
15
+ * conflicts - List conflict files
16
+ * history - Show version history for a file
17
+ * restore - Restore agent workspace from remote
18
+ */
19
+ const program = new (require("commander")).Command();
20
+ program.name("alfesync").description("AlfeSync — agent workspace backup and sync").version("1.0.0");
21
+ program.command("init").description("Initialize AlfeSync in the current workspace").option("-t, --token <token>", "Alfe Connect bearer token").option("-u, --api-url <url>", "AlfeSync API URL", "https://api.alfe.ai").option("-a, --agent-id <id>", "Agent ID for this workspace").option("-n, --display-name <name>", "Display name for the agent").action(async (opts) => {
22
+ const workspacePath = (0, node_path.resolve)(".");
23
+ if (require_sync_engine.isInitialized(workspacePath)) {
24
+ console.log("AlfeSync is already initialized in this workspace.");
25
+ const existing = await require_sync_engine.readConfig(workspacePath);
26
+ if (existing) {
27
+ console.log(` Agent: ${existing.agentId}`);
28
+ console.log(` API: ${existing.apiUrl}`);
29
+ }
30
+ return;
31
+ }
32
+ const token = opts.token ?? process.env.ALFESYNC_TOKEN;
33
+ const apiUrl = opts.apiUrl ?? process.env.ALFESYNC_API_URL ?? "https://api.alfe.ai";
34
+ const agentId = opts.agentId ?? process.env.ALFESYNC_AGENT_ID;
35
+ if (!token) {
36
+ console.error("Error: --token is required (or set ALFESYNC_TOKEN env var)");
37
+ process.exit(1);
38
+ }
39
+ if (!agentId) {
40
+ console.error("Error: --agent-id is required (or set ALFESYNC_AGENT_ID env var)");
41
+ process.exit(1);
42
+ }
43
+ console.log("Registering agent with AlfeSync...");
44
+ const client = require_sync_engine.createApiClient({
45
+ apiUrl,
46
+ token,
47
+ agentId
48
+ });
49
+ try {
50
+ const orgId = (await client.registerAgent(opts.displayName ?? agentId)).agent.orgId;
51
+ await require_sync_engine.writeConfig({
52
+ agentId,
53
+ orgId,
54
+ token,
55
+ workspacePath,
56
+ apiUrl
57
+ });
58
+ console.log("✓ AlfeSync initialized!");
59
+ console.log(` Agent: ${agentId}`);
60
+ console.log(` Org: ${orgId}`);
61
+ console.log(` API: ${apiUrl}`);
62
+ console.log(` Workspace: ${workspacePath}`);
63
+ console.log("");
64
+ console.log("Run 'alfesync push' to sync your workspace.");
65
+ } catch (err) {
66
+ console.error("Failed to register agent:", err instanceof Error ? err.message : String(err));
67
+ process.exit(1);
68
+ }
69
+ });
70
+ program.command("push").description("Push local changes to remote").option("-q, --quiet", "Suppress output").option("-f, --filter <prefix>", "Only push files matching this prefix").action(async (opts) => {
71
+ const workspacePath = (0, node_path.resolve)(".");
72
+ try {
73
+ await (await require_sync_engine.createSyncEngine(workspacePath)).push(void 0, {
74
+ quiet: opts.quiet,
75
+ filter: opts.filter
76
+ });
77
+ } catch (err) {
78
+ console.error(err instanceof Error ? err.message : String(err));
79
+ process.exit(1);
80
+ }
81
+ });
82
+ program.command("pull").description("Pull remote changes to local").option("-q, --quiet", "Suppress output").action(async (opts) => {
83
+ const workspacePath = (0, node_path.resolve)(".");
84
+ try {
85
+ await (await require_sync_engine.createSyncEngine(workspacePath)).pull({ quiet: opts.quiet });
86
+ } catch (err) {
87
+ console.error(err instanceof Error ? err.message : String(err));
88
+ process.exit(1);
89
+ }
90
+ });
91
+ program.command("status").description("Show sync status and pending changes").action(async () => {
92
+ const workspacePath = (0, node_path.resolve)(".");
93
+ try {
94
+ const config = await require_sync_engine.readConfig(workspacePath);
95
+ if (!config) {
96
+ console.log("AlfeSync not initialized. Run: alfesync init");
97
+ return;
98
+ }
99
+ const client = require_sync_engine.createApiClient({
100
+ apiUrl: config.apiUrl,
101
+ token: config.token,
102
+ agentId: config.agentId
103
+ });
104
+ const [localManifest, remoteManifest, stats] = await Promise.all([
105
+ require_sync_engine.readManifest(workspacePath),
106
+ client.getManifest(),
107
+ client.getStats()
108
+ ]);
109
+ const diff = require_sync_engine.diffManifests(localManifest, remoteManifest);
110
+ console.log("AlfeSync Status");
111
+ console.log("═══════════════");
112
+ console.log(`Agent: ${config.agentId}`);
113
+ console.log(`Workspace: ${workspacePath}`);
114
+ console.log(`API: ${config.apiUrl}`);
115
+ console.log("");
116
+ console.log("Storage:");
117
+ console.log(` Standard: ${formatBytes(stats.standardBytes)}`);
118
+ console.log(` Glacier IR: ${formatBytes(stats.glacierBytes)}`);
119
+ console.log(` Total files: ${String(stats.fileCount)}`);
120
+ console.log(` Last sync: ${stats.lastSyncAt ?? "never"}`);
121
+ console.log("");
122
+ console.log("Pending Changes:");
123
+ console.log(` To push: ${String(diff.toPush.length)}`);
124
+ console.log(` To pull: ${String(diff.toPull.length)}`);
125
+ console.log(` Conflicts: ${String(diff.conflicts.length)}`);
126
+ if (diff.toPush.length > 0) {
127
+ console.log("");
128
+ console.log("Files to push:");
129
+ for (const p of diff.toPush.slice(0, 20)) console.log(` ↑ ${p}`);
130
+ if (diff.toPush.length > 20) console.log(` ... and ${String(diff.toPush.length - 20)} more`);
131
+ }
132
+ if (diff.toPull.length > 0) {
133
+ console.log("");
134
+ console.log("Files to pull:");
135
+ for (const p of diff.toPull.slice(0, 20)) console.log(` ↓ ${p}`);
136
+ if (diff.toPull.length > 20) console.log(` ... and ${String(diff.toPull.length - 20)} more`);
137
+ }
138
+ if (diff.conflicts.length > 0) {
139
+ console.log("");
140
+ console.log("Conflicts:");
141
+ for (const p of diff.conflicts) console.log(` ⚡ ${p}`);
142
+ }
143
+ } catch (err) {
144
+ console.error(err instanceof Error ? err.message : String(err));
145
+ process.exit(1);
146
+ }
147
+ });
148
+ program.command("conflicts").description("List conflict files in the workspace").action(async () => {
149
+ const workspacePath = (0, node_path.resolve)(".");
150
+ try {
151
+ const conflicts = await findConflictFiles(workspacePath);
152
+ if (conflicts.length === 0) {
153
+ console.log("No conflict files found.");
154
+ return;
155
+ }
156
+ console.log(`Found ${String(conflicts.length)} conflict file(s):`);
157
+ for (const f of conflicts) console.log(` ⚡ ${f}`);
158
+ } catch (err) {
159
+ console.error(err instanceof Error ? err.message : String(err));
160
+ process.exit(1);
161
+ }
162
+ });
163
+ program.command("history <file>").description("Show version history for a file").action(async (file) => {
164
+ const workspacePath = (0, node_path.resolve)(".");
165
+ try {
166
+ const config = await require_sync_engine.readConfig(workspacePath);
167
+ if (!config) {
168
+ console.log("AlfeSync not initialized. Run: alfesync init");
169
+ return;
170
+ }
171
+ const versions = await require_sync_engine.createApiClient({
172
+ apiUrl: config.apiUrl,
173
+ token: config.token,
174
+ agentId: config.agentId
175
+ }).getFileHistory(file);
176
+ if (versions.length === 0) {
177
+ console.log(`No history found for: ${file}`);
178
+ return;
179
+ }
180
+ console.log(`Version history for: ${file}`);
181
+ console.log("─".repeat(60));
182
+ for (const v of versions) {
183
+ const marker = v.isLatest ? " (latest)" : "";
184
+ console.log(` ${v.lastModified} ${formatBytes(v.size)} ${v.versionId.slice(0, 12)}${marker}`);
185
+ }
186
+ } catch (err) {
187
+ console.error(err instanceof Error ? err.message : String(err));
188
+ process.exit(1);
189
+ }
190
+ });
191
+ program.command("restore").description("Restore agent workspace from remote backup").option("-m, --mode <mode>", "Restore mode: full, active, memory", "full").option("-q, --quiet", "Suppress output").action(async (opts) => {
192
+ const workspacePath = (0, node_path.resolve)(".");
193
+ try {
194
+ const config = await require_sync_engine.readConfig(workspacePath);
195
+ if (!config) {
196
+ console.log("AlfeSync not initialized. Run: alfesync init");
197
+ return;
198
+ }
199
+ const mode = opts.mode;
200
+ if (![
201
+ "full",
202
+ "active",
203
+ "memory"
204
+ ].includes(mode)) {
205
+ console.error("Error: mode must be full, active, or memory");
206
+ process.exit(1);
207
+ }
208
+ const client = require_sync_engine.createApiClient({
209
+ apiUrl: config.apiUrl,
210
+ token: config.token,
211
+ agentId: config.agentId
212
+ });
213
+ if (!opts.quiet) console.log(`Restoring workspace (mode: ${mode})...`);
214
+ const bundle = await client.reconstruct(mode);
215
+ if (!opts.quiet) console.log(`Downloading ${String(bundle.fileCount)} files (${formatBytes(bundle.totalSize)})...`);
216
+ const { writeFile, mkdir } = await import("node:fs/promises");
217
+ const { dirname } = await import("node:path");
218
+ let downloaded = 0;
219
+ let errors = 0;
220
+ for (const file of bundle.files) try {
221
+ const response = await fetch(file.url);
222
+ if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
223
+ const buffer = Buffer.from(await response.arrayBuffer());
224
+ const absolutePath = (0, node_path.join)(workspacePath, file.path);
225
+ await mkdir(dirname(absolutePath), { recursive: true });
226
+ await writeFile(absolutePath, buffer);
227
+ downloaded++;
228
+ if (!opts.quiet) console.log(` ↓ ${file.path} (${formatBytes(file.size)})`);
229
+ } catch (err) {
230
+ errors++;
231
+ if (!opts.quiet) console.error(` ✗ ${file.path}: ${err instanceof Error ? err.message : String(err)}`);
232
+ }
233
+ if (!opts.quiet) console.log(`\nRestore complete: ${String(downloaded)} files downloaded, ${String(errors)} errors.`);
234
+ } catch (err) {
235
+ console.error(err instanceof Error ? err.message : String(err));
236
+ process.exit(1);
237
+ }
238
+ });
239
+ async function findConflictFiles(dir, base) {
240
+ const results = [];
241
+ const entries = await (0, node_fs_promises.readdir)(dir, { withFileTypes: true });
242
+ for (const entry of entries) {
243
+ if (entry.name === "node_modules" || entry.name === ".git" || entry.name === ".alfesync") continue;
244
+ const fullPath = (0, node_path.join)(dir, entry.name);
245
+ const relativePath = base ? (0, node_path.join)(base, entry.name) : entry.name;
246
+ if (entry.isDirectory()) {
247
+ const sub = await findConflictFiles(fullPath, relativePath);
248
+ results.push(...sub);
249
+ } else if (entry.name.includes(".conflict-")) results.push(relativePath);
250
+ }
251
+ return results;
252
+ }
253
+ function formatBytes(bytes) {
254
+ if (bytes < 1024) return `${String(bytes)} B`;
255
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
256
+ if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
257
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
258
+ }
259
+ program.parse();
260
+ //#endregion
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,120 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __exportAll = (all, no_symbols) => {
9
+ let target = {};
10
+ for (var name in all) __defProp(target, name, {
11
+ get: all[name],
12
+ enumerable: true
13
+ });
14
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
15
+ return target;
16
+ };
17
+ var __copyProps = (to, from, except, desc) => {
18
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
19
+ key = keys[i];
20
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
21
+ get: ((k) => from[k]).bind(null, key),
22
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
23
+ });
24
+ }
25
+ return to;
26
+ };
27
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
28
+ value: mod,
29
+ enumerable: true
30
+ }) : target, mod));
31
+ //#endregion
32
+ let node_fs_promises = require("node:fs/promises");
33
+ let node_fs = require("node:fs");
34
+ let node_path = require("node:path");
35
+ let micromatch = require("micromatch");
36
+ micromatch = __toESM(micromatch);
37
+ //#region src/ignore.ts
38
+ /**
39
+ * AlfeSync ignore — parse `.alfesyncignore` (gitignore-style glob matching).
40
+ *
41
+ * Uses micromatch for glob pattern matching, compatible with .gitignore syntax.
42
+ */
43
+ var ignore_exports = /* @__PURE__ */ __exportAll({
44
+ filterIgnored: () => filterIgnored,
45
+ loadIgnorePatterns: () => loadIgnorePatterns,
46
+ shouldIgnore: () => shouldIgnore
47
+ });
48
+ /** Default ignore patterns — always applied */
49
+ const DEFAULT_IGNORES = [
50
+ ".alfesync/**",
51
+ "node_modules/**",
52
+ "*.tmp",
53
+ ".DS_Store",
54
+ ".git/**",
55
+ ".sst/**",
56
+ ".build/**",
57
+ "dist/**"
58
+ ];
59
+ /**
60
+ * Load ignore patterns from `.alfesyncignore` file + defaults.
61
+ */
62
+ async function loadIgnorePatterns(workspacePath) {
63
+ const ignoreFile = (0, node_path.join)(workspacePath, ".alfesyncignore");
64
+ const patterns = [...DEFAULT_IGNORES];
65
+ if ((0, node_fs.existsSync)(ignoreFile)) try {
66
+ const lines = (await (0, node_fs_promises.readFile)(ignoreFile, "utf-8")).split("\n");
67
+ for (const line of lines) {
68
+ const trimmed = line.trim();
69
+ if (!trimmed || trimmed.startsWith("#")) continue;
70
+ patterns.push(trimmed);
71
+ }
72
+ } catch {}
73
+ return patterns;
74
+ }
75
+ /**
76
+ * Check if a relative path should be ignored.
77
+ */
78
+ function shouldIgnore(relativePath, patterns) {
79
+ return micromatch.default.isMatch(relativePath, patterns, {
80
+ dot: true,
81
+ matchBase: true
82
+ });
83
+ }
84
+ /**
85
+ * Filter a list of relative paths, removing ignored ones.
86
+ */
87
+ function filterIgnored(paths, patterns) {
88
+ return paths.filter((p) => !shouldIgnore(p, patterns));
89
+ }
90
+ //#endregion
91
+ Object.defineProperty(exports, "__toESM", {
92
+ enumerable: true,
93
+ get: function() {
94
+ return __toESM;
95
+ }
96
+ });
97
+ Object.defineProperty(exports, "filterIgnored", {
98
+ enumerable: true,
99
+ get: function() {
100
+ return filterIgnored;
101
+ }
102
+ });
103
+ Object.defineProperty(exports, "ignore_exports", {
104
+ enumerable: true,
105
+ get: function() {
106
+ return ignore_exports;
107
+ }
108
+ });
109
+ Object.defineProperty(exports, "loadIgnorePatterns", {
110
+ enumerable: true,
111
+ get: function() {
112
+ return loadIgnorePatterns;
113
+ }
114
+ });
115
+ Object.defineProperty(exports, "shouldIgnore", {
116
+ enumerable: true,
117
+ get: function() {
118
+ return shouldIgnore;
119
+ }
120
+ });