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 +86 -0
- package/addToPath.sh +13 -0
- package/bin/config.json +5 -0
- package/bin/index.js +988 -0
- package/bin/package.json +1 -0
- package/bin/payload.json +29 -0
- package/bin/session.json +5 -0
- package/create_sha.js +8 -0
- package/package.json +44 -0
- package/parseString.cjs +110 -0
- package/release/greptile +0 -0
- package/release/greptile-linux +0 -0
- package/release/greptile-win.exe +0 -0
- package/release/greptile.tar.gz +0 -0
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
|
package/bin/config.json
ADDED
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()
|
package/bin/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
package/bin/payload.json
ADDED
|
@@ -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
|
+
}
|
package/bin/session.json
ADDED
package/create_sha.js
ADDED
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
|
+
}
|
package/parseString.cjs
ADDED
|
@@ -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)
|
package/release/greptile
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|