gitxelectron 1.1.7 → 1.1.8
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/out/main/index.js +137 -8
- package/out/preload/index.js +4 -0
- package/out/renderer/assets/{index-i67_EinM.js → index-BusxICOa.js} +652 -126
- package/out/renderer/assets/index-C6BmlqOs.css +193 -0
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
- package/out/renderer/assets/index-D22RH28n.css +0 -193
package/out/main/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const electron = require("electron");
|
|
3
3
|
const path = require("path");
|
|
4
|
-
const simpleGit = require("simple-git");
|
|
5
4
|
const fs = require("fs/promises");
|
|
5
|
+
const simpleGit = require("simple-git");
|
|
6
6
|
const crypto = require("crypto");
|
|
7
7
|
const generativeAi = require("@google/generative-ai");
|
|
8
8
|
const OpenAI = require("openai");
|
|
@@ -288,6 +288,68 @@ async function getUserRepositories(sessionId) {
|
|
|
288
288
|
}
|
|
289
289
|
return await res.json();
|
|
290
290
|
}
|
|
291
|
+
async function getCollaboratedRepos(sessionId) {
|
|
292
|
+
const token = getToken(sessionId);
|
|
293
|
+
if (!token) throw new Error("Not authenticated in this session");
|
|
294
|
+
const headers = {
|
|
295
|
+
Authorization: `Bearer ${token}`,
|
|
296
|
+
Accept: "application/vnd.github.v3+json",
|
|
297
|
+
"User-Agent": "gitelectron-App"
|
|
298
|
+
};
|
|
299
|
+
const res = await fetch(
|
|
300
|
+
"https://api.github.com/user/repos?affiliation=owner,collaborator,organization_member&per_page=100&sort=updated",
|
|
301
|
+
{ headers }
|
|
302
|
+
);
|
|
303
|
+
if (!res.ok) {
|
|
304
|
+
const errorData = await res.json().catch(() => ({}));
|
|
305
|
+
throw new Error(errorData.message || "Failed to fetch collaborated repositories");
|
|
306
|
+
}
|
|
307
|
+
const allRepos = await res.json();
|
|
308
|
+
const account = getActiveAccount(sessionId);
|
|
309
|
+
const currentUsername = account?.username?.toLowerCase() || "";
|
|
310
|
+
const externalCollabRepos = [];
|
|
311
|
+
const ownedRepos = [];
|
|
312
|
+
for (const repo of allRepos) {
|
|
313
|
+
const ownerLogin = repo.owner?.login?.toLowerCase() || "";
|
|
314
|
+
if (ownerLogin !== currentUsername) {
|
|
315
|
+
externalCollabRepos.push(repo);
|
|
316
|
+
} else {
|
|
317
|
+
ownedRepos.push(repo);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const ownedCollabChecks = await Promise.allSettled(
|
|
321
|
+
ownedRepos.map(async (repo) => {
|
|
322
|
+
try {
|
|
323
|
+
const [collabRes, invRes] = await Promise.all([
|
|
324
|
+
fetch(`https://api.github.com/repos/${repo.owner.login}/${repo.name}/collaborators`, { headers }),
|
|
325
|
+
fetch(`https://api.github.com/repos/${repo.owner.login}/${repo.name}/invitations`, { headers })
|
|
326
|
+
]);
|
|
327
|
+
const collabs = collabRes.ok ? await collabRes.json() : [];
|
|
328
|
+
const invs = invRes.ok ? await invRes.json() : [];
|
|
329
|
+
const hasOtherCollabs = Array.isArray(collabs) && collabs.some(
|
|
330
|
+
(c) => c.login && c.login.toLowerCase() !== currentUsername
|
|
331
|
+
);
|
|
332
|
+
const hasPendingInvs = Array.isArray(invs) && invs.length > 0;
|
|
333
|
+
if (hasOtherCollabs || hasPendingInvs) {
|
|
334
|
+
return {
|
|
335
|
+
...repo,
|
|
336
|
+
collaboratorsList: collabs,
|
|
337
|
+
hasPendingInvitations: hasPendingInvs
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
} catch (err) {
|
|
341
|
+
}
|
|
342
|
+
return null;
|
|
343
|
+
})
|
|
344
|
+
);
|
|
345
|
+
const ownedCollabRepos = [];
|
|
346
|
+
for (const result of ownedCollabChecks) {
|
|
347
|
+
if (result.status === "fulfilled" && result.value) {
|
|
348
|
+
ownedCollabRepos.push(result.value);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return [...externalCollabRepos, ...ownedCollabRepos];
|
|
352
|
+
}
|
|
291
353
|
async function createGitHubRepository(sessionId, name, description, isPrivate, autoInit = false, gitignoreTemplate = "", licenseTemplate = "") {
|
|
292
354
|
const token = getToken(sessionId);
|
|
293
355
|
if (!token) throw new Error("Not authenticated in this session");
|
|
@@ -390,7 +452,9 @@ async function removeCollaborator(sessionId, remoteUrl, usernameOrId, isInvitati
|
|
|
390
452
|
async function searchGitHubUser(sessionId, username) {
|
|
391
453
|
const token = getToken(sessionId);
|
|
392
454
|
if (!token) throw new Error("Not authenticated");
|
|
393
|
-
const
|
|
455
|
+
const trimmed = username.trim();
|
|
456
|
+
if (!trimmed) return null;
|
|
457
|
+
const res = await fetch(`https://api.github.com/users/${encodeURIComponent(trimmed)}`, {
|
|
394
458
|
headers: {
|
|
395
459
|
Authorization: `Bearer ${token}`,
|
|
396
460
|
Accept: "application/vnd.github.v3+json",
|
|
@@ -407,17 +471,32 @@ async function searchGitHubUser(sessionId, username) {
|
|
|
407
471
|
async function searchGitHubUsers(sessionId, query) {
|
|
408
472
|
const token = getToken(sessionId);
|
|
409
473
|
if (!token) throw new Error("Not authenticated");
|
|
410
|
-
|
|
411
|
-
|
|
474
|
+
const trimmed = query.trim();
|
|
475
|
+
if (!trimmed) return [];
|
|
476
|
+
const searchPromise = fetch(
|
|
477
|
+
`https://api.github.com/search/users?q=${encodeURIComponent(trimmed)}+type:user&per_page=15`,
|
|
478
|
+
{
|
|
479
|
+
headers: {
|
|
480
|
+
Authorization: `Bearer ${token}`,
|
|
481
|
+
Accept: "application/vnd.github.v3+json",
|
|
482
|
+
"User-Agent": "gitelectron-App"
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
).then((r) => r.ok ? r.json() : { items: [] }).catch(() => ({ items: [] }));
|
|
486
|
+
const exactPromise = /^[a-zA-Z0-9-]+$/.test(trimmed) ? fetch(`https://api.github.com/users/${encodeURIComponent(trimmed)}`, {
|
|
412
487
|
headers: {
|
|
413
488
|
Authorization: `Bearer ${token}`,
|
|
414
489
|
Accept: "application/vnd.github.v3+json",
|
|
415
490
|
"User-Agent": "gitelectron-App"
|
|
416
491
|
}
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
492
|
+
}).then((r) => r.ok ? r.json() : null).catch(() => null) : Promise.resolve(null);
|
|
493
|
+
const [searchData, exactUser] = await Promise.all([searchPromise, exactPromise]);
|
|
494
|
+
let items = searchData.items || [];
|
|
495
|
+
if (exactUser && exactUser.login) {
|
|
496
|
+
items = items.filter((u) => u.login.toLowerCase() !== exactUser.login.toLowerCase());
|
|
497
|
+
items.unshift(exactUser);
|
|
498
|
+
}
|
|
499
|
+
return items;
|
|
421
500
|
}
|
|
422
501
|
async function getRepositoryBranches(sessionId, owner, repo) {
|
|
423
502
|
const token = getToken(sessionId);
|
|
@@ -1009,6 +1088,22 @@ async function executeRawCommand(sessionId, args) {
|
|
|
1009
1088
|
const { git } = getGitSession(sessionId);
|
|
1010
1089
|
return await git.raw(args);
|
|
1011
1090
|
}
|
|
1091
|
+
async function cloneRepository(sessionId, remoteUrl, destPath) {
|
|
1092
|
+
const authUrl = injectAuthToken(sessionId, remoteUrl);
|
|
1093
|
+
await fs__namespace.mkdir(path__namespace.dirname(destPath), { recursive: true });
|
|
1094
|
+
const git = simpleGit.simpleGit().env({
|
|
1095
|
+
...process.env,
|
|
1096
|
+
GCM_INTERACTIVE: "false",
|
|
1097
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
1098
|
+
GIT_ASKPASS: "echo"
|
|
1099
|
+
});
|
|
1100
|
+
await git.clone(authUrl, destPath);
|
|
1101
|
+
try {
|
|
1102
|
+
await simpleGit.simpleGit().raw(["config", "--global", "--add", "safe.directory", destPath]);
|
|
1103
|
+
} catch (e) {
|
|
1104
|
+
}
|
|
1105
|
+
return destPath;
|
|
1106
|
+
}
|
|
1012
1107
|
const SYSTEM_PROMPT = `You are an autonomous Git Healer Agent for the "GitElectron" app.
|
|
1013
1108
|
The user has encountered a Git error during a push, pull, or merge operation and you are executing as a background process to silently fix it.
|
|
1014
1109
|
You will receive the Git Status and the Raw Error Message.
|
|
@@ -1378,6 +1473,9 @@ electron.app.whenReady().then(async () => {
|
|
|
1378
1473
|
electron.ipcMain.handle("get-user-repositories", async (event) => {
|
|
1379
1474
|
return await getUserRepositories(event.sender.id);
|
|
1380
1475
|
});
|
|
1476
|
+
electron.ipcMain.handle("get-collaborated-repos", async (event) => {
|
|
1477
|
+
return await getCollaboratedRepos(event.sender.id);
|
|
1478
|
+
});
|
|
1381
1479
|
electron.ipcMain.handle(
|
|
1382
1480
|
"create-github-repository",
|
|
1383
1481
|
async (event, name, description, isPrivate, autoInit, gitignoreTemplate, licenseTemplate) => {
|
|
@@ -1497,6 +1595,37 @@ electron.app.whenReady().then(async () => {
|
|
|
1497
1595
|
electron.ipcMain.handle("execute-raw-git", async (event, args) => {
|
|
1498
1596
|
return await executeRawCommand(event.sender.id, args);
|
|
1499
1597
|
});
|
|
1598
|
+
electron.ipcMain.handle("clone-repository", async (event, remoteUrl, destPath) => {
|
|
1599
|
+
return await cloneRepository(event.sender.id, remoteUrl, destPath);
|
|
1600
|
+
});
|
|
1601
|
+
electron.ipcMain.handle("check-path-exists", async (_event, targetPath) => {
|
|
1602
|
+
if (!targetPath) return false;
|
|
1603
|
+
try {
|
|
1604
|
+
const stats = await fs__namespace.stat(targetPath);
|
|
1605
|
+
return stats.isDirectory();
|
|
1606
|
+
} catch {
|
|
1607
|
+
return false;
|
|
1608
|
+
}
|
|
1609
|
+
});
|
|
1610
|
+
electron.ipcMain.handle("upload-files-to-repo", async (event, repoPath) => {
|
|
1611
|
+
const window = electron.BrowserWindow.fromWebContents(event.sender);
|
|
1612
|
+
if (!repoPath) throw new Error("No repository path specified");
|
|
1613
|
+
const result = await electron.dialog.showOpenDialog(window || void 0, {
|
|
1614
|
+
title: "Select Files to Upload to Repository",
|
|
1615
|
+
properties: ["openFile", "multiSelections"]
|
|
1616
|
+
});
|
|
1617
|
+
if (result.canceled || !result.filePaths.length) {
|
|
1618
|
+
return { success: false, count: 0, files: [] };
|
|
1619
|
+
}
|
|
1620
|
+
const copiedFiles = [];
|
|
1621
|
+
for (const filePath of result.filePaths) {
|
|
1622
|
+
const fileName = path__namespace.basename(filePath);
|
|
1623
|
+
const destPath = path__namespace.join(repoPath, fileName);
|
|
1624
|
+
await fs__namespace.copyFile(filePath, destPath);
|
|
1625
|
+
copiedFiles.push(fileName);
|
|
1626
|
+
}
|
|
1627
|
+
return { success: true, count: copiedFiles.length, files: copiedFiles };
|
|
1628
|
+
});
|
|
1500
1629
|
electron.ipcMain.on("toggle-auto-sync", (event, repoPath, enabled) => {
|
|
1501
1630
|
toggleAutoSync(event.sender.id, repoPath, enabled, (msg) => {
|
|
1502
1631
|
event.sender.send("auto-sync-log", msg);
|
package/out/preload/index.js
CHANGED
|
@@ -40,6 +40,7 @@ const api = {
|
|
|
40
40
|
switchAccount: (accountId) => electron.ipcRenderer.invoke("switch-account", accountId),
|
|
41
41
|
removeAccount: (accountId) => electron.ipcRenderer.invoke("remove-account", accountId),
|
|
42
42
|
getUserRepositories: () => electron.ipcRenderer.invoke("get-user-repositories"),
|
|
43
|
+
getCollaboratedRepos: () => electron.ipcRenderer.invoke("get-collaborated-repos"),
|
|
43
44
|
createGitHubRepository: (name, description, isPrivate, autoInit = false, gitignoreTemplate = "", licenseTemplate = "") => electron.ipcRenderer.invoke(
|
|
44
45
|
"create-github-repository",
|
|
45
46
|
name,
|
|
@@ -68,6 +69,9 @@ const api = {
|
|
|
68
69
|
setupUniversalWorkspace: (remoteUrl, branch, baseBranch, dest) => electron.ipcRenderer.invoke("setup-universal-workspace", remoteUrl, branch, baseBranch, dest),
|
|
69
70
|
checkUniversalCollisions: (workspacePath, sourceFiles, dest) => electron.ipcRenderer.invoke("check-universal-collisions", workspacePath, sourceFiles, dest),
|
|
70
71
|
getUniversalDiff: (workspacePath, file) => electron.ipcRenderer.invoke("get-universal-diff", workspacePath, file),
|
|
72
|
+
cloneRepository: (remoteUrl, destPath) => electron.ipcRenderer.invoke("clone-repository", remoteUrl, destPath),
|
|
73
|
+
checkPathExists: (targetPath) => electron.ipcRenderer.invoke("check-path-exists", targetPath),
|
|
74
|
+
uploadFilesToRepo: (repoPath) => electron.ipcRenderer.invoke("upload-files-to-repo", repoPath),
|
|
71
75
|
commitUniversalWorkspace: (workspacePath, msg, branch) => electron.ipcRenderer.invoke("commit-universal-workspace", workspacePath, msg, branch),
|
|
72
76
|
cleanupUniversalWorkspace: (workspacePath) => electron.ipcRenderer.invoke("cleanup-universal-workspace", workspacePath),
|
|
73
77
|
toggleAutoSync: (repoPath, enabled) => electron.ipcRenderer.send("toggle-auto-sync", repoPath, enabled),
|