gent-cli 2.1.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,291 +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
- /**
32
- * Create a new repository
33
- * @param {string} name - Repository name
34
- * @param {string} description - Repository description
35
- * @param {boolean} isPrivate - Whether the repository is private
36
- * @param {string} defaultBranch - Default branch name
37
- * @returns {Promise<Object>} Created repository data
38
- */
39
- async function createRepository(name, description = '', isPrivate = false, defaultBranch = 'main') {
40
- try {
41
- const response = await apiClient.post(API_ENDPOINTS.REPOS_CREATE, {
42
- name,
43
- description,
44
- is_private: isPrivate,
45
- default_branch: defaultBranch
46
- });
47
- return response;
48
- } catch (error) {
49
- throw new Error(`Failed to create repository: ${error.response?.data?.message || error.message}`);
50
- }
51
- }
52
-
53
- /**
54
- * List all repositories owned by the authenticated user
55
- * @returns {Promise<Array>} List of repositories
56
- */
57
- async function listRepositories() {
58
- try {
59
- const response = await apiClient.get(API_ENDPOINTS.REPOS_LIST);
60
- return response;
61
- } catch (error) {
62
- throw new Error(`Failed to list repositories: ${error.response?.data?.message || error.message}`);
63
- }
64
- }
65
-
66
- /**
67
- * Get repository details
68
- * @param {number} ownerId - Owner user ID
69
- * @param {string} name - Repository name
70
- * @returns {Promise<Object>} Repository data
71
- */
72
- async function getRepository(ownerId, name) {
73
- try {
74
- const url = buildUrl(API_ENDPOINTS.REPOS_GET, { owner_id: ownerId, name: name });
75
- const response = await apiClient.get(url);
76
- return response;
77
- } catch (error) {
78
- throw new Error(`Failed to get repository: ${error.response?.data?.message || error.message}`);
79
- }
80
- }
81
-
82
- /**
83
- * Delete a repository
84
- * @param {number} ownerId - Owner user ID
85
- * @param {string} name - Repository name
86
- * @returns {Promise<Object>} Delete response
87
- */
88
- async function deleteRepository(ownerId, name) {
89
- try {
90
- const url = buildUrl(API_ENDPOINTS.REPOS_DELETE, { owner_id: ownerId, name: name });
91
- const response = await apiClient.delete(url);
92
- return response;
93
- } catch (error) {
94
- throw new Error(`Failed to delete repository: ${error.response?.data?.message || error.message}`);
95
- }
96
- }
97
-
98
- /**
99
- * Create a blob (file content) in the repository
100
- * @param {number} ownerId - Owner user ID
101
- * @param {string} name - Repository name
102
- * @param {string} content - File content
103
- * @param {string} encoding - Encoding type (utf-8 or base64)
104
- * @returns {Promise<Object>} Created blob data
105
- */
106
- async function createBlob(ownerId, name, content, encoding = 'utf-8') {
107
- try {
108
- const url = buildUrl(API_ENDPOINTS.BLOB_CREATE, { owner_id: ownerId, name: name });
109
- const response = await apiClient.post(url, {
110
- content,
111
- encoding
112
- });
113
- return response;
114
- } catch (error) {
115
- throw new Error(`Failed to create blob: ${error.response?.data?.message || error.message}`);
116
- }
117
- }
118
-
119
- /**
120
- * Get a blob by SHA
121
- * @param {number} ownerId - Owner user ID
122
- * @param {string} name - Repository name
123
- * @param {string} sha - Blob SHA
124
- * @returns {Promise<Object>} Blob data
125
- */
126
- async function getBlob(ownerId, name, sha) {
127
- try {
128
- const url = buildUrl(API_ENDPOINTS.BLOB_GET, { owner_id: ownerId, name: name, sha });
129
- const response = await apiClient.get(url);
130
- return response;
131
- } catch (error) {
132
- throw new Error(`Failed to get blob: ${error.response?.data?.message || error.message}`);
133
- }
134
- }
135
-
136
- /**
137
- * Create a tree (directory structure) in the repository
138
- * @param {number} ownerId - Owner user ID
139
- * @param {string} name - Repository name
140
- * @param {Array} entries - Tree entries
141
- * @returns {Promise<Object>} Created tree data
142
- */
143
- async function createTree(ownerId, name, entries) {
144
- try {
145
- const url = buildUrl(API_ENDPOINTS.TREE_CREATE, { owner_id: ownerId, name: name });
146
- const response = await apiClient.post(url, {
147
- entries
148
- });
149
- return response;
150
- } catch (error) {
151
- throw new Error(`Failed to create tree: ${error.response?.data?.message || error.message}`);
152
- }
153
- }
154
-
155
- /**
156
- * Get a tree by SHA
157
- * @param {number} ownerId - Owner user ID
158
- * @param {string} name - Repository name
159
- * @param {string} sha - Tree SHA
160
- * @returns {Promise<Object>} Tree data
161
- */
162
- async function getTree(ownerId, name, sha) {
163
- try {
164
- const url = buildUrl(API_ENDPOINTS.TREE_GET, { owner_id: ownerId, name: name, sha });
165
- const response = await apiClient.get(url);
166
- return response;
167
- } catch (error) {
168
- throw new Error(`Failed to get tree: ${error.response?.data?.message || error.message}`);
169
- }
170
- }
171
-
172
- /**
173
- * Create a commit in the repository
174
- * @param {number} ownerId - Owner user ID
175
- * @param {string} name - Repository name
176
- * @param {Object} commitData - Commit data (message, tree_sha, parent_shas, author_name, author_email, branch)
177
- * @returns {Promise<Object>} Created commit data
178
- */
179
- async function createCommit(ownerId, name, commitData) {
180
- try {
181
- const url = buildUrl(API_ENDPOINTS.COMMITS_CREATE, { owner_id: ownerId, name: name });
182
- const response = await apiClient.post(url, commitData);
183
- return response;
184
- } catch (error) {
185
- throw new Error(`Failed to create commit: ${error.response?.data?.message || error.message}`);
186
- }
187
- }
188
-
189
- /**
190
- * List all commits in a repository
191
- * @param {number} ownerId - Owner user ID
192
- * @param {string} name - Repository name
193
- * @returns {Promise<Array>} List of commits
194
- */
195
- async function listCommits(ownerId, name) {
196
- try {
197
- const url = buildUrl(API_ENDPOINTS.COMMITS_LIST, { owner_id: ownerId, name: name });
198
- const response = await apiClient.get(url);
199
- return response;
200
- } catch (error) {
201
- throw new Error(`Failed to list commits: ${error.response?.data?.message || error.message}`);
202
- }
203
- }
204
-
205
- /**
206
- * Get a commit by SHA
207
- * @param {number} ownerId - Owner user ID
208
- * @param {string} name - Repository name
209
- * @param {string} sha - Commit SHA
210
- * @returns {Promise<Object>} Commit data
211
- */
212
- async function getCommit(ownerId, name, sha) {
213
- try {
214
- const url = buildUrl(API_ENDPOINTS.COMMITS_GET, { owner_id: ownerId, name: name, sha });
215
- const response = await apiClient.get(url);
216
- return response;
217
- } catch (error) {
218
- throw new Error(`Failed to get commit: ${error.response?.data?.message || error.message}`);
219
- }
220
- }
221
-
222
- /**
223
- * Create a branch in the repository
224
- * @param {number} ownerId - Owner user ID
225
- * @param {string} name - Repository name
226
- * @param {string} branchName - Branch name
227
- * @param {string} commitSha - Commit SHA to point the branch to
228
- * @returns {Promise<Object>} Created branch data
229
- */
230
- async function createBranch(ownerId, name, branchName, commitSha) {
231
- try {
232
- const url = buildUrl(API_ENDPOINTS.BRANCHES_CREATE, { owner_id: ownerId, name: name });
233
- const response = await apiClient.post(url, {
234
- name: branchName,
235
- commit_sha: commitSha
236
- });
237
- return response;
238
- } catch (error) {
239
- throw new Error(`Failed to create branch: ${error.response?.data?.message || error.message}`);
240
- }
241
- }
242
-
243
- /**
244
- * List all branches in a repository
245
- * @param {number} ownerId - Owner user ID
246
- * @param {string} name - Repository name
247
- * @returns {Promise<Array>} List of branches
248
- */
249
- async function listBranches(ownerId, name) {
250
- try {
251
- const url = buildUrl(API_ENDPOINTS.BRANCHES_LIST, { owner_id: ownerId, name: name });
252
- const response = await apiClient.get(url);
253
- return response;
254
- } catch (error) {
255
- throw new Error(`Failed to list branches: ${error.response?.data?.message || error.message}`);
256
- }
257
- }
258
-
259
- /**
260
- * Get a branch by name
261
- * @param {number} ownerId - Owner user ID
262
- * @param {string} name - Repository name
263
- * @param {string} branchName - Branch name
264
- * @returns {Promise<Object>} Branch data
265
- */
266
- async function getBranch(ownerId, name, branchName) {
267
- try {
268
- const url = buildUrl(API_ENDPOINTS.BRANCHES_GET, { owner_id: ownerId, name: name, branch_name: branchName });
269
- const response = await apiClient.get(url);
270
- return response;
271
- } catch (error) {
272
- throw new Error(`Failed to get branch: ${error.response?.data?.message || error.message}`);
273
- }
274
- }
275
-
276
- module.exports = {
277
- createRepository,
278
- listRepositories,
279
- getRepository,
280
- deleteRepository,
281
- createBlob,
282
- getBlob,
283
- createTree,
284
- getTree,
285
- createCommit,
286
- listCommits,
287
- getCommit,
288
- createBranch,
289
- listBranches,
290
- getBranch
291
- };
@@ -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
- };