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/greptile-fix.js +10 -0
- package/build-app.sh +56 -0
- package/greptile-fix +222 -0
- package/greptile-fix.applescript +52 -0
- package/package.json +24 -36
- package/postinstall.sh +28 -0
- package/preuninstall.sh +10 -0
- package/README.md +0 -114
- package/addToPath.sh +0 -13
- package/bin/index.js +0 -940
- package/bin/package.json +0 -1
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()
|