gent-cli 2.0.0 → 5.0.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.
@@ -1,284 +0,0 @@
1
- /**
2
- * Repository Service - Handles all cloud repository operations
3
- * Provides methods for creating, managing, and syncing repositories with the cloud
4
- */
5
-
6
- const apiClient = require('../utils/api-client');
7
- const { API_ENDPOINTS } = require('../utils/constants');
8
-
9
- /**
10
- * Build URL with path parameters
11
- * @param {string} template - URL template with placeholders
12
- * @param {Object} params - Parameters to replace
13
- * @returns {string} Built URL
14
- */
15
- function buildUrl(template, params = {}) {
16
- let url = template;
17
- Object.keys(params).forEach(key => {
18
- url = url.replace(`{${key}}`, params[key]);
19
- });
20
- return url;
21
- }
22
-
23
- /**
24
- * Create a new repository
25
- * @param {string} name - Repository name
26
- * @param {string} description - Repository description
27
- * @param {boolean} isPrivate - Whether the repository is private
28
- * @param {string} defaultBranch - Default branch name
29
- * @returns {Promise<Object>} Created repository data
30
- */
31
- async function createRepository(name, description = '', isPrivate = false, defaultBranch = 'main') {
32
- try {
33
- const response = await apiClient.post(API_ENDPOINTS.REPOS_CREATE, {
34
- name,
35
- project_name: name, // Add project_name as well for consistency
36
- description,
37
- is_private: isPrivate,
38
- default_branch: defaultBranch
39
- });
40
- return response;
41
- } catch (error) {
42
- throw new Error(`Failed to create repository: ${error.response?.data?.message || error.message}`);
43
- }
44
- }
45
-
46
- /**
47
- * List all repositories owned by the authenticated user
48
- * @returns {Promise<Array>} List of repositories
49
- */
50
- async function listRepositories() {
51
- try {
52
- const response = await apiClient.get(API_ENDPOINTS.REPOS_LIST);
53
- return response;
54
- } catch (error) {
55
- throw new Error(`Failed to list repositories: ${error.response?.data?.message || error.message}`);
56
- }
57
- }
58
-
59
- /**
60
- * Get repository details
61
- * @param {number} ownerId - Owner user ID
62
- * @param {string} projectName - Project name
63
- * @returns {Promise<Object>} Repository data
64
- */
65
- async function getRepository(ownerId, projectName) {
66
- try {
67
- const url = buildUrl(API_ENDPOINTS.REPOS_GET, { owner_id: ownerId, project_name: projectName });
68
- const response = await apiClient.get(url);
69
- return response;
70
- } catch (error) {
71
- throw new Error(`Failed to get repository: ${error.response?.data?.message || error.message}`);
72
- }
73
- }
74
-
75
- /**
76
- * Delete a repository
77
- * @param {number} ownerId - Owner user ID
78
- * @param {string} projectName - Project name
79
- * @returns {Promise<Object>} Delete response
80
- */
81
- async function deleteRepository(ownerId, projectName) {
82
- try {
83
- const url = buildUrl(API_ENDPOINTS.REPOS_DELETE, { owner_id: ownerId, project_name: projectName });
84
- const response = await apiClient.delete(url);
85
- return response;
86
- } catch (error) {
87
- throw new Error(`Failed to delete repository: ${error.response?.data?.message || error.message}`);
88
- }
89
- }
90
-
91
- /**
92
- * Create a blob (file content) in the repository
93
- * @param {number} ownerId - Owner user ID
94
- * @param {string} projectName - Project name
95
- * @param {string} content - File content
96
- * @param {string} encoding - Encoding type (utf-8 or base64)
97
- * @returns {Promise<Object>} Created blob data
98
- */
99
- async function createBlob(ownerId, projectName, content, encoding = 'utf-8') {
100
- try {
101
- const url = buildUrl(API_ENDPOINTS.BLOB_CREATE, { owner_id: ownerId, project_name: projectName });
102
- const response = await apiClient.post(url, {
103
- content,
104
- encoding
105
- });
106
- return response;
107
- } catch (error) {
108
- throw new Error(`Failed to create blob: ${error.response?.data?.message || error.message}`);
109
- }
110
- }
111
-
112
- /**
113
- * Get a blob by SHA
114
- * @param {number} ownerId - Owner user ID
115
- * @param {string} projectName - Project name
116
- * @param {string} sha - Blob SHA
117
- * @returns {Promise<Object>} Blob data
118
- */
119
- async function getBlob(ownerId, projectName, sha) {
120
- try {
121
- const url = buildUrl(API_ENDPOINTS.BLOB_GET, { owner_id: ownerId, project_name: projectName, sha });
122
- const response = await apiClient.get(url);
123
- return response;
124
- } catch (error) {
125
- throw new Error(`Failed to get blob: ${error.response?.data?.message || error.message}`);
126
- }
127
- }
128
-
129
- /**
130
- * Create a tree (directory structure) in the repository
131
- * @param {number} ownerId - Owner user ID
132
- * @param {string} projectName - Project name
133
- * @param {Array} entries - Tree entries
134
- * @returns {Promise<Object>} Created tree data
135
- */
136
- async function createTree(ownerId, projectName, entries) {
137
- try {
138
- const url = buildUrl(API_ENDPOINTS.TREE_CREATE, { owner_id: ownerId, project_name: projectName });
139
- const response = await apiClient.post(url, {
140
- entries
141
- });
142
- return response;
143
- } catch (error) {
144
- throw new Error(`Failed to create tree: ${error.response?.data?.message || error.message}`);
145
- }
146
- }
147
-
148
- /**
149
- * Get a tree by SHA
150
- * @param {number} ownerId - Owner user ID
151
- * @param {string} projectName - Project name
152
- * @param {string} sha - Tree SHA
153
- * @returns {Promise<Object>} Tree data
154
- */
155
- async function getTree(ownerId, projectName, sha) {
156
- try {
157
- const url = buildUrl(API_ENDPOINTS.TREE_GET, { owner_id: ownerId, project_name: projectName, sha });
158
- const response = await apiClient.get(url);
159
- return response;
160
- } catch (error) {
161
- throw new Error(`Failed to get tree: ${error.response?.data?.message || error.message}`);
162
- }
163
- }
164
-
165
- /**
166
- * Create a commit in the repository
167
- * @param {number} ownerId - Owner user ID
168
- * @param {string} projectName - Project name
169
- * @param {Object} commitData - Commit data (message, tree_sha, parent_shas, author_name, author_email, branch)
170
- * @returns {Promise<Object>} Created commit data
171
- */
172
- async function createCommit(ownerId, projectName, commitData) {
173
- try {
174
- const url = buildUrl(API_ENDPOINTS.COMMITS_CREATE, { owner_id: ownerId, project_name: projectName });
175
- const response = await apiClient.post(url, commitData);
176
- return response;
177
- } catch (error) {
178
- throw new Error(`Failed to create commit: ${error.response?.data?.message || error.message}`);
179
- }
180
- }
181
-
182
- /**
183
- * List all commits in a repository
184
- * @param {number} ownerId - Owner user ID
185
- * @param {string} projectName - Project name
186
- * @returns {Promise<Array>} List of commits
187
- */
188
- async function listCommits(ownerId, projectName) {
189
- try {
190
- const url = buildUrl(API_ENDPOINTS.COMMITS_LIST, { owner_id: ownerId, project_name: projectName });
191
- const response = await apiClient.get(url);
192
- return response;
193
- } catch (error) {
194
- throw new Error(`Failed to list commits: ${error.response?.data?.message || error.message}`);
195
- }
196
- }
197
-
198
- /**
199
- * Get a commit by SHA
200
- * @param {number} ownerId - Owner user ID
201
- * @param {string} projectName - Project name
202
- * @param {string} sha - Commit SHA
203
- * @returns {Promise<Object>} Commit data
204
- */
205
- async function getCommit(ownerId, projectName, sha) {
206
- try {
207
- const url = buildUrl(API_ENDPOINTS.COMMITS_GET, { owner_id: ownerId, project_name: projectName, sha });
208
- const response = await apiClient.get(url);
209
- return response;
210
- } catch (error) {
211
- throw new Error(`Failed to get commit: ${error.response?.data?.message || error.message}`);
212
- }
213
- }
214
-
215
- /**
216
- * Create a branch in the repository
217
- * @param {number} ownerId - Owner user ID
218
- * @param {string} projectName - Project name
219
- * @param {string} branchName - Branch name
220
- * @param {string} commitSha - Commit SHA to point the branch to
221
- * @returns {Promise<Object>} Created branch data
222
- */
223
- async function createBranch(ownerId, projectName, branchName, commitSha) {
224
- try {
225
- const url = buildUrl(API_ENDPOINTS.BRANCHES_CREATE, { owner_id: ownerId, project_name: projectName });
226
- const response = await apiClient.post(url, {
227
- name: branchName,
228
- commit_sha: commitSha
229
- });
230
- return response;
231
- } catch (error) {
232
- throw new Error(`Failed to create branch: ${error.response?.data?.message || error.message}`);
233
- }
234
- }
235
-
236
- /**
237
- * List all branches in a repository
238
- * @param {number} ownerId - Owner user ID
239
- * @param {string} projectName - Project name
240
- * @returns {Promise<Array>} List of branches
241
- */
242
- async function listBranches(ownerId, projectName) {
243
- try {
244
- const url = buildUrl(API_ENDPOINTS.BRANCHES_LIST, { owner_id: ownerId, project_name: projectName });
245
- const response = await apiClient.get(url);
246
- return response;
247
- } catch (error) {
248
- throw new Error(`Failed to list branches: ${error.response?.data?.message || error.message}`);
249
- }
250
- }
251
-
252
- /**
253
- * Get a branch by name
254
- * @param {number} ownerId - Owner user ID
255
- * @param {string} projectName - Project name
256
- * @param {string} branchName - Branch name
257
- * @returns {Promise<Object>} Branch data
258
- */
259
- async function getBranch(ownerId, projectName, branchName) {
260
- try {
261
- const url = buildUrl(API_ENDPOINTS.BRANCHES_GET, { owner_id: ownerId, project_name: projectName, branch_name: branchName });
262
- const response = await apiClient.get(url);
263
- return response;
264
- } catch (error) {
265
- throw new Error(`Failed to get branch: ${error.response?.data?.message || error.message}`);
266
- }
267
- }
268
-
269
- module.exports = {
270
- createRepository,
271
- listRepositories,
272
- getRepository,
273
- deleteRepository,
274
- createBlob,
275
- getBlob,
276
- createTree,
277
- getTree,
278
- createCommit,
279
- listCommits,
280
- getCommit,
281
- createBranch,
282
- listBranches,
283
- getBranch
284
- };
@@ -1,323 +0,0 @@
1
- /**
2
- * Cloud Sync Utilities - Handles synchronization between local and cloud repositories
3
- * Provides functions for uploading and downloading commits, blobs, and trees
4
- */
5
-
6
- const fs = require('fs').promises;
7
- const path = require('path');
8
- const chalk = require('chalk');
9
- const ora = require('ora');
10
- const repoService = require('../services/repo-service');
11
- const { GENT_DIR, OBJECTS_DIR } = require('./constants');
12
- const { readJSON, writeJSON, pathExists } = require('./fileSystem');
13
-
14
- /**
15
- * Upload blobs (file contents) to cloud
16
- * @param {Array} files - Array of file objects with path and content
17
- * @param {number} ownerId - Owner user ID
18
- * @param {string} repoName - Repository name
19
- * @returns {Promise<Object>} Map of file paths to blob SHAs
20
- */
21
- async function uploadBlobs(files, ownerId, repoName) {
22
- const spinner = ora('Uploading file contents...').start();
23
- const blobMap = {};
24
-
25
- try {
26
- for (let i = 0; i < files.length; i++) {
27
- const file = files[i];
28
- spinner.text = `Uploading ${file.path} (${i + 1}/${files.length})`;
29
-
30
- const blob = await repoService.createBlob(
31
- ownerId,
32
- repoName,
33
- file.content,
34
- 'utf-8'
35
- );
36
-
37
- blobMap[file.path] = blob.sha;
38
- }
39
-
40
- spinner.succeed(`Uploaded ${files.length} file(s)`);
41
- return blobMap;
42
- } catch (error) {
43
- spinner.fail('Failed to upload files');
44
- throw error;
45
- }
46
- }
47
-
48
- /**
49
- * Download blobs from cloud
50
- * @param {Array} shas - Array of blob SHAs to download
51
- * @param {number} ownerId - Owner user ID
52
- * @param {string} repoName - Repository name
53
- * @returns {Promise<Object>} Map of SHAs to content
54
- */
55
- async function downloadBlobs(shas, ownerId, repoName) {
56
- const spinner = ora('Downloading file contents...').start();
57
- const blobMap = {};
58
-
59
- try {
60
- for (let i = 0; i < shas.length; i++) {
61
- const sha = shas[i];
62
- spinner.text = `Downloading blob ${sha.substring(0, 7)} (${i + 1}/${shas.length})`;
63
-
64
- const blob = await repoService.getBlob(ownerId, repoName, sha);
65
- blobMap[sha] = blob.content;
66
- }
67
-
68
- spinner.succeed(`Downloaded ${shas.length} blob(s)`);
69
- return blobMap;
70
- } catch (error) {
71
- spinner.fail('Failed to download blobs');
72
- throw error;
73
- }
74
- }
75
-
76
- /**
77
- * Build tree structure from file list
78
- * @param {Array} files - Array of file objects with path and SHA
79
- * @returns {Array} Tree entries
80
- */
81
- function buildTreeEntries(files) {
82
- return files.map(file => ({
83
- path: file.path,
84
- mode: '100644', // Regular file
85
- type: 'blob',
86
- sha: file.sha
87
- }));
88
- }
89
-
90
- /**
91
- * Upload a tree structure to cloud
92
- * @param {Array} files - Array of file objects with path and SHA
93
- * @param {number} ownerId - Owner user ID
94
- * @param {string} repoName - Repository name
95
- * @returns {Promise<Object>} Created tree data
96
- */
97
- async function uploadTree(files, ownerId, repoName) {
98
- const spinner = ora('Creating tree structure...').start();
99
-
100
- try {
101
- const entries = buildTreeEntries(files);
102
- const tree = await repoService.createTree(ownerId, repoName, entries);
103
-
104
- spinner.succeed(`Created tree ${tree.sha.substring(0, 7)}`);
105
- return tree;
106
- } catch (error) {
107
- spinner.fail('Failed to create tree');
108
- throw error;
109
- }
110
- }
111
-
112
- /**
113
- * Upload a commit to cloud
114
- * @param {Object} commit - Local commit object
115
- * @param {string} treeSha - Tree SHA
116
- * @param {number} ownerId - Owner user ID
117
- * @param {string} repoName - Repository name
118
- * @param {string} branchName - Branch name
119
- * @returns {Promise<Object>} Created commit data
120
- */
121
- async function uploadCommit(commit, treeSha, ownerId, repoName, branchName) {
122
- const spinner = ora('Creating commit...').start();
123
-
124
- try {
125
- const commitData = {
126
- message: commit.message,
127
- tree_sha: treeSha,
128
- parent_shas: Array.isArray(commit.parent) ? commit.parent : (commit.parent ? [commit.parent] : []),
129
- author_name: commit.author.name,
130
- author_email: commit.author.email,
131
- branch: branchName
132
- };
133
-
134
- const cloudCommit = await repoService.createCommit(ownerId, repoName, commitData);
135
-
136
- spinner.succeed(`Created commit ${cloudCommit.sha.substring(0, 7)}`);
137
- return cloudCommit;
138
- } catch (error) {
139
- spinner.fail('Failed to create commit');
140
- throw error;
141
- }
142
- }
143
-
144
- /**
145
- * Sync local commits to cloud
146
- * @param {Array} commits - Array of local commits to upload
147
- * @param {number} ownerId - Owner user ID
148
- * @param {string} repoName - Repository name
149
- * @param {string} branchName - Branch name
150
- * @param {string} cwd - Current working directory
151
- * @returns {Promise<Array>} Array of created cloud commits
152
- */
153
- async function syncCommitsToCloud(commits, ownerId, repoName, branchName, cwd) {
154
- console.log(chalk.cyan(`\nPushing ${commits.length} commit(s) to ${ownerId}/${repoName}...`));
155
-
156
- const cloudCommits = [];
157
-
158
- for (let i = 0; i < commits.length; i++) {
159
- const commit = commits[i];
160
- console.log(chalk.gray(`\nProcessing commit ${commit.sha.substring(0, 7)}: ${commit.message}`));
161
-
162
- // Read files from commit
163
- const files = [];
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);
167
- if (await pathExists(objectPath)) {
168
- const content = await fs.readFile(objectPath, 'utf-8');
169
- files.push({ path: file.path, content });
170
- }
171
- }
172
-
173
- // Upload blobs
174
- const blobMap = await uploadBlobs(files, ownerId, repoName);
175
-
176
- // Build file list with SHAs
177
- const fileList = Object.keys(blobMap).map(path => ({
178
- path,
179
- sha: blobMap[path]
180
- }));
181
-
182
- // Upload tree
183
- const tree = await uploadTree(fileList, ownerId, repoName);
184
-
185
- // Upload commit
186
- const cloudCommit = await uploadCommit(commit, tree.sha, ownerId, repoName, branchName);
187
-
188
- cloudCommits.push(cloudCommit);
189
- }
190
-
191
- console.log(chalk.green(`\n✓ Successfully pushed ${commits.length} commit(s)`));
192
- return cloudCommits;
193
- }
194
-
195
- /**
196
- * Download commits from cloud to local
197
- * @param {number} ownerId - Owner user ID
198
- * @param {string} repoName - Repository name
199
- * @param {string} cwd - Current working directory
200
- * @returns {Promise<Array>} Array of downloaded commits
201
- */
202
- async function syncCommitsFromCloud(ownerId, repoName, cwd) {
203
- const spinner = ora('Fetching commits from cloud...').start();
204
-
205
- try {
206
- const cloudCommits = await repoService.listCommits(ownerId, repoName);
207
- spinner.succeed(`Fetched ${cloudCommits.length} commit(s)`);
208
-
209
- // Download trees and blobs for each commit
210
- for (const commit of cloudCommits) {
211
- console.log(chalk.gray(`Processing commit ${commit.sha.substring(0, 7)}: ${commit.message}`));
212
-
213
- // Download tree
214
- const tree = await repoService.getTree(ownerId, repoName, commit.tree_sha);
215
-
216
- // Store entries for local metadata
217
- commit.files = tree.entries.map(entry => ({
218
- path: entry.path,
219
- hash: entry.sha
220
- }));
221
-
222
- // Download blobs from tree entries
223
- const blobShas = tree.entries.map(entry => entry.sha);
224
- const blobMap = await downloadBlobs(blobShas, ownerId, repoName);
225
-
226
- // Save blobs to local objects directory
227
- const objectsDir = path.join(cwd, GENT_DIR, OBJECTS_DIR);
228
- for (const [sha, content] of Object.entries(blobMap)) {
229
- const objectPath = path.join(objectsDir, sha);
230
- await fs.writeFile(objectPath, content, 'utf-8');
231
- }
232
- }
233
-
234
- console.log(chalk.green(`\n✓ Successfully pulled ${cloudCommits.length} commit(s)`));
235
- return cloudCommits;
236
- } catch (error) {
237
- spinner.fail('Failed to fetch commits');
238
- throw error;
239
- }
240
- }
241
-
242
- /**
243
- * Get or create remote configuration
244
- * @param {string} cwd - Current working directory
245
- * @returns {Promise<Object>} Remote configuration
246
- */
247
- async function getRemoteConfig(cwd) {
248
- const remotePath = path.join(cwd, GENT_DIR, 'remote.json');
249
-
250
- if (await pathExists(remotePath)) {
251
- return await readJSON(remotePath);
252
- }
253
-
254
- return { remotes: {} };
255
- }
256
-
257
- /**
258
- * Save remote configuration
259
- * @param {Object} config - Remote configuration
260
- * @param {string} cwd - Current working directory
261
- */
262
- async function saveRemoteConfig(config, cwd) {
263
- const remotePath = path.join(cwd, GENT_DIR, 'remote.json');
264
- await writeJSON(remotePath, config);
265
- }
266
-
267
- /**
268
- * Add a remote to configuration
269
- * @param {string} name - Remote name
270
- * @param {number} ownerId - Owner user ID
271
- * @param {string} repoName - Repository name
272
- * @param {string} cwd - Current working directory
273
- */
274
- async function addRemote(name, ownerId, repoName, cwd) {
275
- const config = await getRemoteConfig(cwd);
276
-
277
- config.remotes[name] = {
278
- owner_id: ownerId,
279
- repo_name: repoName
280
- };
281
-
282
- await saveRemoteConfig(config, cwd);
283
- }
284
-
285
- /**
286
- * Remove a remote from configuration
287
- * @param {string} name - Remote name
288
- * @param {string} cwd - Current working directory
289
- */
290
- async function removeRemote(name, cwd) {
291
- const config = await getRemoteConfig(cwd);
292
-
293
- if (config.remotes[name]) {
294
- delete config.remotes[name];
295
- await saveRemoteConfig(config, cwd);
296
- }
297
- }
298
-
299
- /**
300
- * Get remote by name
301
- * @param {string} name - Remote name
302
- * @param {string} cwd - Current working directory
303
- * @returns {Promise<Object|null>} Remote configuration or null
304
- */
305
- async function getRemote(name, cwd) {
306
- const config = await getRemoteConfig(cwd);
307
- return config.remotes[name] || null;
308
- }
309
-
310
- module.exports = {
311
- uploadBlobs,
312
- downloadBlobs,
313
- buildTreeEntries,
314
- uploadTree,
315
- uploadCommit,
316
- syncCommitsToCloud,
317
- syncCommitsFromCloud,
318
- getRemoteConfig,
319
- saveRemoteConfig,
320
- addRemote,
321
- removeRemote,
322
- getRemote
323
- };