greptile 1.0.6 → 2.1.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/bin/index.js DELETED
@@ -1,940 +0,0 @@
1
- #!/usr/bin/env node
2
- const yargs = require("yargs");
3
- const fs = require('fs');
4
- const path = require('path');
5
- // const configPath = 'config.json';
6
- const currentDirectory = __dirname;
7
- const configPath = path.join(currentDirectory, 'config.json');
8
- const sessionPath = path.join(currentDirectory, 'session.json');
9
- const fetch = require('node-fetch');
10
- const { Base64 } = require('js-base64');
11
- const open = require('open');
12
- const readline = require('readline');
13
- const clipboardy = require('clipboardy');
14
- const ora = require('ora');
15
- const spinner = ora();
16
- const exec = require('child_process').exec;
17
- // GitHub credentials
18
- let clientId = '3b18d3e6e037d70908ac';
19
-
20
- clientId = 'Iv1.1bfb3337c164d452'
21
- // clientId = '42a2bd08980b5a89a820'
22
- let firstTime = true;
23
- const scope = 'read:user user:email';
24
- const githubEndpoint = 'https://github.com/login/device/code';
25
- let access_token = null;
26
- const { promisify } = require('util');
27
- const setTimeoutPromise = promisify(setTimeout);
28
- const debugMode = false;
29
- const payloadFilePath = path.resolve(__dirname, 'payload.json');
30
-
31
- const executeAuthCommand = async () => {
32
- if (!isAuthenticated()) {
33
- console.log("Redirecting to GitHub authentication...");
34
- let deviceCode;
35
- let userCode;
36
- const pollingInterval = 10000;
37
- let intervalId;
38
-
39
- const initiateDeviceAuthorization = async () => {
40
- try {
41
- const response = await fetch(githubEndpoint, {
42
- method: 'POST',
43
- headers: {
44
- 'Content-Type': 'application/json',
45
- 'Accept': 'application/json'
46
- },
47
- body: JSON.stringify({ client_id: clientId, scope: scope })
48
- });
49
- const data = await response.json();
50
-
51
- // console.log('Response:', data);
52
-
53
- deviceCode = data.device_code;
54
- userCode = data.user_code;
55
-
56
- console.log(`Please go to ${data.verification_uri} and enter the code: ${userCode}`);
57
- clipboardy.writeSync(userCode);
58
- await setTimeoutPromise(3000);
59
- await open(data.verification_uri);
60
- intervalId = setInterval(checkAuthorization, pollingInterval);
61
- } catch (error) {
62
- if (debugMode) { console.log("Error:", error); }
63
- }
64
- };
65
-
66
- const checkAuthorization = async () => {
67
- try {
68
- const response = await fetch('https://github.com/login/oauth/access_token', {
69
- method: 'POST',
70
- headers: {
71
- 'Content-Type': 'application/json',
72
- 'Accept': 'application/json'
73
- },
74
- body: JSON.stringify({
75
- client_id: clientId,
76
- device_code: deviceCode,
77
- grant_type: 'urn:ietf:params:oauth:grant-type:device_code'
78
- })
79
- });
80
-
81
- const data = await response.json();
82
-
83
- if (data.access_token) {
84
- clearInterval(intervalId);
85
- access_token = data.access_token;
86
- writeConfig(access_token);
87
- spinner.succeed('Authorization successful');
88
- process.exit(0);
89
- } else if (data.error && data.error === 'authorization_pending') {
90
- if (firstTime) {
91
- spinner.start('Authorization pending');
92
- firstTime = false;
93
- }
94
- } else {
95
- clearInterval(intervalId);
96
- spinner.fail('Authorization failed or expired:', data.error_description)
97
- process.exit(1);
98
- }
99
- } catch (error) {
100
- if (debugMode) {
101
- console.error('Error:', error);
102
- }
103
- }
104
- };
105
-
106
- await initiateDeviceAuthorization();
107
-
108
-
109
- } else {
110
- console.log("You are already authenticated");
111
- process.exit(0);
112
- }
113
- };
114
-
115
- // Command line options and commands
116
- const usage = "\nUsage: greptile <command>";
117
- const options = yargs
118
- .usage(usage)
119
- .command("help", "Display help information")
120
- .command("add <repository>", "Add a repository to the session")
121
- .command("list", "List repositories in the current session")
122
- .command("remove <repository>", "Remove a repository from the session")
123
- .command("start", "Start Greptile application")
124
- .command("auth", "Redirect to GitHub authentication")
125
- .command("addPath", "Adds greptie to your Path")
126
- .demandCommand(1, "Please specify a command.")
127
- .help(true)
128
- .argv;
129
-
130
- // Command execution based on user input
131
- async function main() {
132
- if (!fs.existsSync(configPath)) {
133
- const defaultConfig = {
134
- github: {
135
- access_token: null,
136
- },
137
- };
138
- fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2), 'utf-8');
139
- }
140
-
141
- // Check if session.json exists, create with default content if not
142
- if (!fs.existsSync(sessionPath)) {
143
- const defaultSession = {
144
- repositories: [],
145
- };
146
- fs.writeFileSync(sessionPath, JSON.stringify(defaultSession, null, 2), 'utf-8');
147
- }
148
-
149
- // Check if payload.json exists, create with default content if not
150
- if (!fs.existsSync(payloadFilePath)) {
151
- const defaultPayload = {
152
- messages: [],
153
- repositories: [],
154
- sessionId: '',
155
- user: {
156
- email: '',
157
- token: {
158
- github: '',
159
- },
160
- },
161
- };
162
- fs.writeFileSync(payloadFilePath, JSON.stringify(defaultPayload, null, 2), 'utf-8');
163
- }
164
-
165
- const command = options._[0];
166
- switch (command) {
167
-
168
- case "addPath":
169
- addToPath()
170
- break;
171
-
172
- case "add":
173
- await executeAddCommand(options.repository);
174
- process.exit();
175
- break;
176
-
177
- case "help":
178
- executeHelpCommand();
179
- process.exit();
180
- break;
181
-
182
- case "start":
183
- async function runLoop() {
184
- let isDone = false;
185
- while (!isDone) {
186
-
187
- let userQuestion = await getUserQuestion();
188
- if (userQuestion === "exit") {
189
- isDone = true;
190
- } else {
191
- if (hasNoRepositories()) {
192
- console.log("Please first add repositories to the session using greptile add <repo_link>")
193
- process.exit(-1)
194
-
195
- }
196
- else {
197
- await executeStartCommand(userQuestion);
198
- }
199
-
200
- }
201
- }
202
- }
203
- runLoop();
204
- break;
205
-
206
- case "auth":
207
- executeAuthCommand();
208
-
209
- break;
210
-
211
- case "list":
212
- executeListCommand();
213
- process.exit();
214
- break;
215
-
216
- case "remove":
217
- executeRemoveCommand(options.repository);
218
- process.exit();
219
- break;
220
-
221
- default:
222
- console.error("Invalid command. Use 'greptile help' for assistance.");
223
- process.exit();
224
- break;
225
-
226
- }
227
- }
228
-
229
- function executeHelpCommand() {
230
- console.log("Executing help command...");
231
- }
232
-
233
- async function executeAddCommand(repositoryLink) {
234
- if (!isAuthenticated()) {
235
- console.error("Error: Please authenticate with GitHub first. Use 'greptile auth' to authenticate.");
236
- process.exit(1);
237
- } else {
238
- if (!repositoryLink) {
239
- console.error("Error: Please provide a repository name. Example: greptile add owner/repository");
240
- process.exit(1);
241
- }
242
-
243
- // Load existing session data
244
- let sessionData;
245
- try {
246
- const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
247
- sessionData = JSON.parse(sessionFile);
248
- } catch (error) {
249
- if (debugMode) {
250
- console.log(error)
251
- }
252
- // If the file doesn't exist or has invalid JSON, start with an empty session
253
- sessionData = {
254
- repositories: []
255
- };
256
- }
257
- // Add the new repository to the session
258
- const parsedRepo = parseIdentifier(repositoryLink)
259
- try {
260
- repository = parsedRepo.repository;
261
- remote = parsedRepo.remote;
262
- branch = parsedRepo.branch || await getDefaultBranch(remote, repository);
263
- }
264
- catch (error) {
265
- console.log("There was an error processing the repository link. Please check your repository link again")
266
- process.exit(-1)
267
- }
268
- if (typeof repository === 'undefined') {
269
- console.log("Error: Invalid repository name. Enter github link, e.g. https://github.com/facebook/react")
270
- process.exit(-1)
271
- }
272
- const repoInfo = await getRepoInfo(repository, remote, branch);
273
-
274
- try {
275
- if (debugMode) {
276
- console.log(repoInfo)
277
- }
278
-
279
- if (repoInfo.responses[0]) {
280
- await writeRepoToFile(repositoryLink);
281
- }
282
- else {
283
- // Check whether this is supposed to be here
284
- if (repoInfo.failed[0] && repoInfo.failed[0].repository == repository) {
285
- if (repoInfo.failed[0].statusCode === 400) {
286
- console.log(`Error ${repoInfo.failed[0].statusCode}: Bad Request`);
287
- } else if (repoInfo.failed[0].statusCode === 401) {
288
- console.log(`Error ${repoInfo.failed[0].statusCode}: Unauthorized`);
289
- } else if (repoInfo.failed[0].statusCode === 404) {
290
- if (repoInfo.failed[0].message && repoInfo.failed[0].message == "Repository not processed by Greptile.") {
291
- await writeRepoToFile(repositoryLink);
292
- const processRepo = await getRepo(repository);
293
- if (debugMode) {
294
- console.log(processRepo)
295
- }
296
- }
297
- else {
298
- console.log(`Error ${repoInfo.failed[0].statusCode}: Not Found`);
299
- }
300
- } else if (repoInfo.failed[0].statusCode === 500) {
301
- console.log(`Error ${repoInfo.failed[0].statusCode}: Internal Server Error`);
302
- } else {
303
- console.log(`Error ${repoInfo.failed[0].statusCode}: Unhandled Status Code`);
304
- }
305
- process.exit(1)
306
- }
307
- await getRepo(repository);
308
- }
309
- } catch (error) {
310
- if (debugMode) { console.error(error) }
311
- if (repoInfo.failed[0] && repoInfo.failed[0].repository == repository) {
312
- if (repoInfo.failed[0].statusCode === 400) {
313
- console.log(`Error ${repoInfo.failed[0].statusCode}: Bad Request`);
314
- } else if (repoInfo.failed[0].statusCode === 401) {
315
- console.log(`Error ${repoInfo.failed[0].statusCode}: Unauthorized`);
316
- } else if (repoInfo.failed[0].statusCode === 404) {
317
- if (repoInfo.failed[0].message && repoInfo.failed[0].message == "Repository not processed by Greptile.") {
318
- await writeRepoToFile(repositoryLink);
319
- const processRepo = await getRepo(repository);
320
- if (debugMode) { console.log(processRepo) }
321
- }
322
- else {
323
- console.log(`Error ${repoInfo.failed[0].statusCode}: Not Found`);
324
- }
325
- } else if (repoInfo.failed[0].statusCode === 500) {
326
- console.log(`Error ${repoInfo.failed[0].statusCode}: Internal Server Error`);
327
- } else {
328
- console.log(`Error ${repoInfo.failed[0].statusCode}: Unhandled Status Code`);
329
- }
330
- process.exit(1)
331
- }
332
- }
333
- // console.log(response)
334
- // Write the updated session data back to the file
335
- }
336
- }
337
-
338
- async function writeRepoToFile(repositoryLink) {
339
- let sessionData;
340
- try {
341
- const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
342
- sessionData = JSON.parse(sessionFile);
343
- } catch (error) {
344
- // If the file doesn't exist or has invalid JSON, start with an empty session
345
- sessionData = {
346
- repositories: []
347
- };
348
- }
349
-
350
- // Check if the repository link already exists
351
- if (!sessionData.repositories.includes(repositoryLink)) {
352
- try {
353
- sessionData.repositories.push(repositoryLink);
354
- const sessionFile = JSON.stringify(sessionData, null, 2);
355
- fs.writeFileSync(sessionPath, sessionFile, 'utf-8');
356
- console.log(`Repository '${repositoryLink}' added to the session.`);
357
-
358
- // Update payload.json with the new session data
359
- const payload = await createPayload2("", createSessionId());
360
- writePayloadToFile(payload);
361
-
362
- } catch (error) {
363
- console.error('Error writing session data to file:', error);
364
- }
365
- } else {
366
- console.log(`Repository '${repositoryLink}' already exists in the session.`);
367
- }
368
- }
369
-
370
- function executeListCommand() {
371
- if (!isAuthenticated()) {
372
- console.error("Error: Please authenticate with GitHub first. Use 'greptile auth' to authenticate.");
373
- process.exit(1);
374
- } else {
375
- // Load existing session data
376
- let sessionData;
377
- try {
378
- const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
379
- sessionData = JSON.parse(sessionFile);
380
- } catch (error) {
381
- // If the file doesn't exist or has invalid JSON, start with an empty session
382
- sessionData = {
383
- repositories: []
384
- };
385
- }
386
-
387
- // Display the list of repositories in the current session
388
- const repositories = sessionData.repositories;
389
- if (repositories.length === 0) {
390
- console.log("No repositories in the current session.");
391
- } else {
392
- console.log("Repositories in the current session:");
393
- repositories.forEach((repoLink, index) => {
394
- const repo = parseIdentifier(repoLink).repository;
395
- console.log(`${index + 1}. ${repo}`);
396
- });
397
- }
398
- }
399
- }
400
-
401
- function executeRemoveCommand(repository) {
402
- if (!isAuthenticated()) {
403
- console.error("Error: Please authenticate with GitHub first. Use 'greptile auth' to authenticate.");
404
- process.exit(1);
405
- } else {
406
- if (!repository) {
407
- console.error("Error: Please provide a repository name. Example: greptile remove owner/repository or https://github.com/facebook/react");
408
- process.exit(1);
409
- }
410
-
411
- // Load existing session data
412
- let sessionData;
413
- try {
414
- const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
415
- sessionData = JSON.parse(sessionFile);
416
- } catch (error) {
417
- // If the file doesn't exist or has invalid JSON, start with an empty session
418
- sessionData = {
419
- repositories: []
420
- };
421
- }
422
-
423
- // Check if the repository exists in the session
424
- const index = sessionData.repositories.findIndex((repo) => repo.includes(repository));
425
- if (index === -1) {
426
- console.log(`Repository '${repository}' not found in the current session.`);
427
- } else {
428
- // Remove the repository from the session
429
- sessionData.repositories.splice(index, 1);
430
-
431
- // Write the updated session data back to the file
432
- try {
433
- const sessionFile = JSON.stringify(sessionData, null, 2);
434
- fs.writeFileSync(sessionPath, sessionFile, 'utf-8');
435
- console.log(`Repository '${repository}' removed from the session.`);
436
- } catch (error) {
437
- if (debugMode) {
438
- console.error('Error writing session data to file:', error);
439
- }
440
- }
441
- }
442
- }
443
- }
444
- // Function to execute the start command
445
- // Inside executeStartCommand function
446
- async function executeStartCommand(userQuestion) {
447
- try {
448
- if (!isAuthenticated()) {
449
- console.error("Error: Please authenticate with GitHub first. Use 'greptile auth' to authenticate.");
450
- process.exit(1);
451
- } else {
452
-
453
- await useChatApi(userQuestion);
454
- }
455
- }
456
-
457
- catch (error) {
458
- if (debugMode) {
459
- console.log(error)
460
- }
461
- process.exit(-1)
462
-
463
- }
464
- }
465
-
466
- async function getUserQuestion() {
467
- const rl = readline.createInterface({
468
- input: process.stdin,
469
- output: process.stdout
470
- });
471
- function getActualQuestion() {
472
- return new Promise((resolve) => {
473
- rl.question('\n\n Question: (Hint: Type "exit" to exit) ', (answer) => {
474
- resolve(answer);
475
- });
476
-
477
- });
478
- }
479
- const userQuestion = await getActualQuestion();
480
- rl.close();
481
- return userQuestion;
482
-
483
-
484
- }
485
- async function getRepo(repo, branch = "main", remote = "github") {
486
- try {
487
- const body = JSON.stringify({
488
- "remote": remote, // one of "github", "gitlab" for now
489
- "repository": repo, // formatted as owner/repository
490
- // "branch": "main", // optional, defaults to repo default on GH/GL
491
- // "reload": true, // optional, if false will not reprocess if previously successful, default true
492
- // "notify": true // optional, whether to notify the user when finished, default true
493
- })
494
- const repoInfo = await fetch("https://api.greptile.com/v1/repositories", {
495
- method: "POST",
496
- body: body,
497
- headers: {
498
- "Content-Type": "application/json",
499
- "Authorization": "Bearer " + getAccessToken()
500
- },
501
- });
502
-
503
- const repoInfoJson = await repoInfo.json();
504
- return repoInfoJson;
505
- } catch (error) {
506
- if (debugMode) {
507
- console.log("Error:", error);
508
- }
509
- return null;
510
- }
511
- }
512
-
513
- async function getRepoInfo(repo, remote, branch) {
514
- // console.log("Called getRepoInfo with:", repo, remote, branch)
515
- const repoInfo = await fetch('https://api.greptile.com/v1/repositories/batch?repositories=' + getBase64(remote, repo, branch), {
516
- method: "GET",
517
- headers: {
518
- "Content-Type": "application/json",
519
- "Authorization": "Bearer " + getAccessToken()
520
- },
521
- });
522
-
523
- const repoInfoJson = await repoInfo.json();
524
-
525
- return repoInfoJson;
526
- }
527
-
528
- async function useChatApi(userQuestion) {
529
- const session_id = createSessionId();
530
- // userQuestion = "What does this repo do?"
531
- // repository = 'onboardai/onboard-vscode'
532
- // branch = 'main'
533
- let payload = readPayloadFromFile();
534
-
535
- // If the payload is empty, create a new payload with the user's question
536
- if (payload.messages.length === 0) {
537
- if (debugMode) {
538
- console.log("Payload is Empty, creating new Payload")
539
- }
540
- payload = await createPayload2(userQuestion, session_id);
541
- } else {
542
- if (debugMode) {
543
- console.log("Appending user Message to Payload")
544
- }
545
- // If the payload already has messages, append the user's new question
546
- payload = appendMessageToPayload(payload, userQuestion);
547
- }
548
- if (debugMode) {
549
- console.log(payload)
550
- }
551
-
552
- try {
553
- const response = await fetch("https://api.greptile.com/v1/query", {
554
- method: 'POST',
555
- headers: {
556
- 'Content-Type': 'application/json',
557
- "Authorization": "Bearer " + getAccessToken()
558
- },
559
- body: JSON.stringify(payload),
560
- })
561
- if (debugMode) {
562
- console.log("Response: ", response)
563
- }
564
-
565
- let buffer = '';
566
- decoder = new TextDecoder();
567
- fullResponse = ""
568
- for await (const chunk of response.body) {
569
- const chunkText = decoder.decode(chunk);
570
- // console.log(chunkText)
571
- buffer += chunkText;
572
- const lines = buffer.split(/\r?\n/);
573
- for (let i = 0; i < lines.length - 1; i++) {
574
- const line = lines[i].trim();
575
-
576
- if (line.length > 0) {
577
- try {
578
- const jsonData = JSON.parse(line);
579
- // console.log('JSONDATA: ',jsonData)
580
- if (jsonData.type == "status") {
581
- if (jsonData.message == '') {
582
- // console.log(" d :, ", fullResponse)
583
- appendMessageToPayload(payload, fullResponse);
584
- // process.exit(0)
585
- }
586
- console.log(jsonData.message)
587
- if (jsonData.message == "Started processing request") {
588
- spinner.start();
589
- }
590
- if (jsonData.message == "Writing response") {
591
- spinner.succeed('Request processed successfully');
592
- }
593
-
594
- }
595
- else {
596
- if (typeof jsonData.message === 'string') {
597
- fullResponse += jsonData.message;
598
- }
599
- process.stdout.write(jsonData.message)
600
- }
601
- } catch (error) {
602
- // console.error('Error parsing JSON:', error);
603
- }
604
- }
605
- }
606
-
607
- buffer = lines[lines.length - 1];
608
- }
609
-
610
-
611
- } catch (error) {
612
-
613
- if (debugMode) {
614
- console.error('Error:', error.message);
615
- }
616
- // Handle errors here
617
- }
618
- }
619
-
620
- function isAuthenticated() {
621
- try {
622
- const configFile = fs.readFileSync(configPath, 'utf-8');
623
- const configFileData = JSON.parse(configFile)
624
-
625
- if (configFileData.github.access_token != null) {
626
- access_token = configFileData.github.access_token
627
- return true;
628
- }
629
- else {
630
- return false;
631
- }
632
- } catch (error) {
633
- if (debugMode) {
634
- console.log(error)
635
- }
636
- return {};
637
- }
638
- }
639
-
640
- function getAccessToken() {
641
- try {
642
- const configFile = fs.readFileSync(configPath, 'utf-8');
643
- const configFileData = JSON.parse(configFile)
644
-
645
- if (configFileData.github.access_token != null) {
646
- access_token = configFileData.github.access_token
647
- return access_token;
648
- }
649
- else {
650
- return null;
651
- }
652
- } catch (error) {
653
- if (debugMode) {
654
- console.log(error)
655
- }
656
- return {};
657
- }
658
- }
659
-
660
- async function getDefaultBranch(remote, repository) {
661
- // console.log("Called getDefaultBranch with:", remote, repository)
662
-
663
- const token = getAccessToken();
664
- const url = remote === "github" ? `https://api.github.com/repos/${repository}`
665
- // TODO: Add full support for other remotes
666
- // : remote === "gitlab" ? `https://gitlab.com/api/v4/projects/${repository}`
667
- // : remote === "bitbucket" ? `https://api.bitbucket.org/2.0/repositories/${repository}`
668
- // : remote === "azure" ? `https://dev.azure.com/${repository}/_apis/git/repositories`
669
- // : remote === "visualstudio" ? `https://dev.azure.com/${repository}/_apis/git/repositories`
670
- : null;
671
-
672
- if (!url) return "main";
673
-
674
- try {
675
- const data = await fetch(url, {
676
- headers: {
677
- Authorization: `Bearer ${token}`,
678
- },
679
- }).then((response) => {
680
- return response.json();
681
- });
682
- return data.default_branch;
683
- } catch (error) {
684
- if (debugMode) {
685
- console.error('Error:', error);
686
- }
687
- return "main";
688
- }
689
- }
690
-
691
- function writeConfig(access__token) {
692
- // Create and write to the file
693
- const config = {
694
- "github": {
695
- "access_token": access__token
696
- }
697
- };
698
- const configFile = JSON.stringify(config, null, 2);
699
-
700
- try {
701
- fs.writeFileSync(configPath, configFile, 'utf-8');
702
- if (debugMode) {
703
- console.log('File written successfully');
704
- }
705
- } catch (err) {
706
- if (debugMode) {
707
- console.error('Error writing to the file:', err);
708
- }
709
- }
710
- }
711
-
712
- function getBase64(remote, repository, branch) {
713
- let repo = remote + ":" + repository + ":" + branch;
714
- if (debugMode) {
715
- console.log(repo)
716
- }
717
- return (Base64.encode(repo))
718
- }
719
-
720
- function createSessionId() {
721
- return Math.random().toString(36).substring(2, 15) +
722
- Math.random().toString(36).substring(2, 15);
723
- }
724
-
725
- async function createPayload2(userQuestion, session_id, remote = "github", branch = "main", external = false) {
726
- // Load existing session data
727
- let sessionData;
728
- try {
729
- const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
730
- sessionData = JSON.parse(sessionFile);
731
- } catch (error) {
732
- // If the file doesn't exist or has invalid JSON, start with an empty session
733
- sessionData = {
734
- repositories: []
735
- };
736
- }
737
-
738
- const payload = {
739
- messages: [
740
- {
741
- id: '1',
742
- role: "user",
743
- content: userQuestion
744
- }
745
- ],
746
- repositories: await Promise.all(sessionData.repositories.map(async (repo) => {
747
- const parsedRepo = parseIdentifier(repo);
748
- return {
749
- remote: parsedRepo.remote,
750
- name: parsedRepo.repository,
751
- branch: parsedRepo.branch || await getDefaultBranch(parsedRepo.remote, parsedRepo.repository),
752
- name: parsedRepo.repository,
753
- external: external,
754
- };
755
- })),
756
- sessionId: session_id,
757
- }
758
-
759
- return payload;
760
- }
761
-
762
- function readPayloadFromFile() {
763
- try {
764
- const payloadFile = fs.readFileSync(payloadFilePath, 'utf-8');
765
- const payload = JSON.parse(payloadFile);
766
-
767
- return payload;
768
- } catch (error) {
769
- // If the file doesn't exist or has invalid JSON, return an empty payload
770
- return {
771
- messages: [],
772
- repositories: [],
773
- sessionId: '',
774
- user: {
775
- email: '',
776
- token: {
777
- github: '',
778
- },
779
- },
780
- };
781
- }
782
- }
783
-
784
- function writePayloadToFile(payload) {
785
- try {
786
- const payloadFile = JSON.stringify(payload, null, 2);
787
- fs.writeFileSync(payloadFilePath, payloadFile, 'utf-8');
788
- } catch (error) {
789
- if (debugMode) {
790
- console.error('Error writing payload to file:', error);
791
- }
792
- }
793
- }
794
-
795
- function appendMessageToPayload(payload, content) {
796
- payload.messages.push({
797
- id: (payload.messages.length + 1).toString(),
798
- role: 'user',
799
- content: content,
800
- });
801
- writePayloadToFile(payload);
802
- return payload;
803
- }
804
-
805
- function hasNoRepositories() {
806
- try {
807
- const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
808
- const sessionData = JSON.parse(sessionFile);
809
- if (debugMode) {
810
- console.log(sessionData.repositories.length)
811
- }
812
- return sessionData.repositories.length === 0;
813
- } catch (error) {
814
- if (debugMode) {
815
- console.log(error)
816
- }
817
- // If the file doesn't exist or has invalid JSON, return true (no repositories)
818
- return true;
819
- }
820
- }
821
-
822
- function parseIdentifier(input) {
823
- if (!isDomain(input)) {
824
- const regex = /^(([^:]*):([^:]*):|[^:]*)([^:]*)$/;
825
- const match = input.match(regex);
826
- if (!match) return null;
827
- const keys = input.split(":");
828
- if (keys.length === 1)
829
- return {
830
- remote: "github",
831
- branch: "",
832
- repository: keys[0],
833
- };
834
- if (keys.length === 3) {
835
- let remote = keys[0],
836
- branch = keys[1],
837
- repository = keys[2];
838
- if (remote === "azure" && repository.split("/").length == 2) {
839
- let repository_list = repository.split("/");
840
- repository_list.push(repository_list[1]);
841
- repository = repository_list.join("/");
842
- }
843
- return {
844
- remote: remote,
845
- branch: branch,
846
- repository: repository,
847
- };
848
- }
849
- return null; // only 2 entries may be ambiguous (1 might be as well...)
850
- }
851
- if (!input.startsWith("http")) input = "https://" + input;
852
- if (input.endsWith(".git")) input = input.slice(0, -4);
853
- try {
854
- const url = new URL(input);
855
- let remote = (() => {
856
- try {
857
- const services = ["github", "gitlab", "bitbucket", "azure", "visualstudio"];
858
- return (services.find((service) => url.hostname.includes(service)) || null)
859
- } catch (e) {
860
- return null;
861
- }
862
- })();
863
- if (!remote) return null;
864
- let repository, branch, regex, match;
865
- switch (remote) {
866
- case "github":
867
- regex =
868
- /([a-zA-Z0-9\._-]+\/[a-zA-Z0-9\%\._-]+)[\/tree\/]*([a-zA-Z0-0\._-]+)?/;
869
- match = url.pathname.match(regex);
870
- repository = decodeURIComponent(match?.[1] || "");
871
- branch = match?.[2];
872
- break;
873
- case "gitlab":
874
- regex =
875
- /([a-zA-Z0-9\._-]+\/[a-zA-Z0-9\%\._-]+)(?:\/\-)?(?:(?:\/tree\/)([a-zA-Z0-0\._-]+))?/;
876
- match = url.pathname.match(regex);
877
- repository = decodeURIComponent(match?.[1] || "");
878
- branch = match?.[2];
879
- break;
880
-
881
- case "azure":
882
- regex = /([a-zA-Z0-9\%\.\/_-]+)/;
883
- match = url.pathname.match(regex);
884
- repository =
885
- match?.[1].split("/").filter((x) => x !== "_git" && x !== "") || [];
886
- repository.push(repository?.slice(-1)[0]);
887
- repository = decodeURIComponent(repository.slice(0, 3).join("/"));
888
- branch = url.searchParams.get("version")?.slice(2); // remove 'GB' from the beginning
889
- break;
890
-
891
- case "visualstudio":
892
- remote = "azure"
893
- regex = /([a-zA-Z0-9\%\.\/_-]+)/;
894
- const org = url.hostname.split(".")[0];
895
- match = url.pathname.match(regex);
896
- repository =
897
- match?.[1].split("/").filter((x) => x !== "_git" && x !== "") || [];
898
- repository = decodeURIComponent([org, ...(repository.slice(0, 2))].join("/"));
899
- branch = url.searchParams.get("version")?.slice(2); // remove 'GB' from the beginning
900
- break;
901
- default:
902
- return url.hostname;
903
- }
904
- if (!repository) return null;
905
- // console.log(remote,branch,repository)
906
- return { remote, branch, repository };
907
- } catch (e) {
908
- return null;
909
- }
910
- };
911
-
912
- function isDomain(input) {
913
- try {
914
- new URL(input);
915
- const regex = /^(([^:]*):([^:]*):|[^:]*)([^:]*)$/;
916
- const match = input.match(regex);
917
- if (match) return false;
918
- return true;
919
- } catch (e) {
920
- return false;
921
- }
922
- }
923
-
924
- function addToPath() {
925
- // Execute the Bash script
926
- bashFile = path.join(currentDirectory.replace("/bin", "") + "/addToPath.sh")
927
- exec(bashFile, (error, stdout, stderr) => {
928
- if (error) {
929
- console.error(`Error: ${error.message}`);
930
- return;
931
- }
932
- if (stderr) {
933
- console.error(`Error: ${stderr}`);
934
- return;
935
- }
936
- console.log(stdout);
937
- });
938
- }
939
-
940
- main()