@kodrunhq/claudefy 1.3.4 → 1.4.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.
Files changed (37) hide show
  1. package/dist/claude-json-sync/claude-json-sync.d.ts +12 -0
  2. package/dist/claude-json-sync/claude-json-sync.js +129 -0
  3. package/dist/claude-json-sync/claude-json-sync.js.map +1 -0
  4. package/dist/commands/doctor.js +9 -5
  5. package/dist/commands/doctor.js.map +1 -1
  6. package/dist/commands/init.js +64 -60
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/join.js +62 -55
  9. package/dist/commands/join.js.map +1 -1
  10. package/dist/commands/override.js +32 -28
  11. package/dist/commands/override.js.map +1 -1
  12. package/dist/commands/pull.d.ts +1 -0
  13. package/dist/commands/pull.js +234 -186
  14. package/dist/commands/pull.js.map +1 -1
  15. package/dist/commands/push.js +146 -101
  16. package/dist/commands/push.js.map +1 -1
  17. package/dist/commands/restore.js +31 -27
  18. package/dist/commands/restore.js.map +1 -1
  19. package/dist/config/config-manager.js +1 -0
  20. package/dist/config/config-manager.js.map +1 -1
  21. package/dist/config/defaults.d.ts +7 -1
  22. package/dist/config/defaults.js +20 -0
  23. package/dist/config/defaults.js.map +1 -1
  24. package/dist/config/types.d.ts +16 -0
  25. package/dist/lockfile/lockfile.d.ts +8 -0
  26. package/dist/lockfile/lockfile.js +101 -0
  27. package/dist/lockfile/lockfile.js.map +1 -0
  28. package/dist/merger/merger.js +19 -4
  29. package/dist/merger/merger.js.map +1 -1
  30. package/dist/path-mapper/path-mapper.js +1 -1
  31. package/dist/path-mapper/path-mapper.js.map +1 -1
  32. package/dist/secret-scanner/scanner.d.ts +7 -0
  33. package/dist/secret-scanner/scanner.js +17 -3
  34. package/dist/secret-scanner/scanner.js.map +1 -1
  35. package/dist/sync-filter/sync-filter.js +1 -1
  36. package/dist/sync-filter/sync-filter.js.map +1 -1
  37. package/package.json +1 -1
@@ -0,0 +1,12 @@
1
+ export interface ClaudeJsonSyncOptions {
2
+ claudeJsonPath: string;
3
+ storePath: string;
4
+ homeDir: string;
5
+ syncMcpServers: boolean;
6
+ }
7
+ export declare class ClaudeJsonSync {
8
+ extract(options: ClaudeJsonSyncOptions): Record<string, unknown>;
9
+ merge(options: ClaudeJsonSyncOptions): Record<string, unknown>;
10
+ private canonicalizePaths;
11
+ private localizePaths;
12
+ }
@@ -0,0 +1,129 @@
1
+ import { readFileSync, existsSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { output } from "../output.js";
4
+ const ALWAYS_SYNCABLE_KEYS = ["theme", "preferredNotifChannel"];
5
+ const OPT_IN_SYNCABLE_KEYS = ["mcpServers"];
6
+ export class ClaudeJsonSync {
7
+ extract(options) {
8
+ if (!existsSync(options.claudeJsonPath))
9
+ return {};
10
+ let parsed;
11
+ try {
12
+ parsed = JSON.parse(readFileSync(options.claudeJsonPath, "utf-8"));
13
+ }
14
+ catch {
15
+ output.warn("Could not parse ~/.claude.json — skipping sync");
16
+ return {};
17
+ }
18
+ const result = {};
19
+ for (const key of ALWAYS_SYNCABLE_KEYS) {
20
+ if (key in parsed) {
21
+ result[key] = parsed[key];
22
+ }
23
+ }
24
+ if (options.syncMcpServers) {
25
+ for (const key of OPT_IN_SYNCABLE_KEYS) {
26
+ if (key in parsed) {
27
+ result[key] = this.canonicalizePaths(parsed[key], options.homeDir);
28
+ }
29
+ }
30
+ }
31
+ return result;
32
+ }
33
+ merge(options) {
34
+ let local = {};
35
+ if (existsSync(options.claudeJsonPath)) {
36
+ try {
37
+ local = JSON.parse(readFileSync(options.claudeJsonPath, "utf-8"));
38
+ }
39
+ catch {
40
+ output.warn("Could not parse local ~/.claude.json — using empty base");
41
+ }
42
+ }
43
+ if (!existsSync(options.storePath)) {
44
+ return local;
45
+ }
46
+ let remote;
47
+ try {
48
+ remote = JSON.parse(readFileSync(options.storePath, "utf-8"));
49
+ }
50
+ catch {
51
+ output.warn("Could not parse stored claude-json-sync.json — skipping merge");
52
+ return local;
53
+ }
54
+ const result = { ...local };
55
+ for (const key of ALWAYS_SYNCABLE_KEYS) {
56
+ if (key in remote) {
57
+ result[key] = remote[key];
58
+ }
59
+ }
60
+ if (options.syncMcpServers && "mcpServers" in remote) {
61
+ const localServers = (local.mcpServers ?? {});
62
+ const remoteServers = this.localizePaths(remote.mcpServers, options.homeDir);
63
+ // Validate remote MCP server entries before merging
64
+ const shellMetacharPattern = /[;&|`$]/;
65
+ const validatedServers = {};
66
+ for (const [name, cfg] of Object.entries(remoteServers)) {
67
+ const server = cfg;
68
+ if (typeof server.command === "string" && shellMetacharPattern.test(server.command)) {
69
+ output.warn(`Skipping remote MCP server "${name}": command contains shell metacharacters`);
70
+ continue;
71
+ }
72
+ // Also validate args array entries for shell metacharacters
73
+ if (Array.isArray(server.args)) {
74
+ const unsafeArg = server.args.find((arg) => typeof arg === "string" && shellMetacharPattern.test(arg));
75
+ if (unsafeArg) {
76
+ output.warn(`Skipping remote MCP server "${name}": args contain shell metacharacters`);
77
+ continue;
78
+ }
79
+ }
80
+ validatedServers[name] = server;
81
+ }
82
+ result.mcpServers = { ...localServers, ...validatedServers };
83
+ }
84
+ return result;
85
+ }
86
+ canonicalizePaths(obj, homeDir) {
87
+ if (typeof obj === "string") {
88
+ return obj.startsWith(homeDir) ? "@@HOME@@" + obj.slice(homeDir.length) : obj;
89
+ }
90
+ if (Array.isArray(obj)) {
91
+ return obj.map((item) => this.canonicalizePaths(item, homeDir));
92
+ }
93
+ if (obj !== null && typeof obj === "object") {
94
+ const result = {};
95
+ for (const [key, value] of Object.entries(obj)) {
96
+ result[key] = this.canonicalizePaths(value, homeDir);
97
+ }
98
+ return result;
99
+ }
100
+ return obj;
101
+ }
102
+ localizePaths(obj, homeDir) {
103
+ if (typeof obj === "string" && obj.startsWith("@@HOME@@")) {
104
+ const expanded = homeDir + obj.slice("@@HOME@@".length);
105
+ const resolved = resolve(expanded);
106
+ // Prevent path traversal — resolved path must stay within homeDir
107
+ if (!resolved.startsWith(homeDir + "/") && resolved !== homeDir) {
108
+ output.warn(`Skipping unsafe @@HOME@@ path: ${obj}`);
109
+ return obj;
110
+ }
111
+ return resolved;
112
+ }
113
+ if (typeof obj === "string") {
114
+ return obj;
115
+ }
116
+ if (Array.isArray(obj)) {
117
+ return obj.map((item) => this.localizePaths(item, homeDir));
118
+ }
119
+ if (obj !== null && typeof obj === "object") {
120
+ const result = {};
121
+ for (const [key, value] of Object.entries(obj)) {
122
+ result[key] = this.localizePaths(value, homeDir);
123
+ }
124
+ return result;
125
+ }
126
+ return obj;
127
+ }
128
+ }
129
+ //# sourceMappingURL=claude-json-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-json-sync.js","sourceRoot":"","sources":["../../src/claude-json-sync/claude-json-sync.ts"],"names":[],"mappings":"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"}
@@ -10,7 +10,7 @@ export class DoctorCommand {
10
10
  async execute() {
11
11
  const checks = [];
12
12
  checks.push(await this.checkBinary("git", "git --version"));
13
- checks.push(await this.checkBinary("git-lfs", "git lfs version"));
13
+ checks.push(await this.checkBinary("git-lfs", "git lfs version", "warn"));
14
14
  checks.push(this.checkInitialized());
15
15
  const configManager = new ConfigManager(this.homeDir);
16
16
  if (configManager.isInitialized()) {
@@ -20,14 +20,14 @@ export class DoctorCommand {
20
20
  }
21
21
  return checks;
22
22
  }
23
- async checkBinary(name, command) {
23
+ async checkBinary(name, command, failSeverity = "fail") {
24
24
  const [cmd, ...args] = command.split(" ");
25
25
  try {
26
26
  const { stdout } = await execFileAsync(cmd, args);
27
27
  return { name, status: "pass", detail: stdout.trim().split("\n")[0] };
28
28
  }
29
29
  catch {
30
- return { name, status: "fail", detail: `${name} not found in PATH` };
30
+ return { name, status: failSeverity, detail: `${name} not found in PATH` };
31
31
  }
32
32
  }
33
33
  checkInitialized() {
@@ -43,12 +43,16 @@ export class DoctorCommand {
43
43
  }
44
44
  checkEncryption(config) {
45
45
  if (config.encryption.enabled) {
46
- return { name: "encryption", status: "pass", detail: "encryption enabled" };
46
+ return {
47
+ name: "encryption",
48
+ status: "pass",
49
+ detail: `Enabled (mode: ${config.encryption.mode ?? "reactive"})`,
50
+ };
47
51
  }
48
52
  return {
49
53
  name: "encryption",
50
54
  status: "warn",
51
- detail: "encryption disabled — files pushed in cleartext",
55
+ detail: "Disabled — files stored in plaintext",
52
56
  };
53
57
  }
54
58
  async checkRemote(url) {
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ import { PushCommand } from "./push.js";
6
6
  import { HookManager } from "../hook-manager/hook-manager.js";
7
7
  import { output } from "../output.js";
8
8
  import { promptPassphraseSetup } from "../encryptor/passphrase.js";
9
+ import { withLock } from "../lockfile/lockfile.js";
9
10
  const LFS_GITATTRIBUTES = [
10
11
  "projects/**/*.jsonl filter=lfs diff=lfs merge=lfs -text",
11
12
  "projects/**/*.jsonl.age filter=lfs diff=lfs merge=lfs -text",
@@ -17,71 +18,74 @@ export class InitCommand {
17
18
  this.homeDir = homeDir;
18
19
  }
19
20
  async execute(options) {
20
- let backend = options.backend;
21
- if (!backend && options.createRepo) {
22
- const { RepoCreator } = await import("../repo-creator/repo-creator.js");
23
- const creator = new RepoCreator();
24
- const repoName = "claude-sync";
25
- backend = await creator.create(repoName);
26
- if (!options.quiet) {
27
- output.info(`Created remote repository: ${backend}`);
21
+ const claudefyDir = join(this.homeDir, ".claudefy");
22
+ await withLock("init", !!options.quiet, claudefyDir, async () => {
23
+ let backend = options.backend;
24
+ if (!backend && options.createRepo) {
25
+ const { RepoCreator } = await import("../repo-creator/repo-creator.js");
26
+ const creator = new RepoCreator();
27
+ const repoName = "claude-sync";
28
+ backend = await creator.create(repoName);
29
+ if (!options.quiet) {
30
+ output.info(`Created remote repository: ${backend}`);
31
+ }
28
32
  }
29
- }
30
- if (!backend) {
31
- throw new Error("Either --backend <url> or --create-repo is required.");
32
- }
33
- const configManager = new ConfigManager(this.homeDir);
34
- if (configManager.isInitialized()) {
35
- throw new Error("claudefy is already initialized. Use 'claudefy push' to sync.");
36
- }
37
- // Prompt for passphrase if not provided and not skipping encryption
38
- let passphrase = options.passphrase;
39
- let useKeychain = false;
40
- let skipEncryption = options.skipEncryption ?? false;
41
- if (!passphrase && !skipEncryption && process.stdin.isTTY) {
42
- const setup = await promptPassphraseSetup();
43
- if (setup) {
44
- passphrase = setup.passphrase;
45
- useKeychain = setup.storedInKeychain;
33
+ if (!backend) {
34
+ throw new Error("Either --backend <url> or --create-repo is required.");
46
35
  }
47
- else {
48
- skipEncryption = true;
36
+ const configManager = new ConfigManager(this.homeDir);
37
+ if (configManager.isInitialized()) {
38
+ throw new Error("claudefy is already initialized. Use 'claudefy push' to sync.");
39
+ }
40
+ // Prompt for passphrase if not provided and not skipping encryption
41
+ let passphrase = options.passphrase;
42
+ let useKeychain = false;
43
+ let skipEncryption = options.skipEncryption ?? false;
44
+ if (!passphrase && !skipEncryption && process.stdin.isTTY) {
45
+ const setup = await promptPassphraseSetup();
46
+ if (setup) {
47
+ passphrase = setup.passphrase;
48
+ useKeychain = setup.storedInKeychain;
49
+ }
50
+ else {
51
+ skipEncryption = true;
52
+ }
53
+ }
54
+ // 1. Initialize config
55
+ const config = await configManager.initialize(backend, { useKeychain });
56
+ if (skipEncryption) {
57
+ config.encryption.enabled = false;
58
+ await configManager.set("encryption.enabled", false);
49
59
  }
50
- }
51
- // 1. Initialize config
52
- const config = await configManager.initialize(backend, { useKeychain });
53
- if (skipEncryption) {
54
- config.encryption.enabled = false;
55
- await configManager.set("encryption.enabled", false);
56
- }
57
- if (!options.quiet) {
58
- output.info(`Initialized claudefy with machine ID: ${config.machineId}`);
59
- }
60
- // 2. Initialize git store
61
- const gitAdapter = new GitAdapter(join(this.homeDir, ".claudefy"));
62
- await gitAdapter.initStore(backend);
63
- await gitAdapter.ensureMachineBranch(config.machineId);
64
- // 3. Write .gitattributes for LFS tracking of large session files
65
- await writeFile(join(gitAdapter.getStorePath(), ".gitattributes"), LFS_GITATTRIBUTES);
66
- // 4. Run initial push
67
- const pushCommand = new PushCommand(this.homeDir);
68
- await pushCommand.execute({
69
- quiet: options.quiet,
70
- skipEncryption,
71
- skipSecretScan: options.skipSecretScan,
72
- passphrase,
73
- });
74
- // 5. Install hooks if requested
75
- if (options.installHooks) {
76
- const hookManager = new HookManager(join(this.homeDir, ".claude", "settings.json"));
77
- await hookManager.install();
78
60
  if (!options.quiet) {
79
- output.info("Auto-sync hooks installed.");
61
+ output.info(`Initialized claudefy with machine ID: ${config.machineId}`);
80
62
  }
81
- }
82
- if (!options.quiet) {
83
- output.success("Setup complete. Your Claude config is now synced.");
84
- }
63
+ // 2. Initialize git store
64
+ const gitAdapter = new GitAdapter(join(this.homeDir, ".claudefy"));
65
+ await gitAdapter.initStore(backend);
66
+ await gitAdapter.ensureMachineBranch(config.machineId);
67
+ // 3. Write .gitattributes for LFS tracking of large session files
68
+ await writeFile(join(gitAdapter.getStorePath(), ".gitattributes"), LFS_GITATTRIBUTES);
69
+ // 4. Run initial push
70
+ const pushCommand = new PushCommand(this.homeDir);
71
+ await pushCommand.execute({
72
+ quiet: options.quiet,
73
+ skipEncryption,
74
+ skipSecretScan: options.skipSecretScan,
75
+ passphrase,
76
+ });
77
+ // 5. Install hooks if requested
78
+ if (options.installHooks) {
79
+ const hookManager = new HookManager(join(this.homeDir, ".claude", "settings.json"));
80
+ await hookManager.install();
81
+ if (!options.quiet) {
82
+ output.info("Auto-sync hooks installed.");
83
+ }
84
+ }
85
+ if (!options.quiet) {
86
+ output.success("Setup complete. Your Claude config is now synced.");
87
+ }
88
+ });
85
89
  }
86
90
  }
87
91
  //# sourceMappingURL=init.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ import { MachineRegistry } from "../machine-registry/machine-registry.js";
8
8
  import { hostname, platform } from "node:os";
9
9
  import { output } from "../output.js";
10
10
  import { promptExistingPassphrase } from "../encryptor/passphrase.js";
11
+ import { withLock } from "../lockfile/lockfile.js";
11
12
  import { STORE_CONFIG_DIR, STORE_UNKNOWN_DIR, STORE_MANIFEST_FILE } from "../config/defaults.js";
12
13
  export class JoinCommand {
13
14
  homeDir;
@@ -15,65 +16,71 @@ export class JoinCommand {
15
16
  this.homeDir = homeDir;
16
17
  }
17
18
  async execute(options) {
18
- const configManager = new ConfigManager(this.homeDir);
19
- if (configManager.isInitialized()) {
20
- throw new Error("claudefy is already initialized. Use 'claudefy pull' to sync.");
21
- }
22
- // 1. Initialize config
23
- const config = await configManager.initialize(options.backend);
24
- if (!options.quiet) {
25
- output.info(`Joined sync with machine ID: ${config.machineId}`);
26
- }
27
- // 2. Initialize git store and pull
28
- const gitAdapter = new GitAdapter(join(this.homeDir, ".claudefy"));
29
- await gitAdapter.initStore(options.backend);
30
- await gitAdapter.ensureMachineBranch(config.machineId);
31
- // 3. Prompt for passphrase if the store has encrypted files and none was provided
32
- let passphrase = options.passphrase;
33
- let useKeychain = false;
34
- if (!passphrase && !options.skipEncryption) {
35
- const hasEncrypted = await this.storeHasAgeFiles(gitAdapter.getStorePath());
36
- if (hasEncrypted && process.stdin.isTTY) {
37
- const setup = await promptExistingPassphrase();
38
- if (setup) {
39
- passphrase = setup.passphrase;
40
- useKeychain = setup.storedInKeychain;
19
+ const claudefyDir = join(this.homeDir, ".claudefy");
20
+ await withLock("join", !!options.quiet, claudefyDir, async () => {
21
+ const configManager = new ConfigManager(this.homeDir);
22
+ if (configManager.isInitialized()) {
23
+ throw new Error("claudefy is already initialized. Use 'claudefy pull' to sync.");
24
+ }
25
+ // 1. Initialize config
26
+ const config = await configManager.initialize(options.backend);
27
+ if (!options.quiet) {
28
+ output.info(`Joined sync with machine ID: ${config.machineId}`);
29
+ }
30
+ // 2. Initialize git store and pull
31
+ const gitAdapter = new GitAdapter(join(this.homeDir, ".claudefy"));
32
+ await gitAdapter.initStore(options.backend);
33
+ await gitAdapter.ensureMachineBranch(config.machineId);
34
+ // 3. Prompt for passphrase if the store has encrypted files and none was provided
35
+ let passphrase = options.passphrase;
36
+ let useKeychain = false;
37
+ if (!passphrase && !options.skipEncryption) {
38
+ const hasEncrypted = await this.storeHasAgeFiles(gitAdapter.getStorePath());
39
+ if (hasEncrypted && process.stdin.isTTY) {
40
+ const setup = await promptExistingPassphrase();
41
+ if (setup) {
42
+ passphrase = setup.passphrase;
43
+ useKeychain = setup.storedInKeychain;
44
+ }
45
+ }
46
+ }
47
+ if (useKeychain) {
48
+ await configManager.set("encryption.useKeychain", true);
49
+ }
50
+ // 4. Run pull to get remote config
51
+ const pullCommand = new PullCommand(this.homeDir);
52
+ await pullCommand.execute({
53
+ quiet: options.quiet,
54
+ skipEncryption: options.skipEncryption,
55
+ passphrase,
56
+ });
57
+ // 4b. Detect encryption state from store
58
+ if (!options.skipEncryption && !passphrase) {
59
+ // No passphrase was needed/provided — store is not encrypted
60
+ await configManager.set("encryption.enabled", false);
61
+ }
62
+ // 5. Register this machine and commit
63
+ const registry = new MachineRegistry(join(gitAdapter.getStorePath(), STORE_MANIFEST_FILE));
64
+ await registry.register(config.machineId, hostname(), platform());
65
+ const commitResult = await gitAdapter.commitAndPush(`sync: ${config.machineId} joined`, config.machineId);
66
+ if (!commitResult.pushed && !options.quiet) {
67
+ output.warn("Machine registry update could not be pushed to the remote. Check your connection and try 'claudefy push'.");
68
+ }
69
+ // 6. Install hooks if requested
70
+ if (options.installHooks) {
71
+ const hookManager = new HookManager(join(this.homeDir, ".claude", "settings.json"));
72
+ await hookManager.install();
73
+ if (!options.quiet) {
74
+ output.info("Auto-sync hooks installed.");
41
75
  }
42
76
  }
43
- }
44
- if (useKeychain) {
45
- await configManager.set("encryption.useKeychain", true);
46
- }
47
- // 4. Run pull to get remote config
48
- const pullCommand = new PullCommand(this.homeDir);
49
- await pullCommand.execute({
50
- quiet: options.quiet,
51
- skipEncryption: options.skipEncryption,
52
- passphrase,
53
- });
54
- // 4b. Detect encryption state from store
55
- if (!options.skipEncryption && !passphrase) {
56
- // No passphrase was needed/provided — store is not encrypted
57
- await configManager.set("encryption.enabled", false);
58
- }
59
- // 5. Register this machine and commit
60
- const registry = new MachineRegistry(join(gitAdapter.getStorePath(), STORE_MANIFEST_FILE));
61
- await registry.register(config.machineId, hostname(), platform());
62
- const commitResult = await gitAdapter.commitAndPush(`sync: ${config.machineId} joined`, config.machineId);
63
- if (!commitResult.pushed && !options.quiet) {
64
- output.warn("Machine registry update could not be pushed to the remote. Check your connection and try 'claudefy push'.");
65
- }
66
- // 6. Install hooks if requested
67
- if (options.installHooks) {
68
- const hookManager = new HookManager(join(this.homeDir, ".claude", "settings.json"));
69
- await hookManager.install();
70
77
  if (!options.quiet) {
71
- output.info("Auto-sync hooks installed.");
78
+ output.success("Join complete. Your Claude config has been synced from remote.");
72
79
  }
73
- }
74
- if (!options.quiet) {
75
- output.success("Join complete. Your Claude config has been synced from remote.");
76
- }
80
+ if (!options.installHooks && !options.quiet) {
81
+ output.dim("Tip: run 'claudefy hooks install' to enable auto-sync on this machine");
82
+ }
83
+ });
77
84
  }
78
85
  async storeHasAgeFiles(storePath) {
79
86
  const configDir = join(storePath, STORE_CONFIG_DIR);
@@ -1 +1 @@
1
- {"version":3,"file":"join.js","sourceRoot":"","sources":["../../src/commands/join.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"join.js","sourceRoot":"","sources":["../../src/commands/join.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { ConfigManager } from "../config/config-manager.js";
3
3
  import { GitAdapter } from "../git-adapter/git-adapter.js";
4
4
  import { PushCommand } from "./push.js";
5
5
  import { output } from "../output.js";
6
+ import { withLock } from "../lockfile/lockfile.js";
6
7
  export class OverrideCommand {
7
8
  homeDir;
8
9
  configManager;
@@ -11,35 +12,38 @@ export class OverrideCommand {
11
12
  this.configManager = new ConfigManager(homeDir);
12
13
  }
13
14
  async execute(options) {
14
- if (!options.confirm) {
15
- throw new Error("Override requires --confirm flag. This will wipe the remote store and replace it with your local config.");
16
- }
17
- const config = await this.configManager.load();
18
- if (!options.quiet) {
19
- output.warn(`Overriding remote store as machine: ${config.machineId}`);
20
- }
21
- // 1. Initialize git adapter
22
- const gitAdapter = new GitAdapter(join(this.homeDir, ".claudefy"));
23
- await gitAdapter.initStore(config.backend.url);
24
- await gitAdapter.ensureMachineBranch(config.machineId);
25
- try {
26
- await gitAdapter.pullAndMergeMain();
27
- }
28
- catch {
29
- // Fresh store with no remote history yet
30
- }
31
- // 2. Wipe remote and write override marker
32
- await gitAdapter.wipeAndPush(config.machineId);
33
- // 3. Run full push pipeline to repopulate store
34
- const pushCommand = new PushCommand(this.homeDir);
35
- await pushCommand.execute({
36
- quiet: options.quiet,
37
- skipEncryption: options.skipEncryption,
38
- passphrase: options.passphrase,
15
+ const claudefyDir = join(this.homeDir, ".claudefy");
16
+ await withLock("override", !!options.quiet, claudefyDir, async () => {
17
+ if (!options.confirm) {
18
+ throw new Error("Override requires --confirm flag. This will wipe the remote store and replace it with your local config.");
19
+ }
20
+ const config = await this.configManager.load();
21
+ if (!options.quiet) {
22
+ output.warn(`Overriding remote store as machine: ${config.machineId}`);
23
+ }
24
+ // 1. Initialize git adapter
25
+ const gitAdapter = new GitAdapter(join(this.homeDir, ".claudefy"));
26
+ await gitAdapter.initStore(config.backend.url);
27
+ await gitAdapter.ensureMachineBranch(config.machineId);
28
+ try {
29
+ await gitAdapter.pullAndMergeMain();
30
+ }
31
+ catch {
32
+ // Fresh store with no remote history yet
33
+ }
34
+ // 2. Wipe remote and write override marker
35
+ await gitAdapter.wipeAndPush(config.machineId);
36
+ // 3. Run full push pipeline to repopulate store
37
+ const pushCommand = new PushCommand(this.homeDir);
38
+ await pushCommand.execute({
39
+ quiet: options.quiet,
40
+ skipEncryption: options.skipEncryption,
41
+ passphrase: options.passphrase,
42
+ });
43
+ if (!options.quiet) {
44
+ output.success("Override complete. All other machines will receive your config on next pull.");
45
+ }
39
46
  });
40
- if (!options.quiet) {
41
- output.success("Override complete. All other machines will receive your config on next pull.");
42
- }
43
47
  }
44
48
  }
45
49
  //# sourceMappingURL=override.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"override.js","sourceRoot":"","sources":["../../src/commands/override.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAStC,MAAM,OAAO,eAAe;IAClB,OAAO,CAAS;IAChB,aAAa,CAAgB;IAErC,YAAY,OAAe;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAwB;QACpC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CACb,0GAA0G,CAC3G,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;QAE/C,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,CAAC,uCAAuC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QACzE,CAAC;QAED,4BAA4B;QAC5B,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;QACnE,MAAM,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,UAAU,CAAC,mBAAmB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,gBAAgB,EAAE,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,yCAAyC;QAC3C,CAAC;QAED,2CAA2C;QAC3C,MAAM,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAE/C,gDAAgD;QAChD,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClD,MAAM,WAAW,CAAC,OAAO,CAAC;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,CAAC,OAAO,CACZ,8EAA8E,CAC/E,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"override.js","sourceRoot":"","sources":["../../src/commands/override.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AASnD,MAAM,OAAO,eAAe;IAClB,OAAO,CAAS;IAChB,aAAa,CAAgB;IAErC,YAAY,OAAe;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAwB;QACpC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACpD,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,IAAI,EAAE;YAClE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CACb,0GAA0G,CAC3G,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;YAE/C,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBACnB,MAAM,CAAC,IAAI,CAAC,uCAAuC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YACzE,CAAC;YAED,4BAA4B;YAC5B,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;YACnE,MAAM,UAAU,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC/C,MAAM,UAAU,CAAC,mBAAmB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACvD,IAAI,CAAC;gBACH,MAAM,UAAU,CAAC,gBAAgB,EAAE,CAAC;YACtC,CAAC;YAAC,MAAM,CAAC;gBACP,yCAAyC;YAC3C,CAAC;YAED,2CAA2C;YAC3C,MAAM,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAE/C,gDAAgD;YAChD,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClD,MAAM,WAAW,CAAC,OAAO,CAAC;gBACxB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,cAAc,EAAE,OAAO,CAAC,cAAc;gBACtC,UAAU,EAAE,OAAO,CAAC,UAAU;aAC/B,CAAC,CAAC;YAEH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBACnB,MAAM,CAAC,OAAO,CACZ,8EAA8E,CAC/E,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -14,6 +14,7 @@ export declare class PullCommand {
14
14
  private configManager;
15
15
  constructor(homeDir: string);
16
16
  execute(options: PullOptions): Promise<PullResult>;
17
+ private executeLocked;
17
18
  /**
18
19
  * Check for an override marker. First checks current branch, then checks
19
20
  * the main branch (override markers may not survive merge into machine branch