gent-cli 1.7.0 → 1.9.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.7.0",
3
+ "version": "1.9.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": {
@@ -82,21 +82,22 @@ async function commit(options) {
82
82
 
83
83
  // Create commit object
84
84
  const commit = {
85
- hash: generateCommitHash(),
85
+ sha: generateCommitHash(),
86
86
  message: message,
87
87
  author: {
88
88
  name: authorName,
89
89
  email: authorEmail
90
90
  },
91
91
  timestamp: new Date().toISOString(),
92
- parent: repository.branches[repository.currentBranch] || null,
92
+ parent: repository.branches[repository.currentBranch] ? [repository.branches[repository.currentBranch]] : [],
93
93
  files: []
94
94
  };
95
95
 
96
96
  // Create a map of parent files for quick lookup
97
97
  const parentFilesMap = new Map();
98
- if (commit.parent) {
99
- const parentCommit = repository.commits.find(c => c.hash === commit.parent);
98
+ if (commit.parent && commit.parent.length > 0) {
99
+ const parentSha = commit.parent[0];
100
+ const parentCommit = repository.commits.find(c => c.sha === parentSha);
100
101
  if (parentCommit) {
101
102
  parentCommit.files.forEach(f => parentFilesMap.set(f.path, f.hash));
102
103
  }
@@ -140,7 +141,7 @@ async function commit(options) {
140
141
  // Add commit to repository
141
142
  repository.commits = repository.commits || [];
142
143
  repository.commits.push(commit);
143
- repository.branches[repository.currentBranch] = commit.hash;
144
+ repository.branches[repository.currentBranch] = commit.sha;
144
145
 
145
146
  // Save repository and clear staging
146
147
  await writeJSON(path.join(gentPath, COMMITS_FILE), repository);
@@ -150,7 +151,7 @@ async function commit(options) {
150
151
  spinner.succeed(chalk.green('✓ Changes committed successfully!'));
151
152
 
152
153
  // Display commit info
153
- 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}`));
154
155
  console.log(chalk.gray(`Author: ${commit.author.name} <${commit.author.email}>`));
155
156
  console.log(chalk.gray(`Date: ${new Date(commit.timestamp).toLocaleString()}`));
156
157
  console.log(chalk.gray(`\n${commit.files.length} file(s) changed`));
@@ -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
 
@@ -92,7 +92,7 @@ async function pull(remoteName, branchName, options) {
92
92
  },
93
93
  timestamp: cloudCommit.committed_at,
94
94
  parent: cloudCommit.parent_shas || [],
95
- files: {} // Files are stored in objects directory
95
+ files: cloudCommit.files || []
96
96
  });
97
97
  }
98
98
  }
@@ -73,11 +73,12 @@ async function push(remoteName, branchName, options) {
73
73
  let currentSha = branchCommitSha;
74
74
 
75
75
  while (currentSha) {
76
- const commit = commits.find(c => c.sha === currentSha);
76
+ const commit = commits.find(c => (c.sha || c.hash) === currentSha);
77
77
  if (!commit) break;
78
78
 
79
79
  commitsToPush.unshift(commit); // Add to beginning to maintain order
80
- currentSha = commit.parent ? commit.parent[0] : null;
80
+ const parents = Array.isArray(commit.parent) ? commit.parent : (commit.parent ? [commit.parent] : []);
81
+ currentSha = parents.length > 0 ? parents[0] : null;
81
82
  }
82
83
 
83
84
  if (commitsToPush.length === 0) {
@@ -58,12 +58,12 @@ async function listRepositories() {
58
58
  /**
59
59
  * Get repository details
60
60
  * @param {number} ownerId - Owner user ID
61
- * @param {string} repoName - Repository name
61
+ * @param {string} projectName - Project name
62
62
  * @returns {Promise<Object>} Repository data
63
63
  */
64
- async function getRepository(ownerId, repoName) {
64
+ async function getRepository(ownerId, projectName) {
65
65
  try {
66
- const url = buildUrl(API_ENDPOINTS.REPOS_GET, { owner_id: ownerId, repo_name: repoName });
66
+ const url = buildUrl(API_ENDPOINTS.REPOS_GET, { owner_id: ownerId, project_name: projectName });
67
67
  const response = await apiClient.get(url);
68
68
  return response;
69
69
  } catch (error) {
@@ -74,12 +74,12 @@ async function getRepository(ownerId, repoName) {
74
74
  /**
75
75
  * Delete a repository
76
76
  * @param {number} ownerId - Owner user ID
77
- * @param {string} repoName - Repository name
77
+ * @param {string} projectName - Project name
78
78
  * @returns {Promise<Object>} Delete response
79
79
  */
80
- async function deleteRepository(ownerId, repoName) {
80
+ async function deleteRepository(ownerId, projectName) {
81
81
  try {
82
- const url = buildUrl(API_ENDPOINTS.REPOS_DELETE, { owner_id: ownerId, repo_name: repoName });
82
+ const url = buildUrl(API_ENDPOINTS.REPOS_DELETE, { owner_id: ownerId, project_name: projectName });
83
83
  const response = await apiClient.delete(url);
84
84
  return response;
85
85
  } catch (error) {
@@ -90,14 +90,14 @@ async function deleteRepository(ownerId, repoName) {
90
90
  /**
91
91
  * Create a blob (file content) in the repository
92
92
  * @param {number} ownerId - Owner user ID
93
- * @param {string} repoName - Repository name
93
+ * @param {string} projectName - Project name
94
94
  * @param {string} content - File content
95
95
  * @param {string} encoding - Encoding type (utf-8 or base64)
96
96
  * @returns {Promise<Object>} Created blob data
97
97
  */
98
- async function createBlob(ownerId, repoName, content, encoding = 'utf-8') {
98
+ async function createBlob(ownerId, projectName, content, encoding = 'utf-8') {
99
99
  try {
100
- const url = buildUrl(API_ENDPOINTS.BLOB_CREATE, { owner_id: ownerId, repo_name: repoName });
100
+ const url = buildUrl(API_ENDPOINTS.BLOB_CREATE, { owner_id: ownerId, project_name: projectName });
101
101
  const response = await apiClient.post(url, {
102
102
  content,
103
103
  encoding
@@ -111,13 +111,13 @@ async function createBlob(ownerId, repoName, content, encoding = 'utf-8') {
111
111
  /**
112
112
  * Get a blob by SHA
113
113
  * @param {number} ownerId - Owner user ID
114
- * @param {string} repoName - Repository name
114
+ * @param {string} projectName - Project name
115
115
  * @param {string} sha - Blob SHA
116
116
  * @returns {Promise<Object>} Blob data
117
117
  */
118
- async function getBlob(ownerId, repoName, sha) {
118
+ async function getBlob(ownerId, projectName, sha) {
119
119
  try {
120
- const url = buildUrl(API_ENDPOINTS.BLOB_GET, { owner_id: ownerId, repo_name: repoName, sha });
120
+ const url = buildUrl(API_ENDPOINTS.BLOB_GET, { owner_id: ownerId, project_name: projectName, sha });
121
121
  const response = await apiClient.get(url);
122
122
  return response;
123
123
  } catch (error) {
@@ -128,13 +128,13 @@ async function getBlob(ownerId, repoName, sha) {
128
128
  /**
129
129
  * Create a tree (directory structure) in the repository
130
130
  * @param {number} ownerId - Owner user ID
131
- * @param {string} repoName - Repository name
131
+ * @param {string} projectName - Project name
132
132
  * @param {Array} entries - Tree entries
133
133
  * @returns {Promise<Object>} Created tree data
134
134
  */
135
- async function createTree(ownerId, repoName, entries) {
135
+ async function createTree(ownerId, projectName, entries) {
136
136
  try {
137
- const url = buildUrl(API_ENDPOINTS.TREE_CREATE, { owner_id: ownerId, repo_name: repoName });
137
+ const url = buildUrl(API_ENDPOINTS.TREE_CREATE, { owner_id: ownerId, project_name: projectName });
138
138
  const response = await apiClient.post(url, {
139
139
  entries
140
140
  });
@@ -147,13 +147,13 @@ async function createTree(ownerId, repoName, entries) {
147
147
  /**
148
148
  * Get a tree by SHA
149
149
  * @param {number} ownerId - Owner user ID
150
- * @param {string} repoName - Repository name
150
+ * @param {string} projectName - Project name
151
151
  * @param {string} sha - Tree SHA
152
152
  * @returns {Promise<Object>} Tree data
153
153
  */
154
- async function getTree(ownerId, repoName, sha) {
154
+ async function getTree(ownerId, projectName, sha) {
155
155
  try {
156
- const url = buildUrl(API_ENDPOINTS.TREE_GET, { owner_id: ownerId, repo_name: repoName, sha });
156
+ const url = buildUrl(API_ENDPOINTS.TREE_GET, { owner_id: ownerId, project_name: projectName, sha });
157
157
  const response = await apiClient.get(url);
158
158
  return response;
159
159
  } catch (error) {
@@ -164,13 +164,13 @@ async function getTree(ownerId, repoName, sha) {
164
164
  /**
165
165
  * Create a commit in the repository
166
166
  * @param {number} ownerId - Owner user ID
167
- * @param {string} repoName - Repository name
167
+ * @param {string} projectName - Project name
168
168
  * @param {Object} commitData - Commit data (message, tree_sha, parent_shas, author_name, author_email, branch)
169
169
  * @returns {Promise<Object>} Created commit data
170
170
  */
171
- async function createCommit(ownerId, repoName, commitData) {
171
+ async function createCommit(ownerId, projectName, commitData) {
172
172
  try {
173
- const url = buildUrl(API_ENDPOINTS.COMMITS_CREATE, { owner_id: ownerId, repo_name: repoName });
173
+ const url = buildUrl(API_ENDPOINTS.COMMITS_CREATE, { owner_id: ownerId, project_name: projectName });
174
174
  const response = await apiClient.post(url, commitData);
175
175
  return response;
176
176
  } catch (error) {
@@ -181,12 +181,12 @@ async function createCommit(ownerId, repoName, commitData) {
181
181
  /**
182
182
  * List all commits in a repository
183
183
  * @param {number} ownerId - Owner user ID
184
- * @param {string} repoName - Repository name
184
+ * @param {string} projectName - Project name
185
185
  * @returns {Promise<Array>} List of commits
186
186
  */
187
- async function listCommits(ownerId, repoName) {
187
+ async function listCommits(ownerId, projectName) {
188
188
  try {
189
- const url = buildUrl(API_ENDPOINTS.COMMITS_LIST, { owner_id: ownerId, repo_name: repoName });
189
+ const url = buildUrl(API_ENDPOINTS.COMMITS_LIST, { owner_id: ownerId, project_name: projectName });
190
190
  const response = await apiClient.get(url);
191
191
  return response;
192
192
  } catch (error) {
@@ -197,13 +197,13 @@ async function listCommits(ownerId, repoName) {
197
197
  /**
198
198
  * Get a commit by SHA
199
199
  * @param {number} ownerId - Owner user ID
200
- * @param {string} repoName - Repository name
200
+ * @param {string} projectName - Project name
201
201
  * @param {string} sha - Commit SHA
202
202
  * @returns {Promise<Object>} Commit data
203
203
  */
204
- async function getCommit(ownerId, repoName, sha) {
204
+ async function getCommit(ownerId, projectName, sha) {
205
205
  try {
206
- const url = buildUrl(API_ENDPOINTS.COMMITS_GET, { owner_id: ownerId, repo_name: repoName, sha });
206
+ const url = buildUrl(API_ENDPOINTS.COMMITS_GET, { owner_id: ownerId, project_name: projectName, sha });
207
207
  const response = await apiClient.get(url);
208
208
  return response;
209
209
  } catch (error) {
@@ -214,14 +214,14 @@ async function getCommit(ownerId, repoName, sha) {
214
214
  /**
215
215
  * Create a branch in the repository
216
216
  * @param {number} ownerId - Owner user ID
217
- * @param {string} repoName - Repository name
217
+ * @param {string} projectName - Project name
218
218
  * @param {string} branchName - Branch name
219
219
  * @param {string} commitSha - Commit SHA to point the branch to
220
220
  * @returns {Promise<Object>} Created branch data
221
221
  */
222
- async function createBranch(ownerId, repoName, branchName, commitSha) {
222
+ async function createBranch(ownerId, projectName, branchName, commitSha) {
223
223
  try {
224
- const url = buildUrl(API_ENDPOINTS.BRANCHES_CREATE, { owner_id: ownerId, repo_name: repoName });
224
+ const url = buildUrl(API_ENDPOINTS.BRANCHES_CREATE, { owner_id: ownerId, project_name: projectName });
225
225
  const response = await apiClient.post(url, {
226
226
  name: branchName,
227
227
  commit_sha: commitSha
@@ -235,12 +235,12 @@ async function createBranch(ownerId, repoName, branchName, commitSha) {
235
235
  /**
236
236
  * List all branches in a repository
237
237
  * @param {number} ownerId - Owner user ID
238
- * @param {string} repoName - Repository name
238
+ * @param {string} projectName - Project name
239
239
  * @returns {Promise<Array>} List of branches
240
240
  */
241
- async function listBranches(ownerId, repoName) {
241
+ async function listBranches(ownerId, projectName) {
242
242
  try {
243
- const url = buildUrl(API_ENDPOINTS.BRANCHES_LIST, { owner_id: ownerId, repo_name: repoName });
243
+ const url = buildUrl(API_ENDPOINTS.BRANCHES_LIST, { owner_id: ownerId, project_name: projectName });
244
244
  const response = await apiClient.get(url);
245
245
  return response;
246
246
  } catch (error) {
@@ -251,13 +251,13 @@ async function listBranches(ownerId, repoName) {
251
251
  /**
252
252
  * Get a branch by name
253
253
  * @param {number} ownerId - Owner user ID
254
- * @param {string} repoName - Repository name
254
+ * @param {string} projectName - Project name
255
255
  * @param {string} branchName - Branch name
256
256
  * @returns {Promise<Object>} Branch data
257
257
  */
258
- async function getBranch(ownerId, repoName, branchName) {
258
+ async function getBranch(ownerId, projectName, branchName) {
259
259
  try {
260
- const url = buildUrl(API_ENDPOINTS.BRANCHES_GET, { owner_id: ownerId, repo_name: repoName, branch_name: branchName });
260
+ const url = buildUrl(API_ENDPOINTS.BRANCHES_GET, { owner_id: ownerId, project_name: projectName, branch_name: branchName });
261
261
  const response = await apiClient.get(url);
262
262
  return response;
263
263
  } catch (error) {
@@ -125,7 +125,7 @@ async function uploadCommit(commit, treeSha, ownerId, repoName, branchName) {
125
125
  const commitData = {
126
126
  message: commit.message,
127
127
  tree_sha: treeSha,
128
- parent_shas: commit.parent || [],
128
+ parent_shas: Array.isArray(commit.parent) ? commit.parent : (commit.parent ? [commit.parent] : []),
129
129
  author_name: commit.author.name,
130
130
  author_email: commit.author.email,
131
131
  branch: branchName
@@ -161,11 +161,12 @@ async function syncCommitsToCloud(commits, ownerId, repoName, branchName, cwd) {
161
161
 
162
162
  // Read files from commit
163
163
  const files = [];
164
- for (const [filePath, fileSha] of Object.entries(commit.files || {})) {
165
- const objectPath = path.join(cwd, GENT_DIR, OBJECTS_DIR, fileSha);
164
+ const commitFiles = Array.isArray(commit.files) ? commit.files : [];
165
+ for (const file of commitFiles) {
166
+ const objectPath = path.join(cwd, GENT_DIR, OBJECTS_DIR, file.hash);
166
167
  if (await pathExists(objectPath)) {
167
168
  const content = await fs.readFile(objectPath, 'utf-8');
168
- files.push({ path: filePath, content });
169
+ files.push({ path: file.path, content });
169
170
  }
170
171
  }
171
172
 
@@ -212,6 +213,12 @@ async function syncCommitsFromCloud(ownerId, repoName, cwd) {
212
213
  // Download tree
213
214
  const tree = await repoService.getTree(ownerId, repoName, commit.tree_sha);
214
215
 
216
+ // Store entries for local metadata
217
+ commit.files = tree.entries.map(entry => ({
218
+ path: entry.path,
219
+ hash: entry.sha
220
+ }));
221
+
215
222
  // Download blobs from tree entries
216
223
  const blobShas = tree.entries.map(entry => entry.sha);
217
224
  const blobMap = await downloadBlobs(blobShas, ownerId, repoName);
@@ -27,26 +27,26 @@ module.exports = {
27
27
  // Repository endpoints
28
28
  REPOS_LIST: '/api/repos/',
29
29
  REPOS_CREATE: '/api/repos/create/',
30
- REPOS_GET: '/api/repos/{owner_id}/{repo_name}/',
31
- REPOS_DELETE: '/api/repos/{owner_id}/{repo_name}/delete/',
30
+ REPOS_GET: '/api/repos/{owner_id}/{project_name}/',
31
+ REPOS_DELETE: '/api/repos/{owner_id}/{project_name}/delete/',
32
32
 
33
33
  // Blob endpoints
34
- BLOB_GET: '/api/repos/{owner_id}/{repo_name}/blob/{sha}/',
35
- BLOB_CREATE: '/api/repos/{owner_id}/{repo_name}/blob/create/',
34
+ BLOB_GET: '/api/repos/{owner_id}/{project_name}/blob/{sha}/',
35
+ BLOB_CREATE: '/api/repos/{owner_id}/{project_name}/blob/create/',
36
36
 
37
37
  // Tree endpoints
38
- TREE_GET: '/api/repos/{owner_id}/{repo_name}/tree/{sha}/',
39
- TREE_CREATE: '/api/repos/{owner_id}/{repo_name}/tree/create/',
38
+ TREE_GET: '/api/repos/{owner_id}/{project_name}/tree/{sha}/',
39
+ TREE_CREATE: '/api/repos/{owner_id}/{project_name}/tree/create/',
40
40
 
41
41
  // Commit endpoints
42
- COMMITS_LIST: '/api/repos/{owner_id}/{repo_name}/commits/',
43
- COMMITS_GET: '/api/repos/{owner_id}/{repo_name}/commits/{sha}/',
44
- COMMITS_CREATE: '/api/repos/{owner_id}/{repo_name}/commits/create/',
42
+ COMMITS_LIST: '/api/repos/{owner_id}/{project_name}/commits/',
43
+ COMMITS_GET: '/api/repos/{owner_id}/{project_name}/commits/{sha}/',
44
+ COMMITS_CREATE: '/api/repos/{owner_id}/{project_name}/commits/create/',
45
45
 
46
46
  // Branch endpoints
47
- BRANCHES_LIST: '/api/repos/{owner_id}/{repo_name}/branches/',
48
- BRANCHES_GET: '/api/repos/{owner_id}/{repo_name}/branches/{branch_name}/',
49
- BRANCHES_CREATE: '/api/repos/{owner_id}/{repo_name}/branches/create/'
47
+ BRANCHES_LIST: '/api/repos/{owner_id}/{project_name}/branches/',
48
+ BRANCHES_GET: '/api/repos/{owner_id}/{project_name}/branches/{branch_name}/',
49
+ BRANCHES_CREATE: '/api/repos/{owner_id}/{project_name}/branches/create/'
50
50
  },
51
51
 
52
52
  // Default ignore patterns
@@ -170,7 +170,7 @@ async function getTrackedFiles(gentPath, commitHash) {
170
170
  }
171
171
 
172
172
  const repository = await readJSON(path.join(gentPath, 'commits.json'));
173
- const commit = repository.commits.find(c => c.hash === commitHash);
173
+ const commit = repository.commits.find(c => c.sha === commitHash);
174
174
 
175
175
  return commit ? commit.files : [];
176
176
  }