jvcs 1.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.
Files changed (56) hide show
  1. package/.env +4 -0
  2. package/.jvcs/HEAD +1 -0
  3. package/.jvcs/commits/292abee1-42ea-4ddf-b590-be7c98abaf45/jvcs_hashcode.json +1 -0
  4. package/.jvcs/commits/292abee1-42ea-4ddf-b590-be7c98abaf45/meta.json +7 -0
  5. package/.jvcs/commits/302af5ea-5789-4ee9-98fe-eab9308b2e27/jvcs_hashcode.json +1 -0
  6. package/.jvcs/commits/302af5ea-5789-4ee9-98fe-eab9308b2e27/meta.json +7 -0
  7. package/.jvcs/commits/376d44d4-c595-429e-b711-ae6ec7c9ef74/jvcs_hashcode.json +1 -0
  8. package/.jvcs/commits/376d44d4-c595-429e-b711-ae6ec7c9ef74/meta.json +7 -0
  9. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/add.js +122 -0
  10. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/begin.js +201 -0
  11. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/commit.js +82 -0
  12. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/init.js +60 -0
  13. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/login.js +33 -0
  14. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/pull.js +98 -0
  15. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/push.js +135 -0
  16. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/revert.js +110 -0
  17. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/signup.js +28 -0
  18. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/unstage.js +96 -0
  19. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/utility.js +28 -0
  20. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/controllers/verifyOtp.js +55 -0
  21. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/jvcs_hashcode.json +50 -0
  22. package/.jvcs/commits/484ac37d-c1a9-4ddd-8796-6e3facda1e11/meta.json +7 -0
  23. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/add.js +122 -0
  24. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/begin.js +201 -0
  25. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/commit.js +82 -0
  26. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/init.js +60 -0
  27. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/login.js +33 -0
  28. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/pull.js +98 -0
  29. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/push.js +135 -0
  30. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/revert.js +110 -0
  31. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/signup.js +28 -0
  32. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/unstage.js +96 -0
  33. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/utility.js +28 -0
  34. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/controllers/verifyOtp.js +55 -0
  35. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/jvcs_hashcode.json +50 -0
  36. package/.jvcs/commits/c3f6ff7a-13bd-4697-a80e-041f7dae8a09/meta.json +7 -0
  37. package/.jvcs/commits/c7aa89bd-5016-4f21-8979-02e3c0a2c8ee/jvcs_hashcode.json +1 -0
  38. package/.jvcs/commits/c7aa89bd-5016-4f21-8979-02e3c0a2c8ee/meta.json +7 -0
  39. package/.jvcs/config.json +9 -0
  40. package/.jvcs/staging/jvcs_hashcode.json +1 -0
  41. package/config/drive-config.js +25 -0
  42. package/controllers/add.js +122 -0
  43. package/controllers/begin.js +201 -0
  44. package/controllers/commit.js +82 -0
  45. package/controllers/init.js +60 -0
  46. package/controllers/log.js +99 -0
  47. package/controllers/login.js +33 -0
  48. package/controllers/pull.js +98 -0
  49. package/controllers/push.js +135 -0
  50. package/controllers/revert.js +110 -0
  51. package/controllers/signup.js +28 -0
  52. package/controllers/unstage.js +96 -0
  53. package/controllers/utility.js +28 -0
  54. package/controllers/verifyOtp.js +55 -0
  55. package/index.js +131 -0
  56. package/package.json +21 -0
@@ -0,0 +1,110 @@
1
+ const fs = require("fs");
2
+ const fsPromises = require("fs").promises;
3
+ const path = require("path");
4
+ const { v4: uuidv4 } = require("uuid");
5
+ const chalk = require("chalk");
6
+ const { drive } = require("../config/drive-config");
7
+ const { checkInitialization, checkRepoExists, getCLIConfig } = require("./utils");
8
+
9
+ async function revertCmd(commitId, reponame) {
10
+ try {
11
+ if (!checkInitialization()) return;
12
+ if (!checkRepoExists(reponame)) return;
13
+
14
+ const repoPath = path.join(process.cwd(), `.${reponame}`);
15
+ const commitFolder = path.join(repoPath, "commits");
16
+ if (!fs.existsSync(commitFolder)) fs.mkdirSync(commitFolder, { recursive: true });
17
+
18
+ const config = await getCLIConfig();
19
+ if (!config) return console.log(chalk.red("Could not read CLI configuration."));
20
+
21
+ // 1️⃣ Get user folder
22
+ const userFolderRes = await drive.files.list({
23
+ q: `name='${config.username}' and '1ahuoMCN_Ls5kGF2KPUGLbRZb9kGVMe0V' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false`,
24
+ fields: "files(id, name)"
25
+ });
26
+ if (!userFolderRes.data.files.length) return console.log(chalk.red("User folder not found on Drive."));
27
+ const userFolderId = userFolderRes.data.files[0].id;
28
+
29
+ // 2️⃣ Get repo folder
30
+ const repoFolderRes = await drive.files.list({
31
+ q: `name='${reponame}' and '${userFolderId}' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false`,
32
+ fields: "files(id, name)"
33
+ });
34
+ if (!repoFolderRes.data.files.length) return console.log(chalk.red("Repo folder not found on Drive."));
35
+ const repoFolderId = repoFolderRes.data.files[0].id;
36
+
37
+ // 3️⃣ Get commit folder
38
+ const commitRes = await drive.files.list({
39
+ q: `name='${commitId}' and '${repoFolderId}' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false`,
40
+ fields: "files(id, name)"
41
+ });
42
+ if (!commitRes.data.files.length) return console.log(chalk.red(`Commit '${commitId}' not found on Drive.`));
43
+ const driveCommitId = commitRes.data.files[0].id;
44
+
45
+ // 4️⃣ Create new revert commit folder locally
46
+ const newCommitId = `revert_${commitId}_${uuidv4()}`;
47
+ const newCommitPath = path.join(commitFolder, newCommitId);
48
+ await fsPromises.mkdir(newCommitPath, { recursive: true });
49
+
50
+ // 5️⃣ Recursively download commit files from Drive
51
+ await downloadFolderFromDrive(driveCommitId, newCommitPath);
52
+
53
+ // 6️⃣ Clean working directory (except hidden files)
54
+ const cwd = process.cwd();
55
+ const entries = await fsPromises.readdir(cwd);
56
+ for (const entry of entries) {
57
+ if (entry.startsWith(".")) continue;
58
+ await fsPromises.rm(path.join(cwd, entry), { recursive: true, force: true });
59
+ }
60
+
61
+ // 7️⃣ Copy new revert commit into working directory
62
+ await copyFolderRecursive(newCommitPath, cwd);
63
+
64
+ console.log(chalk.green(`Reverted to commit '${commitId}'. New revert commit: '${newCommitId}'`));
65
+
66
+ } catch (err) {
67
+ console.log(chalk.red("Error in revertCmd:"), err.message);
68
+ }
69
+ }
70
+
71
+ // Recursive download helper
72
+ async function downloadFolderFromDrive(folderId, localPath) {
73
+ const res = await drive.files.list({
74
+ q: `'${folderId}' in parents and trashed=false`,
75
+ fields: "files(id, name, mimeType)"
76
+ });
77
+
78
+ for (const file of res.data.files) {
79
+ const filePath = path.join(localPath, file.name);
80
+ if (file.mimeType === "application/vnd.google-apps.folder") {
81
+ await fsPromises.mkdir(filePath, { recursive: true });
82
+ await downloadFolderFromDrive(file.id, filePath);
83
+ } else {
84
+ const destStream = fs.createWriteStream(filePath);
85
+ await new Promise((resolve, reject) => {
86
+ drive.files.get({ fileId: file.id, alt: "media" }, { responseType: "stream" }, (err, response) => {
87
+ if (err) return reject(err);
88
+ response.data.pipe(destStream).on("finish", resolve).on("error", reject);
89
+ });
90
+ });
91
+ }
92
+ }
93
+ }
94
+
95
+ // Recursive copy helper
96
+ async function copyFolderRecursive(src, dest) {
97
+ const entries = await fsPromises.readdir(src, { withFileTypes: true });
98
+ for (const entry of entries) {
99
+ const srcPath = path.join(src, entry.name);
100
+ const destPath = path.join(dest, entry.name);
101
+ if (entry.isDirectory()) {
102
+ await fsPromises.mkdir(destPath, { recursive: true });
103
+ await copyFolderRecursive(srcPath, destPath);
104
+ } else {
105
+ await fsPromises.copyFile(srcPath, destPath);
106
+ }
107
+ }
108
+ }
109
+
110
+ module.exports = revertCmd;
@@ -0,0 +1,28 @@
1
+ const chalk = require("chalk")
2
+ const verifyOtp = require("./verifyOtp")
3
+ async function signup(signupData) {
4
+
5
+ const response = await fetch("http://localhost:3000/signup", {
6
+ method: "POST",
7
+ headers: {
8
+ 'Content-Type': 'application/json'
9
+ },
10
+ credentials: "include",
11
+ body: JSON.stringify(signupData)
12
+ })
13
+
14
+ const data = await response.json()
15
+
16
+ if(data.status === true) {
17
+ console.log(chalk.green(data.message))
18
+ await verifyOtp(signupData)
19
+ }
20
+ else if(data.status == "user") {
21
+ console.log(chalk.yellow(data.message))
22
+ }
23
+ else {
24
+ throw new Error(data.message)
25
+ }
26
+ }
27
+
28
+ module.exports = signup
@@ -0,0 +1,96 @@
1
+ const fs = require("fs").promises;
2
+ const fssync = require("fs");
3
+ const path = require("path");
4
+ const chalk = require("chalk");
5
+ const { checkGlobalConfig, getGlobalConfig, checkforjvcs } = require("./utility");
6
+
7
+ function removeHashesForFolder(hashData,folderPath) {
8
+
9
+ for(const key of Object.keys(hashData)) {
10
+ if(key.startsWith(folderPath+path.sep)) {
11
+ delete hashData[key]
12
+ }
13
+ }
14
+ }
15
+
16
+ async function unstageCmd(paths) {
17
+
18
+ if(!paths || paths.length === 0) {
19
+ console.log(chalk.yellow("Please specify files or folders to unstage."));
20
+ return;
21
+ }
22
+
23
+ if(!checkGlobalConfig()) {
24
+ console.log(chalk.red("No existing session found. Please login or signup."));
25
+ console.log(chalk.green("jvcs --help for help"));
26
+ return;
27
+ }
28
+
29
+ const configData = getGlobalConfig();
30
+ if(!configData) {
31
+ console.log(chalk.red("No existing session found. Please login or signup."));
32
+ return;
33
+ }
34
+
35
+ if(!checkforjvcs()) {
36
+ console.log(chalk.red("Repository is not initialized or is deleted."));
37
+ return;
38
+ }
39
+
40
+ const repoPath = path.join(process.cwd(), ".jvcs");
41
+ const stagingPath = path.join(repoPath, "staging");
42
+ const hashPath = path.join(stagingPath, "jvcs_hashcode.json");
43
+
44
+ if(!fssync.existsSync(stagingPath)) {
45
+ console.log(chalk.yellow("Nothing is staged yet."));
46
+ return;
47
+ }
48
+
49
+ const stagedItems = fssync.readdirSync(stagingPath).filter((item)=> item !== "jvcs_hashcode.json")
50
+ if(stagedItems.length === 0) {
51
+ console.log(chalk.yellow("Staging area is empty. Nothing to unstage."));
52
+ return;
53
+ }
54
+
55
+ let hashData = {};
56
+ if(fssync.existsSync(hashPath)) {
57
+ hashData = JSON.parse(await fs.readFile(hashPath, "utf-8"));
58
+ }
59
+
60
+ if(paths.length === 1 && paths[0] === ".") {
61
+ await fs.rm(stagingPath, {recursive: true, force: true})
62
+ await fs.mkdir(stagingPath, {recursive: true})
63
+ console.log(chalk.cyan("Unstaged all files and folders."));
64
+ return
65
+ }
66
+
67
+ const targets = paths.map((p) => path.resolve(process.cwd(), p));
68
+
69
+ for(const target of targets) {
70
+
71
+ const stagedTarget = path.join(stagingPath, path.relative(process.cwd(),target))
72
+
73
+ if(!fssync.existsSync(stagedTarget)) {
74
+ console.log(chalk.yellow(`Not found in staging: ${path.relative(process.cwd(), target)}`));
75
+ continue;
76
+ }
77
+
78
+ const stats = await fs.stat(stagedTarget);
79
+
80
+ if(stats.isDirectory()) {
81
+ await fs.rm(stagedTarget, {recursive: true, force: true})
82
+ removeHashesForFolder(hashData,path.relative(process.cwd(),target))
83
+ console.log(chalk.cyan(`Unstaged folder: ${path.relative(process.cwd(), target)}`));
84
+ }
85
+ else if(stats.isFile()) {
86
+ await fs.rm(stagedTarget)
87
+ delete hashData[path.relative(process.cwd(),target)]
88
+ console.log(chalk.green(`Unstaged file: ${path.relative(process.cwd(), target)}`));
89
+ }
90
+
91
+ }
92
+
93
+ await fs.writeFile(hashPath, JSON.stringify(hashData, null, 2));
94
+ }
95
+
96
+ module.exports = unstageCmd
@@ -0,0 +1,28 @@
1
+ const fs = require("fs")
2
+ const path = require("path")
3
+
4
+ const config = path.join(require("os").homedir(),".jvcs","config.json")
5
+
6
+ function checkGlobalConfig() {
7
+ return fs.existsSync(config)
8
+ }
9
+
10
+ function getGlobalConfig() {
11
+ if(checkGlobalConfig()) {
12
+ const configData = JSON.parse(fs.readFileSync(config,"utf-8"))
13
+ return configData
14
+ }
15
+
16
+ return null
17
+ }
18
+
19
+ function checkforjvcs() {
20
+ const jvcsPath = path.join(process.cwd(),".jvcs")
21
+ return fs.existsSync(jvcsPath)
22
+ }
23
+
24
+ module.exports = {
25
+ checkGlobalConfig,
26
+ getGlobalConfig,
27
+ checkforjvcs
28
+ }
@@ -0,0 +1,55 @@
1
+ const inquirer = require("inquirer");
2
+ const fs = require("fs")
3
+ const path = require("path")
4
+ const chalk = require("chalk")
5
+
6
+ async function verifyOtp(signupData) {
7
+
8
+ const otp = await inquirer.prompt([
9
+ {
10
+ type: 'password',
11
+ name: 'otp',
12
+ validate: function(input) {
13
+ if(input.length !== 6)
14
+ return "OTP must be of 6 length"
15
+
16
+ return true
17
+ },
18
+ filter: function(input) {
19
+ return input.trim()
20
+ },
21
+ mask: '*',
22
+ }
23
+ ])
24
+
25
+ console.log(`otp is : ${otp.otp}`)
26
+ const response = await fetch("http://localhost:3000/verifyEmail", {
27
+ method: "POST",
28
+ headers: { 'Content-Type': 'application/json' },
29
+ credentials: "include",
30
+ body: JSON.stringify({email:signupData.email,otp:otp.otp,cli:true})
31
+ });
32
+
33
+ const data = await response.json();
34
+
35
+ if (data.status === true) {
36
+ console.log(chalk.green(data.message))
37
+
38
+ const dirPath = path.join(require("os").homedir(), ".jvcs");
39
+ if (!fs.existsSync(dirPath)) {
40
+ fs.mkdirSync(dirPath, { recursive: true });
41
+ }
42
+
43
+ const configPath = path.join(dirPath, "config.json");
44
+ fs.writeFileSync(configPath,JSON.stringify({email: signupData.email,username: signupData.username,token: data.token},null,2));
45
+ }
46
+ else if(data.status === "user") {
47
+ console.log(chalk.yellow(data.message))
48
+ }
49
+ else {
50
+ throw new Error(data.message)
51
+ }
52
+
53
+ }
54
+
55
+ module.exports = verifyOtp
@@ -0,0 +1,50 @@
1
+ {
2
+ "controllers\\add.js": {
3
+ "hash": "1108e6f710b0e3bc171fe91b4bb05b06e184536b7ff481a835e0d58e8fb6dd86",
4
+ "time": "2025-10-27T14:28:57.120Z"
5
+ },
6
+ "controllers\\begin.js": {
7
+ "hash": "228ccbb0e8965765aa039b27cd4a6ffaad388b9b09c52fafe8f807b7b568f378",
8
+ "time": "2025-10-27T14:28:57.122Z"
9
+ },
10
+ "controllers\\commit.js": {
11
+ "hash": "605f17f8bd9b41031ec4b8622b16a8df23e0fc9e61eaabfa208e3c86e8393225",
12
+ "time": "2025-10-27T14:28:57.123Z"
13
+ },
14
+ "controllers\\init.js": {
15
+ "hash": "32343d60e405454a913fddb507749648f9888a9da0d600e521c2c629216d3692",
16
+ "time": "2025-10-27T14:28:57.124Z"
17
+ },
18
+ "controllers\\login.js": {
19
+ "hash": "221da70c0993adf46cefd25ed4c8fd23d0a0608da9e6cc9ab829757cd4807bd1",
20
+ "time": "2025-10-27T14:28:57.124Z"
21
+ },
22
+ "controllers\\pull.js": {
23
+ "hash": "470e368a19c7c7e8d9779410442a38c8edc935c4c4c2ddc31da5f718aa03765b",
24
+ "time": "2025-10-27T14:28:57.125Z"
25
+ },
26
+ "controllers\\push.js": {
27
+ "hash": "adc10399b4de39d76fee60f30cda01d19a173ff6e2a5efef91ee2d4687f813d4",
28
+ "time": "2025-10-27T14:28:57.125Z"
29
+ },
30
+ "controllers\\revert.js": {
31
+ "hash": "9cb908b0bfc6b5fd5d46ed95a847c9639297293c1bd9948991ba6ea797ad8cb0",
32
+ "time": "2025-10-27T14:28:57.126Z"
33
+ },
34
+ "controllers\\signup.js": {
35
+ "hash": "67c1f5ad80f8a64e92fd8cd685a06a605831011fd4246256a60e09a6b5d161b8",
36
+ "time": "2025-10-27T14:28:57.126Z"
37
+ },
38
+ "controllers\\unstage.js": {
39
+ "hash": "dad05d36b99737206255ff62655968ede6b5f941b56622df48b50ac8ed48f582",
40
+ "time": "2025-10-27T14:28:57.127Z"
41
+ },
42
+ "controllers\\utility.js": {
43
+ "hash": "7102c426a65ff9b875f43bf5ca77ddc9c6050bb057b4e8c269529dccef44b921",
44
+ "time": "2025-10-27T14:28:57.127Z"
45
+ },
46
+ "controllers\\verifyOtp.js": {
47
+ "hash": "bca1ca95df41204ade025dea0822c29422c17cd67cc24584ef17231c4382701f",
48
+ "time": "2025-10-27T14:28:57.127Z"
49
+ }
50
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "author": "jagdish",
3
+ "id": "c3f6ff7a-13bd-4697-a80e-041f7dae8a09",
4
+ "message": "commit 1",
5
+ "timeStamp": "2025-10-27T14:29:11.973Z",
6
+ "parentId": null
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "author": "jagdish",
3
+ "id": "c7aa89bd-5016-4f21-8979-02e3c0a2c8ee",
4
+ "message": "commit 6",
5
+ "timeStamp": "2025-10-27T15:14:06.380Z",
6
+ "parentId": "376d44d4-c595-429e-b711-ae6ec7c9ef74"
7
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "repoName": "backend2",
3
+ "createdAt": "2025-10-27T14:28:52.288Z",
4
+ "remote": null,
5
+ "owner": {
6
+ "username": "jagdish",
7
+ "email": "pathakjijagdish1@gmail.com"
8
+ }
9
+ }
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,25 @@
1
+ const { google } = require("googleapis");
2
+ const dotenv = require("dotenv")
3
+ dotenv.config()
4
+
5
+ // Replace these with your own credentials from Google Cloud Console
6
+ const CLIENT_ID = process.env.CLIENT_ID
7
+ const CLIENT_SECRET = process.env.CLIENT_SECRET
8
+ const REDIRECT_URI = process.env.REDIRECT_URI
9
+ // Your generated refresh token from OAuth Playground or your OAuth flow
10
+ const REFRESH_TOKEN = process.env.REFRESH_TOKEN
11
+
12
+ const oauth2client = new google.auth.OAuth2(
13
+ CLIENT_ID,
14
+ CLIENT_SECRET,
15
+ REDIRECT_URI
16
+ );
17
+
18
+ oauth2client.setCredentials({ refresh_token: REFRESH_TOKEN });
19
+
20
+ const drive = google.drive({
21
+ version: 'v3',
22
+ auth: oauth2client
23
+ });
24
+
25
+ module.exports = { drive };
@@ -0,0 +1,122 @@
1
+ const { checkGlobalConfig, getGlobalConfig, checkforjvcs } = require("./utility")
2
+ const path = require("path")
3
+ const fssync = require("fs")
4
+ const chalk = require("chalk")
5
+ const fs = require("fs").promises
6
+ const crypto = require("crypto")
7
+
8
+ async function getFileHash(filepath) {
9
+ const buffer = await fs.readFile(filepath)
10
+ return crypto.createHash("sha256").update(buffer).digest("hex")
11
+ }
12
+
13
+ async function hashDirectoryRecursive(dir,hashData) {
14
+
15
+ const entries = await fs.readdir(dir, {withFileTypes: true})
16
+ console.log(entries)
17
+
18
+ for(const entry of entries) {
19
+
20
+ const fullPath = path.join(dir,entry.name)
21
+ const relativePath = path.relative(process.cwd(),fullPath)
22
+
23
+ if(entry.isFile()) {
24
+ const hash = await getFileHash(fullPath)
25
+ hashData[relativePath] = {
26
+ hash,
27
+ time: new Date().toISOString(),
28
+ }
29
+ }
30
+ else if(entry.isDirectory()) {
31
+ await hashDirectoryRecursive(fullPath,hashData)
32
+ }
33
+ }
34
+ }
35
+
36
+ async function addCmd(paths) {
37
+
38
+ if(!paths || paths.length === 0) {
39
+ console.log(chalk.yellow("Please specify files or folders to add."));
40
+ return
41
+ }
42
+
43
+ if(!checkGlobalConfig()) {
44
+ console.log(chalk.red("No existing session found. Please login or signup."))
45
+ console.log(chalk.green("jvcs --help for help"))
46
+ return
47
+ }
48
+
49
+ let configData = getGlobalConfig()
50
+
51
+ if(!configData) {
52
+ console.log(chalk.red("No existing session found. Please login or signup."))
53
+ console.log(chalk.green("jvcs --help for help"))
54
+ return
55
+ }
56
+
57
+ if(!checkforjvcs()) {
58
+ console.log(chalk.red("Repository is not initialized or is deleted. Please create it."))
59
+ return
60
+ }
61
+
62
+ const repoPath = path.join(process.cwd(),".jvcs")
63
+ const staging = path.join(repoPath,"staging")
64
+
65
+ if(!fssync.existsSync(staging))
66
+ fssync.mkdirSync(staging, {recursive: true})
67
+
68
+ const hashPath = path.join(staging,"jvcs_hashcode.json")
69
+ let hashData = {}
70
+
71
+ if(fssync.existsSync(hashPath)) {
72
+ hashData = JSON.parse(await fs.readFile(hashPath,"utf-8"))
73
+ }
74
+
75
+ let targets = []
76
+ if(paths.length === 1 && paths[0] === ".") {
77
+ targets = await fs.readdir(process.cwd(),{withFileTypes: true})
78
+ targets = targets.filter((target)=> target.name !== ".jvcs").map((item)=> path.resolve(process.cwd(),item.name))
79
+ }
80
+ else {
81
+ targets = paths.map((p)=> path.resolve(process.cwd(),p))
82
+ }
83
+
84
+ // copying the files and folders to staging area
85
+ for(const target of targets) {
86
+
87
+ try {
88
+
89
+ if(!fssync.existsSync(target)) {
90
+ console.log(chalk.red(`Path not found: ${target}`))
91
+ continue
92
+ }
93
+
94
+ const destination = path.join(staging,path.relative(process.cwd(),target))
95
+ await fs.mkdir(path.dirname(destination), {recursive: true})
96
+
97
+ const stats = await fs.stat(target)
98
+
99
+ if(stats.isFile()) {
100
+ await fs.copyFile(target,destination)
101
+ const hash = await getFileHash(target)
102
+ hashData[path.relative(process.cwd(),target)] = {
103
+ hash,
104
+ time: new Date().toISOString(),
105
+ }
106
+ console.log(chalk.green(`Added file: ${path.relative(process.cwd(), target)}`));
107
+ }
108
+ else if(stats.isDirectory()) {
109
+ await fs.cp(target,destination,{recursive: true})
110
+ await hashDirectoryRecursive(target,hashData)
111
+ console.log(chalk.cyan(`Added folder: ${path.relative(process.cwd(), target)}`));
112
+ }
113
+ }
114
+ catch(error) {
115
+ console.log(chalk.red(`Unexpected error: ${error.message}`));
116
+ }
117
+ }
118
+
119
+ await fs.writeFile(hashPath, JSON.stringify(hashData, null, 2));
120
+ }
121
+
122
+ module.exports = addCmd