jean-claude 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 (68) hide show
  1. package/README.md +71 -0
  2. package/dist/cli.d.ts +4 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +56 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/doctor.d.ts +3 -0
  7. package/dist/commands/doctor.d.ts.map +1 -0
  8. package/dist/commands/doctor.js +139 -0
  9. package/dist/commands/doctor.js.map +1 -0
  10. package/dist/commands/index.d.ts +5 -0
  11. package/dist/commands/index.d.ts.map +1 -0
  12. package/dist/commands/index.js +5 -0
  13. package/dist/commands/index.js.map +1 -0
  14. package/dist/commands/init.d.ts +3 -0
  15. package/dist/commands/init.d.ts.map +1 -0
  16. package/dist/commands/init.js +69 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/commands/pull.d.ts +3 -0
  19. package/dist/commands/pull.d.ts.map +1 -0
  20. package/dist/commands/pull.js +48 -0
  21. package/dist/commands/pull.js.map +1 -0
  22. package/dist/commands/push.d.ts +3 -0
  23. package/dist/commands/push.d.ts.map +1 -0
  24. package/dist/commands/push.js +73 -0
  25. package/dist/commands/push.js.map +1 -0
  26. package/dist/commands/status.d.ts +3 -0
  27. package/dist/commands/status.d.ts.map +1 -0
  28. package/dist/commands/status.js +81 -0
  29. package/dist/commands/status.js.map +1 -0
  30. package/dist/index.d.ts +3 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +4 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/lib/git.d.ts +21 -0
  35. package/dist/lib/git.d.ts.map +1 -0
  36. package/dist/lib/git.js +137 -0
  37. package/dist/lib/git.js.map +1 -0
  38. package/dist/lib/paths.d.ts +7 -0
  39. package/dist/lib/paths.d.ts.map +1 -0
  40. package/dist/lib/paths.js +43 -0
  41. package/dist/lib/paths.js.map +1 -0
  42. package/dist/lib/scaffold.d.ts +2 -0
  43. package/dist/lib/scaffold.d.ts.map +1 -0
  44. package/dist/lib/scaffold.js +77 -0
  45. package/dist/lib/scaffold.js.map +1 -0
  46. package/dist/lib/sync.d.ts +16 -0
  47. package/dist/lib/sync.d.ts.map +1 -0
  48. package/dist/lib/sync.js +229 -0
  49. package/dist/lib/sync.js.map +1 -0
  50. package/dist/types/index.d.ts +57 -0
  51. package/dist/types/index.d.ts.map +1 -0
  52. package/dist/types/index.js +24 -0
  53. package/dist/types/index.js.map +1 -0
  54. package/dist/utils/logger.d.ts +13 -0
  55. package/dist/utils/logger.d.ts.map +1 -0
  56. package/dist/utils/logger.js +32 -0
  57. package/dist/utils/logger.js.map +1 -0
  58. package/dist/utils/logo.d.ts +2 -0
  59. package/dist/utils/logo.d.ts.map +1 -0
  60. package/dist/utils/logo.js +39 -0
  61. package/dist/utils/logo.js.map +1 -0
  62. package/dist/utils/prompts.d.ts +7 -0
  63. package/dist/utils/prompts.d.ts.map +1 -0
  64. package/dist/utils/prompts.js +35 -0
  65. package/dist/utils/prompts.js.map +1 -0
  66. package/package.json +58 -0
  67. package/templates/CLAUDE.md +33 -0
  68. package/templates/settings.json +2 -0
package/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # JEAN-CLAUDE
2
+
3
+ **A companion for syncing Claude Code configuration across machines**
4
+
5
+ ## Why?
6
+
7
+ You've spent hours crafting the perfect `CLAUDE.md`. Your hooks are *chef's kiss*. Your settings are dialed in just right.
8
+
9
+ Then you sit down at another machine and... nothing. Back to square one.
10
+
11
+ **Jean-Claude fixes that.** It syncs your Claude Code configuration across all your machines using Git.
12
+
13
+ ## What gets synced?
14
+
15
+ - `CLAUDE.md` - Your custom instructions
16
+ - `settings.json` - Your preferences
17
+ - `hooks/` - Your automation scripts
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install -g jean-claude
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### First time setup
28
+
29
+ ```bash
30
+ jean-claude init
31
+ ```
32
+
33
+ You'll be asked for a Git repository URL. Create an empty private repo on GitHub/GitLab/etc and paste the URL.
34
+
35
+ ### Push your config
36
+
37
+ Made changes to your Claude Code setup? Push them:
38
+
39
+ ```bash
40
+ jean-claude push
41
+ ```
42
+
43
+ ### Pull on another machine
44
+
45
+ On a new machine, initialize with the same repo:
46
+
47
+ ```bash
48
+ jean-claude init
49
+ ```
50
+
51
+ Then pull the latest:
52
+
53
+ ```bash
54
+ jean-claude pull
55
+ ```
56
+
57
+ ### Check status
58
+
59
+ See what's in sync:
60
+
61
+ ```bash
62
+ jean-claude status
63
+ ```
64
+
65
+ ## That's it!
66
+
67
+ Four commands. No options. No complexity. Just sync.
68
+
69
+ ---
70
+
71
+ *Named after the famous Belgian martial artist and philosopher, because your config deserves to do the splits across multiple machines.*
package/dist/cli.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { Command } from 'commander';
2
+ export declare function createProgram(): Command;
3
+ export declare function run(argv: string[]): Promise<void>;
4
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,wBAAgB,aAAa,IAAI,OAAO,CAkBvC;AAED,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCvD"}
package/dist/cli.js ADDED
@@ -0,0 +1,56 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { initCommand, pullCommand, pushCommand, statusCommand, } from './commands/index.js';
4
+ import { JeanClaudeError } from './types/index.js';
5
+ import { printLogo } from './utils/logo.js';
6
+ const VERSION = '0.1.0';
7
+ export function createProgram() {
8
+ const program = new Command();
9
+ program
10
+ .name('jean-claude')
11
+ .description('Sync Claude Code configuration across machines using Git')
12
+ .version(VERSION)
13
+ .addHelpText('before', () => {
14
+ printLogo();
15
+ return '';
16
+ });
17
+ program.addCommand(initCommand);
18
+ program.addCommand(pullCommand);
19
+ program.addCommand(pushCommand);
20
+ program.addCommand(statusCommand);
21
+ return program;
22
+ }
23
+ export async function run(argv) {
24
+ const program = createProgram();
25
+ // Global error handling
26
+ program.exitOverride();
27
+ try {
28
+ await program.parseAsync(argv);
29
+ }
30
+ catch (err) {
31
+ if (err instanceof JeanClaudeError) {
32
+ console.error(chalk.red('error') + ' ' + err.message);
33
+ if (err.suggestion) {
34
+ console.log('\n' + chalk.dim('Suggestion: ') + err.suggestion);
35
+ }
36
+ process.exit(1);
37
+ }
38
+ // Commander errors (like --help, --version)
39
+ if (err && typeof err === 'object' && 'code' in err) {
40
+ const code = err.code;
41
+ if (code === 'commander.helpDisplayed' || code === 'commander.version' || code === 'commander.help') {
42
+ process.exit(0);
43
+ }
44
+ }
45
+ // Unexpected error
46
+ console.error(chalk.red('error') + ' An unexpected error occurred');
47
+ if (process.env.DEBUG) {
48
+ console.error(err);
49
+ }
50
+ else {
51
+ console.log(chalk.dim('Run with DEBUG=1 for more details'));
52
+ }
53
+ process.exit(1);
54
+ }
55
+ }
56
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,GACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,MAAM,UAAU,aAAa;IAC3B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,aAAa,CAAC;SACnB,WAAW,CAAC,0DAA0D,CAAC;SACvE,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,QAAQ,EAAE,GAAG,EAAE;QAC1B,SAAS,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;IAEL,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAChC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAChC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAChC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAElC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc;IACtC,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAEhC,wBAAwB;IACxB,OAAO,CAAC,YAAY,EAAE,CAAC;IAEvB,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,eAAe,EAAE,CAAC;YACnC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;YACtD,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;gBACnB,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC;YACjE,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,4CAA4C;QAC5C,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;YACpD,MAAM,IAAI,GAAI,GAAwB,CAAC,IAAI,CAAC;YAC5C,IAAI,IAAI,KAAK,yBAAyB,IAAI,IAAI,KAAK,mBAAmB,IAAI,IAAI,KAAK,gBAAgB,EAAE,CAAC;gBACpG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,mBAAmB;QACnB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,+BAA+B,CAAC,CAAC;QACpE,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const doctorCommand: Command;
3
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuHpC,eAAO,MAAM,aAAa,SAkCtB,CAAC"}
@@ -0,0 +1,139 @@
1
+ import { Command } from 'commander';
2
+ import fs from 'fs-extra';
3
+ import chalk from 'chalk';
4
+ import { logger, formatPath } from '../utils/logger.js';
5
+ import { getConfigPaths } from '../lib/paths.js';
6
+ import { isGitRepo, getGitStatus, hasMergeConflicts } from '../lib/git.js';
7
+ import { readMetaJson } from '../lib/sync.js';
8
+ async function runChecks() {
9
+ const checks = [];
10
+ const { jeanClaudeDir, claudeConfigDir } = getConfigPaths();
11
+ // Check 1: Directory exists
12
+ const dirExists = fs.existsSync(jeanClaudeDir);
13
+ checks.push({
14
+ name: 'Jean-Claude directory exists',
15
+ passed: dirExists,
16
+ message: dirExists
17
+ ? formatPath(jeanClaudeDir)
18
+ : `${formatPath(jeanClaudeDir)} not found`,
19
+ suggestion: dirExists ? undefined : 'Run "jean-claude init" to set up.',
20
+ });
21
+ if (!dirExists) {
22
+ return checks; // Can't continue without directory
23
+ }
24
+ // Check 2: Is Git repo
25
+ const isRepo = await isGitRepo(jeanClaudeDir);
26
+ checks.push({
27
+ name: 'Is a Git repository',
28
+ passed: isRepo,
29
+ message: isRepo ? 'Yes' : 'Not a Git repository',
30
+ suggestion: isRepo
31
+ ? undefined
32
+ : 'Run "git init" in ~/.jean-claude or re-run "jean-claude init".',
33
+ });
34
+ if (!isRepo) {
35
+ return checks; // Can't continue without Git
36
+ }
37
+ // Check 3: Remote configured
38
+ const gitStatus = await getGitStatus(jeanClaudeDir);
39
+ checks.push({
40
+ name: 'Git remote configured',
41
+ passed: !!gitStatus.remote,
42
+ message: gitStatus.remote || 'No remote',
43
+ suggestion: gitStatus.remote
44
+ ? undefined
45
+ : 'Add a remote: git -C ~/.jean-claude remote add origin <url>',
46
+ });
47
+ // Check 4: No merge conflicts
48
+ const hasConflicts = await hasMergeConflicts(jeanClaudeDir);
49
+ checks.push({
50
+ name: 'No merge conflicts',
51
+ passed: !hasConflicts,
52
+ message: hasConflicts ? 'Conflicts detected!' : 'Clean',
53
+ suggestion: hasConflicts
54
+ ? 'Resolve conflicts in ~/.jean-claude before continuing.'
55
+ : undefined,
56
+ });
57
+ // Check 5: Claude config directory exists
58
+ const claudeExists = fs.existsSync(claudeConfigDir);
59
+ checks.push({
60
+ name: 'Claude Code config directory exists',
61
+ passed: claudeExists,
62
+ message: claudeExists
63
+ ? formatPath(claudeConfigDir)
64
+ : `${formatPath(claudeConfigDir)} not found`,
65
+ suggestion: claudeExists
66
+ ? undefined
67
+ : 'Run "jean-claude pull" to create it, or start Claude Code once.',
68
+ });
69
+ // Check 6: meta.json is valid
70
+ const meta = await readMetaJson(jeanClaudeDir);
71
+ checks.push({
72
+ name: 'meta.json is valid',
73
+ passed: !!meta,
74
+ message: meta ? `Machine: ${meta.machineId}` : 'Invalid or missing',
75
+ suggestion: meta
76
+ ? undefined
77
+ : 'Run "jean-claude init" again to regenerate meta.json.',
78
+ });
79
+ // Check 7: Required files exist
80
+ const claudeMdExists = fs.existsSync(`${jeanClaudeDir}/CLAUDE.md`);
81
+ checks.push({
82
+ name: 'CLAUDE.md exists',
83
+ passed: claudeMdExists,
84
+ message: claudeMdExists ? 'Present' : 'Missing',
85
+ suggestion: claudeMdExists
86
+ ? undefined
87
+ : 'Create CLAUDE.md in ~/.jean-claude with your configuration.',
88
+ });
89
+ // Check 8: Permissions
90
+ let permissionsOk = true;
91
+ try {
92
+ fs.accessSync(jeanClaudeDir, fs.constants.R_OK | fs.constants.W_OK);
93
+ }
94
+ catch {
95
+ permissionsOk = false;
96
+ }
97
+ checks.push({
98
+ name: 'Directory permissions',
99
+ passed: permissionsOk,
100
+ message: permissionsOk ? 'OK (read/write)' : 'Permission denied',
101
+ suggestion: permissionsOk
102
+ ? undefined
103
+ : `Fix permissions: chmod -R u+rw ${formatPath(jeanClaudeDir)}`,
104
+ });
105
+ return checks;
106
+ }
107
+ export const doctorCommand = new Command('doctor')
108
+ .description('Diagnose common issues')
109
+ .option('--json', 'Output as JSON')
110
+ .action(async (options) => {
111
+ const checks = await runChecks();
112
+ if (options.json) {
113
+ console.log(JSON.stringify({ checks }, null, 2));
114
+ const allPassed = checks.every((c) => c.passed);
115
+ process.exit(allPassed ? 0 : 1);
116
+ return;
117
+ }
118
+ logger.heading('Jean-Claude Doctor');
119
+ console.log('');
120
+ let allPassed = true;
121
+ checks.forEach((check) => {
122
+ const icon = check.passed ? chalk.green('✓') : chalk.red('✗');
123
+ console.log(` ${icon} ${check.name}`);
124
+ console.log(` ${chalk.dim(check.message)}`);
125
+ if (!check.passed && check.suggestion) {
126
+ console.log(` ${chalk.yellow('→')} ${check.suggestion}`);
127
+ allPassed = false;
128
+ }
129
+ });
130
+ console.log('');
131
+ if (allPassed) {
132
+ logger.success('All checks passed!');
133
+ }
134
+ else {
135
+ logger.warn('Some checks failed. See suggestions above.');
136
+ process.exit(1);
137
+ }
138
+ });
139
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE,GAAG,cAAc,EAAE,CAAC;IAE5D,4BAA4B;IAC5B,MAAM,SAAS,GAAG,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAC/C,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,8BAA8B;QACpC,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,SAAS;YAChB,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC;YAC3B,CAAC,CAAC,GAAG,UAAU,CAAC,aAAa,CAAC,YAAY;QAC5C,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,mCAAmC;KACxE,CAAC,CAAC;IAEH,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,MAAM,CAAC,CAAC,mCAAmC;IACpD,CAAC;IAED,uBAAuB;IACvB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,aAAa,CAAC,CAAC;IAC9C,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,qBAAqB;QAC3B,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,sBAAsB;QAChD,UAAU,EAAE,MAAM;YAChB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,gEAAgE;KACrE,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,MAAM,CAAC,CAAC,6BAA6B;IAC9C,CAAC;IAED,6BAA6B;IAC7B,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,CAAC;IACpD,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,uBAAuB;QAC7B,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM;QAC1B,OAAO,EAAE,SAAS,CAAC,MAAM,IAAI,WAAW;QACxC,UAAU,EAAE,SAAS,CAAC,MAAM;YAC1B,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,6DAA6D;KAClE,CAAC,CAAC;IAEH,8BAA8B;IAC9B,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAAC,aAAa,CAAC,CAAC;IAC5D,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,oBAAoB;QAC1B,MAAM,EAAE,CAAC,YAAY;QACrB,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,OAAO;QACvD,UAAU,EAAE,YAAY;YACtB,CAAC,CAAC,wDAAwD;YAC1D,CAAC,CAAC,SAAS;KACd,CAAC,CAAC;IAEH,0CAA0C;IAC1C,MAAM,YAAY,GAAG,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;IACpD,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,qCAAqC;QAC3C,MAAM,EAAE,YAAY;QACpB,OAAO,EAAE,YAAY;YACnB,CAAC,CAAC,UAAU,CAAC,eAAe,CAAC;YAC7B,CAAC,CAAC,GAAG,UAAU,CAAC,eAAe,CAAC,YAAY;QAC9C,UAAU,EAAE,YAAY;YACtB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,iEAAiE;KACtE,CAAC,CAAC;IAEH,8BAA8B;IAC9B,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,CAAC;IAC/C,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,oBAAoB;QAC1B,MAAM,EAAE,CAAC,CAAC,IAAI;QACd,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,oBAAoB;QACnE,UAAU,EAAE,IAAI;YACd,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,uDAAuD;KAC5D,CAAC,CAAC;IAEH,gCAAgC;IAChC,MAAM,cAAc,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,aAAa,YAAY,CAAC,CAAC;IACnE,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,cAAc;QACtB,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QAC/C,UAAU,EAAE,cAAc;YACxB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,6DAA6D;KAClE,CAAC,CAAC;IAEH,uBAAuB;IACvB,IAAI,aAAa,GAAG,IAAI,CAAC;IACzB,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,aAAa,GAAG,KAAK,CAAC;IACxB,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;QACV,IAAI,EAAE,uBAAuB;QAC7B,MAAM,EAAE,aAAa;QACrB,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,mBAAmB;QAChE,UAAU,EAAE,aAAa;YACvB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,kCAAkC,UAAU,CAAC,aAAa,CAAC,EAAE;KAClE,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,wBAAwB,CAAC;KACrC,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KAClC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;IAEjC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACjD,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,OAAO;IACT,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,SAAS,GAAG,IAAI,CAAC;IACrB,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QACvB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;YAC5D,SAAS,GAAG,KAAK,CAAC;QACpB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACvC,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { initCommand } from './init.js';
2
+ export { pullCommand } from './pull.js';
3
+ export { pushCommand } from './push.js';
4
+ export { statusCommand } from './status.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { initCommand } from './init.js';
2
+ export { pullCommand } from './pull.js';
3
+ export { pushCommand } from './push.js';
4
+ export { statusCommand } from './status.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const initCommand: Command;
3
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC,eAAO,MAAM,WAAW,SAyEpB,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { Command } from 'commander';
2
+ import fs from 'fs-extra';
3
+ import { logger, formatPath } from '../utils/logger.js';
4
+ import { input } from '../utils/prompts.js';
5
+ import { getConfigPaths, ensureDir } from '../lib/paths.js';
6
+ import { isGitRepo, initRepo, addRemote, testRemoteConnection, cloneRepo } from '../lib/git.js';
7
+ import { createMetaJson, writeMetaJson, syncFromClaudeConfig, } from '../lib/sync.js';
8
+ import { JeanClaudeError, ErrorCode } from '../types/index.js';
9
+ import { printLogo } from '../utils/logo.js';
10
+ export const initCommand = new Command('init')
11
+ .description('Initialize Jean-Claude on this machine')
12
+ .action(async () => {
13
+ const { jeanClaudeDir, claudeConfigDir } = getConfigPaths();
14
+ printLogo();
15
+ logger.heading('Setup');
16
+ // Check if already initialized
17
+ if (fs.existsSync(jeanClaudeDir)) {
18
+ const isRepo = await isGitRepo(jeanClaudeDir);
19
+ if (isRepo) {
20
+ logger.success(`Already initialized at ${formatPath(jeanClaudeDir)}`);
21
+ logger.dim('Run "jean-claude status" to see current state.');
22
+ return;
23
+ }
24
+ throw new JeanClaudeError(`${formatPath(jeanClaudeDir)} exists but is not a Git repository`, ErrorCode.NOT_GIT_REPO, 'Remove the directory and run init again.');
25
+ }
26
+ // Get repository URL
27
+ const repoUrl = await input('Enter your Git repository URL:');
28
+ // Test connection to remote
29
+ logger.step(1, 4, 'Testing connection to repository...');
30
+ const canConnect = await testRemoteConnection(repoUrl);
31
+ if (!canConnect) {
32
+ throw new JeanClaudeError('Cannot connect to repository', ErrorCode.NETWORK_ERROR, 'Check that the URL is correct and you have access.');
33
+ }
34
+ logger.success('Connection successful');
35
+ // Try to clone (will work if repo has content) or init fresh (if empty)
36
+ logger.step(2, 4, 'Setting up local repository...');
37
+ try {
38
+ await cloneRepo(repoUrl, jeanClaudeDir);
39
+ logger.success('Cloned existing config from repository');
40
+ }
41
+ catch {
42
+ // Repo is empty, init locally and add remote
43
+ ensureDir(jeanClaudeDir);
44
+ await initRepo(jeanClaudeDir);
45
+ await addRemote(jeanClaudeDir, repoUrl);
46
+ logger.success('Initialized new repository');
47
+ }
48
+ // Create meta.json
49
+ const meta = createMetaJson(claudeConfigDir);
50
+ await writeMetaJson(jeanClaudeDir, meta);
51
+ // Sync from ~/.claude to ~/.jean-claude
52
+ logger.step(3, 4, `Syncing from ${formatPath(claudeConfigDir)}...`);
53
+ const syncResults = await syncFromClaudeConfig(claudeConfigDir, jeanClaudeDir);
54
+ const synced = syncResults.filter((r) => r.action !== 'skipped');
55
+ if (synced.length > 0) {
56
+ logger.success(`Synced ${synced.length} file(s)`);
57
+ }
58
+ // Done
59
+ logger.step(4, 4, 'Done!');
60
+ console.log('');
61
+ logger.success('Jean-Claude initialized!');
62
+ console.log('');
63
+ logger.dim('Next steps:');
64
+ logger.list([
65
+ 'Run "jean-claude push" to push your config to Git',
66
+ 'Run "jean-claude pull" on other machines to sync',
67
+ ]);
68
+ });
69
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAChG,OAAO,EACL,cAAc,EACd,aAAa,EACb,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE,GAAG,cAAc,EAAE,CAAC;IAE5D,SAAS,EAAE,CAAC;IACZ,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAExB,+BAA+B;IAC/B,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,aAAa,CAAC,CAAC;QAC9C,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,OAAO,CAAC,0BAA0B,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;YACtE,MAAM,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;YAC7D,OAAO;QACT,CAAC;QACD,MAAM,IAAI,eAAe,CACvB,GAAG,UAAU,CAAC,aAAa,CAAC,qCAAqC,EACjE,SAAS,CAAC,YAAY,EACtB,0CAA0C,CAC3C,CAAC;IACJ,CAAC;IAED,qBAAqB;IACrB,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAE9D,4BAA4B;IAC5B,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,qCAAqC,CAAC,CAAC;IACzD,MAAM,UAAU,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACvD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,eAAe,CACvB,8BAA8B,EAC9B,SAAS,CAAC,aAAa,EACvB,oDAAoD,CACrD,CAAC;IACJ,CAAC;IACD,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAExC,wEAAwE;IACxE,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,gCAAgC,CAAC,CAAC;IACpD,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QACxC,MAAM,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,6CAA6C;QAC7C,SAAS,CAAC,aAAa,CAAC,CAAC;QACzB,MAAM,QAAQ,CAAC,aAAa,CAAC,CAAC;QAC9B,MAAM,SAAS,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACxC,MAAM,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC;IAC/C,CAAC;IAED,mBAAmB;IACnB,MAAM,IAAI,GAAG,cAAc,CAAC,eAAe,CAAC,CAAC;IAC7C,MAAM,aAAa,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IAEzC,wCAAwC;IACxC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,gBAAgB,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IACpE,MAAM,WAAW,GAAG,MAAM,oBAAoB,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC;IAC/E,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;IACjE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,OAAO,CAAC,UAAU,MAAM,CAAC,MAAM,UAAU,CAAC,CAAC;IACpD,CAAC;IAED,OAAO;IACP,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,MAAM,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC1B,MAAM,CAAC,IAAI,CAAC;QACV,mDAAmD;QACnD,kDAAkD;KACnD,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const pullCommand: Command;
3
+ //# sourceMappingURL=pull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,eAAO,MAAM,WAAW,SA8DpB,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { Command } from 'commander';
2
+ import fs from 'fs-extra';
3
+ import chalk from 'chalk';
4
+ import { logger, formatPath } from '../utils/logger.js';
5
+ import { getConfigPaths } from '../lib/paths.js';
6
+ import { isGitRepo, pull, getGitStatus, hasMergeConflicts, resetHard } from '../lib/git.js';
7
+ import { syncToClaudeConfig, updateLastSync } from '../lib/sync.js';
8
+ import { JeanClaudeError, ErrorCode } from '../types/index.js';
9
+ export const pullCommand = new Command('pull')
10
+ .description('Pull latest config from Git and apply to Claude Code')
11
+ .action(async () => {
12
+ const { jeanClaudeDir, claudeConfigDir } = getConfigPaths();
13
+ // Verify initialized
14
+ if (!fs.existsSync(jeanClaudeDir)) {
15
+ throw new JeanClaudeError('Jean-Claude is not initialized', ErrorCode.NOT_INITIALIZED, 'Run "jean-claude init" first.');
16
+ }
17
+ if (!(await isGitRepo(jeanClaudeDir))) {
18
+ throw new JeanClaudeError(`${formatPath(jeanClaudeDir)} is not a Git repository`, ErrorCode.NOT_GIT_REPO, 'Run "jean-claude init" to set up properly.');
19
+ }
20
+ // Check if remote is configured
21
+ const gitStatus = await getGitStatus(jeanClaudeDir);
22
+ if (!gitStatus.remote) {
23
+ throw new JeanClaudeError('No remote configured', ErrorCode.NO_REMOTE, 'Run "jean-claude init" to set up a remote repository.');
24
+ }
25
+ // Reset any local changes and pull
26
+ logger.step(1, 2, 'Pulling from Git...');
27
+ await resetHard(jeanClaudeDir);
28
+ const pullResult = await pull(jeanClaudeDir);
29
+ logger.success(pullResult.message);
30
+ // Check for merge conflicts (shouldn't happen after reset, but just in case)
31
+ if (await hasMergeConflicts(jeanClaudeDir)) {
32
+ throw new JeanClaudeError('Merge conflicts detected', ErrorCode.MERGE_CONFLICT, `Resolve conflicts in ${formatPath(jeanClaudeDir)} and run pull again.`);
33
+ }
34
+ // Apply to ~/.claude
35
+ logger.step(2, 2, `Applying to ${formatPath(claudeConfigDir)}...`);
36
+ const results = await syncToClaudeConfig(jeanClaudeDir, claudeConfigDir);
37
+ const applied = results.filter((r) => r.action !== 'skipped');
38
+ // Update last sync time
39
+ await updateLastSync(jeanClaudeDir);
40
+ // Summary
41
+ console.log('');
42
+ logger.success(`Applied ${applied.length} file(s)`);
43
+ applied.forEach((r) => {
44
+ const icon = r.action === 'created' ? chalk.green('+') : chalk.yellow('~');
45
+ console.log(` ${icon} ${r.file}`);
46
+ });
47
+ });
48
+ //# sourceMappingURL=pull.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const pushCommand: Command;
3
+ //# sourceMappingURL=push.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/commands/push.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,eAAO,MAAM,WAAW,SA2EpB,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { Command } from 'commander';
2
+ import fs from 'fs-extra';
3
+ import os from 'os';
4
+ import chalk from 'chalk';
5
+ import { logger, formatPath } from '../utils/logger.js';
6
+ import { getConfigPaths } from '../lib/paths.js';
7
+ import { isGitRepo, getGitStatus, commitAndPush } from '../lib/git.js';
8
+ import { updateLastSync, syncFromClaudeConfig } from '../lib/sync.js';
9
+ import { JeanClaudeError, ErrorCode } from '../types/index.js';
10
+ function generateCommitMessage() {
11
+ const hostname = os.hostname();
12
+ const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 19);
13
+ return `Update from ${hostname} at ${timestamp}`;
14
+ }
15
+ export const pushCommand = new Command('push')
16
+ .description('Commit and push config changes to Git')
17
+ .action(async () => {
18
+ const { jeanClaudeDir, claudeConfigDir } = getConfigPaths();
19
+ // Verify initialized
20
+ if (!fs.existsSync(jeanClaudeDir)) {
21
+ throw new JeanClaudeError('Jean-Claude is not initialized', ErrorCode.NOT_INITIALIZED, 'Run "jean-claude init" first.');
22
+ }
23
+ if (!(await isGitRepo(jeanClaudeDir))) {
24
+ throw new JeanClaudeError(`${formatPath(jeanClaudeDir)} is not a Git repository`, ErrorCode.NOT_GIT_REPO, 'Run "jean-claude init" to set up properly.');
25
+ }
26
+ // Step 1: Copy files from ~/.claude to ~/.jean-claude
27
+ logger.step(1, 2, `Syncing from ${formatPath(claudeConfigDir)}...`);
28
+ const syncResults = await syncFromClaudeConfig(claudeConfigDir, jeanClaudeDir);
29
+ const synced = syncResults.filter((r) => r.action !== 'skipped');
30
+ if (synced.length > 0) {
31
+ synced.forEach((r) => {
32
+ console.log(` ${chalk.blue('synced')} ${r.file}`);
33
+ });
34
+ }
35
+ // Step 2: Check git status
36
+ const gitStatus = await getGitStatus(jeanClaudeDir);
37
+ if (gitStatus.isClean) {
38
+ logger.success('Nothing to push - everything is in sync.');
39
+ return;
40
+ }
41
+ // Show changes
42
+ logger.dim('Changes to push:');
43
+ if (gitStatus.modified.length > 0) {
44
+ gitStatus.modified.forEach((f) => {
45
+ console.log(` ${chalk.yellow('modified')} ${f}`);
46
+ });
47
+ }
48
+ if (gitStatus.untracked.length > 0) {
49
+ gitStatus.untracked.forEach((f) => {
50
+ console.log(` ${chalk.green('new file')} ${f}`);
51
+ });
52
+ }
53
+ // Commit message
54
+ const commitMessage = generateCommitMessage();
55
+ // Commit and push
56
+ logger.step(2, 2, 'Committing and pushing...');
57
+ const result = await commitAndPush(jeanClaudeDir, commitMessage, true);
58
+ // Update last sync
59
+ await updateLastSync(jeanClaudeDir);
60
+ // Summary
61
+ console.log('');
62
+ if (result.committed) {
63
+ logger.success('Changes committed');
64
+ }
65
+ if (result.pushed) {
66
+ logger.success('Pushed to remote');
67
+ }
68
+ else if (!gitStatus.remote) {
69
+ logger.warn('No remote configured - changes committed locally only');
70
+ logger.dim('Add a remote with: git -C ~/.jean-claude remote add origin <url>');
71
+ }
72
+ });
73
+ //# sourceMappingURL=push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/commands/push.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const statusCommand: Command;
3
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,eAAO,MAAM,aAAa,SAyFtB,CAAC"}