@alfe.ai/openclaw-sync 0.1.11 → 0.2.0

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.
@@ -29,7 +29,8 @@ function buildClient() {
29
29
  apiKey: config.apiKey,
30
30
  apiUrl: config.apiUrl
31
31
  }),
32
- workspacePath: config.workspacePath
32
+ workspacePath: config.workspacePath,
33
+ runtime: config.runtime
33
34
  };
34
35
  }
35
36
  const program = new commander.Command();
@@ -49,10 +50,11 @@ program.command("register").description("Register this agent with the sync servi
49
50
  });
50
51
  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) => {
51
52
  try {
52
- const { client, workspacePath } = buildClient();
53
+ const { client, workspacePath, runtime } = buildClient();
53
54
  await require_sync_engine.createSyncEngine({
54
55
  workspacePath,
55
- client
56
+ client,
57
+ runtime
56
58
  }).push(void 0, {
57
59
  quiet: opts.quiet,
58
60
  filter: opts.filter
@@ -64,10 +66,11 @@ program.command("push").description("Push local changes to remote").option("-q,
64
66
  });
65
67
  program.command("pull").description("Pull remote changes to local").option("-q, --quiet", "Suppress output").action(async (opts) => {
66
68
  try {
67
- const { client, workspacePath } = buildClient();
69
+ const { client, workspacePath, runtime } = buildClient();
68
70
  await require_sync_engine.createSyncEngine({
69
71
  workspacePath,
70
- client
72
+ client,
73
+ runtime
71
74
  }).pull({ quiet: opts.quiet });
72
75
  } catch (err) {
73
76
  console.error(err instanceof Error ? err.message : String(err));
@@ -137,8 +140,8 @@ program.command("conflicts").description("List conflict files in the workspace")
137
140
  });
138
141
  program.command("prune").description("Delete cloud files matching .alfesyncignore. Dry-run by default; pass --yes to actually delete.").option("-y, --yes", "Actually delete files (default is dry-run)").action(async (opts) => {
139
142
  try {
140
- const { client, workspacePath } = buildClient();
141
- const ignorePatterns = await require_sync_engine.loadIgnorePatterns(workspacePath);
143
+ const { client, workspacePath, runtime } = buildClient();
144
+ const ignorePatterns = await require_sync_engine.loadIgnorePatterns(workspacePath, runtime);
142
145
  const remoteManifest = await client.syncGetManifest();
143
146
  const ignoredPaths = [];
144
147
  for (const [path, entry] of Object.entries(remoteManifest.files)) if (require_sync_engine.shouldIgnore(path, ignorePatterns)) ignoredPaths.push({
@@ -162,7 +165,8 @@ program.command("prune").description("Delete cloud files matching .alfesyncignor
162
165
  console.log(`Deleting ${String(ignoredPaths.length)} file(s) from cloud (${formatBytes(totalSize)})...`);
163
166
  const result = await require_sync_engine.createSyncEngine({
164
167
  workspacePath,
165
- client
168
+ client,
169
+ runtime
166
170
  }).pushDeletes(ignoredPaths.map((e) => e.path), { quiet: true });
167
171
  console.log(`Prune complete: ${String(result.pushed)} deleted, ${String(result.errors)} failed.`);
168
172
  } catch (err) {
package/dist/cli/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { l as diffManifests, o as loadIgnorePatterns, s as shouldIgnore, t as createSyncEngine, u as readManifest } from "../sync-engine.js";
2
+ import { c as shouldIgnore, d as diffManifests, f as readManifest, s as loadIgnorePatterns, t as createSyncEngine } from "../sync-engine.js";
3
3
  import { readdir } from "node:fs/promises";
4
4
  import { join } from "node:path";
5
5
  import { configExists, resolveConfig } from "@alfe.ai/config";
@@ -29,7 +29,8 @@ function buildClient() {
29
29
  apiKey: config.apiKey,
30
30
  apiUrl: config.apiUrl
31
31
  }),
32
- workspacePath: config.workspacePath
32
+ workspacePath: config.workspacePath,
33
+ runtime: config.runtime
33
34
  };
34
35
  }
35
36
  const program = new Command();
@@ -49,10 +50,11 @@ program.command("register").description("Register this agent with the sync servi
49
50
  });
50
51
  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) => {
51
52
  try {
52
- const { client, workspacePath } = buildClient();
53
+ const { client, workspacePath, runtime } = buildClient();
53
54
  await createSyncEngine({
54
55
  workspacePath,
55
- client
56
+ client,
57
+ runtime
56
58
  }).push(void 0, {
57
59
  quiet: opts.quiet,
58
60
  filter: opts.filter
@@ -64,10 +66,11 @@ program.command("push").description("Push local changes to remote").option("-q,
64
66
  });
65
67
  program.command("pull").description("Pull remote changes to local").option("-q, --quiet", "Suppress output").action(async (opts) => {
66
68
  try {
67
- const { client, workspacePath } = buildClient();
69
+ const { client, workspacePath, runtime } = buildClient();
68
70
  await createSyncEngine({
69
71
  workspacePath,
70
- client
72
+ client,
73
+ runtime
71
74
  }).pull({ quiet: opts.quiet });
72
75
  } catch (err) {
73
76
  console.error(err instanceof Error ? err.message : String(err));
@@ -137,8 +140,8 @@ program.command("conflicts").description("List conflict files in the workspace")
137
140
  });
138
141
  program.command("prune").description("Delete cloud files matching .alfesyncignore. Dry-run by default; pass --yes to actually delete.").option("-y, --yes", "Actually delete files (default is dry-run)").action(async (opts) => {
139
142
  try {
140
- const { client, workspacePath } = buildClient();
141
- const ignorePatterns = await loadIgnorePatterns(workspacePath);
143
+ const { client, workspacePath, runtime } = buildClient();
144
+ const ignorePatterns = await loadIgnorePatterns(workspacePath, runtime);
142
145
  const remoteManifest = await client.syncGetManifest();
143
146
  const ignoredPaths = [];
144
147
  for (const [path, entry] of Object.entries(remoteManifest.files)) if (shouldIgnore(path, ignorePatterns)) ignoredPaths.push({
@@ -162,7 +165,8 @@ program.command("prune").description("Delete cloud files matching .alfesyncignor
162
165
  console.log(`Deleting ${String(ignoredPaths.length)} file(s) from cloud (${formatBytes(totalSize)})...`);
163
166
  const result = await createSyncEngine({
164
167
  workspacePath,
165
- client
168
+ client,
169
+ runtime
166
170
  }).pushDeletes(ignoredPaths.map((e) => e.path), { quiet: true });
167
171
  console.log(`Prune complete: ${String(result.pushed)} deleted, ${String(result.errors)} failed.`);
168
172
  } catch (err) {
@@ -1 +1 @@
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 * prune - Delete cloud files matching .alfesyncignore (dry-run by default)\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\";\nimport { loadIgnorePatterns, shouldIgnore } from \"../ignore.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// ─── prune ────────────────────────────────────────────────\n\nprogram\n .command(\"prune\")\n .description(\n \"Delete cloud files matching .alfesyncignore. Dry-run by default; pass --yes to actually delete.\",\n )\n .option(\"-y, --yes\", \"Actually delete files (default is dry-run)\")\n .action(async (opts: { yes?: boolean }) => {\n try {\n const { client, workspacePath } = buildClient();\n const ignorePatterns = await loadIgnorePatterns(workspacePath);\n const remoteManifest = await client.syncGetManifest();\n\n const ignoredPaths: { path: string; size: number }[] = [];\n for (const [path, entry] of Object.entries(remoteManifest.files)) {\n if (shouldIgnore(path, ignorePatterns)) {\n ignoredPaths.push({ path, size: entry.size });\n }\n }\n\n if (ignoredPaths.length === 0) {\n console.log(\"Nothing to prune — no cloud files match .alfesyncignore.\");\n return;\n }\n\n const totalSize = ignoredPaths.reduce((s, e) => s + e.size, 0);\n\n if (!opts.yes) {\n console.log(\n `Dry-run: ${String(ignoredPaths.length)} cloud file(s) would be deleted (${formatBytes(totalSize)}).`,\n );\n console.log(\"\");\n for (const { path, size } of ignoredPaths.slice(0, 50)) {\n console.log(` ✗ ${path} (${formatBytes(size)})`);\n }\n if (ignoredPaths.length > 50) {\n console.log(` ... and ${String(ignoredPaths.length - 50)} more`);\n }\n console.log(\"\");\n console.log(\"Re-run with --yes to delete these files from the cloud.\");\n return;\n }\n\n console.log(\n `Deleting ${String(ignoredPaths.length)} file(s) from cloud (${formatBytes(totalSize)})...`,\n );\n const engine = createSyncEngine({ workspacePath, client });\n const result = await engine.pushDeletes(\n ignoredPaths.map((e) => e.path),\n { quiet: true },\n );\n console.log(\n `Prune complete: ${String(result.pushed)} deleted, ${String(result.errors)} failed.`,\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(\"-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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"}
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 * prune - Delete cloud files matching .alfesyncignore (dry-run by default)\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\";\nimport { loadIgnorePatterns, shouldIgnore } from \"../ignore.js\";\n\nfunction buildClient(): { client: AgentApiClient; workspacePath: string; runtime: 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 runtime: config.runtime,\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, runtime } = buildClient();\n const engine = createSyncEngine({ workspacePath, client, runtime });\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, runtime } = buildClient();\n const engine = createSyncEngine({ workspacePath, client, runtime });\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// ─── prune ────────────────────────────────────────────────\n\nprogram\n .command(\"prune\")\n .description(\n \"Delete cloud files matching .alfesyncignore. Dry-run by default; pass --yes to actually delete.\",\n )\n .option(\"-y, --yes\", \"Actually delete files (default is dry-run)\")\n .action(async (opts: { yes?: boolean }) => {\n try {\n const { client, workspacePath, runtime } = buildClient();\n const ignorePatterns = await loadIgnorePatterns(workspacePath, runtime);\n const remoteManifest = await client.syncGetManifest();\n\n const ignoredPaths: { path: string; size: number }[] = [];\n for (const [path, entry] of Object.entries(remoteManifest.files)) {\n if (shouldIgnore(path, ignorePatterns)) {\n ignoredPaths.push({ path, size: entry.size });\n }\n }\n\n if (ignoredPaths.length === 0) {\n console.log(\"Nothing to prune — no cloud files match .alfesyncignore.\");\n return;\n }\n\n const totalSize = ignoredPaths.reduce((s, e) => s + e.size, 0);\n\n if (!opts.yes) {\n console.log(\n `Dry-run: ${String(ignoredPaths.length)} cloud file(s) would be deleted (${formatBytes(totalSize)}).`,\n );\n console.log(\"\");\n for (const { path, size } of ignoredPaths.slice(0, 50)) {\n console.log(` ✗ ${path} (${formatBytes(size)})`);\n }\n if (ignoredPaths.length > 50) {\n console.log(` ... and ${String(ignoredPaths.length - 50)} more`);\n }\n console.log(\"\");\n console.log(\"Re-run with --yes to delete these files from the cloud.\");\n return;\n }\n\n console.log(\n `Deleting ${String(ignoredPaths.length)} file(s) from cloud (${formatBytes(totalSize)})...`,\n );\n const engine = createSyncEngine({ workspacePath, client, runtime });\n const result = await engine.pushDeletes(\n ignoredPaths.map((e) => e.path),\n { quiet: true },\n );\n console.log(\n `Prune complete: ${String(result.pushed)} deleted, ${String(result.errors)} failed.`,\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(\"-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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"}
@@ -0,0 +1,43 @@
1
+ # AlfeSync default ignores — applied to EVERY runtime.
2
+ #
3
+ # Source of truth for the sync's baseline ignore set (previously the hardcoded
4
+ # DEFAULT_IGNORES array). Entries are full micromatch globs, NOT gitignore
5
+ # shorthand — they are used verbatim (the workspace `.alfesyncignore` is the
6
+ # gitignore-shorthand surface). Match a name at any depth with a `**/` prefix;
7
+ # `matchBase` is never used (it breaks deep `**/X/**` in micromatch 4.x).
8
+ #
9
+ # Categories:
10
+ # VCS / build / package metadata; OS + editor noise; sync-internal backstop;
11
+ # secrets (never sync); OpenClaw config-rotation backups; Chromium/Electron
12
+ # browser caches (zero restore value, tens of MB); language churn.
13
+
14
+ **/.alfesync/**
15
+ # shared/ mirrors org/team/project files (OrgFilesBucket) into the workspace via
16
+ # shared-sync — the PRIVATE backup must not re-store them into SyncBucket, or a
17
+ # rebuild would restore stale shared files from the wrong bucket. Root-anchored
18
+ # to the runtime home; a nested user `workspace/shared/` still syncs.
19
+ shared/**
20
+ **/node_modules/**
21
+ **/*.tmp
22
+ **/.DS_Store
23
+ **/.git/**
24
+ **/.sst/**
25
+ **/.build/**
26
+ **/dist/**
27
+ **/.env
28
+ **/.env.*
29
+ **/openclaw.json.bak*
30
+ **/openclaw.json.clobbered.*
31
+ **/openclaw.json.preserve.*
32
+ **/Cache/**
33
+ **/Code Cache/**
34
+ **/GPUCache/**
35
+ **/CacheStorage/**
36
+ **/Service Worker/CacheStorage/**
37
+ **/blob_storage/**
38
+ **/Crashpad/**
39
+ **/ShaderCache/**
40
+ **/component_crx_cache/**
41
+ **/__pycache__/**
42
+ **/*.pyc
43
+ **/*.log
@@ -0,0 +1,14 @@
1
+ # AlfeSync default ignores — Hermes runtime only.
2
+ #
3
+ # The sync watches the Hermes runtime HOME (~/.hermes), whose top level holds
4
+ # the Python venv and the installed agent code as siblings of user files.
5
+ # Large / high-churn / regenerable — never sync.
6
+ #
7
+ # `.venv/` is matched at any depth (nested venvs are common); `hermes-agent/`
8
+ # is root-anchored to the runtime home. Full micromatch globs, used verbatim.
9
+ # (`__pycache__` and `*.pyc` are already covered by the common set.)
10
+
11
+ # Python virtual environment
12
+ **/.venv/**
13
+ # Hermes runtime code installed by the installer: ~/.hermes/hermes-agent/...
14
+ hermes-agent/**
@@ -0,0 +1,17 @@
1
+ # AlfeSync default ignores — OpenClaw runtime only.
2
+ #
3
+ # The sync watches the OpenClaw runtime HOME (~/.openclaw), whose top level
4
+ # holds runtime-internal dirs as siblings of the agent-owned `workspace/`.
5
+ # These are large, high-churn, and have zero restore value — if synced they
6
+ # exhaust the OS inotify watch limit and crash-loop the runtime.
7
+ #
8
+ # Root-anchored (no `**/` prefix) so they only match the runtime home's top
9
+ # level — a user dir named `plugins/` deeper in the workspace still syncs.
10
+ # Full micromatch globs, used verbatim.
11
+
12
+ # npm plugin registry (OpenClaw 2026.5+): ~/.openclaw/npm/node_modules/...
13
+ npm/**
14
+ # Plugin extension installs (OpenClaw 2026.4): ~/.openclaw/extensions/...
15
+ extensions/**
16
+ # Plugin install metadata (installs.json etc.): ~/.openclaw/plugins/...
17
+ plugins/**
package/dist/index.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_sync_engine = require("./sync-engine.cjs");
3
3
  const require_plugin = require("./plugin2.cjs");
4
+ exports.DEFAULT_IGNORES = require_sync_engine.DEFAULT_IGNORES;
4
5
  exports.computeFileHash = require_sync_engine.computeFileHash;
5
6
  exports.createSharedSyncEngine = require_plugin.createSharedSyncEngine;
6
7
  exports.createSyncEngine = require_sync_engine.createSyncEngine;
@@ -12,6 +13,7 @@ exports.plugin = require_plugin.plugin;
12
13
  exports.readManifest = require_sync_engine.readManifest;
13
14
  exports.removeManifestEntry = require_sync_engine.removeManifestEntry;
14
15
  exports.shouldIgnore = require_sync_engine.shouldIgnore;
16
+ exports.shouldIgnoreDir = require_sync_engine.shouldIgnoreDir;
15
17
  exports.startWatcher = require_plugin.startWatcher;
16
18
  exports.updateManifestEntry = require_sync_engine.updateManifestEntry;
17
19
  exports.uploadFiles = require_sync_engine.uploadFiles;
package/dist/index.d.cts CHANGED
@@ -81,8 +81,10 @@ declare function diffManifests(local: LocalManifest, remote: RemoteManifest): Ma
81
81
  //# sourceMappingURL=manifest.d.ts.map
82
82
  //#endregion
83
83
  //#region src/ignore.d.ts
84
- declare function loadIgnorePatterns(workspacePath: string): Promise<string[]>;
84
+ declare const DEFAULT_IGNORES: string[];
85
+ declare function loadIgnorePatterns(workspacePath: string, runtime?: string): Promise<string[]>;
85
86
  declare function shouldIgnore(relativePath: string, patterns: string[]): boolean;
87
+ declare function shouldIgnoreDir(relativeDir: string, patterns: string[]): boolean;
86
88
  declare function filterIgnored(paths: string[], patterns: string[]): string[];
87
89
  //# sourceMappingURL=ignore.d.ts.map
88
90
  //#endregion
@@ -1415,6 +1417,11 @@ interface SyncResult {
1415
1417
  interface SyncEngineOptions {
1416
1418
  workspacePath: string;
1417
1419
  client: AgentApiClient;
1420
+ /**
1421
+ * Active agent runtime — selects the per-runtime default ignore set used by
1422
+ * every scan (push / fullSync / firstRunReconcile). Default: "openclaw".
1423
+ */
1424
+ runtime?: string;
1418
1425
  }
1419
1426
  /**
1420
1427
  * Construct a sync engine bound to a workspace + agent API client.
@@ -1424,10 +1431,12 @@ interface SyncEngineOptions {
1424
1431
  */
1425
1432
  declare function createSyncEngine({
1426
1433
  workspacePath,
1427
- client
1434
+ client,
1435
+ runtime
1428
1436
  }: SyncEngineOptions): {
1429
1437
  workspacePath: string;
1430
1438
  client: AgentApiClient;
1439
+ runtime: string;
1431
1440
  /**
1432
1441
  * Upload changed files. Pass `paths` for an explicit list, or omit
1433
1442
  * to scan the workspace for anything that drifted from the manifest.
@@ -1487,6 +1496,20 @@ declare function createSyncEngine({
1487
1496
  pullFiles(paths: string[], options?: {
1488
1497
  quiet?: boolean;
1489
1498
  }): Promise<SyncResult>;
1499
+ /**
1500
+ * Purge cloud files that match the current (per-runtime) ignore set.
1501
+ *
1502
+ * Self-heals workspaces whose cloud copy still holds runtime-internal junk
1503
+ * (node_modules, the openclaw npm cache, …) that a pre-fix ignore engine
1504
+ * uploaded before it was correctly ignored. Bounded to ignored paths only,
1505
+ * so it can never delete a legitimately-synced file, and it deletes the
1506
+ * cloud copy directly (not via the watcher) so the rolling-window delete
1507
+ * brake — which guards against a buggy `rm -rf` — does not apply.
1508
+ */
1509
+ pruneIgnored(options?: {
1510
+ quiet?: boolean;
1511
+ limit?: number;
1512
+ }): Promise<SyncResult>;
1490
1513
  /**
1491
1514
  * Delete a file locally and from the manifest. Used when the sync relay
1492
1515
  * tells us a file was removed remotely.
@@ -1507,6 +1530,12 @@ type SyncEngine = ReturnType<typeof createSyncEngine>;
1507
1530
  */
1508
1531
  interface WatcherOptions {
1509
1532
  workspacePath: string;
1533
+ /**
1534
+ * Active agent runtime — selects the per-runtime default ignore set so the
1535
+ * watcher never descends into runtime-internal dirs (openclaw `npm/`,
1536
+ * hermes `.venv/`, …). Default: "openclaw".
1537
+ */
1538
+ runtime?: string;
1510
1539
  /** Debounce delay per file in milliseconds. Default: 2000 */
1511
1540
  debounceMs?: number;
1512
1541
  /** Callback invoked with batches of changed relative paths */
@@ -1592,5 +1621,5 @@ interface SharedSyncEngine {
1592
1621
  }
1593
1622
  declare function createSharedSyncEngine(config: SharedSyncConfig, log: PluginLogger): SharedSyncEngine;
1594
1623
  //#endregion
1595
- export { type DownloadResult, type LocalManifest, type ManifestDiff, type ManifestEntry, type RemoteManifest, type RetryOptions, type SharedScope, type SharedSyncConfig, type SharedSyncEngine, type SyncEngine, type SyncPluginConfig, type SyncResult, type UploadResult, type WatcherOptions, computeFileHash, createSharedSyncEngine, createSyncEngine, diffManifests, downloadFiles, filterIgnored, loadIgnorePatterns, plugin, readManifest, removeManifestEntry, shouldIgnore, startWatcher, updateManifestEntry, uploadFiles, withRetry, writeManifest };
1624
+ export { DEFAULT_IGNORES, type DownloadResult, type LocalManifest, type ManifestDiff, type ManifestEntry, type RemoteManifest, type RetryOptions, type SharedScope, type SharedSyncConfig, type SharedSyncEngine, type SyncEngine, type SyncPluginConfig, type SyncResult, type UploadResult, type WatcherOptions, computeFileHash, createSharedSyncEngine, createSyncEngine, diffManifests, downloadFiles, filterIgnored, loadIgnorePatterns, plugin, readManifest, removeManifestEntry, shouldIgnore, shouldIgnoreDir, startWatcher, updateManifestEntry, uploadFiles, withRetry, writeManifest };
1596
1625
  //# sourceMappingURL=index.d.cts.map