@alfe.ai/openclaw-sync 0.0.16 → 0.0.18

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,39 +1,46 @@
1
1
  #!/usr/bin/env node
2
- require("../ignore.cjs");
3
2
  const require_sync_engine = require("../sync-engine.cjs");
4
- let node_path = require("node:path");
5
3
  let node_fs_promises = require("node:fs/promises");
4
+ let node_path = require("node:path");
5
+ let _alfe_ai_config = require("@alfe.ai/config");
6
+ let _alfe_ai_agent_api_client = require("@alfe.ai/agent-api-client");
7
+ let commander = require("commander");
6
8
  //#region src/cli/index.ts
7
9
  /**
8
- * AlfeSync CLI — alfesync command-line interface.
10
+ * AlfeSync CLI — `alfesync` command-line interface.
9
11
  *
10
12
  * Credentials come from `~/.alfe/config.toml` (set up via `alfe login`).
11
13
  * No separate sync init step is required.
12
14
  *
13
15
  * Commands:
14
- * register - Register this agent with the sync service (one-time)
16
+ * register - Idempotently register this agent with the sync service
15
17
  * push - Push local changes to remote
16
18
  * pull - Pull remote changes to local
17
19
  * status - Show sync status and pending changes
18
20
  * conflicts - List conflict files
19
- * history - Show version history for a file
20
21
  * restore - Restore agent workspace from remote
21
22
  */
22
- const program = new (require("commander")).Command();
23
+ function buildClient() {
24
+ if (!(0, _alfe_ai_config.configExists)()) throw new Error("Alfe not configured — run `alfe login` first.");
25
+ const config = (0, _alfe_ai_config.resolveConfig)();
26
+ return {
27
+ client: new _alfe_ai_agent_api_client.AgentApiClient({
28
+ apiKey: config.apiKey,
29
+ apiUrl: config.apiUrl
30
+ }),
31
+ workspacePath: config.workspacePath
32
+ };
33
+ }
34
+ const program = new commander.Command();
23
35
  program.name("alfesync").description("AlfeSync — agent workspace backup and sync").version("1.0.0");
24
- program.command("register").description("Register this agent with the sync service (one-time)").option("-n, --display-name <name>", "Display name for the agent").action(async (opts) => {
36
+ program.command("register").description("Register this agent with the sync service (idempotent)").option("-n, --display-name <name>", "Display name for the agent").action(async (opts) => {
25
37
  try {
26
- const config = await require_sync_engine.requireConfig();
27
- const result = await require_sync_engine.createApiClient({
28
- apiUrl: config.apiUrl,
29
- token: config.token,
30
- agentId: config.agentId
31
- }).registerAgent(opts.displayName ?? config.agentId);
38
+ const { client, workspacePath } = buildClient();
39
+ const result = await client.syncRegister(opts.displayName ? { displayName: opts.displayName } : void 0);
32
40
  console.log("✓ Agent registered with AlfeSync");
33
- console.log(` Agent: ${config.agentId}`);
34
- console.log(` Org: ${result.agent.orgId}`);
35
- console.log(` API: ${config.apiUrl}`);
36
- console.log(` Workspace: ${config.workspacePath}`);
41
+ console.log(` Agent: ${result.agent.agentId}`);
42
+ console.log(` Org: ${result.agent.tenantId}`);
43
+ console.log(` Workspace: ${workspacePath}`);
37
44
  } catch (err) {
38
45
  console.error(err instanceof Error ? err.message : String(err));
39
46
  process.exit(1);
@@ -41,7 +48,11 @@ program.command("register").description("Register this agent with the sync servi
41
48
  });
42
49
  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) => {
43
50
  try {
44
- await (await require_sync_engine.createSyncEngine()).push(void 0, {
51
+ const { client, workspacePath } = buildClient();
52
+ await require_sync_engine.createSyncEngine({
53
+ workspacePath,
54
+ client
55
+ }).push(void 0, {
45
56
  quiet: opts.quiet,
46
57
  filter: opts.filter
47
58
  });
@@ -52,7 +63,11 @@ program.command("push").description("Push local changes to remote").option("-q,
52
63
  });
53
64
  program.command("pull").description("Pull remote changes to local").option("-q, --quiet", "Suppress output").action(async (opts) => {
54
65
  try {
55
- await (await require_sync_engine.createSyncEngine()).pull({ quiet: opts.quiet });
66
+ const { client, workspacePath } = buildClient();
67
+ await require_sync_engine.createSyncEngine({
68
+ workspacePath,
69
+ client
70
+ }).pull({ quiet: opts.quiet });
56
71
  } catch (err) {
57
72
  console.error(err instanceof Error ? err.message : String(err));
58
73
  process.exit(1);
@@ -60,23 +75,17 @@ program.command("pull").description("Pull remote changes to local").option("-q,
60
75
  });
61
76
  program.command("status").description("Show sync status and pending changes").action(async () => {
62
77
  try {
63
- const config = await require_sync_engine.requireConfig();
64
- const client = require_sync_engine.createApiClient({
65
- apiUrl: config.apiUrl,
66
- token: config.token,
67
- agentId: config.agentId
68
- });
78
+ const { client, workspacePath } = buildClient();
69
79
  const [localManifest, remoteManifest, stats] = await Promise.all([
70
- require_sync_engine.readManifest(config.workspacePath),
71
- client.getManifest(),
72
- client.getStats()
80
+ require_sync_engine.readManifest(workspacePath),
81
+ client.syncGetManifest(),
82
+ client.syncGetStats()
73
83
  ]);
74
84
  const diff = require_sync_engine.diffManifests(localManifest, remoteManifest);
75
85
  console.log("AlfeSync Status");
76
86
  console.log("═══════════════");
77
- console.log(`Agent: ${config.agentId}`);
78
- console.log(`Workspace: ${config.workspacePath}`);
79
- console.log(`API: ${config.apiUrl}`);
87
+ console.log(`Agent: ${stats.agentId}`);
88
+ console.log(`Workspace: ${workspacePath}`);
80
89
  console.log("");
81
90
  console.log("Storage:");
82
91
  console.log(` Standard: ${formatBytes(stats.standardBytes)}`);
@@ -112,7 +121,8 @@ program.command("status").description("Show sync status and pending changes").ac
112
121
  });
113
122
  program.command("conflicts").description("List conflict files in the workspace").action(async () => {
114
123
  try {
115
- const conflicts = await findConflictFiles((await require_sync_engine.requireConfig()).workspacePath);
124
+ const { workspacePath } = buildClient();
125
+ const conflicts = await findConflictFiles(workspacePath);
116
126
  if (conflicts.length === 0) {
117
127
  console.log("No conflict files found.");
118
128
  return;
@@ -124,32 +134,9 @@ program.command("conflicts").description("List conflict files in the workspace")
124
134
  process.exit(1);
125
135
  }
126
136
  });
127
- program.command("history <file>").description("Show version history for a file").action(async (file) => {
128
- try {
129
- const config = await require_sync_engine.requireConfig();
130
- const versions = await require_sync_engine.createApiClient({
131
- apiUrl: config.apiUrl,
132
- token: config.token,
133
- agentId: config.agentId
134
- }).getFileHistory(file);
135
- if (versions.length === 0) {
136
- console.log(`No history found for: ${file}`);
137
- return;
138
- }
139
- console.log(`Version history for: ${file}`);
140
- console.log("─".repeat(60));
141
- for (const v of versions) {
142
- const marker = v.isLatest ? " (latest)" : "";
143
- console.log(` ${v.lastModified} ${formatBytes(v.size)} ${v.versionId.slice(0, 12)}${marker}`);
144
- }
145
- } catch (err) {
146
- console.error(err instanceof Error ? err.message : String(err));
147
- process.exit(1);
148
- }
149
- });
150
137
  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) => {
151
138
  try {
152
- const config = await require_sync_engine.requireConfig();
139
+ const { client, workspacePath } = buildClient();
153
140
  const mode = opts.mode;
154
141
  if (![
155
142
  "full",
@@ -159,13 +146,8 @@ program.command("restore").description("Restore agent workspace from remote back
159
146
  console.error("Error: mode must be full, active, or memory");
160
147
  process.exit(1);
161
148
  }
162
- const client = require_sync_engine.createApiClient({
163
- apiUrl: config.apiUrl,
164
- token: config.token,
165
- agentId: config.agentId
166
- });
167
149
  if (!opts.quiet) console.log(`Restoring workspace (mode: ${mode})...`);
168
- const bundle = await client.reconstruct(mode);
150
+ const bundle = await client.syncReconstruct({ mode });
169
151
  if (!opts.quiet) console.log(`Downloading ${String(bundle.fileCount)} files (${formatBytes(bundle.totalSize)})...`);
170
152
  const { writeFile, mkdir } = await import("node:fs/promises");
171
153
  const { dirname } = await import("node:path");
@@ -175,7 +157,7 @@ program.command("restore").description("Restore agent workspace from remote back
175
157
  const response = await fetch(file.url);
176
158
  if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
177
159
  const buffer = Buffer.from(await response.arrayBuffer());
178
- const absolutePath = (0, node_path.join)(config.workspacePath, file.path);
160
+ const absolutePath = (0, node_path.join)(workspacePath, file.path);
179
161
  await mkdir(dirname(absolutePath), { recursive: true });
180
162
  await writeFile(absolutePath, buffer);
181
163
  downloaded++;
package/dist/cli/index.js CHANGED
@@ -1,39 +1,46 @@
1
1
  #!/usr/bin/env node
2
- import { i as createApiClient, o as diffManifests, p as requireConfig, s as readManifest, t as createSyncEngine } from "../sync-engine.js";
3
- import { join } from "node:path";
2
+ import { l as diffManifests, t as createSyncEngine, u as readManifest } from "../sync-engine.js";
4
3
  import { readdir } from "node:fs/promises";
4
+ import { join } from "node:path";
5
+ import { configExists, resolveConfig } from "@alfe.ai/config";
6
+ import { AgentApiClient } from "@alfe.ai/agent-api-client";
5
7
  import { Command } from "commander";
6
8
  //#region src/cli/index.ts
7
9
  /**
8
- * AlfeSync CLI — alfesync command-line interface.
10
+ * AlfeSync CLI — `alfesync` command-line interface.
9
11
  *
10
12
  * Credentials come from `~/.alfe/config.toml` (set up via `alfe login`).
11
13
  * No separate sync init step is required.
12
14
  *
13
15
  * Commands:
14
- * register - Register this agent with the sync service (one-time)
16
+ * register - Idempotently register this agent with the sync service
15
17
  * push - Push local changes to remote
16
18
  * pull - Pull remote changes to local
17
19
  * status - Show sync status and pending changes
18
20
  * conflicts - List conflict files
19
- * history - Show version history for a file
20
21
  * restore - Restore agent workspace from remote
21
22
  */
23
+ function buildClient() {
24
+ if (!configExists()) throw new Error("Alfe not configured — run `alfe login` first.");
25
+ const config = resolveConfig();
26
+ return {
27
+ client: new AgentApiClient({
28
+ apiKey: config.apiKey,
29
+ apiUrl: config.apiUrl
30
+ }),
31
+ workspacePath: config.workspacePath
32
+ };
33
+ }
22
34
  const program = new Command();
23
35
  program.name("alfesync").description("AlfeSync — agent workspace backup and sync").version("1.0.0");
24
- program.command("register").description("Register this agent with the sync service (one-time)").option("-n, --display-name <name>", "Display name for the agent").action(async (opts) => {
36
+ program.command("register").description("Register this agent with the sync service (idempotent)").option("-n, --display-name <name>", "Display name for the agent").action(async (opts) => {
25
37
  try {
26
- const config = await requireConfig();
27
- const result = await createApiClient({
28
- apiUrl: config.apiUrl,
29
- token: config.token,
30
- agentId: config.agentId
31
- }).registerAgent(opts.displayName ?? config.agentId);
38
+ const { client, workspacePath } = buildClient();
39
+ const result = await client.syncRegister(opts.displayName ? { displayName: opts.displayName } : void 0);
32
40
  console.log("✓ Agent registered with AlfeSync");
33
- console.log(` Agent: ${config.agentId}`);
34
- console.log(` Org: ${result.agent.orgId}`);
35
- console.log(` API: ${config.apiUrl}`);
36
- console.log(` Workspace: ${config.workspacePath}`);
41
+ console.log(` Agent: ${result.agent.agentId}`);
42
+ console.log(` Org: ${result.agent.tenantId}`);
43
+ console.log(` Workspace: ${workspacePath}`);
37
44
  } catch (err) {
38
45
  console.error(err instanceof Error ? err.message : String(err));
39
46
  process.exit(1);
@@ -41,7 +48,11 @@ program.command("register").description("Register this agent with the sync servi
41
48
  });
42
49
  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) => {
43
50
  try {
44
- await (await createSyncEngine()).push(void 0, {
51
+ const { client, workspacePath } = buildClient();
52
+ await createSyncEngine({
53
+ workspacePath,
54
+ client
55
+ }).push(void 0, {
45
56
  quiet: opts.quiet,
46
57
  filter: opts.filter
47
58
  });
@@ -52,7 +63,11 @@ program.command("push").description("Push local changes to remote").option("-q,
52
63
  });
53
64
  program.command("pull").description("Pull remote changes to local").option("-q, --quiet", "Suppress output").action(async (opts) => {
54
65
  try {
55
- await (await createSyncEngine()).pull({ quiet: opts.quiet });
66
+ const { client, workspacePath } = buildClient();
67
+ await createSyncEngine({
68
+ workspacePath,
69
+ client
70
+ }).pull({ quiet: opts.quiet });
56
71
  } catch (err) {
57
72
  console.error(err instanceof Error ? err.message : String(err));
58
73
  process.exit(1);
@@ -60,23 +75,17 @@ program.command("pull").description("Pull remote changes to local").option("-q,
60
75
  });
61
76
  program.command("status").description("Show sync status and pending changes").action(async () => {
62
77
  try {
63
- const config = await requireConfig();
64
- const client = createApiClient({
65
- apiUrl: config.apiUrl,
66
- token: config.token,
67
- agentId: config.agentId
68
- });
78
+ const { client, workspacePath } = buildClient();
69
79
  const [localManifest, remoteManifest, stats] = await Promise.all([
70
- readManifest(config.workspacePath),
71
- client.getManifest(),
72
- client.getStats()
80
+ readManifest(workspacePath),
81
+ client.syncGetManifest(),
82
+ client.syncGetStats()
73
83
  ]);
74
84
  const diff = diffManifests(localManifest, remoteManifest);
75
85
  console.log("AlfeSync Status");
76
86
  console.log("═══════════════");
77
- console.log(`Agent: ${config.agentId}`);
78
- console.log(`Workspace: ${config.workspacePath}`);
79
- console.log(`API: ${config.apiUrl}`);
87
+ console.log(`Agent: ${stats.agentId}`);
88
+ console.log(`Workspace: ${workspacePath}`);
80
89
  console.log("");
81
90
  console.log("Storage:");
82
91
  console.log(` Standard: ${formatBytes(stats.standardBytes)}`);
@@ -112,7 +121,8 @@ program.command("status").description("Show sync status and pending changes").ac
112
121
  });
113
122
  program.command("conflicts").description("List conflict files in the workspace").action(async () => {
114
123
  try {
115
- const conflicts = await findConflictFiles((await requireConfig()).workspacePath);
124
+ const { workspacePath } = buildClient();
125
+ const conflicts = await findConflictFiles(workspacePath);
116
126
  if (conflicts.length === 0) {
117
127
  console.log("No conflict files found.");
118
128
  return;
@@ -124,32 +134,9 @@ program.command("conflicts").description("List conflict files in the workspace")
124
134
  process.exit(1);
125
135
  }
126
136
  });
127
- program.command("history <file>").description("Show version history for a file").action(async (file) => {
128
- try {
129
- const config = await requireConfig();
130
- const versions = await createApiClient({
131
- apiUrl: config.apiUrl,
132
- token: config.token,
133
- agentId: config.agentId
134
- }).getFileHistory(file);
135
- if (versions.length === 0) {
136
- console.log(`No history found for: ${file}`);
137
- return;
138
- }
139
- console.log(`Version history for: ${file}`);
140
- console.log("─".repeat(60));
141
- for (const v of versions) {
142
- const marker = v.isLatest ? " (latest)" : "";
143
- console.log(` ${v.lastModified} ${formatBytes(v.size)} ${v.versionId.slice(0, 12)}${marker}`);
144
- }
145
- } catch (err) {
146
- console.error(err instanceof Error ? err.message : String(err));
147
- process.exit(1);
148
- }
149
- });
150
137
  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) => {
151
138
  try {
152
- const config = await requireConfig();
139
+ const { client, workspacePath } = buildClient();
153
140
  const mode = opts.mode;
154
141
  if (![
155
142
  "full",
@@ -159,13 +146,8 @@ program.command("restore").description("Restore agent workspace from remote back
159
146
  console.error("Error: mode must be full, active, or memory");
160
147
  process.exit(1);
161
148
  }
162
- const client = createApiClient({
163
- apiUrl: config.apiUrl,
164
- token: config.token,
165
- agentId: config.agentId
166
- });
167
149
  if (!opts.quiet) console.log(`Restoring workspace (mode: ${mode})...`);
168
- const bundle = await client.reconstruct(mode);
150
+ const bundle = await client.syncReconstruct({ mode });
169
151
  if (!opts.quiet) console.log(`Downloading ${String(bundle.fileCount)} files (${formatBytes(bundle.totalSize)})...`);
170
152
  const { writeFile, mkdir } = await import("node:fs/promises");
171
153
  const { dirname } = await import("node:path");
@@ -175,7 +157,7 @@ program.command("restore").description("Restore agent workspace from remote back
175
157
  const response = await fetch(file.url);
176
158
  if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
177
159
  const buffer = Buffer.from(await response.arrayBuffer());
178
- const absolutePath = join(config.workspacePath, file.path);
160
+ const absolutePath = join(workspacePath, file.path);
179
161
  await mkdir(dirname(absolutePath), { recursive: true });
180
162
  await writeFile(absolutePath, buffer);
181
163
  downloaded++;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * AlfeSync CLI — alfesync command-line interface.\n *\n * Credentials come from `~/.alfe/config.toml` (set up via `alfe login`).\n * No separate sync init step is required.\n *\n * Commands:\n * register - Register this agent with the sync service (one-time)\n * push - Push local changes to remote\n * pull - Pull remote changes to local\n * status - Show sync status and pending changes\n * conflicts - List conflict files\n * history - Show version history for a file\n * restore - Restore agent workspace from remote\n */\n\nimport { Command } from \"commander\";\nimport { join } from \"node:path\";\nimport { readdir } from \"node:fs/promises\";\nimport { requireConfig } from \"../config.js\";\nimport { createApiClient } from \"../api-client.js\";\nimport { createSyncEngine } from \"../sync-engine.js\";\nimport { readManifest, diffManifests } from \"../manifest.js\";\n\n\nconst program = new Command();\n\nprogram\n .name(\"alfesync\")\n .description(\"AlfeSync — agent workspace backup and sync\")\n .version(\"1.0.0\");\n\n// ─── register ─────────────────────────────────────────────\n\nprogram\n .command(\"register\")\n .description(\"Register this agent with the sync service (one-time)\")\n .option(\"-n, --display-name <name>\", \"Display name for the agent\")\n .action(async (opts: { displayName?: string }) => {\n try {\n const config = await requireConfig();\n const client = createApiClient({\n apiUrl: config.apiUrl,\n token: config.token,\n agentId: config.agentId,\n });\n\n const result = await client.registerAgent(opts.displayName ?? config.agentId);\n console.log(\"✓ Agent registered with AlfeSync\");\n console.log(` Agent: ${config.agentId}`);\n console.log(` Org: ${result.agent.orgId}`);\n console.log(` API: ${config.apiUrl}`);\n console.log(` Workspace: ${config.workspacePath}`);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── push ─────────────────────────────────────────────────\n\nprogram\n .command(\"push\")\n .description(\"Push local changes to remote\")\n .option(\"-q, --quiet\", \"Suppress output\")\n .option(\"-f, --filter <prefix>\", \"Only push files matching this prefix\")\n .action(async (opts: { quiet?: boolean; filter?: string }) => {\n try {\n const engine = await createSyncEngine();\n await engine.push(undefined, {\n quiet: opts.quiet,\n filter: opts.filter,\n });\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── pull ─────────────────────────────────────────────────\n\nprogram\n .command(\"pull\")\n .description(\"Pull remote changes to local\")\n .option(\"-q, --quiet\", \"Suppress output\")\n .action(async (opts: { quiet?: boolean }) => {\n try {\n const engine = await createSyncEngine();\n await engine.pull({ quiet: opts.quiet });\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── status ───────────────────────────────────────────────\n\nprogram\n .command(\"status\")\n .description(\"Show sync status and pending changes\")\n .action(async () => {\n try {\n const config = await requireConfig();\n const client = createApiClient({\n apiUrl: config.apiUrl,\n token: config.token,\n agentId: config.agentId,\n });\n\n const [localManifest, remoteManifest, stats] = await Promise.all([\n readManifest(config.workspacePath),\n client.getManifest(),\n client.getStats(),\n ]);\n\n const diff = diffManifests(localManifest, remoteManifest);\n\n console.log(\"AlfeSync Status\");\n console.log(\"═══════════════\");\n console.log(`Agent: ${config.agentId}`);\n console.log(`Workspace: ${config.workspacePath}`);\n console.log(`API: ${config.apiUrl}`);\n console.log(\"\");\n\n console.log(\"Storage:\");\n console.log(` Standard: ${formatBytes(stats.standardBytes)}`);\n console.log(` Glacier IR: ${formatBytes(stats.glacierBytes)}`);\n console.log(` Total files: ${String(stats.fileCount)}`);\n console.log(` Last sync: ${stats.lastSyncAt ?? \"never\"}`);\n console.log(\"\");\n\n console.log(\"Pending Changes:\");\n console.log(` To push: ${String(diff.toPush.length)}`);\n console.log(` To pull: ${String(diff.toPull.length)}`);\n console.log(` Conflicts: ${String(diff.conflicts.length)}`);\n\n if (diff.toPush.length > 0) {\n console.log(\"\");\n console.log(\"Files to push:\");\n for (const p of diff.toPush.slice(0, 20)) {\n console.log(` ↑ ${p}`);\n }\n if (diff.toPush.length > 20) {\n console.log(` ... and ${String(diff.toPush.length - 20)} more`);\n }\n }\n\n if (diff.toPull.length > 0) {\n console.log(\"\");\n console.log(\"Files to pull:\");\n for (const p of diff.toPull.slice(0, 20)) {\n console.log(` ↓ ${p}`);\n }\n if (diff.toPull.length > 20) {\n console.log(` ... and ${String(diff.toPull.length - 20)} more`);\n }\n }\n\n if (diff.conflicts.length > 0) {\n console.log(\"\");\n console.log(\"Conflicts:\");\n for (const p of diff.conflicts) {\n console.log(` ⚡ ${p}`);\n }\n }\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── conflicts ────────────────────────────────────────────\n\nprogram\n .command(\"conflicts\")\n .description(\"List conflict files in the workspace\")\n .action(async () => {\n try {\n const config = await requireConfig();\n const conflicts = await findConflictFiles(config.workspacePath);\n if (conflicts.length === 0) {\n console.log(\"No conflict files found.\");\n return;\n }\n\n console.log(`Found ${String(conflicts.length)} conflict file(s):`);\n for (const f of conflicts) {\n console.log(` ⚡ ${f}`);\n }\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── history ──────────────────────────────────────────────\n\nprogram\n .command(\"history <file>\")\n .description(\"Show version history for a file\")\n .action(async (file: string) => {\n try {\n const config = await requireConfig();\n const client = createApiClient({\n apiUrl: config.apiUrl,\n token: config.token,\n agentId: config.agentId,\n });\n\n const versions = await client.getFileHistory(file);\n if (versions.length === 0) {\n console.log(`No history found for: ${file}`);\n return;\n }\n\n console.log(`Version history for: ${file}`);\n console.log(\"─\".repeat(60));\n for (const v of versions) {\n const marker = v.isLatest ? \" (latest)\" : \"\";\n console.log(\n ` ${v.lastModified} ${formatBytes(v.size)} ${v.versionId.slice(0, 12)}${marker}`,\n );\n }\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── restore ──────────────────────────────────────────────\n\nprogram\n .command(\"restore\")\n .description(\"Restore agent workspace from remote backup\")\n .option(\n \"-m, --mode <mode>\",\n \"Restore mode: full, active, memory\",\n \"full\",\n )\n .option(\"-q, --quiet\", \"Suppress output\")\n .action(async (opts: { mode?: string; quiet?: boolean }) => {\n try {\n const config = await requireConfig();\n const mode = opts.mode as \"full\" | \"active\" | \"memory\";\n if (![\"full\", \"active\", \"memory\"].includes(mode)) {\n console.error(\"Error: mode must be full, active, or memory\");\n process.exit(1);\n }\n\n const client = createApiClient({\n apiUrl: config.apiUrl,\n token: config.token,\n agentId: config.agentId,\n });\n\n if (!opts.quiet) {\n console.log(`Restoring workspace (mode: ${mode})...`);\n }\n\n const bundle = await client.reconstruct(mode);\n\n if (!opts.quiet) {\n console.log(\n `Downloading ${String(bundle.fileCount)} files (${formatBytes(bundle.totalSize)})...`,\n );\n }\n\n // Download each file from the bundle's presigned URLs\n const { writeFile, mkdir } = await import(\"node:fs/promises\");\n const { dirname } = await import(\"node:path\");\n\n let downloaded = 0;\n let errors = 0;\n\n for (const file of bundle.files) {\n try {\n const response = await fetch(file.url);\n if (!response.ok) {\n throw new Error(`HTTP ${String(response.status)}`);\n }\n\n const buffer = Buffer.from(await response.arrayBuffer());\n const absolutePath = join(config.workspacePath, file.path);\n await mkdir(dirname(absolutePath), { recursive: true });\n await writeFile(absolutePath, buffer);\n\n downloaded++;\n if (!opts.quiet) {\n console.log(` ↓ ${file.path} (${formatBytes(file.size)})`);\n }\n } catch (err) {\n errors++;\n if (!opts.quiet) {\n console.error(\n ` ✗ ${file.path}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n }\n\n if (!opts.quiet) {\n console.log(\n `\\nRestore complete: ${String(downloaded)} files downloaded, ${String(errors)} errors.`,\n );\n }\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── Helpers ──────────────────────────────────────────────\n\nasync function findConflictFiles(\n dir: string,\n base?: string,\n): Promise<string[]> {\n const results: string[] = [];\n const entries = await readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (\n entry.name === \"node_modules\" ||\n entry.name === \".git\"\n ) {\n continue;\n }\n\n const fullPath = join(dir, entry.name);\n const relativePath = base\n ? join(base, entry.name)\n : entry.name;\n\n if (entry.isDirectory()) {\n const sub = await findConflictFiles(fullPath, relativePath);\n results.push(...sub);\n } else if (entry.name.includes(\".conflict-\")) {\n results.push(relativePath);\n }\n }\n\n return results;\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${String(bytes)} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024)\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;\n}\n\n// ─── Run ──────────────────────────────────────────────────\n\nprogram.parse();\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["resolveAlfeConfig"],"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * AlfeSync CLI — `alfesync` command-line interface.\n *\n * Credentials come from `~/.alfe/config.toml` (set up via `alfe login`).\n * No separate sync init step is required.\n *\n * Commands:\n * register - Idempotently register this agent with the sync service\n * push - Push local changes to remote\n * pull - Pull remote changes to local\n * status - Show sync status and pending changes\n * conflicts - List conflict files\n * restore - Restore agent workspace from remote\n */\n\nimport { Command } from \"commander\";\nimport { join } from \"node:path\";\nimport { readdir } from \"node:fs/promises\";\nimport { AgentApiClient } from \"@alfe.ai/agent-api-client\";\nimport { resolveConfig as resolveAlfeConfig, configExists } from \"@alfe.ai/config\";\nimport { createSyncEngine } from \"../sync-engine.js\";\nimport { readManifest, diffManifests } from \"../manifest.js\";\n\nfunction buildClient(): { client: AgentApiClient; workspacePath: string } {\n if (!configExists()) {\n throw new Error(\"Alfe not configured — run `alfe login` first.\");\n }\n const config = resolveAlfeConfig();\n return {\n client: new AgentApiClient({ apiKey: config.apiKey, apiUrl: config.apiUrl }),\n workspacePath: config.workspacePath,\n };\n}\n\nconst program = new Command();\n\nprogram\n .name(\"alfesync\")\n .description(\"AlfeSync — agent workspace backup and sync\")\n .version(\"1.0.0\");\n\n// ─── register ─────────────────────────────────────────────\n\nprogram\n .command(\"register\")\n .description(\"Register this agent with the sync service (idempotent)\")\n .option(\"-n, --display-name <name>\", \"Display name for the agent\")\n .action(async (opts: { displayName?: string }) => {\n try {\n const { client, workspacePath } = buildClient();\n const result = await client.syncRegister(\n opts.displayName ? { displayName: opts.displayName } : undefined,\n );\n console.log(\"✓ Agent registered with AlfeSync\");\n console.log(` Agent: ${result.agent.agentId}`);\n console.log(` Org: ${result.agent.tenantId}`);\n console.log(` Workspace: ${workspacePath}`);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── push ─────────────────────────────────────────────────\n\nprogram\n .command(\"push\")\n .description(\"Push local changes to remote\")\n .option(\"-q, --quiet\", \"Suppress output\")\n .option(\"-f, --filter <prefix>\", \"Only push files matching this prefix\")\n .action(async (opts: { quiet?: boolean; filter?: string }) => {\n try {\n const { client, workspacePath } = buildClient();\n const engine = createSyncEngine({ workspacePath, client });\n await engine.push(undefined, { quiet: opts.quiet, filter: opts.filter });\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── pull ─────────────────────────────────────────────────\n\nprogram\n .command(\"pull\")\n .description(\"Pull remote changes to local\")\n .option(\"-q, --quiet\", \"Suppress output\")\n .action(async (opts: { quiet?: boolean }) => {\n try {\n const { client, workspacePath } = buildClient();\n const engine = createSyncEngine({ workspacePath, client });\n await engine.pull({ quiet: opts.quiet });\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── status ───────────────────────────────────────────────\n\nprogram\n .command(\"status\")\n .description(\"Show sync status and pending changes\")\n .action(async () => {\n try {\n const { client, workspacePath } = buildClient();\n const [localManifest, remoteManifest, stats] = await Promise.all([\n readManifest(workspacePath),\n client.syncGetManifest(),\n client.syncGetStats(),\n ]);\n const diff = diffManifests(localManifest, remoteManifest);\n\n console.log(\"AlfeSync Status\");\n console.log(\"═══════════════\");\n console.log(`Agent: ${stats.agentId}`);\n console.log(`Workspace: ${workspacePath}`);\n console.log(\"\");\n\n console.log(\"Storage:\");\n console.log(` Standard: ${formatBytes(stats.standardBytes)}`);\n console.log(` Glacier IR: ${formatBytes(stats.glacierBytes)}`);\n console.log(` Total files: ${String(stats.fileCount)}`);\n console.log(` Last sync: ${stats.lastSyncAt ?? \"never\"}`);\n console.log(\"\");\n\n console.log(\"Pending Changes:\");\n console.log(` To push: ${String(diff.toPush.length)}`);\n console.log(` To pull: ${String(diff.toPull.length)}`);\n console.log(` Conflicts: ${String(diff.conflicts.length)}`);\n\n if (diff.toPush.length > 0) {\n console.log(\"\");\n console.log(\"Files to push:\");\n for (const p of diff.toPush.slice(0, 20)) console.log(` ↑ ${p}`);\n if (diff.toPush.length > 20) {\n console.log(` ... and ${String(diff.toPush.length - 20)} more`);\n }\n }\n\n if (diff.toPull.length > 0) {\n console.log(\"\");\n console.log(\"Files to pull:\");\n for (const p of diff.toPull.slice(0, 20)) console.log(` ↓ ${p}`);\n if (diff.toPull.length > 20) {\n console.log(` ... and ${String(diff.toPull.length - 20)} more`);\n }\n }\n\n if (diff.conflicts.length > 0) {\n console.log(\"\");\n console.log(\"Conflicts:\");\n for (const p of diff.conflicts) console.log(` ⚡ ${p}`);\n }\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── conflicts ────────────────────────────────────────────\n\nprogram\n .command(\"conflicts\")\n .description(\"List conflict files in the workspace\")\n .action(async () => {\n try {\n const { workspacePath } = buildClient();\n const conflicts = await findConflictFiles(workspacePath);\n if (conflicts.length === 0) {\n console.log(\"No conflict files found.\");\n return;\n }\n console.log(`Found ${String(conflicts.length)} conflict file(s):`);\n for (const f of conflicts) console.log(` ⚡ ${f}`);\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── restore ──────────────────────────────────────────────\n\nprogram\n .command(\"restore\")\n .description(\"Restore agent workspace from remote backup\")\n .option(\"-m, --mode <mode>\", \"Restore mode: full, active, memory\", \"full\")\n .option(\"-q, --quiet\", \"Suppress output\")\n .action(async (opts: { mode?: string; quiet?: boolean }) => {\n try {\n const { client, workspacePath } = buildClient();\n const mode = opts.mode as \"full\" | \"active\" | \"memory\";\n if (![\"full\", \"active\", \"memory\"].includes(mode)) {\n console.error(\"Error: mode must be full, active, or memory\");\n process.exit(1);\n }\n\n if (!opts.quiet) console.log(`Restoring workspace (mode: ${mode})...`);\n const bundle = await client.syncReconstruct({ mode });\n\n if (!opts.quiet) {\n console.log(\n `Downloading ${String(bundle.fileCount)} files (${formatBytes(bundle.totalSize)})...`,\n );\n }\n\n const { writeFile, mkdir } = await import(\"node:fs/promises\");\n const { dirname } = await import(\"node:path\");\n\n let downloaded = 0;\n let errors = 0;\n for (const file of bundle.files) {\n try {\n const response = await fetch(file.url);\n if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);\n const buffer = Buffer.from(await response.arrayBuffer());\n const absolutePath = join(workspacePath, file.path);\n await mkdir(dirname(absolutePath), { recursive: true });\n await writeFile(absolutePath, buffer);\n downloaded++;\n if (!opts.quiet) console.log(` ↓ ${file.path} (${formatBytes(file.size)})`);\n } catch (err) {\n errors++;\n if (!opts.quiet) {\n console.error(\n ` ✗ ${file.path}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n }\n\n if (!opts.quiet) {\n console.log(\n `\\nRestore complete: ${String(downloaded)} files downloaded, ${String(errors)} errors.`,\n );\n }\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ─── Helpers ──────────────────────────────────────────────\n\nasync function findConflictFiles(dir: string, base?: string): Promise<string[]> {\n const results: string[] = [];\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.name === \"node_modules\" || entry.name === \".git\") continue;\n const fullPath = join(dir, entry.name);\n const relativePath = base ? join(base, entry.name) : entry.name;\n if (entry.isDirectory()) {\n const sub = await findConflictFiles(fullPath, relativePath);\n results.push(...sub);\n } else if (entry.name.includes(\".conflict-\")) {\n results.push(relativePath);\n }\n }\n return results;\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${String(bytes)} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;\n}\n\n// ─── Run ──────────────────────────────────────────────────\n\nprogram.parse();\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -1,25 +1,19 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_ignore = require("./ignore.cjs");
3
2
  const require_sync_engine = require("./sync-engine.cjs");
4
3
  const require_plugin = require("./plugin2.cjs");
5
4
  exports.computeFileHash = require_sync_engine.computeFileHash;
6
- exports.createApiClient = require_sync_engine.createApiClient;
7
5
  exports.createSharedSyncEngine = require_plugin.createSharedSyncEngine;
8
6
  exports.createSyncEngine = require_sync_engine.createSyncEngine;
9
7
  exports.diffManifests = require_sync_engine.diffManifests;
10
8
  exports.downloadFiles = require_sync_engine.downloadFiles;
11
- exports.filterIgnored = require_ignore.filterIgnored;
12
- exports.invalidateSyncConfigCache = require_sync_engine.invalidateSyncConfigCache;
13
- exports.isInitialized = require_sync_engine.isInitialized;
14
- exports.loadIgnorePatterns = require_ignore.loadIgnorePatterns;
9
+ exports.filterIgnored = require_sync_engine.filterIgnored;
10
+ exports.loadIgnorePatterns = require_sync_engine.loadIgnorePatterns;
15
11
  exports.plugin = require_plugin.plugin;
16
12
  exports.readManifest = require_sync_engine.readManifest;
17
13
  exports.removeManifestEntry = require_sync_engine.removeManifestEntry;
18
- exports.requireConfig = require_sync_engine.requireConfig;
19
- exports.resolveSyncConfig = require_sync_engine.resolveSyncConfig;
20
- exports.shouldIgnore = require_ignore.shouldIgnore;
14
+ exports.shouldIgnore = require_sync_engine.shouldIgnore;
21
15
  exports.startWatcher = require_plugin.startWatcher;
22
- exports.syncStateDir = require_sync_engine.syncStateDir;
23
16
  exports.updateManifestEntry = require_sync_engine.updateManifestEntry;
24
17
  exports.uploadFiles = require_sync_engine.uploadFiles;
18
+ exports.withRetry = require_sync_engine.withRetry;
25
19
  exports.writeManifest = require_sync_engine.writeManifest;