gent-cli 1.3.0 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gent-cli",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "A Git-like version control CLI tool with cloud authentication",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -8,6 +8,7 @@ const chalk = require('chalk');
8
8
  const inquirer = require('inquirer');
9
9
  const ora = require('ora');
10
10
  const { getGentPath, readJSON, writeJSON } = require('../utils/fileSystem');
11
+ const authStorage = require('../utils/auth-storage');
11
12
  const { STAGING_FILE, COMMITS_FILE, CONFIG_FILE } = require('../utils/constants');
12
13
  const { generateCommitHash, getFileHash } = require('../utils/helpers');
13
14
 
@@ -49,17 +50,41 @@ async function commit(options) {
49
50
 
50
51
  const spinner = ora('Creating commit...').start();
51
52
 
52
- // Read config and repository
53
53
  const config = await readJSON(path.join(gentPath, CONFIG_FILE));
54
54
  const repository = await readJSON(path.join(gentPath, COMMITS_FILE));
55
55
 
56
+ // Resolve author identity
57
+ let authorName = config.user.name;
58
+ let authorEmail = config.user.email;
59
+
60
+ // Fallback to global auth if local config is empty
61
+ if (!authorName || !authorEmail) {
62
+ const globalUser = await authStorage.getUser();
63
+ if (globalUser) {
64
+ if (!authorName) {
65
+ authorName = [globalUser.first_name, globalUser.last_name].filter(Boolean).join(' ');
66
+ }
67
+ if (!authorEmail) {
68
+ authorEmail = globalUser.email;
69
+ }
70
+ }
71
+ }
72
+
73
+ // Fail if still no identity
74
+ if (!authorName || !authorEmail) {
75
+ spinner.stop();
76
+ console.error(chalk.red('Author identity unknown'));
77
+ console.log(chalk.yellow('Please run "gent login" to set your identity globally'));
78
+ return;
79
+ }
80
+
56
81
  // Create commit object
57
82
  const commit = {
58
83
  hash: generateCommitHash(),
59
84
  message: message,
60
85
  author: {
61
- name: config.user.name,
62
- email: config.user.email
86
+ name: authorName,
87
+ email: authorEmail
63
88
  },
64
89
  timestamp: new Date().toISOString(),
65
90
  parent: repository.branches[repository.currentBranch] || null,
@@ -6,10 +6,8 @@
6
6
  const fs = require('fs').promises;
7
7
  const path = require('path');
8
8
  const chalk = require('chalk');
9
- const inquirer = require('inquirer');
10
- const ora = require('ora');
11
- const boxen = require('boxen');
12
9
  const { ensureDir, writeJSON, pathExists } = require('../utils/fileSystem');
10
+ const authStorage = require('../utils/auth-storage');
13
11
  const { GENT_DIR, CONFIG_FILE, STAGING_FILE, COMMITS_FILE } = require('../utils/constants');
14
12
 
15
13
  /**
@@ -17,8 +15,6 @@ const { GENT_DIR, CONFIG_FILE, STAGING_FILE, COMMITS_FILE } = require('../utils/
17
15
  * @param {Object} options - Command options
18
16
  */
19
17
  async function init(options) {
20
- const spinner = ora('Initializing gent repository...').start();
21
-
22
18
  try {
23
19
  const cwd = process.cwd();
24
20
  const gentPath = path.join(cwd, GENT_DIR);
@@ -26,28 +22,31 @@ async function init(options) {
26
22
 
27
23
  // Check if already initialized
28
24
  if (await pathExists(gentPath)) {
29
- spinner.stop();
30
- const { reinitialize } = await inquirer.prompt([
31
- {
32
- type: 'confirm',
33
- name: 'reinitialize',
34
- message: 'Gent repository already exists. Re-initialize? (This preserves your history)',
35
- default: true
36
- }
37
- ]);
25
+ isReinit = true;
26
+ }
27
+
28
+ // Get authenticated user profile if available
29
+ let defaultName = '';
30
+ let defaultEmail = '';
38
31
 
39
- if (!reinitialize) {
40
- console.log(chalk.yellow('\nℹ Use gent status to see the current state'));
41
- return;
32
+ try {
33
+ const user = await authStorage.getUser();
34
+ if (user) {
35
+ if (user.first_name || user.last_name) {
36
+ defaultName = [user.first_name, user.last_name].filter(Boolean).join(' ');
37
+ }
38
+ if (user.email) {
39
+ defaultEmail = user.email;
40
+ }
42
41
  }
43
- isReinit = true;
42
+ } catch (error) {
43
+ // Ignore auth errors
44
44
  }
45
45
 
46
- // Get user configuration if not using defaults
47
46
  let config = {
48
47
  user: {
49
- name: 'Anonymous',
50
- email: 'anonymous@example.com'
48
+ name: defaultName,
49
+ email: defaultEmail
51
50
  },
52
51
  repository: {
53
52
  name: path.basename(cwd),
@@ -56,48 +55,6 @@ async function init(options) {
56
55
  }
57
56
  };
58
57
 
59
- if (!options.yes) {
60
- spinner.stop(); // Ensure spinner is stopped before prompt
61
-
62
- const answers = await inquirer.prompt([
63
- {
64
- type: 'input',
65
- name: 'userName',
66
- message: 'Enter your name:',
67
- default: 'Anonymous'
68
- },
69
- {
70
- type: 'input',
71
- name: 'userEmail',
72
- message: 'Enter your email:',
73
- default: 'anonymous@example.com',
74
- validate: (input) => {
75
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
76
- return emailRegex.test(input) || 'Please enter a valid email';
77
- }
78
- },
79
- {
80
- type: 'input',
81
- name: 'repoName',
82
- message: 'Repository name:',
83
- default: path.basename(cwd)
84
- },
85
- {
86
- type: 'input',
87
- name: 'repoDescription',
88
- message: 'Repository description:',
89
- default: 'A gent repository'
90
- }
91
- ]);
92
-
93
- config.user.name = answers.userName;
94
- config.user.email = answers.userEmail;
95
- config.repository.name = answers.repoName;
96
- config.repository.description = answers.repoDescription;
97
-
98
- spinner.start(isReinit ? 'Re-initializing repository...' : 'Creating repository structure...');
99
- }
100
-
101
58
  // Create directory structure
102
59
  await ensureDir(gentPath);
103
60
  await ensureDir(path.join(gentPath, 'objects'));
@@ -105,28 +62,37 @@ async function init(options) {
105
62
  await ensureDir(path.join(gentPath, 'refs', 'tags'));
106
63
 
107
64
  // Create/Update configuration
108
- await writeJSON(path.join(gentPath, CONFIG_FILE), config);
65
+ // Only write config if it doesn't exist OR if we have valid user info to update
66
+ const configPath = path.join(gentPath, CONFIG_FILE);
67
+ if (!(await pathExists(configPath)) || (defaultName && defaultEmail)) {
68
+ // If re-init, we might want to preserve existing config unless we have better info?
69
+ // Git re-init doesn't overwrite config usually.
70
+ // But for now, let's write ensuring we have a config file.
71
+ if (!isReinit || !(await pathExists(configPath))) {
72
+ await writeJSON(configPath, config);
73
+ }
74
+ }
109
75
 
110
- // Create initial files only if they don't exist (preserve history on re-init)
76
+ // Create initial files only if they don't exist
111
77
  const stagingPath = path.join(gentPath, STAGING_FILE);
112
- if (!isReinit || !(await pathExists(stagingPath))) {
78
+ if (!(await pathExists(stagingPath))) {
113
79
  await writeJSON(stagingPath, { files: [] });
114
80
  }
115
81
 
116
82
  const commitsPath = path.join(gentPath, COMMITS_FILE);
117
- if (!isReinit || !(await pathExists(commitsPath))) {
83
+ if (!(await pathExists(commitsPath))) {
118
84
  await writeJSON(commitsPath, { commits: [], branches: { main: null }, currentBranch: 'main' });
119
85
  }
120
86
 
121
87
  // Create HEAD file only if it doesn't exist
122
88
  const headPath = path.join(gentPath, 'HEAD');
123
- if (!isReinit || !(await pathExists(headPath))) {
89
+ if (!(await pathExists(headPath))) {
124
90
  await fs.writeFile(headPath, 'ref: refs/heads/main\n');
125
91
  }
126
92
 
127
93
  // Create .gentignore only if it doesn't exist
128
94
  const ignorePath = path.join(cwd, '.gentignore');
129
- if (!isReinit || !(await pathExists(ignorePath))) {
95
+ if (!(await pathExists(ignorePath))) {
130
96
  const gentignore = `# Gent ignore patterns
131
97
  node_modules/
132
98
  .DS_Store
@@ -138,33 +104,14 @@ node_modules/
138
104
  }
139
105
 
140
106
  if (isReinit) {
141
- spinner.succeed(chalk.green('✓ Gent repository re-initialized successfully!'));
107
+ console.log(chalk.gray(`Reinitialized existing Gent repository in ${gentPath}`));
142
108
  } else {
143
- spinner.succeed(chalk.green('✓ Gent repository initialized successfully!'));
109
+ console.log(chalk.gray(`Initialized empty Gent repository in ${gentPath}`));
144
110
  }
145
111
 
146
- // Display success message
147
- const message = chalk.white(`
148
- ${chalk.bold('Repository:')} ${config.repository.name}
149
- ${chalk.bold('User:')} ${config.user.name} <${config.user.email}>
150
- ${chalk.bold('Branch:')} main
151
-
152
- ${chalk.cyan('Next steps:')}
153
- ${chalk.gray('•')} gent add <files> - Add files to staging
154
- ${chalk.gray('•')} gent commit - Commit your changes
155
- ${chalk.gray('•')} gent status - View repository status
156
- `);
157
-
158
- console.log(boxen(message, {
159
- padding: 1,
160
- margin: 1,
161
- borderStyle: 'round',
162
- borderColor: 'cyan'
163
- }));
164
-
165
112
  } catch (error) {
166
- spinner.fail(chalk.red('Failed to initialize repository'));
167
- console.error(chalk.red('\nError:'), error.message);
113
+ console.error(chalk.red('Failed to initialize repository'));
114
+ console.error(chalk.red('Error:'), error.message);
168
115
  process.exit(1);
169
116
  }
170
117
  }
@@ -5,6 +5,7 @@
5
5
 
6
6
  const fs = require('fs').promises;
7
7
  const path = require('path');
8
+ const os = require('os');
8
9
  const CryptoJS = require('crypto-js');
9
10
  const { GENT_DIR, AUTH_FILE } = require('./constants');
10
11
 
@@ -16,7 +17,7 @@ const ENCRYPTION_KEY = 'gent-cli-secret-key-v1';
16
17
  * @returns {string} Path to auth.json file
17
18
  */
18
19
  function getAuthFilePath() {
19
- return path.join(process.cwd(), GENT_DIR, AUTH_FILE);
20
+ return path.join(os.homedir(), GENT_DIR, AUTH_FILE);
20
21
  }
21
22
 
22
23
  /**
@@ -48,7 +49,7 @@ function decrypt(encryptedData) {
48
49
  */
49
50
  async function saveTokens(accessToken, refreshToken, user) {
50
51
  const authFilePath = getAuthFilePath();
51
- const gentDir = path.join(process.cwd(), GENT_DIR);
52
+ const gentDir = path.join(os.homedir(), GENT_DIR);
52
53
 
53
54
  const authData = {
54
55
  accessToken,
@@ -149,7 +150,7 @@ async function updateAccessToken(newAccessToken) {
149
150
  authData.timestamp = new Date().toISOString();
150
151
 
151
152
  const authFilePath = getAuthFilePath();
152
- const gentDir = path.join(process.cwd(), GENT_DIR);
153
+ const gentDir = path.join(os.homedir(), GENT_DIR);
153
154
  const encryptedData = encrypt(authData);
154
155
 
155
156
  // Ensure .gent directory exists