greptile 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.
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # Greptile CLI
2
+
3
+ Greptile is a Command Line Interface (CLI) tool for managing and interacting with multiple repositories through a chat-based interface. This tool facilitates the process of querying information, asking questions, and managing tasks across various code repositories.
4
+
5
+ ## How to Download
6
+
7
+ To use Greptile, you need to have Node.js installed on your machine. You can download and install Node.js from [here](https://nodejs.org/).
8
+
9
+ Once Node.js is installed, you can download Greptile by cloning the repository:
10
+
11
+ ```bash
12
+ git clone https://github.com/dhruv317/greptile.git
13
+ ```
14
+
15
+ Navigate to the Greptile directory:
16
+
17
+ ```bash
18
+ cd greptile
19
+ ```
20
+
21
+ Install the required dependencies:
22
+
23
+ ```bash
24
+ npm install
25
+ ```
26
+
27
+ ## How to Run
28
+
29
+ You can run Greptile using the following commands:
30
+
31
+ ### Authentication
32
+
33
+ To authenticate with GitHub, use the following command:
34
+
35
+ ```bash
36
+ greptile auth
37
+ ```
38
+
39
+ ### Adding a Repository
40
+
41
+ To add a repository to the session, use the following command:
42
+
43
+ ```bash
44
+ greptile add <repository_link>
45
+ ```
46
+
47
+ Replace `<repository_link>` with the GitHub repository you want to add.
48
+
49
+ ### Listing Repositories
50
+
51
+ To list repositories in the current session, use the following command:
52
+
53
+ ```bash
54
+ greptile list
55
+ ```
56
+
57
+ ### Removing a Repository
58
+
59
+ To remove a repository from the session, use the following command:
60
+
61
+ ```bash
62
+ greptile remove <repository_link>
63
+ ```
64
+
65
+ Replace `<repository_link>` with the GitHub repository you want to remove.
66
+
67
+ ### Starting Greptile
68
+
69
+ To start the Greptile application and interact with the repositories, use the following command:
70
+
71
+ ```bash
72
+ greptile start
73
+ ```
74
+
75
+ Follow the prompts to ask questions and retrieve information from the added repositories.
76
+
77
+ ### Help
78
+
79
+ To display help information, use the following command:
80
+
81
+ ```bash
82
+ greptile help
83
+ ```
84
+ Note: The commands assume you are in the Greptile directory. If you want to use the commands globally, you may need to install Greptile globally or add it to your system's PATH.
85
+
86
+ Feel free to explore and interact with Greptile to manage your repositories efficiently!
package/addToPath.sh ADDED
@@ -0,0 +1,13 @@
1
+ #!/bin/bash
2
+
3
+ # Get the current directory
4
+ CURRENT_DIR=$(dirname "$(readlink -f "$0")")
5
+
6
+ # Check if the current directory is already in the PATH
7
+ if [[ ":$PATH:" == *":$CURRENT_DIR:"* ]]; then
8
+ echo "Current directory '$CURRENT_DIR' is already in the PATH."
9
+ else
10
+ # Add the current directory to the PATH in ~/.bashrc
11
+ echo "export PATH=$CURRENT_DIR:\$PATH" >> ~/.bashrc
12
+ echo "Current directory '$CURRENT_DIR' added to the PATH in ~/.bashrc. Changes will take effect after restarting the terminal."
13
+ fi
@@ -0,0 +1,5 @@
1
+ {
2
+ "github": {
3
+ "access_token": "ghu_HCWM0szjQI621vSzHbq3K2qSr3hhrH1MS8GJ"
4
+ }
5
+ }
package/bin/index.js ADDED
@@ -0,0 +1,988 @@
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 { debug } = require("console");
28
+ const setTimeoutPromise = promisify(setTimeout);
29
+ const debugMode = false;
30
+ const payloadFilePath = path.resolve(__dirname, 'payload.json');
31
+ var shell = require('shelljs');
32
+
33
+
34
+ const executeAuthCommand = async () => {
35
+ if (!isAuthenticated()) {
36
+ console.log("Redirecting to GitHub authentication...");
37
+ let deviceCode;
38
+ let userCode;
39
+ const pollingInterval = 10000;
40
+ let intervalId;
41
+
42
+ const initiateDeviceAuthorization = async () => {
43
+ try {
44
+ const response = await fetch(githubEndpoint, {
45
+ method: 'POST',
46
+ headers: {
47
+ 'Content-Type': 'application/json',
48
+ 'Accept': 'application/json'
49
+ },
50
+ body: JSON.stringify({ client_id: clientId, scope: scope })
51
+ });
52
+ const data = await response.json();
53
+
54
+ // console.log('Response:', data);
55
+
56
+ deviceCode = data.device_code;
57
+ userCode = data.user_code;
58
+
59
+ console.log(`Please go to ${data.verification_uri} and enter the code: ${userCode}`);
60
+ clipboardy.writeSync(userCode);
61
+ await setTimeoutPromise(3000);
62
+ await open(data.verification_uri);
63
+ intervalId = setInterval(checkAuthorization, pollingInterval);
64
+ } catch (error) {
65
+ if (debugMode) { console.log("Error:", error); }
66
+ }
67
+ };
68
+
69
+ const checkAuthorization = async () => {
70
+ try {
71
+ const response = await fetch('https://github.com/login/oauth/access_token', {
72
+ method: 'POST',
73
+ headers: {
74
+ 'Content-Type': 'application/json',
75
+ 'Accept': 'application/json'
76
+ },
77
+ body: JSON.stringify({
78
+ client_id: clientId,
79
+ device_code: deviceCode,
80
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code'
81
+ })
82
+ });
83
+
84
+ const data = await response.json();
85
+
86
+ if (data.access_token) {
87
+ clearInterval(intervalId);
88
+ access_token = data.access_token;
89
+ writeConfig(access_token);
90
+ spinner.succeed('Authorization successful');
91
+ process.exit(0);
92
+ } else if (data.error && data.error === 'authorization_pending') {
93
+ if (firstTime) {
94
+ spinner.start('Authorization pending');
95
+ firstTime = false;
96
+ }
97
+ } else {
98
+ clearInterval(intervalId);
99
+ spinner.fail('Authorization failed or expired:', data.error_description)
100
+ process.exit(1);
101
+ }
102
+ } catch (error) {
103
+ if (debugMode) {
104
+ console.error('Error:', error);
105
+ }
106
+ }
107
+ };
108
+
109
+ await initiateDeviceAuthorization();
110
+
111
+
112
+ } else {
113
+ console.log("You are already authenticated");
114
+ process.exit(0);
115
+ }
116
+ };
117
+
118
+ // Command line options and commands
119
+ const usage = "\nUsage: greptile <command>";
120
+ const options = yargs
121
+ .usage(usage)
122
+ .command("help", "Display help information")
123
+ .command("add <repository>", "Add a repository to the session")
124
+ .command("list", "List repositories in the current session")
125
+ .command("remove <repository>", "Remove a repository from the session")
126
+ .command("start", "Start Greptile application")
127
+ .command("auth", "Redirect to GitHub authentication")
128
+ .command("config", "Configure Greptile settings")
129
+ .command("addPath","Adds greptie to your Path")
130
+ .demandCommand(1, "Please specify a command.")
131
+ .help(true)
132
+ .argv;
133
+
134
+ // Command execution based on user input
135
+ async function main() {
136
+ const command = options._[0];
137
+ switch (command) {
138
+
139
+ case "addPath":
140
+ addToPath()
141
+ break;
142
+
143
+ case "add":
144
+ await executeAddCommand(options.repository);
145
+ process.exit();
146
+ break;
147
+
148
+ case "help":
149
+ executeHelpCommand();
150
+ process.exit();
151
+ break;
152
+
153
+ case "config":
154
+ executeConfigCommand();
155
+ process.exit();
156
+ break;
157
+
158
+ case "start":
159
+ async function runLoop() {
160
+ let isDone = false;
161
+ while (!isDone) {
162
+
163
+ let userQuestion = await getUserQuestion();
164
+ if (userQuestion === "exit") {
165
+ isDone = true;
166
+ } else {
167
+ if (hasNoRepositories()) {
168
+ console.log("Please first add repositories to the session using greptile add <repo_link>")
169
+ process.exit(-1)
170
+
171
+ }
172
+ else {
173
+ await executeStartCommand(userQuestion);
174
+ }
175
+
176
+ }
177
+ }
178
+ }
179
+ runLoop();
180
+ break;
181
+
182
+ case "auth":
183
+ executeAuthCommand();
184
+
185
+ break;
186
+
187
+ case "list":
188
+ executeListCommand();
189
+ process.exit();
190
+ break;
191
+
192
+ case "remove":
193
+ executeRemoveCommand(options.repository);
194
+ process.exit();
195
+ break;
196
+
197
+ default:
198
+ console.error("Invalid command. Use 'greptile help' for assistance.");
199
+ process.exit();
200
+ break;
201
+
202
+ }
203
+ }
204
+
205
+ function executeHelpCommand() {
206
+ console.log("Executing help command...");
207
+ }
208
+
209
+ async function executeAddCommand(repositoryLink) {
210
+ if (!isAuthenticated()) {
211
+ console.error("Error: Please authenticate with GitHub first. Use 'greptile auth' to authenticate.");
212
+ process.exit(1);
213
+ } else {
214
+ if (!repositoryLink) {
215
+ console.error("Error: Please provide a repository name. Example: greptile add owner/repository");
216
+ process.exit(1);
217
+ }
218
+
219
+ // Load existing session data
220
+ let sessionData;
221
+ try {
222
+ const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
223
+ sessionData = JSON.parse(sessionFile);
224
+ } catch (error) {
225
+ if (debugMode) {
226
+ console.log(error)
227
+ }
228
+ // If the file doesn't exist or has invalid JSON, start with an empty session
229
+ sessionData = {
230
+ repositories: []
231
+ };
232
+ }
233
+ // Add the new repository to the session
234
+ const parsedRepo = parseIdentifier(repositoryLink)
235
+ try {
236
+ repository = parsedRepo.repository;
237
+ remote = parsedRepo.remote;
238
+ branch = parsedRepo.branch
239
+ }
240
+ catch (error) {
241
+ console.log("There was an error processing the repository link. Please check your repository link again")
242
+ process.exit(-1)
243
+ }
244
+ if (typeof repository === 'undefined') {
245
+ console.log("Error: Invalid repository name. Enter github link, e.g. https://github.com/facebook/react")
246
+ process.exit(-1)
247
+ }
248
+ const repoInfo = await getRepoInfo(repository, remote, branch);
249
+
250
+ try {
251
+ if (debugMode) {
252
+ console.log(repoInfo)
253
+ }
254
+
255
+ if (repoInfo.responses[0]) {
256
+ writeRepoToFile(repositoryLink);
257
+ }
258
+ else {
259
+ // Check whether this is supposed to be here
260
+ if (repoInfo.failed[0] && repoInfo.failed[0].repository == repository) {
261
+ if (repoInfo.failed[0].statusCode === 400) {
262
+ console.log(`Error ${repoInfo.failed[0].statusCode}: Bad Request`);
263
+ } else if (repoInfo.failed[0].statusCode === 401) {
264
+ console.log(`Error ${repoInfo.failed[0].statusCode}: Unauthorized`);
265
+ } else if (repoInfo.failed[0].statusCode === 404) {
266
+ if (repoInfo.failed[0].message && repoInfo.failed[0].message == "Repository not processed by Onboard.") {
267
+ writeRepoToFile(repositoryLink);
268
+ const processRepo = await getRepo(repository);
269
+ console.log(processRepo)
270
+ }
271
+ else {
272
+ console.log(`Error ${repoInfo.failed[0].statusCode}: Not Found`);
273
+ }
274
+ } else if (repoInfo.failed[0].statusCode === 500) {
275
+ console.log(`Error ${repoInfo.failed[0].statusCode}: Internal Server Error`);
276
+ } else {
277
+ console.log(`Error ${repoInfo.failed[0].statusCode}: Unhandled Status Code`);
278
+ }
279
+ process.exit(1)
280
+ }
281
+ await getRepo(repository);
282
+ }
283
+ } catch (error) {
284
+ if (debugMode) { console.error(error) }
285
+ if (repoInfo.failed[0] && repoInfo.failed[0].repository == repository) {
286
+ if (repoInfo.failed[0].statusCode === 400) {
287
+ console.log(`Error ${repoInfo.failed[0].statusCode}: Bad Request`);
288
+ } else if (repoInfo.failed[0].statusCode === 401) {
289
+ console.log(`Error ${repoInfo.failed[0].statusCode}: Unauthorized`);
290
+ } else if (repoInfo.failed[0].statusCode === 404) {
291
+ if (repoInfo.failed[0].message && repoInfo.failed[0].message == "Repository not processed by Onboard.") {
292
+ writeRepoToFile(repositoryLink);
293
+ const processRepo = await getRepo(repository);
294
+ if (debugMode) { console.log(processRepo) }
295
+ }
296
+ else {
297
+ console.log(`Error ${repoInfo.failed[0].statusCode}: Not Found`);
298
+ }
299
+ } else if (repoInfo.failed[0].statusCode === 500) {
300
+ console.log(`Error ${repoInfo.failed[0].statusCode}: Internal Server Error`);
301
+ } else {
302
+ console.log(`Error ${repoInfo.failed[0].statusCode}: Unhandled Status Code`);
303
+ }
304
+ process.exit(1)
305
+ }
306
+ }
307
+ // console.log(response)
308
+ // Write the updated session data back to the file
309
+ }
310
+ }
311
+ function writeRepoToFile(repositoryLink) {
312
+ let sessionData;
313
+ try {
314
+ const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
315
+ sessionData = JSON.parse(sessionFile);
316
+ } catch (error) {
317
+ // If the file doesn't exist or has invalid JSON, start with an empty session
318
+ sessionData = {
319
+ repositories: []
320
+ };
321
+ }
322
+
323
+ // Check if the repository link already exists
324
+ if (!sessionData.repositories.includes(repositoryLink)) {
325
+ try {
326
+ sessionData.repositories.push(repositoryLink);
327
+ const sessionFile = JSON.stringify(sessionData, null, 2);
328
+ fs.writeFileSync(sessionPath, sessionFile, 'utf-8');
329
+ console.log(`Repository '${repositoryLink}' added to the session.`);
330
+ } catch (error) {
331
+ console.error('Error writing session data to file:', error);
332
+ }
333
+ } else {
334
+ console.log(`Repository '${repositoryLink}' already exists in the session.`);
335
+ }
336
+ }
337
+ function executeListCommand() {
338
+ if (!isAuthenticated()) {
339
+ console.error("Error: Please authenticate with GitHub first. Use 'greptile auth' to authenticate.");
340
+ process.exit(1);
341
+ } else {
342
+ // Load existing session data
343
+ let sessionData;
344
+ try {
345
+ const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
346
+ sessionData = JSON.parse(sessionFile);
347
+ } catch (error) {
348
+ // If the file doesn't exist or has invalid JSON, start with an empty session
349
+ sessionData = {
350
+ repositories: []
351
+ };
352
+ }
353
+
354
+ // Display the list of repositories in the current session
355
+ const repositories = sessionData.repositories;
356
+ if (repositories.length === 0) {
357
+ console.log("No repositories in the current session.");
358
+ } else {
359
+ console.log("Repositories in the current session:");
360
+ repositories.forEach((repoLink, index) => {
361
+ const repo = parseIdentifier(repoLink).repository;
362
+ console.log(`${index + 1}. ${repo}`);
363
+ });
364
+ }
365
+ }
366
+ }
367
+
368
+ function executeRemoveCommand(repository) {
369
+ if (!isAuthenticated()) {
370
+ console.error("Error: Please authenticate with GitHub first. Use 'greptile auth' to authenticate.");
371
+ process.exit(1);
372
+ } else {
373
+ if (!repository) {
374
+ console.error("Error: Please provide a repository name. Example: greptile remove owner/repository");
375
+ process.exit(1);
376
+ }
377
+
378
+ // Load existing session data
379
+ let sessionData;
380
+ try {
381
+ const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
382
+ sessionData = JSON.parse(sessionFile);
383
+ } catch (error) {
384
+ // If the file doesn't exist or has invalid JSON, start with an empty session
385
+ sessionData = {
386
+ repositories: []
387
+ };
388
+ }
389
+
390
+ // Check if the repository exists in the session
391
+ const index = sessionData.repositories.indexOf(repository);
392
+ if (index === -1) {
393
+ console.log(`Repository '${repository}' not found in the current session.`);
394
+ } else {
395
+ // Remove the repository from the session
396
+ sessionData.repositories.splice(index, 1);
397
+
398
+ // Write the updated session data back to the file
399
+ try {
400
+ const sessionFile = JSON.stringify(sessionData, null, 2);
401
+ fs.writeFileSync(sessionPath, sessionFile, 'utf-8');
402
+ console.log(`Repository '${repository}' removed from the session.`);
403
+ } catch (error) {
404
+ if (debugMode) {
405
+ console.error('Error writing session data to file:', error);
406
+ }
407
+ }
408
+ }
409
+ }
410
+ }
411
+ // Function to execute the start command
412
+ // Inside executeStartCommand function
413
+ async function executeStartCommand(userQuestion) {
414
+ try {
415
+ if (!isAuthenticated()) {
416
+ console.error("Error: Please authenticate with GitHub first. Use 'greptile auth' to authenticate.");
417
+ process.exit(1);
418
+ } else {
419
+
420
+ await useChatApi(userQuestion);
421
+ }
422
+ }
423
+
424
+ catch (error) {
425
+ if (debugMode) {
426
+ console.log(error)
427
+ }
428
+ process.exit(-1)
429
+
430
+ }
431
+ }
432
+
433
+ async function getUserQuestion() {
434
+ const rl = readline.createInterface({
435
+ input: process.stdin,
436
+ output: process.stdout
437
+ });
438
+ function getActualQuestion() {
439
+ return new Promise((resolve) => {
440
+ rl.question('\n\n Question: (Hint: Type "exit" to exit) ', (answer) => {
441
+ resolve(answer);
442
+ });
443
+
444
+ });
445
+ }
446
+ const userQuestion = await getActualQuestion();
447
+ rl.close();
448
+ return userQuestion;
449
+
450
+
451
+ }
452
+ async function getRepo(repo, branch = "main", remote = "github") {
453
+ try {
454
+ const body = JSON.stringify({
455
+ "remote": remote, // one of "github", "gitlab" for now
456
+ "repository": repo, // formatted as owner/repository
457
+ // "branch": "main", // optional, defaults to repo default on GH/GL
458
+ // "reload": true, // optional, if false will not reprocess if previously successful, default true
459
+ // "notify": true // optional, whether to notify the user when finished, default true
460
+ })
461
+ const repoInfo = await fetch(`https://dprnu1tro5.execute-api.us-east-1.amazonaws.com/prod/v1/repositories`, {
462
+ method: "POST",
463
+ body: body,
464
+ headers: {
465
+ "Content-Type": "application/json",
466
+ "Authorization": "Bearer " + getAccessToken()
467
+ },
468
+ });
469
+
470
+ const repoInfoJson = await repoInfo.json();
471
+ return repoInfoJson;
472
+ } catch (error) {
473
+ if (debugMode) {
474
+ console.log("Error:", error);
475
+ }
476
+ return null;
477
+ }
478
+ }
479
+
480
+ async function getRepoInfo(repo, remote, branch) {
481
+ const repoInfo = await fetch('https://dprnu1tro5.execute-api.us-east-1.amazonaws.com/prod/v1/repositories/batch?repositories=' + getBase64(remote, repo, branch), {
482
+ method: "GET",
483
+ headers: {
484
+ "Content-Type": "application/json",
485
+ "Authorization": "Bearer " + getAccessToken()
486
+ },
487
+ });
488
+
489
+ const repoInfoJson = await repoInfo.json();
490
+
491
+ return repoInfoJson;
492
+ }
493
+
494
+ async function getMembership() {
495
+ const membershipUrl = 'https://dprnu1tro5.execute-api.us-east-1.amazonaws.com/prod/v1/membership';
496
+ try {
497
+ const response = await fetch(membershipUrl, {
498
+ method: 'GET',
499
+ headers: {
500
+ 'Content-Type': 'application/json',
501
+ "Authorization": "Bearer " + getAccessToken()
502
+ }
503
+ });
504
+ const responseData = await response.text();
505
+ if (debugMode) {
506
+ console.log(responseData);
507
+ }
508
+
509
+ } catch (error) {
510
+ if (debugMode) {
511
+ console.error('Error:', error.message);
512
+ }
513
+
514
+ }
515
+ }
516
+
517
+ async function useChatApi(userQuestion) {
518
+ const session_id = createSessionId();
519
+ // userQuestion = "What does this repo do?"
520
+ // repository = 'onboardai/onboard-vscode'
521
+ // branch = 'main'
522
+ let payload = readPayloadFromFile();
523
+
524
+ // If the payload is empty, create a new payload with the user's question
525
+ if (payload.messages.length === 0) {
526
+ if (debugMode) {
527
+ console.log("Payload is Empty, creating new Payload")
528
+ }
529
+ payload = createPayload2(userQuestion, session_id);
530
+ } else {
531
+ if (debugMode) {
532
+ console.log("Appending user Message to Payload")
533
+ }
534
+ // If the payload already has messages, append the user's new question
535
+ payload = appendMessageToPayload(payload, userQuestion);
536
+ }
537
+ if (debugMode) {
538
+ console.log(payload)
539
+ }
540
+
541
+ let newApiUrl = 'https://y32rqryql6ccw5nqa6qvr7bfbi0tmxuc.lambda-url.us-east-1.on.aws/'
542
+ // newApiUrl = 'https://mcxeqf7hzekaahjdqpojzf4hya0aflwj.lambda-url.us-east-1.on.aws/'
543
+ try {
544
+ const response = await fetch(newApiUrl, {
545
+ method: 'POST',
546
+ headers: {
547
+ 'Content-Type': 'application/json',
548
+ "Authorization": "Bearer " + getAccessToken()
549
+ },
550
+ body: JSON.stringify(payload),
551
+ })
552
+
553
+
554
+ let buffer = '';
555
+ decoder = new TextDecoder();
556
+ fullResponse = ""
557
+ for await (const chunk of response.body) {
558
+ const chunkText = decoder.decode(chunk);
559
+ // console.log(chunkText)
560
+ buffer += chunkText;
561
+ const lines = buffer.split(/\r?\n/);
562
+ for (let i = 0; i < lines.length - 1; i++) {
563
+ const line = lines[i].trim();
564
+
565
+ if (line.length > 0) {
566
+ try {
567
+ const jsonData = JSON.parse(line);
568
+ // console.log('JSONDATA: ',jsonData)
569
+ if (jsonData.type == "status") {
570
+ if (jsonData.message == '') {
571
+ // console.log(" d :, ", fullResponse)
572
+ appendMessageToPayload(payload, fullResponse);
573
+ // process.exit(0)
574
+ }
575
+ console.log(jsonData.message)
576
+ if (jsonData.message == "Started processing request") {
577
+ spinner.start();
578
+ }
579
+ if (jsonData.message == "Writing response") {
580
+ spinner.succeed('Request processed successfully');
581
+ }
582
+
583
+ }
584
+ else {
585
+ if (typeof jsonData.message === 'string') {
586
+ fullResponse += jsonData.message;
587
+ }
588
+ process.stdout.write(jsonData.message)
589
+ }
590
+ } catch (error) {
591
+ // console.error('Error parsing JSON:', error);
592
+ }
593
+ }
594
+ }
595
+
596
+ buffer = lines[lines.length - 1];
597
+ }
598
+
599
+
600
+ } catch (error) {
601
+
602
+ if (debugMode) {
603
+ console.error('Error:', error.message);
604
+ }
605
+ // Handle errors here
606
+ }
607
+ }
608
+
609
+
610
+ function isAuthenticated() {
611
+ try {
612
+ const configFile = fs.readFileSync(configPath, 'utf-8');
613
+ const configFileData = JSON.parse(configFile)
614
+
615
+ if (configFileData.github.access_token != null) {
616
+ access_token = configFileData.github.access_token
617
+ return true;
618
+ }
619
+ else {
620
+ return false;
621
+ }
622
+ } catch (error) {
623
+ if (debugMode) {
624
+ console.log(error)
625
+ }
626
+ return {};
627
+ }
628
+ }
629
+
630
+ function getAccessToken() {
631
+ try {
632
+ const configFile = fs.readFileSync(configPath, 'utf-8');
633
+ const configFileData = JSON.parse(configFile)
634
+
635
+ if (configFileData.github.access_token != null) {
636
+ access_token = configFileData.github.access_token
637
+ return access_token;
638
+ }
639
+ else {
640
+ return null;
641
+ }
642
+ } catch (error) {
643
+ if (debugMode) {
644
+ console.log(error)
645
+ }
646
+ return {};
647
+ }
648
+ }
649
+ function writeConfig(access__token) {
650
+ // Create and write to the file
651
+ const config = {
652
+ "github": {
653
+ "access_token": access__token
654
+ }
655
+ };
656
+ const configFile = JSON.stringify(config, null, 2);
657
+
658
+ try {
659
+ fs.writeFileSync(configPath, configFile, 'utf-8');
660
+ if (debugMode) {
661
+ console.log('File written successfully');
662
+ }
663
+ } catch (err) {
664
+ if (debugMode) {
665
+ console.error('Error writing to the file:', err);
666
+ }
667
+ }
668
+ }
669
+
670
+
671
+ function getBase64(remote, repository, branch) {
672
+ let repo = remote + ":" + repository + ":" + branch;
673
+ if (debugMode) {
674
+ console.log(repo)
675
+ }
676
+ return (Base64.encode(repo))
677
+ }
678
+
679
+ function createSessionId() {
680
+ return Math.random().toString(36).substring(2, 15) +
681
+ Math.random().toString(36).substring(2, 15);
682
+ }
683
+
684
+
685
+ function createPayload2(userQuestion, session_id, remote = "github", branch = "main", external = false) {
686
+ // Load existing session data
687
+ let sessionData;
688
+ try {
689
+ const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
690
+ sessionData = JSON.parse(sessionFile);
691
+ } catch (error) {
692
+ // If the file doesn't exist or has invalid JSON, start with an empty session
693
+ sessionData = {
694
+ repositories: []
695
+ };
696
+ }
697
+
698
+ const payload = {
699
+ messages: [
700
+ {
701
+ id: '1',
702
+ role: "user",
703
+ content: userQuestion
704
+ }
705
+ ],
706
+ repositories: sessionData.repositories.map(repo => ({
707
+ remote: parseIdentifier(repo).remote,
708
+ repository: parseIdentifier(repo).repository,
709
+ branch: parseIdentifier(repo).branch,
710
+ name: parseIdentifier(repo).repository,
711
+ external: external,
712
+ })),
713
+ sessionId: session_id,
714
+ }
715
+
716
+ return payload;
717
+ }
718
+
719
+
720
+ function readPayloadFromFile() {
721
+ try {
722
+ const payloadFile = fs.readFileSync(payloadFilePath, 'utf-8');
723
+ const payload = JSON.parse(payloadFile);
724
+
725
+ return payload;
726
+ } catch (error) {
727
+ // If the file doesn't exist or has invalid JSON, return an empty payload
728
+ return {
729
+ messages: [],
730
+ repositories: [],
731
+ sessionId: '',
732
+ user: {
733
+ email: '',
734
+ token: {
735
+ github: '',
736
+ },
737
+ },
738
+ };
739
+ }
740
+ }
741
+
742
+ function writePayloadToFile(payload) {
743
+ try {
744
+ const payloadFile = JSON.stringify(payload, null, 2);
745
+ fs.writeFileSync(payloadFilePath, payloadFile, 'utf-8');
746
+ } catch (error) {
747
+ if (debugMode) {
748
+ console.error('Error writing payload to file:', error);
749
+ }
750
+ }
751
+ }
752
+
753
+ function appendMessageToPayload(payload, content) {
754
+ payload.messages.push({
755
+ id: (payload.messages.length + 1).toString(),
756
+ role: 'user',
757
+ content: content,
758
+ });
759
+ writePayloadToFile(payload);
760
+ return payload;
761
+ }
762
+
763
+ function hasRepositoriesInSession() {
764
+ try {
765
+ const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
766
+ const sessionData = JSON.parse(sessionFile);
767
+
768
+ return sessionData.repositories.length > 0;
769
+ } catch (error) {
770
+ // If the file doesn't exist or has invalid JSON, return false
771
+ return false;
772
+ }
773
+ }
774
+
775
+ function hasNoRepositories() {
776
+ try {
777
+ const sessionFile = fs.readFileSync(sessionPath, 'utf-8');
778
+ const sessionData = JSON.parse(sessionFile);
779
+ console.log(sessionData.repositories.length)
780
+ return sessionData.repositories.length === 0;
781
+ } catch (error) {
782
+ if (debugMode) {
783
+ console.log(error)
784
+ }
785
+ // If the file doesn't exist or has invalid JSON, return true (no repositories)
786
+ return true;
787
+ }
788
+ }
789
+
790
+ function parseIdentifier(input) {
791
+ if (!isDomain(input)) {
792
+ const regex = /^(([^:]*):([^:]*):|[^:]*)([^:]*)$/;
793
+ const match = input.match(regex);
794
+ if (!match) return null;
795
+ const keys = input.split(":");
796
+ if (keys.length === 1)
797
+ return serializeRepoKey({
798
+ remote: "github",
799
+ branch: "",
800
+ repository: keys[0],
801
+ });
802
+ if (keys.length === 3) {
803
+ let remote = keys[0],
804
+ branch = keys[1],
805
+ repository = keys[2];
806
+ if (remote === "azure" && repository.split("/").length == 2) {
807
+ let repository_list = repository.split("/");
808
+ repository_list.push(repository_list[1]);
809
+ repository = repository_list.join("/");
810
+ }
811
+ return serializeRepoKey({
812
+ remote: remote,
813
+ branch: branch,
814
+ repository: repository,
815
+ });
816
+ }
817
+ return null; // only 2 entries may be ambiguous (1 might be as well...)
818
+ }
819
+ if (!input.startsWith("http")) input = "https://" + input;
820
+ if (input.endsWith(".git")) input = input.slice(0, -4);
821
+ try {
822
+ const url = new URL(input);
823
+ let remote = (() => {
824
+ try {
825
+ const services = ["github", "gitlab", "bitbucket", "azure", "visualstudio"];
826
+ return (services.find((service) => url.hostname.includes(service)) || null)
827
+ } catch (e) {
828
+ return null;
829
+ }
830
+ })();
831
+ if (!remote) return null;
832
+ let repository, branch, regex, match;
833
+ switch (remote) {
834
+ case "github":
835
+ regex =
836
+ /([a-zA-Z0-9\._-]+\/[a-zA-Z0-9\%\._-]+)[\/tree\/]*([a-zA-Z0-0\._-]+)?/;
837
+ match = url.pathname.match(regex);
838
+ repository = decodeURIComponent(match?.[1] || "");
839
+ branch = match?.[2];
840
+ break;
841
+ case "gitlab":
842
+ regex =
843
+ /([a-zA-Z0-9\._-]+\/[a-zA-Z0-9\%\._-]+)(?:\/\-)?(?:(?:\/tree\/)([a-zA-Z0-0\._-]+))?/;
844
+ match = url.pathname.match(regex);
845
+ repository = decodeURIComponent(match?.[1] || "");
846
+ branch = match?.[2];
847
+ break;
848
+
849
+ case "azure":
850
+ regex = /([a-zA-Z0-9\%\.\/_-]+)/;
851
+ match = url.pathname.match(regex);
852
+ repository =
853
+ match?.[1].split("/").filter((x) => x !== "_git" && x !== "") || [];
854
+ repository.push(repository?.slice(-1)[0]);
855
+ repository = decodeURIComponent(repository.slice(0, 3).join("/"));
856
+ branch = url.searchParams.get("version")?.slice(2); // remove 'GB' from the beginning
857
+ break;
858
+
859
+ case "visualstudio":
860
+ remote = "azure"
861
+ regex = /([a-zA-Z0-9\%\.\/_-]+)/;
862
+ const org = url.hostname.split(".")[0];
863
+ match = url.pathname.match(regex);
864
+ repository =
865
+ match?.[1].split("/").filter((x) => x !== "_git" && x !== "") || [];
866
+ repository = decodeURIComponent([org, ...(repository.slice(0, 2))].join("/"));
867
+ branch = url.searchParams.get("version")?.slice(2); // remove 'GB' from the beginning
868
+ break;
869
+ default:
870
+ return url.hostname;
871
+ }
872
+ if (!repository) return null;
873
+ // console.log(remote,branch,repository)
874
+ if (typeof branch === "undefined") {
875
+ branch = "main";
876
+ }
877
+ return { remote, branch, repository };
878
+ // return serializeRepoKey({
879
+ // remote: remote,
880
+ // branch: branch || "main",
881
+ // repository: repository,
882
+ // });
883
+ } catch (e) {
884
+ return null;
885
+ }
886
+ };
887
+
888
+ function isDomain(input) {
889
+ try {
890
+ new URL(input);
891
+ const regex = /^(([^:]*):([^:]*):|[^:]*)([^:]*)$/;
892
+ const match = input.match(regex);
893
+ if (match) return false;
894
+ return true;
895
+ } catch (e) {
896
+ return false;
897
+ }
898
+ }
899
+
900
+ function serializeRepoKey(repoKey) {
901
+ const { remote, branch, repository } = repoKey;
902
+ return `${remote}:${branch}:${repository}`;
903
+ }
904
+
905
+ function addToPath5() {
906
+ dirToAdd = __dirname.replace("/bin","")
907
+ exec('export PATH="' + dirToAdd + ':$PATH"',
908
+ (error, stdout, stderr) => {
909
+ // console.log(`stdout: ${stdout}`);
910
+ // console.log(`stderr: ${stderr}`);
911
+ if (error !== null) {
912
+ // console.log(`exec error: ${error}`);
913
+ }
914
+ else{
915
+ // console.log("Sucessfuly added to path")
916
+ }
917
+ });
918
+ }
919
+
920
+ function addToPath3() {
921
+ // Get the current directory
922
+ const currentDirectory = __dirname.replace("/bin","");
923
+
924
+ // Get the current PATH variable value or use an empty string if it doesn't exist
925
+ const currentPath = process.env.PATH || '';
926
+
927
+ // Check if the current directory is already in the PATH
928
+ if (currentPath.includes(currentDirectory)) {
929
+ console.log(`Current directory '${currentDirectory}' is already in the PATH.`);
930
+ return;
931
+ }
932
+
933
+ // Update the PATH variable by adding the current directory
934
+ process.env.PATH = `${currentDirectory}${path.delimiter}${currentPath}`;
935
+
936
+ // Optionally, you can persist the changes to a user's profile (e.g., .bashrc, .zshrc)
937
+ // Uncomment the following lines if you want to make the change permanent
938
+ const profilePath = path.join(process.env.HOME || process.env.USERPROFILE, '.bashrc');
939
+ fs.appendFileSync(profilePath, `\nexport PATH=${process.env.PATH}\n`);
940
+ console.log(`Current directory '${currentDirectory}' added to the PATH.`);
941
+ }
942
+
943
+ function addToPath() {
944
+ // Execute the Bash script
945
+ bashFile = path.join(currentDirectory.replace("/bin","") + "/addToPath.sh")
946
+ exec(bashFile, (error, stdout, stderr) => {
947
+ if (error) {
948
+ console.error(`Error: ${error.message}`);
949
+ return;
950
+ }
951
+ if (stderr) {
952
+ console.error(`Error: ${stderr}`);
953
+ return;
954
+ }
955
+ console.log(stdout);
956
+ });
957
+ }
958
+
959
+ function addToPath5() {
960
+ // Get the current directory
961
+ const currentDirectory = __dirname.replace("/bin","");
962
+
963
+ // Get the current PATH variable value or use an empty string if it doesn't exist
964
+ const currentPath = process.env.PATH || '';
965
+
966
+ // Check if the current directory is already in the PATH
967
+ if (currentPath.includes(currentDirectory)) {
968
+ console.log(`Current directory '${currentDirectory}' is already in the PATH.`);
969
+ return;
970
+ }
971
+
972
+ // Update the PATH variable by adding the current directory
973
+ process.env.PATH = `${currentDirectory}${path.delimiter}${currentPath}`;
974
+
975
+ // Append the change to a user's profile to make it permanent
976
+ // Choose the correct profile file based on your shell
977
+ const profilePath = path.join(process.env.HOME || process.env.USERPROFILE, '.bashrc'); // For Bash users
978
+ // const profilePath = path.join(process.env.HOME || process.env.USERPROFILE, '.zshrc'); // For Zsh users
979
+ fs.appendFileSync(profilePath, `\nexport PATH="${process.env.PATH}"\n`);
980
+ console.log(`Current directory '${currentDirectory}' added to the PATH.`);
981
+ }
982
+
983
+ // Call the function
984
+ // addToPath();
985
+
986
+ // addToPath()
987
+
988
+ main()
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,29 @@
1
+ {
2
+ "messages": [
3
+ {
4
+ "id": "1",
5
+ "role": "user",
6
+ "content": "What does this repo do?"
7
+ },
8
+ {
9
+ "id": "2",
10
+ "role": "user",
11
+ "content": "The `facebook/react` repository is for React, a declarative, efficient, and flexible JavaScript library for building user interfaces. It allows developers to create large web applications that can change data, without reloading the page. React's goal is to be simple to use, making it easy to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.\n\nKey aspects of React include:\n\n- **Declarative**: React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes. Declarative views make your code more predictable and easier to debug.\n\n- **Component-Based**: Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM.\n\n- **Learn Once, Write Anywhere**: You can develop new features in React without rewriting existing code. React can also render on the server using Node and power mobile apps using React Native.\n\nThe repository includes documentation on how to get started with React, installation instructions, and links to further resources. It also outlines how to contribute to the project, the project's security policies, and the terms under which the software is licensed (MIT License)."
12
+ },
13
+ {
14
+ "id": "3",
15
+ "role": "user",
16
+ "content": "What does this repo do?"
17
+ }
18
+ ],
19
+ "repositories": [
20
+ {
21
+ "remote": "github",
22
+ "repository": "facebook/react",
23
+ "branch": "main",
24
+ "name": "facebook/react",
25
+ "external": false
26
+ }
27
+ ],
28
+ "sessionId": "qsyi629gm9ajhqgjwok4a"
29
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "repositories": [
3
+ "https://github.com/facebook/react"
4
+ ]
5
+ }
package/create_sha.js ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ const { createHash } = require('crypto');
3
+
4
+ function hash(string) {
5
+ return createHash('sha256').update(string).digest('hex');
6
+ }
7
+
8
+ hash('vkameswaran/test')
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "greptile",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "bin": {
6
+ "greptile": "./bin/index.js"
7
+ },
8
+ "type": "module",
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "assets": [
13
+ "bin/config.json"
14
+ ],
15
+ "author": "",
16
+ "license": "ISC",
17
+ "dependencies": {
18
+ "@octokit/rest": "^20.0.2",
19
+ "axios": "^1.6.7",
20
+ "cli-spinners": "^2.9.2",
21
+ "clipboardy": "^2.3.0",
22
+ "express": "^4.18.2",
23
+ "js-base64": "^3.7.6",
24
+ "node-fetch": "^2.7.0",
25
+ "open": "^8.4.0",
26
+ "ora": "^5.4.1",
27
+ "punycode": "^2.3.1",
28
+ "yargs": "^17.7.2",
29
+ "shelljs": "^0.8.4"
30
+ },
31
+ "description": "",
32
+ "pkg": {
33
+ "targets": [
34
+ "node14-linux-x64",
35
+ "node14-macos-x64",
36
+ "node14-win-x64"
37
+ ],
38
+ "outputPath": "release",
39
+ "scripts": [
40
+ "bin/index.js",
41
+ "bin/config.json"
42
+ ]
43
+ }
44
+ }
@@ -0,0 +1,110 @@
1
+ const path = require('path');
2
+ function isDomain(input) {
3
+ try {
4
+ new URL(input);
5
+ const regex = /^(([^:]*):([^:]*):|[^:]*)([^:]*)$/;
6
+ const match = input.match(regex);
7
+ if (match) return false;
8
+ return true;
9
+ } catch (e) {
10
+ return false;
11
+ }
12
+ }
13
+
14
+ function serializeRepoKey(repoKey) {
15
+ const { remote, branch, repository } = repoKey;
16
+ return `${remote}:${branch}:${repository}`;
17
+ }
18
+ function parseIdentifier(input) {
19
+ if (!isDomain(input)) {
20
+ const regex = /^(([^:]*):([^:]*):|[^:]*)([^:]*)$/;
21
+ const match = input.match(regex);
22
+ if (!match) return null;
23
+ const keys = input.split(":");
24
+ if (keys.length === 1)
25
+ return serializeRepoKey({
26
+ remote: "github",
27
+ branch: "",
28
+ repository: keys[0],
29
+ });
30
+ if (keys.length === 3) {
31
+ let remote = keys[0],
32
+ branch = keys[1],
33
+ repository = keys[2];
34
+ if (remote === "azure" && repository.split("/").length == 2) {
35
+ let repository_list = repository.split("/");
36
+ repository_list.push(repository_list[1]);
37
+ repository = repository_list.join("/");
38
+ }
39
+ return serializeRepoKey({
40
+ remote: remote,
41
+ branch: branch,
42
+ repository: repository,
43
+ });
44
+ }
45
+ return null; // only 2 entries may be ambiguous (1 might be as well...)
46
+ }
47
+ if (!input.startsWith("http")) input = "https://" + input;
48
+ if (input.endsWith(".git")) input = input.slice(0, -4);
49
+ try {
50
+ const url = new URL(input);
51
+ let remote = (() => {
52
+ try {
53
+ const services = ["github", "gitlab", "bitbucket", "azure", "visualstudio"];
54
+ return (services.find((service) => url.hostname.includes(service)) || null)
55
+ } catch (e) {
56
+ return null;
57
+ }
58
+ })();
59
+ if (!remote) return null;
60
+ let repository, branch, regex, match;
61
+ switch (remote) {
62
+ case "github":
63
+ regex =
64
+ /([a-zA-Z0-9\._-]+\/[a-zA-Z0-9\%\._-]+)[\/tree\/]*([a-zA-Z0-0\._-]+)?/;
65
+ match = url.pathname.match(regex);
66
+ repository = decodeURIComponent(match?.[1] || "");
67
+ branch = match?.[2];
68
+ break;
69
+ case "gitlab":
70
+ regex =
71
+ /([a-zA-Z0-9\._-]+\/[a-zA-Z0-9\%\._-]+)(?:\/\-)?(?:(?:\/tree\/)([a-zA-Z0-0\._-]+))?/;
72
+ match = url.pathname.match(regex);
73
+ repository = decodeURIComponent(match?.[1] || "");
74
+ branch = match?.[2];
75
+ break;
76
+ case "azure":
77
+ regex = /([a-zA-Z0-9\%\.\/_-]+)/;
78
+ match = url.pathname.match(regex);
79
+ repository =
80
+ match?.[1].split("/").filter((x) => x !== "_git" && x !== "") || [];
81
+ repository.push(repository?.slice(-1)[0]);
82
+ repository = decodeURIComponent(repository.slice(0, 3).join("/"));
83
+ branch = url.searchParams.get("version")?.slice(2); // remove 'GB' from the beginning
84
+ break;
85
+ case "visualstudio":
86
+ remote = "azure"
87
+ regex = /([a-zA-Z0-9\%\.\/_-]+)/;
88
+ const org = url.hostname.split(".")[0];
89
+ match = url.pathname.match(regex);
90
+ repository =
91
+ match?.[1].split("/").filter((x) => x !== "_git" && x !== "") || [];
92
+ repository = decodeURIComponent([org, ...(repository.slice(0, 2))].join("/"));
93
+ branch = url.searchParams.get("version")?.slice(2); // remove 'GB' from the beginning
94
+ break;
95
+ default:
96
+ return url.hostname;
97
+ }
98
+ if (!repository) return null;
99
+ // console.log(remote,branch,repository)
100
+ return { remote, branch , repository };
101
+
102
+ } catch (e) {
103
+ return null;
104
+ }
105
+ };
106
+
107
+
108
+ const x = (parseIdentifier('https://github.com/Dhruv317/HighPeakSWInternship'));
109
+ console.log(typeof x)
110
+ console.log(x.repository)
Binary file
Binary file
Binary file
Binary file