gent-cli 1.6.0 → 1.8.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/README.md CHANGED
@@ -2,13 +2,14 @@
2
2
 
3
3
  > A modern, Git-like version control CLI with built-in cloud authentication and global user identity management.
4
4
 
5
- Gent is a lightweight version control system that feels exactly like Git but handles user identity automatically through the cloud. No more configuring user.name and user.email for every repository!
5
+ Gent is a lightweight version control system that feels exactly like Git but handles user identity automatically through the cloud. No more configuring `user.name` and `user.email` for every repository!
6
6
 
7
7
  ## Features
8
8
 
9
9
  - **Cloud Authentication**: Login once, work everywhere. Your identity follows you across projects.
10
10
  - **Git-like Experience**: Familiar commands (init, add, commit, status, log, branch, checkout).
11
- - **Zero Configuration**: gent init is silent and auto-detects your authenticated user profile.
11
+ - **Cloud Synchronization**: Push and pull repositories to/from the cloud.
12
+ - **Zero Configuration**: `gent init` is silent and auto-detects your authenticated user profile.
12
13
  - **Global Identity**: Commits are automatically authored with your cloud profile.
13
14
  - **Secure**: Tokens stored securely in your home directory.
14
15
 
@@ -48,12 +49,10 @@ gent whoami
48
49
  gent logout
49
50
  ```
50
51
 
51
- ## Usage
52
+ ## Local Usage
52
53
 
53
54
  ### 1. Initialize a Repository
54
55
 
55
- Just like Git, gent init is silent and sets up a new repository in your current directory. It automatically uses your logged-in identity for configuration.
56
-
57
56
  ```bash
58
57
  gent init
59
58
  # Output: Initialized empty Gent repository in /path/to/project
@@ -61,16 +60,12 @@ gent init
61
60
 
62
61
  ### 2. Check Status
63
62
 
64
- See which files are modified or untracked.
65
-
66
63
  ```bash
67
64
  gent status
68
65
  ```
69
66
 
70
67
  ### 3. Stage Files
71
68
 
72
- Add files to the staging area.
73
-
74
69
  ```bash
75
70
  gent add filename.js
76
71
  # or add all files
@@ -79,55 +74,74 @@ gent add .
79
74
 
80
75
  ### 4. Commit Changes
81
76
 
82
- Create a commit. Gent automatically fetches your name and email from your global login session.
83
-
84
77
  ```bash
85
78
  gent commit -m "Initial commit"
86
79
  # Output: [main a1b2c3d] Initial commit
87
80
  # Author: Your Name <your.email@example.com>
88
81
  ```
89
82
 
90
- ### 5. View History
83
+ ## Cloud Features
84
+
85
+ ### 1. Create a Cloud Repository
86
+
87
+ ```bash
88
+ # Create and link a local repo
89
+ gent create my-repo --init-local
90
+
91
+ # Or initialize with cloud directly
92
+ gent init --cloud
93
+ ```
91
94
 
92
- See your commit history.
95
+ ### 2. List Your Repositories
93
96
 
94
97
  ```bash
95
- gent log
96
- # or compact view
97
- gent log --oneline
98
+ gent list
99
+ # or
100
+ gent ls
98
101
  ```
99
102
 
100
- ## Branching
103
+ ### 3. Clone a Repository
101
104
 
102
- Manage branches just like you're used to.
105
+ ```bash
106
+ gent clone <owner_id>/<repo_name>
107
+ # Example: gent clone 1/my-repo
108
+ ```
109
+
110
+ ### 4. Push Changes
103
111
 
104
112
  ```bash
105
- # Create and switch to a new branch
106
- gent checkout -b feature-login
113
+ gent push
114
+ # or commit and push in one go
115
+ gent commit -m "Update README" --push
116
+ ```
107
117
 
108
- # List branches
109
- gent branch
118
+ ### 5. Pull Changes
110
119
 
111
- # Switch back to main
112
- gent checkout main
120
+ ```bash
121
+ gent pull
122
+ ```
113
123
 
114
- # Delete a branch
115
- gent branch -d feature-login
124
+ ### 6. Manage Remotes
125
+
126
+ ```bash
127
+ gent remote add origin <owner_id>/<repo_name>
128
+ gent remote -v
116
129
  ```
117
130
 
118
131
  ## Repository Structure
119
132
 
120
- Gent creates a .gent directory in your project root:
133
+ Gent creates a `.gent` directory in your project root:
121
134
 
122
135
  ```
123
136
  .gent/
124
137
  ├── config.json # Project configuration
125
138
  ├── objects/ # Stored file contents
126
139
  ├── refs/ # Branch pointers
140
+ ├── remote.json # Remote configuration
127
141
  └── HEAD # Current branch reference
128
142
  ```
129
143
 
130
- Your authentication tokens are stored globally in ~/.gent/auth.json.
144
+ Your authentication tokens are stored globally in `~/.gent/auth.json`.
131
145
 
132
146
  ## Contributing
133
147
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gent-cli",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "A modern, Git-like version control CLI with built-in cloud authentication and global user identity management.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Clone Command - Clone a cloud repository to local
3
+ * Downloads repository data and sets up local working copy
4
+ */
5
+
6
+ const fs = require('fs').promises;
7
+ const chalk = require('chalk');
8
+ const ora = require('ora');
9
+ const path = require('path');
10
+ const repoService = require('../services/repo-service');
11
+ const authStorage = require('../utils/auth-storage');
12
+ const { ensureDir, writeJSON, pathExists } = require('../utils/fileSystem');
13
+ const { GENT_DIR, CONFIG_FILE, STAGING_FILE, COMMITS_FILE } = require('../utils/constants');
14
+ const { addRemote, syncCommitsFromCloud } = require('../utils/cloud-sync');
15
+
16
+ /**
17
+ * Clone a cloud repository
18
+ * @param {string} repoUrl - Repository URL (owner_id/repo_name)
19
+ * @param {string} directory - Target directory (optional)
20
+ * @param {Object} options - Command options
21
+ */
22
+ async function clone(repoUrl, directory, options) {
23
+ try {
24
+ // Check authentication
25
+ const user = await authStorage.getUser();
26
+ if (!user) {
27
+ console.error(chalk.red('Error: You must be logged in to clone a repository'));
28
+ console.log(chalk.yellow('Run'), chalk.cyan('gent login'), chalk.yellow('to authenticate'));
29
+ process.exit(1);
30
+ }
31
+
32
+ // Parse repository URL
33
+ if (!repoUrl) {
34
+ console.error(chalk.red('Error: Repository URL is required'));
35
+ console.log(chalk.yellow('Usage:'), chalk.cyan('gent clone <owner_id>/<repo_name> [directory]'));
36
+ process.exit(1);
37
+ }
38
+
39
+ const parts = repoUrl.split('/');
40
+ if (parts.length !== 2) {
41
+ console.error(chalk.red('Error: Invalid repository URL format'));
42
+ console.log(chalk.yellow('Expected:'), chalk.cyan('<owner_id>/<repo_name>'));
43
+ process.exit(1);
44
+ }
45
+
46
+ const ownerId = parseInt(parts[0]);
47
+ const repoName = parts[1];
48
+
49
+ if (isNaN(ownerId)) {
50
+ console.error(chalk.red('Error: Owner ID must be a number'));
51
+ process.exit(1);
52
+ }
53
+
54
+ // Determine target directory
55
+ const targetDir = directory || repoName;
56
+ const targetPath = path.resolve(process.cwd(), targetDir);
57
+
58
+ // Check if directory already exists
59
+ if (await pathExists(targetPath)) {
60
+ console.error(chalk.red(`Error: Directory '${targetDir}' already exists`));
61
+ process.exit(1);
62
+ }
63
+
64
+ console.log(chalk.cyan(`Cloning ${ownerId}/${repoName} into '${targetDir}'...\n`));
65
+
66
+ // Fetch repository metadata
67
+ const spinner = ora('Fetching repository...').start();
68
+ const repository = await repoService.getRepository(ownerId, repoName);
69
+ spinner.succeed('Repository fetched');
70
+
71
+ // Create directory structure
72
+ await ensureDir(targetPath);
73
+ const gentPath = path.join(targetPath, GENT_DIR);
74
+ await ensureDir(gentPath);
75
+ await ensureDir(path.join(gentPath, 'objects'));
76
+ await ensureDir(path.join(gentPath, 'refs', 'heads'));
77
+ await ensureDir(path.join(gentPath, 'refs', 'tags'));
78
+
79
+ // Create configuration
80
+ const config = {
81
+ user: {
82
+ name: user.first_name && user.last_name ? `${user.first_name} ${user.last_name}` : '',
83
+ email: user.email
84
+ },
85
+ repository: {
86
+ name: repository.name,
87
+ description: repository.description,
88
+ created: new Date().toISOString()
89
+ }
90
+ };
91
+ await writeJSON(path.join(gentPath, CONFIG_FILE), config);
92
+
93
+ // Create initial files
94
+ await writeJSON(path.join(gentPath, STAGING_FILE), { files: [] });
95
+ await writeJSON(path.join(gentPath, COMMITS_FILE), {
96
+ commits: [],
97
+ branches: { [repository.default_branch]: null },
98
+ currentBranch: repository.default_branch
99
+ });
100
+
101
+ // Create HEAD file
102
+ await fs.writeFile(
103
+ path.join(gentPath, 'HEAD'),
104
+ `ref: refs/heads/${repository.default_branch}\n`
105
+ );
106
+
107
+ // Add remote
108
+ await addRemote('origin', ownerId, repoName, targetPath);
109
+
110
+ // Fetch commits, branches, and files
111
+ try {
112
+ await syncCommitsFromCloud(ownerId, repoName, targetPath);
113
+ } catch (error) {
114
+ // Ignore if repository has no commits yet
115
+ if (!error.message.includes('404')) {
116
+ throw error;
117
+ }
118
+ console.log(chalk.yellow('Note: Repository has no commits yet'));
119
+ }
120
+
121
+ console.log(chalk.green(`\n✓ Successfully cloned into '${targetDir}'`));
122
+ console.log(chalk.yellow('\nNext steps:'));
123
+ console.log(chalk.cyan(` cd ${targetDir}`));
124
+ console.log(chalk.cyan(' gent status'), chalk.gray('- Check repository status'));
125
+
126
+ } catch (error) {
127
+ console.error(chalk.red('Failed to clone repository'));
128
+ console.error(chalk.red('Error:'), error.message);
129
+ process.exit(1);
130
+ }
131
+ }
132
+
133
+ module.exports = clone;
@@ -4,13 +4,15 @@
4
4
  */
5
5
 
6
6
  const path = require('path');
7
+ const fs = require('fs').promises;
7
8
  const chalk = require('chalk');
8
9
  const inquirer = require('inquirer');
9
10
  const ora = require('ora');
10
- const { getGentPath, readJSON, writeJSON } = require('../utils/fileSystem');
11
+ const { getGentPath, readJSON, writeJSON, saveBlob, getBlob } = require('../utils/fileSystem');
11
12
  const authStorage = require('../utils/auth-storage');
12
13
  const { STAGING_FILE, COMMITS_FILE, CONFIG_FILE } = require('../utils/constants');
13
14
  const { generateCommitHash, getFileHash } = require('../utils/helpers');
15
+ const { computeDiff } = require('../utils/diff');
14
16
 
15
17
  /**
16
18
  * Create a new commit
@@ -80,31 +82,66 @@ async function commit(options) {
80
82
 
81
83
  // Create commit object
82
84
  const commit = {
83
- hash: generateCommitHash(),
85
+ sha: generateCommitHash(),
84
86
  message: message,
85
87
  author: {
86
88
  name: authorName,
87
89
  email: authorEmail
88
90
  },
89
91
  timestamp: new Date().toISOString(),
90
- parent: repository.branches[repository.currentBranch] || null,
92
+ parent: repository.branches[repository.currentBranch] ? [repository.branches[repository.currentBranch]] : [],
91
93
  files: []
92
94
  };
93
95
 
94
- // Hash staged files
96
+ // Create a map of parent files for quick lookup
97
+ const parentFilesMap = new Map();
98
+ if (commit.parent && commit.parent.length > 0) {
99
+ const parentSha = commit.parent[0];
100
+ const parentCommit = repository.commits.find(c => c.sha === parentSha);
101
+ if (parentCommit) {
102
+ parentCommit.files.forEach(f => parentFilesMap.set(f.path, f.hash));
103
+ }
104
+ }
105
+
106
+ // Hash staged files and compute diffs
95
107
  for (const file of stagedFiles) {
96
108
  const filePath = path.join(cwd, file);
109
+ let content;
110
+
111
+ try {
112
+ content = await fs.readFile(filePath, 'utf-8');
113
+ } catch (err) {
114
+ // If file is deleted or unreadable, we handle it as empty content or handle deletion if we supported it
115
+ // For now assuming staged files exist
116
+ content = '';
117
+ }
118
+
97
119
  const hash = await getFileHash(filePath);
120
+
121
+ // Save the blob for future diffs
122
+ await saveBlob(content, hash);
123
+
124
+ // Get previous content
125
+ let oldContent = '';
126
+ if (parentFilesMap.has(file)) {
127
+ const oldHash = parentFilesMap.get(file);
128
+ oldContent = await getBlob(oldHash);
129
+ }
130
+
131
+ // Compute Myers diff
132
+ const changes = computeDiff(oldContent, content);
133
+
98
134
  commit.files.push({
99
135
  path: file,
100
- hash: hash
136
+ hash: hash,
137
+ diff: changes
101
138
  });
102
139
  }
103
140
 
104
141
  // Add commit to repository
105
142
  repository.commits = repository.commits || [];
106
143
  repository.commits.push(commit);
107
- repository.branches[repository.currentBranch] = commit.hash;
144
+ repository.branches[repository.currentBranch] = commit.sha;
108
145
 
109
146
  // Save repository and clear staging
110
147
  await writeJSON(path.join(gentPath, COMMITS_FILE), repository);
@@ -114,11 +151,17 @@ async function commit(options) {
114
151
  spinner.succeed(chalk.green('✓ Changes committed successfully!'));
115
152
 
116
153
  // Display commit info
117
- console.log(chalk.cyan(`\n[${repository.currentBranch} ${commit.hash.substring(0, 7)}] ${message}`));
154
+ console.log(chalk.cyan(`\n[${repository.currentBranch} ${commit.sha.substring(0, 7)}] ${message}`));
118
155
  console.log(chalk.gray(`Author: ${commit.author.name} <${commit.author.email}>`));
119
156
  console.log(chalk.gray(`Date: ${new Date(commit.timestamp).toLocaleString()}`));
120
157
  console.log(chalk.gray(`\n${commit.files.length} file(s) changed`));
121
158
 
159
+ // Handle --push option
160
+ if (options.push) {
161
+ const push = require('./push');
162
+ await push('origin', repository.currentBranch, {});
163
+ }
164
+
122
165
  } catch (error) {
123
166
  if (error.code === 'ENOENT' && error.message.includes('.gent')) {
124
167
  console.error(chalk.red('Error: Not a gent repository'));
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Create Command - Create a new cloud repository
3
+ * Creates a repository on the cloud and optionally initializes locally
4
+ */
5
+
6
+ const chalk = require('chalk');
7
+ const inquirer = require('inquirer');
8
+ const ora = require('ora');
9
+ const path = require('path');
10
+ const repoService = require('../services/repo-service');
11
+ const authStorage = require('../utils/auth-storage');
12
+ const { ensureDir, writeJSON } = require('../utils/fileSystem');
13
+ const { GENT_DIR } = require('../utils/constants');
14
+ const { addRemote } = require('../utils/cloud-sync');
15
+
16
+ /**
17
+ * Create a new repository on the cloud
18
+ * @param {string} repoName - Repository name
19
+ * @param {Object} options - Command options
20
+ */
21
+ async function create(repoName, options) {
22
+ try {
23
+ // Check authentication
24
+ const user = await authStorage.getUser();
25
+ if (!user) {
26
+ console.error(chalk.red('Error: You must be logged in to create a repository'));
27
+ console.log(chalk.yellow('Run'), chalk.cyan('gent login'), chalk.yellow('to authenticate'));
28
+ process.exit(1);
29
+ }
30
+
31
+ // Validate repository name
32
+ if (!repoName) {
33
+ console.error(chalk.red('Error: Repository name is required'));
34
+ console.log(chalk.yellow('Usage:'), chalk.cyan('gent create <repo-name>'));
35
+ process.exit(1);
36
+ }
37
+
38
+ // Prompt for additional details if not provided
39
+ let description = options.description || '';
40
+ let isPrivate = options.private || false;
41
+
42
+ if (!options.yes) {
43
+ const answers = await inquirer.prompt([
44
+ {
45
+ type: 'input',
46
+ name: 'description',
47
+ message: 'Repository description (optional):',
48
+ default: description
49
+ },
50
+ {
51
+ type: 'confirm',
52
+ name: 'isPrivate',
53
+ message: 'Make repository private?',
54
+ default: isPrivate
55
+ },
56
+ {
57
+ type: 'confirm',
58
+ name: 'initLocal',
59
+ message: 'Initialize local repository and link remote?',
60
+ default: true
61
+ }
62
+ ]);
63
+
64
+ description = answers.description;
65
+ isPrivate = answers.isPrivate;
66
+ options.initLocal = answers.initLocal;
67
+ }
68
+
69
+ // Create repository
70
+ const spinner = ora('Creating repository...').start();
71
+
72
+ const repository = await repoService.createRepository(
73
+ repoName,
74
+ description,
75
+ isPrivate,
76
+ 'main'
77
+ );
78
+
79
+ spinner.succeed(chalk.green(`Repository created: ${repository.name}`));
80
+
81
+ console.log(chalk.cyan('\nRepository Details:'));
82
+ console.log(chalk.gray(' Name:'), repository.name);
83
+ console.log(chalk.gray(' Owner:'), repository.owner_email);
84
+ console.log(chalk.gray(' Private:'), repository.is_private ? 'Yes' : 'No');
85
+ console.log(chalk.gray(' Description:'), repository.description || '(none)');
86
+ console.log(chalk.gray(' Created:'), new Date(repository.created_at).toLocaleString());
87
+
88
+ // Initialize local repository if requested
89
+ if (options.initLocal) {
90
+ const cwd = process.cwd();
91
+ const gentPath = path.join(cwd, GENT_DIR);
92
+
93
+ // Create .gent directory
94
+ await ensureDir(gentPath);
95
+ await ensureDir(path.join(gentPath, 'objects'));
96
+ await ensureDir(path.join(gentPath, 'refs', 'heads'));
97
+
98
+ // Add remote
99
+ await addRemote('origin', repository.owner_id, repository.name, cwd);
100
+
101
+ console.log(chalk.green('\n✓ Local repository initialized and remote added'));
102
+ console.log(chalk.yellow('\nNext steps:'));
103
+ console.log(chalk.cyan(' gent add <files>'), chalk.gray('- Add files to staging'));
104
+ console.log(chalk.cyan(' gent commit -m "message"'), chalk.gray('- Commit changes'));
105
+ console.log(chalk.cyan(' gent push'), chalk.gray('- Push to cloud'));
106
+ } else {
107
+ console.log(chalk.yellow('\nTo clone this repository:'));
108
+ console.log(chalk.cyan(` gent clone ${repository.owner_id}/${repository.name}`));
109
+ }
110
+
111
+ } catch (error) {
112
+ console.error(chalk.red('Failed to create repository'));
113
+ console.error(chalk.red('Error:'), error.message);
114
+ process.exit(1);
115
+ }
116
+ }
117
+
118
+ module.exports = create;
@@ -28,9 +28,10 @@ async function init(options) {
28
28
  // Get authenticated user profile if available
29
29
  let defaultName = '';
30
30
  let defaultEmail = '';
31
+ let user = null;
31
32
 
32
33
  try {
33
- const user = await authStorage.getUser();
34
+ user = await authStorage.getUser();
34
35
  if (user) {
35
36
  if (user.first_name || user.last_name) {
36
37
  defaultName = [user.first_name, user.last_name].filter(Boolean).join(' ');
@@ -62,12 +63,8 @@ async function init(options) {
62
63
  await ensureDir(path.join(gentPath, 'refs', 'tags'));
63
64
 
64
65
  // Create/Update configuration
65
- // Only write config if it doesn't exist OR if we have valid user info to update
66
66
  const configPath = path.join(gentPath, CONFIG_FILE);
67
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
68
  if (!isReinit || !(await pathExists(configPath))) {
72
69
  await writeJSON(configPath, config);
73
70
  }
@@ -109,6 +106,37 @@ node_modules/
109
106
  console.log(chalk.gray(`Initialized empty Gent repository in ${gentPath}`));
110
107
  }
111
108
 
109
+ // Handle --cloud option
110
+ if (options.cloud) {
111
+ if (!user) {
112
+ console.log(chalk.yellow('\nWarning: Skipping cloud repository creation (not logged in)'));
113
+ console.log(chalk.gray('Run "gent login" then "gent create <name> --init-local"'));
114
+ } else {
115
+ try {
116
+ const repoService = require('../services/repo-service');
117
+ const { addRemote } = require('../utils/cloud-sync');
118
+ const ora = require('ora');
119
+
120
+ const spinner = ora('Creating cloud repository...').start();
121
+ const repoName = path.basename(cwd);
122
+
123
+ const repository = await repoService.createRepository(
124
+ repoName,
125
+ options.description || 'A gent repository',
126
+ options.private || false,
127
+ 'main'
128
+ );
129
+
130
+ await addRemote('origin', repository.owner_id, repository.name, cwd);
131
+ spinner.succeed(chalk.green(`Created cloud repository: ${repository.owner_id}/${repository.name}`));
132
+ console.log(chalk.gray(`Remote 'origin' added`));
133
+ } catch (error) {
134
+ console.log(chalk.red(`\nFailed to create cloud repository: ${error.message}`));
135
+ console.log(chalk.gray('You can create it later with "gent create <name>"'));
136
+ }
137
+ }
138
+ }
139
+
112
140
  } catch (error) {
113
141
  console.error(chalk.red('Failed to initialize repository'));
114
142
  console.error(chalk.red('Error:'), error.message);
@@ -0,0 +1,67 @@
1
+ /**
2
+ * List Command - List all cloud repositories
3
+ * Displays all repositories owned by the authenticated user
4
+ */
5
+
6
+ const chalk = require('chalk');
7
+ const ora = require('ora');
8
+ const repoService = require('../services/repo-service');
9
+ const authStorage = require('../utils/auth-storage');
10
+
11
+ /**
12
+ * Format date for display
13
+ * @param {string} dateString - ISO date string
14
+ * @returns {string} Formatted date
15
+ */
16
+ function formatDate(dateString) {
17
+ const date = new Date(dateString);
18
+ return date.toLocaleDateString();
19
+ }
20
+
21
+ /**
22
+ * List all repositories owned by the authenticated user
23
+ * @param {Object} options - Command options
24
+ */
25
+ async function list(options) {
26
+ try {
27
+ // Check authentication
28
+ const user = await authStorage.getUser();
29
+ if (!user) {
30
+ console.error(chalk.red('Error: You must be logged in to list repositories'));
31
+ console.log(chalk.yellow('Run'), chalk.cyan('gent login'), chalk.yellow('to authenticate'));
32
+ process.exit(1);
33
+ }
34
+
35
+ // Fetch repositories
36
+ const spinner = ora('Fetching repositories...').start();
37
+ const repositories = await repoService.listRepositories();
38
+ spinner.stop();
39
+
40
+ if (repositories.length === 0) {
41
+ console.log(chalk.yellow('No repositories found'));
42
+ console.log(chalk.gray('Create a new repository with:'), chalk.cyan('gent create <repo-name>'));
43
+ return;
44
+ }
45
+
46
+ console.log(chalk.cyan(`\nYour Repositories (${repositories.length}):\n`));
47
+
48
+ repositories.forEach(repo => {
49
+ const privacy = repo.is_private ? chalk.red('🔒 Private') : chalk.green('🌐 Public');
50
+ console.log(chalk.bold(repo.name), privacy);
51
+ if (repo.description) {
52
+ console.log(chalk.gray(` ${repo.description}`));
53
+ }
54
+ console.log(chalk.gray(` Owner: ${repo.owner_email}`));
55
+ console.log(chalk.gray(` Created: ${formatDate(repo.created_at)}`));
56
+ console.log(chalk.gray(` Default branch: ${repo.default_branch}`));
57
+ console.log(chalk.gray(` Clone: gent clone ${repo.owner_id}/${repo.name}\n`));
58
+ });
59
+
60
+ } catch (error) {
61
+ console.error(chalk.red('Failed to list repositories'));
62
+ console.error(chalk.red('Error:'), error.message);
63
+ process.exit(1);
64
+ }
65
+ }
66
+
67
+ module.exports = list;
@@ -55,10 +55,10 @@ function displayDetailedLog(commits, currentCommitHash, currentBranch) {
55
55
  console.log(chalk.bold.cyan(`\nCommit History (${currentBranch} branch):\n`));
56
56
 
57
57
  commits.forEach((commit, index) => {
58
- const isHead = commit.hash === currentCommitHash;
58
+ const isHead = commit.sha === currentCommitHash;
59
59
  const headLabel = isHead ? chalk.yellow.bold(' (HEAD)') : '';
60
60
 
61
- console.log(chalk.yellow(`commit ${commit.hash}`) + headLabel);
61
+ console.log(chalk.yellow(`commit ${commit.sha}`) + headLabel);
62
62
  console.log(chalk.white(`Author: ${commit.author.name} <${commit.author.email}>`));
63
63
  console.log(chalk.white(`Date: ${new Date(commit.timestamp).toLocaleString()}`));
64
64
  console.log(chalk.gray(` (${formatDistanceToNow(new Date(commit.timestamp), { addSuffix: true })})`));
@@ -79,9 +79,9 @@ function displayDetailedLog(commits, currentCommitHash, currentBranch) {
79
79
  */
80
80
  function displayOnelineLog(commits, currentCommitHash) {
81
81
  commits.forEach(commit => {
82
- const isHead = commit.hash === currentCommitHash;
82
+ const isHead = commit.sha === currentCommitHash;
83
83
  const headLabel = isHead ? chalk.yellow(' (HEAD)') : '';
84
- const shortHash = chalk.yellow(commit.hash.substring(0, 7));
84
+ const shortHash = chalk.yellow(commit.sha.substring(0, 7));
85
85
  const message = chalk.white(commit.message);
86
86
  const timeAgo = chalk.gray(`(${formatDistanceToNow(new Date(commit.timestamp), { addSuffix: true })})`);
87
87