@kodrunhq/claudefy 0.1.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 (96) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +147 -0
  3. package/dist/backup-manager/backup-manager.d.ts +6 -0
  4. package/dist/backup-manager/backup-manager.js +27 -0
  5. package/dist/backup-manager/backup-manager.js.map +1 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.js +296 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/commands/config.d.ts +8 -0
  10. package/dist/commands/config.js +56 -0
  11. package/dist/commands/config.js.map +1 -0
  12. package/dist/commands/doctor.d.ts +14 -0
  13. package/dist/commands/doctor.js +64 -0
  14. package/dist/commands/doctor.js.map +1 -0
  15. package/dist/commands/hooks.d.ts +7 -0
  16. package/dist/commands/hooks.js +18 -0
  17. package/dist/commands/hooks.js.map +1 -0
  18. package/dist/commands/init.d.ts +13 -0
  19. package/dist/commands/init.js +66 -0
  20. package/dist/commands/init.js.map +1 -0
  21. package/dist/commands/join.d.ts +12 -0
  22. package/dist/commands/join.js +51 -0
  23. package/dist/commands/join.js.map +1 -0
  24. package/dist/commands/link.d.ts +12 -0
  25. package/dist/commands/link.js +34 -0
  26. package/dist/commands/link.js.map +1 -0
  27. package/dist/commands/machines.d.ts +6 -0
  28. package/dist/commands/machines.js +25 -0
  29. package/dist/commands/machines.js.map +1 -0
  30. package/dist/commands/override.d.ts +12 -0
  31. package/dist/commands/override.js +44 -0
  32. package/dist/commands/override.js.map +1 -0
  33. package/dist/commands/pull.d.ts +17 -0
  34. package/dist/commands/pull.js +220 -0
  35. package/dist/commands/pull.js.map +1 -0
  36. package/dist/commands/push.d.ts +14 -0
  37. package/dist/commands/push.js +175 -0
  38. package/dist/commands/push.js.map +1 -0
  39. package/dist/commands/status.d.ts +14 -0
  40. package/dist/commands/status.js +50 -0
  41. package/dist/commands/status.js.map +1 -0
  42. package/dist/config/config-manager.d.ts +22 -0
  43. package/dist/config/config-manager.js +118 -0
  44. package/dist/config/config-manager.js.map +1 -0
  45. package/dist/config/defaults.d.ts +7 -0
  46. package/dist/config/defaults.js +33 -0
  47. package/dist/config/defaults.js.map +1 -0
  48. package/dist/config/types.d.ts +25 -0
  49. package/dist/config/types.js +2 -0
  50. package/dist/config/types.js.map +1 -0
  51. package/dist/encryptor/encryptor.d.ts +10 -0
  52. package/dist/encryptor/encryptor.js +68 -0
  53. package/dist/encryptor/encryptor.js.map +1 -0
  54. package/dist/encryptor/passphrase.d.ts +7 -0
  55. package/dist/encryptor/passphrase.js +34 -0
  56. package/dist/encryptor/passphrase.js.map +1 -0
  57. package/dist/git-adapter/git-adapter.d.ts +19 -0
  58. package/dist/git-adapter/git-adapter.js +104 -0
  59. package/dist/git-adapter/git-adapter.js.map +1 -0
  60. package/dist/git-adapter/types.d.ts +14 -0
  61. package/dist/git-adapter/types.js +2 -0
  62. package/dist/git-adapter/types.js.map +1 -0
  63. package/dist/hook-manager/hook-manager.d.ts +11 -0
  64. package/dist/hook-manager/hook-manager.js +110 -0
  65. package/dist/hook-manager/hook-manager.js.map +1 -0
  66. package/dist/index.d.ts +2 -0
  67. package/dist/index.js +4 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/machine-registry/machine-registry.d.ts +16 -0
  70. package/dist/machine-registry/machine-registry.js +65 -0
  71. package/dist/machine-registry/machine-registry.js.map +1 -0
  72. package/dist/merger/merger.d.ts +10 -0
  73. package/dist/merger/merger.js +15 -0
  74. package/dist/merger/merger.js.map +1 -0
  75. package/dist/output.d.ts +8 -0
  76. package/dist/output.js +10 -0
  77. package/dist/output.js.map +1 -0
  78. package/dist/path-mapper/git-identity.d.ts +8 -0
  79. package/dist/path-mapper/git-identity.js +35 -0
  80. package/dist/path-mapper/git-identity.js.map +1 -0
  81. package/dist/path-mapper/path-mapper.d.ts +19 -0
  82. package/dist/path-mapper/path-mapper.js +101 -0
  83. package/dist/path-mapper/path-mapper.js.map +1 -0
  84. package/dist/repo-creator/repo-creator.d.ts +6 -0
  85. package/dist/repo-creator/repo-creator.js +52 -0
  86. package/dist/repo-creator/repo-creator.js.map +1 -0
  87. package/dist/secret-scanner/scanner.d.ts +10 -0
  88. package/dist/secret-scanner/scanner.js +48 -0
  89. package/dist/secret-scanner/scanner.js.map +1 -0
  90. package/dist/sync-filter/sync-filter.d.ts +8 -0
  91. package/dist/sync-filter/sync-filter.js +37 -0
  92. package/dist/sync-filter/sync-filter.js.map +1 -0
  93. package/dist/sync-filter/types.d.ts +13 -0
  94. package/dist/sync-filter/types.js +2 -0
  95. package/dist/sync-filter/types.js.map +1 -0
  96. package/package.json +72 -0
@@ -0,0 +1,64 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { ConfigManager } from "../config/config-manager.js";
4
+ const execFileAsync = promisify(execFile);
5
+ export class DoctorCommand {
6
+ homeDir;
7
+ constructor(homeDir) {
8
+ this.homeDir = homeDir;
9
+ }
10
+ async execute() {
11
+ const checks = [];
12
+ checks.push(await this.checkBinary("git", "git --version"));
13
+ checks.push(await this.checkBinary("git-lfs", "git lfs version"));
14
+ checks.push(this.checkInitialized());
15
+ const configManager = new ConfigManager(this.homeDir);
16
+ if (configManager.isInitialized()) {
17
+ const config = await configManager.load();
18
+ checks.push(this.checkEncryption(config));
19
+ checks.push(await this.checkRemote(config.backend.url));
20
+ }
21
+ return checks;
22
+ }
23
+ async checkBinary(name, command) {
24
+ const [cmd, ...args] = command.split(" ");
25
+ try {
26
+ const { stdout } = await execFileAsync(cmd, args);
27
+ return { name, status: "pass", detail: stdout.trim().split("\n")[0] };
28
+ }
29
+ catch {
30
+ return { name, status: "fail", detail: `${name} not found in PATH` };
31
+ }
32
+ }
33
+ checkInitialized() {
34
+ const configManager = new ConfigManager(this.homeDir);
35
+ if (configManager.isInitialized()) {
36
+ return { name: "store-initialized", status: "pass", detail: "claudefy is initialized" };
37
+ }
38
+ return {
39
+ name: "store-initialized",
40
+ status: "fail",
41
+ detail: "Not initialized. Run 'claudefy init' first.",
42
+ };
43
+ }
44
+ checkEncryption(config) {
45
+ if (config.encryption.enabled) {
46
+ return { name: "encryption", status: "pass", detail: "encryption enabled" };
47
+ }
48
+ return {
49
+ name: "encryption",
50
+ status: "warn",
51
+ detail: "encryption disabled — files pushed in cleartext",
52
+ };
53
+ }
54
+ async checkRemote(url) {
55
+ try {
56
+ await execFileAsync("git", ["ls-remote", url], { timeout: 10000 });
57
+ return { name: "remote-reachable", status: "pass", detail: `remote ${url} is reachable` };
58
+ }
59
+ catch {
60
+ return { name: "remote-reachable", status: "fail", detail: `Cannot reach remote: ${url}` };
61
+ }
62
+ }
63
+ }
64
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare class HooksCommand {
2
+ private hookManager;
3
+ constructor(homeDir: string);
4
+ install(): Promise<void>;
5
+ remove(): Promise<void>;
6
+ isInstalled(): Promise<boolean>;
7
+ }
@@ -0,0 +1,18 @@
1
+ import { join } from "node:path";
2
+ import { HookManager } from "../hook-manager/hook-manager.js";
3
+ export class HooksCommand {
4
+ hookManager;
5
+ constructor(homeDir) {
6
+ this.hookManager = new HookManager(join(homeDir, ".claude", "settings.json"));
7
+ }
8
+ async install() {
9
+ await this.hookManager.install();
10
+ }
11
+ async remove() {
12
+ await this.hookManager.remove();
13
+ }
14
+ async isInstalled() {
15
+ return this.hookManager.isInstalled();
16
+ }
17
+ }
18
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/commands/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,MAAM,OAAO,YAAY;IACf,WAAW,CAAc;IAEjC,YAAY,OAAe;QACzB,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,MAAM;QACV,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;IACxC,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ export interface InitOptions {
2
+ backend?: string;
3
+ quiet: boolean;
4
+ skipEncryption?: boolean;
5
+ passphrase?: string;
6
+ installHooks?: boolean;
7
+ createRepo?: boolean;
8
+ }
9
+ export declare class InitCommand {
10
+ private homeDir;
11
+ constructor(homeDir: string);
12
+ execute(options: InitOptions): Promise<void>;
13
+ }
@@ -0,0 +1,66 @@
1
+ import { join } from "node:path";
2
+ import { writeFile } from "node:fs/promises";
3
+ import { ConfigManager } from "../config/config-manager.js";
4
+ import { GitAdapter } from "../git-adapter/git-adapter.js";
5
+ import { PushCommand } from "./push.js";
6
+ import { HookManager } from "../hook-manager/hook-manager.js";
7
+ import { output } from "../output.js";
8
+ const LFS_GITATTRIBUTES = [
9
+ "projects/**/*.jsonl filter=lfs diff=lfs merge=lfs -text",
10
+ "projects/**/*.jsonl.age filter=lfs diff=lfs merge=lfs -text",
11
+ "",
12
+ ].join("\n");
13
+ export class InitCommand {
14
+ homeDir;
15
+ constructor(homeDir) {
16
+ this.homeDir = homeDir;
17
+ }
18
+ async execute(options) {
19
+ let backend = options.backend;
20
+ if (!backend && options.createRepo) {
21
+ const { RepoCreator } = await import("../repo-creator/repo-creator.js");
22
+ const creator = new RepoCreator();
23
+ const repoName = "claude-sync";
24
+ backend = await creator.create(repoName);
25
+ if (!options.quiet) {
26
+ output.info(`Created remote repository: ${backend}`);
27
+ }
28
+ }
29
+ if (!backend) {
30
+ throw new Error("Either --backend <url> or --create-repo is required.");
31
+ }
32
+ const configManager = new ConfigManager(this.homeDir);
33
+ if (configManager.isInitialized()) {
34
+ throw new Error("claudefy is already initialized. Use 'claudefy push' to sync.");
35
+ }
36
+ // 1. Initialize config
37
+ const config = await configManager.initialize(backend);
38
+ if (!options.quiet) {
39
+ output.info(`Initialized claudefy with machine ID: ${config.machineId}`);
40
+ }
41
+ // 2. Initialize git store
42
+ const gitAdapter = new GitAdapter(join(this.homeDir, ".claudefy"));
43
+ await gitAdapter.initStore(backend);
44
+ // 3. Write .gitattributes for LFS tracking of large session files
45
+ await writeFile(join(gitAdapter.getStorePath(), ".gitattributes"), LFS_GITATTRIBUTES);
46
+ // 4. Run initial push
47
+ const pushCommand = new PushCommand(this.homeDir);
48
+ await pushCommand.execute({
49
+ quiet: options.quiet,
50
+ skipEncryption: options.skipEncryption,
51
+ passphrase: options.passphrase,
52
+ });
53
+ // 5. Install hooks if requested
54
+ if (options.installHooks) {
55
+ const hookManager = new HookManager(join(this.homeDir, ".claude", "settings.json"));
56
+ await hookManager.install();
57
+ if (!options.quiet) {
58
+ output.info("Auto-sync hooks installed.");
59
+ }
60
+ }
61
+ if (!options.quiet) {
62
+ output.success("Setup complete. Your Claude config is now synced.");
63
+ }
64
+ }
65
+ }
66
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface JoinOptions {
2
+ backend: string;
3
+ quiet: boolean;
4
+ skipEncryption?: boolean;
5
+ passphrase?: string;
6
+ installHooks?: boolean;
7
+ }
8
+ export declare class JoinCommand {
9
+ private homeDir;
10
+ constructor(homeDir: string);
11
+ execute(options: JoinOptions): Promise<void>;
12
+ }
@@ -0,0 +1,51 @@
1
+ import { join } from "node:path";
2
+ import { ConfigManager } from "../config/config-manager.js";
3
+ import { GitAdapter } from "../git-adapter/git-adapter.js";
4
+ import { PullCommand } from "./pull.js";
5
+ import { HookManager } from "../hook-manager/hook-manager.js";
6
+ import { MachineRegistry } from "../machine-registry/machine-registry.js";
7
+ import { hostname, platform } from "node:os";
8
+ import { output } from "../output.js";
9
+ export class JoinCommand {
10
+ homeDir;
11
+ constructor(homeDir) {
12
+ this.homeDir = homeDir;
13
+ }
14
+ async execute(options) {
15
+ const configManager = new ConfigManager(this.homeDir);
16
+ if (configManager.isInitialized()) {
17
+ throw new Error("claudefy is already initialized. Use 'claudefy pull' to sync.");
18
+ }
19
+ // 1. Initialize config
20
+ const config = await configManager.initialize(options.backend);
21
+ if (!options.quiet) {
22
+ output.info(`Joined sync with machine ID: ${config.machineId}`);
23
+ }
24
+ // 2. Initialize git store and pull
25
+ const gitAdapter = new GitAdapter(join(this.homeDir, ".claudefy"));
26
+ await gitAdapter.initStore(options.backend);
27
+ // 3. Register this machine and commit
28
+ const registry = new MachineRegistry(join(gitAdapter.getStorePath(), "manifest.json"));
29
+ await registry.register(config.machineId, hostname(), platform());
30
+ await gitAdapter.commitAndPush(`sync: ${config.machineId} joined`);
31
+ // 4. Run pull to get remote config
32
+ const pullCommand = new PullCommand(this.homeDir);
33
+ await pullCommand.execute({
34
+ quiet: options.quiet,
35
+ skipEncryption: options.skipEncryption,
36
+ passphrase: options.passphrase,
37
+ });
38
+ // 5. Install hooks if requested
39
+ if (options.installHooks) {
40
+ const hookManager = new HookManager(join(this.homeDir, ".claude", "settings.json"));
41
+ await hookManager.install();
42
+ if (!options.quiet) {
43
+ output.info("Auto-sync hooks installed.");
44
+ }
45
+ }
46
+ if (!options.quiet) {
47
+ output.success("Join complete. Your Claude config has been synced from remote.");
48
+ }
49
+ }
50
+ }
51
+ //# sourceMappingURL=join.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"join.js","sourceRoot":"","sources":["../../src/commands/join.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,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAUtC,MAAM,OAAO,WAAW;IACd,OAAO,CAAS;IAExB,YAAY,OAAe;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAoB;QAChC,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEtD,IAAI,aAAa,CAAC,aAAa,EAAE,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;QACnF,CAAC;QAED,uBAAuB;QACvB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE/D,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,CAAC,gCAAgC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,mCAAmC;QACnC,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;QACnE,MAAM,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE5C,sCAAsC;QACtC,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;QACvF,MAAM,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClE,MAAM,UAAU,CAAC,aAAa,CAAC,SAAS,MAAM,CAAC,SAAS,SAAS,CAAC,CAAC;QAEnE,mCAAmC;QACnC,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,gCAAgC;QAChC,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YACzB,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC;YACpF,MAAM,WAAW,CAAC,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBACnB,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,CAAC,OAAO,CAAC,gEAAgE,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ export declare class LinkCommand {
2
+ private homeDir;
3
+ private configManager;
4
+ constructor(homeDir: string);
5
+ add(alias: string, localPath: string): Promise<void>;
6
+ remove(alias: string): Promise<void>;
7
+ list(): Promise<Record<string, {
8
+ localPath: string;
9
+ canonicalId: string;
10
+ gitRemote: string | null;
11
+ }>>;
12
+ }
@@ -0,0 +1,34 @@
1
+ import { ConfigManager } from "../config/config-manager.js";
2
+ import { GitIdentity } from "../path-mapper/git-identity.js";
3
+ export class LinkCommand {
4
+ homeDir;
5
+ configManager;
6
+ constructor(homeDir) {
7
+ this.homeDir = homeDir;
8
+ this.configManager = new ConfigManager(homeDir);
9
+ }
10
+ async add(alias, localPath) {
11
+ const identity = new GitIdentity();
12
+ const result = await identity.detect(localPath);
13
+ await this.configManager.addLink(alias, localPath, {
14
+ canonicalId: result?.canonicalId || alias,
15
+ gitRemote: result?.gitRemote || null,
16
+ });
17
+ }
18
+ async remove(alias) {
19
+ await this.configManager.removeLink(alias);
20
+ }
21
+ async list() {
22
+ const links = await this.configManager.getLinks();
23
+ const result = {};
24
+ for (const [alias, entry] of Object.entries(links)) {
25
+ result[alias] = {
26
+ localPath: entry.localPath,
27
+ canonicalId: entry.canonicalId,
28
+ gitRemote: entry.gitRemote,
29
+ };
30
+ }
31
+ return result;
32
+ }
33
+ }
34
+ //# sourceMappingURL=link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/commands/link.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAE7D,MAAM,OAAO,WAAW;IACd,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,GAAG,CAAC,KAAa,EAAE,SAAiB;QACxC,MAAM,QAAQ,GAAG,IAAI,WAAW,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAEhD,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE;YACjD,WAAW,EAAE,MAAM,EAAE,WAAW,IAAI,KAAK;YACzC,SAAS,EAAE,MAAM,EAAE,SAAS,IAAI,IAAI;SACrC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACxB,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,IAAI;QAGR,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC;QAClD,MAAM,MAAM,GAGR,EAAE,CAAC;QACP,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACnD,MAAM,CAAC,KAAK,CAAC,GAAG;gBACd,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,SAAS,EAAE,KAAK,CAAC,SAAS;aAC3B,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ import { MachineEntry } from "../machine-registry/machine-registry.js";
2
+ export declare class MachinesCommand {
3
+ private homeDir;
4
+ constructor(homeDir: string);
5
+ execute(): Promise<MachineEntry[]>;
6
+ }
@@ -0,0 +1,25 @@
1
+ import { join } from "node:path";
2
+ import { ConfigManager } from "../config/config-manager.js";
3
+ import { GitAdapter } from "../git-adapter/git-adapter.js";
4
+ import { MachineRegistry } from "../machine-registry/machine-registry.js";
5
+ export class MachinesCommand {
6
+ homeDir;
7
+ constructor(homeDir) {
8
+ this.homeDir = homeDir;
9
+ }
10
+ async execute() {
11
+ const configManager = new ConfigManager(this.homeDir);
12
+ const config = await configManager.load();
13
+ const gitAdapter = new GitAdapter(join(this.homeDir, ".claudefy"));
14
+ await gitAdapter.initStore(config.backend.url);
15
+ try {
16
+ await gitAdapter.pull();
17
+ }
18
+ catch {
19
+ // Fresh store
20
+ }
21
+ const registry = new MachineRegistry(join(gitAdapter.getStorePath(), "manifest.json"));
22
+ return registry.list();
23
+ }
24
+ }
25
+ //# sourceMappingURL=machines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"machines.js","sourceRoot":"","sources":["../../src/commands/machines.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,eAAe,EAAgB,MAAM,yCAAyC,CAAC;AAExF,MAAM,OAAO,eAAe;IAClB,OAAO,CAAS;IAExB,YAAY,OAAe;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC;QAE1C,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,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;QACvF,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ export interface OverrideOptions {
2
+ quiet: boolean;
3
+ skipEncryption?: boolean;
4
+ passphrase?: string;
5
+ confirm?: boolean;
6
+ }
7
+ export declare class OverrideCommand {
8
+ private homeDir;
9
+ private configManager;
10
+ constructor(homeDir: string);
11
+ execute(options: OverrideOptions): Promise<void>;
12
+ }
@@ -0,0 +1,44 @@
1
+ import { join } from "node:path";
2
+ import { ConfigManager } from "../config/config-manager.js";
3
+ import { GitAdapter } from "../git-adapter/git-adapter.js";
4
+ import { PushCommand } from "./push.js";
5
+ import { output } from "../output.js";
6
+ export class OverrideCommand {
7
+ homeDir;
8
+ configManager;
9
+ constructor(homeDir) {
10
+ this.homeDir = homeDir;
11
+ this.configManager = new ConfigManager(homeDir);
12
+ }
13
+ 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
+ try {
25
+ await gitAdapter.pull();
26
+ }
27
+ catch {
28
+ // Fresh store with no remote history yet
29
+ }
30
+ // 2. Wipe remote and write override marker
31
+ await gitAdapter.wipeAndPush(config.machineId);
32
+ // 3. Run full push pipeline to repopulate store
33
+ const pushCommand = new PushCommand(this.homeDir);
34
+ await pushCommand.execute({
35
+ quiet: options.quiet,
36
+ skipEncryption: options.skipEncryption,
37
+ passphrase: options.passphrase,
38
+ });
39
+ if (!options.quiet) {
40
+ output.success("Override complete. All other machines will receive your config on next pull.");
41
+ }
42
+ }
43
+ }
44
+ //# sourceMappingURL=override.js.map
@@ -0,0 +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,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,IAAI,EAAE,CAAC;QAC1B,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"}
@@ -0,0 +1,17 @@
1
+ export interface PullOptions {
2
+ quiet: boolean;
3
+ skipEncryption?: boolean;
4
+ passphrase?: string;
5
+ }
6
+ export interface PullResult {
7
+ overrideDetected: boolean;
8
+ backupPath?: string;
9
+ filesUpdated: number;
10
+ }
11
+ export declare class PullCommand {
12
+ private homeDir;
13
+ private claudeDir;
14
+ private configManager;
15
+ constructor(homeDir: string);
16
+ execute(options: PullOptions): Promise<PullResult>;
17
+ }