gitxelectron 1.3.8 → 1.3.9
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
CHANGED
|
@@ -612,6 +612,20 @@ function initGit(sessionId, baseDir) {
|
|
|
612
612
|
GIT_ASKPASS: "echo"
|
|
613
613
|
});
|
|
614
614
|
gitSessions.set(sessionId, { git, repoPath: baseDir });
|
|
615
|
+
(async () => {
|
|
616
|
+
try {
|
|
617
|
+
const name = await git.getConfig("user.name");
|
|
618
|
+
if (!name.value) {
|
|
619
|
+
await git.addConfig("user.name", "GitElectron User");
|
|
620
|
+
}
|
|
621
|
+
const email = await git.getConfig("user.email");
|
|
622
|
+
if (!email.value) {
|
|
623
|
+
await git.addConfig("user.email", "auto@gitelectron.local");
|
|
624
|
+
}
|
|
625
|
+
} catch (e) {
|
|
626
|
+
console.warn("Failed to ensure git identity:", e);
|
|
627
|
+
}
|
|
628
|
+
})();
|
|
615
629
|
}
|
|
616
630
|
function createSafeGit(baseDir, sessionId) {
|
|
617
631
|
const options = {
|
|
@@ -1160,6 +1174,49 @@ async function pushToRemote(sessionId, remote, branch) {
|
|
|
1160
1174
|
throw err;
|
|
1161
1175
|
}
|
|
1162
1176
|
}
|
|
1177
|
+
async function masterForcePush(sessionId, remote, branch) {
|
|
1178
|
+
const { git } = getGitSession(sessionId);
|
|
1179
|
+
const remotes = await getRemotes(sessionId);
|
|
1180
|
+
const remoteObj = remotes.find((r) => r.name === remote);
|
|
1181
|
+
await git.raw(["add", "-A", "-f"]);
|
|
1182
|
+
try {
|
|
1183
|
+
const name = await git.getConfig("user.name");
|
|
1184
|
+
if (!name.value) await git.addConfig("user.name", "GitElectron User");
|
|
1185
|
+
const email = await git.getConfig("user.email");
|
|
1186
|
+
if (!email.value) await git.addConfig("user.email", "auto@gitelectron.local");
|
|
1187
|
+
} catch (e) {
|
|
1188
|
+
console.warn("Failed to ensure git identity before master push:", e);
|
|
1189
|
+
}
|
|
1190
|
+
try {
|
|
1191
|
+
await git.commit("Master Force Push - Including all files");
|
|
1192
|
+
} catch (e) {
|
|
1193
|
+
if (!e.message.includes("nothing to commit")) {
|
|
1194
|
+
throw e;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
const tempGit = simpleGit.simpleGit({
|
|
1198
|
+
baseDir: getGitSession(sessionId).repoPath,
|
|
1199
|
+
unsafe: { allowUnsafeEditor: true, allowUnsafeAskPass: true, allowUnsafeCredentialHelper: true }
|
|
1200
|
+
}).env({
|
|
1201
|
+
...process.env,
|
|
1202
|
+
GCM_INTERACTIVE: "false",
|
|
1203
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
1204
|
+
GIT_ASKPASS: "echo"
|
|
1205
|
+
});
|
|
1206
|
+
const pushArgs = [
|
|
1207
|
+
"-c",
|
|
1208
|
+
"credential.helper=",
|
|
1209
|
+
"push",
|
|
1210
|
+
"--progress",
|
|
1211
|
+
"--no-verify",
|
|
1212
|
+
"-f"
|
|
1213
|
+
];
|
|
1214
|
+
if (remoteObj && remoteObj.refs.push) {
|
|
1215
|
+
const authUrl = injectAuthToken(sessionId, remoteObj.refs.push);
|
|
1216
|
+
return await tempGit.raw([...pushArgs, authUrl, branch]);
|
|
1217
|
+
}
|
|
1218
|
+
return await tempGit.raw([...pushArgs, remote, branch]);
|
|
1219
|
+
}
|
|
1163
1220
|
async function pullFromRemote(sessionId, remote, branch) {
|
|
1164
1221
|
const { git, repoPath } = getGitSession(sessionId);
|
|
1165
1222
|
const remotes = await getRemotes(sessionId);
|
|
@@ -1168,6 +1225,14 @@ async function pullFromRemote(sessionId, remote, branch) {
|
|
|
1168
1225
|
}
|
|
1169
1226
|
const remoteObj = (remote ? remotes.find((r) => r.name === remote) : null) || remotes[0];
|
|
1170
1227
|
const targetRemote = remoteObj.name;
|
|
1228
|
+
try {
|
|
1229
|
+
const name = await git.getConfig("user.name");
|
|
1230
|
+
if (!name.value) await git.addConfig("user.name", "GitElectron User");
|
|
1231
|
+
const email = await git.getConfig("user.email");
|
|
1232
|
+
if (!email.value) await git.addConfig("user.email", "auto@gitelectron.local");
|
|
1233
|
+
} catch (e) {
|
|
1234
|
+
console.warn("Failed to ensure git identity before pull:", e);
|
|
1235
|
+
}
|
|
1171
1236
|
let targetBranch = branch;
|
|
1172
1237
|
if (!targetBranch) {
|
|
1173
1238
|
const status = await git.status();
|
|
@@ -1185,11 +1250,19 @@ async function pullFromRemote(sessionId, remote, branch) {
|
|
|
1185
1250
|
let didStash = false;
|
|
1186
1251
|
try {
|
|
1187
1252
|
const status = await git.status();
|
|
1253
|
+
if (status.conflicted && status.conflicted.length > 0) {
|
|
1254
|
+
throw new Error(
|
|
1255
|
+
`Pulling is not possible because you have unmerged files (${status.conflicted.join(", ")}). Please resolve conflicts or abort the merge.`
|
|
1256
|
+
);
|
|
1257
|
+
}
|
|
1188
1258
|
if (!status.isClean()) {
|
|
1189
1259
|
await git.raw(["stash", "push", "-u", "-m", "gitquickpush-autostash-before-pull"]);
|
|
1190
1260
|
didStash = true;
|
|
1191
1261
|
}
|
|
1192
1262
|
} catch (err) {
|
|
1263
|
+
if (err.message && err.message.includes("unmerged files")) {
|
|
1264
|
+
throw err;
|
|
1265
|
+
}
|
|
1193
1266
|
console.warn("Stash check before pull warning:", err);
|
|
1194
1267
|
}
|
|
1195
1268
|
try {
|
|
@@ -1999,183 +2072,6 @@ async function removeGitLock(sessionId) {
|
|
|
1999
2072
|
return false;
|
|
2000
2073
|
}
|
|
2001
2074
|
}
|
|
2002
|
-
async function masterPush(sessionId, remote, branch) {
|
|
2003
|
-
const { git, repoPath } = getGitSession(sessionId);
|
|
2004
|
-
const remotes = await getRemotes(sessionId);
|
|
2005
|
-
const remoteObj = (remote ? remotes.find((r) => r.name === remote) : null) || remotes[0];
|
|
2006
|
-
if (!remoteObj) throw new Error("No remote repository configured.");
|
|
2007
|
-
const targetRemote = remoteObj.name;
|
|
2008
|
-
const authUrl = remoteObj.refs?.push ? injectAuthToken(sessionId, remoteObj.refs.push) : targetRemote;
|
|
2009
|
-
let originalBranch = branch;
|
|
2010
|
-
try {
|
|
2011
|
-
const branchSummary = await git.branchLocal();
|
|
2012
|
-
originalBranch = branchSummary.current || branch;
|
|
2013
|
-
} catch (e) {
|
|
2014
|
-
}
|
|
2015
|
-
const tempBranch = `__master_push_temp_${Date.now()}`;
|
|
2016
|
-
const hiddenPointers = [];
|
|
2017
|
-
const cleanedAttrsFiles = [];
|
|
2018
|
-
const lfsOffFlags = [
|
|
2019
|
-
"-c",
|
|
2020
|
-
"filter.lfs.clean=cat",
|
|
2021
|
-
"-c",
|
|
2022
|
-
"filter.lfs.smudge=cat",
|
|
2023
|
-
"-c",
|
|
2024
|
-
"filter.lfs.process=",
|
|
2025
|
-
"-c",
|
|
2026
|
-
"filter.lfs.required=false",
|
|
2027
|
-
"-c",
|
|
2028
|
-
"lfs.allowincompletepush=true",
|
|
2029
|
-
"-c",
|
|
2030
|
-
"http.postBuffer=524288000",
|
|
2031
|
-
"-c",
|
|
2032
|
-
"credential.helper="
|
|
2033
|
-
];
|
|
2034
|
-
function runGit(args, allowFail = false) {
|
|
2035
|
-
return new Promise((resolve, reject) => {
|
|
2036
|
-
const child = child_process.spawn("git", [...lfsOffFlags, ...args], {
|
|
2037
|
-
cwd: repoPath,
|
|
2038
|
-
env: {
|
|
2039
|
-
...process.env,
|
|
2040
|
-
GIT_LFS_SKIP_SMUDGE: "1",
|
|
2041
|
-
GIT_LFS_SKIP_PUSH: "1",
|
|
2042
|
-
GCM_INTERACTIVE: "false",
|
|
2043
|
-
GIT_TERMINAL_PROMPT: "0",
|
|
2044
|
-
GIT_ASKPASS: "echo"
|
|
2045
|
-
}
|
|
2046
|
-
});
|
|
2047
|
-
const stdout = [];
|
|
2048
|
-
const stderr = [];
|
|
2049
|
-
child.stdout?.on("data", (d) => stdout.push(d.toString()));
|
|
2050
|
-
child.stderr?.on("data", (d) => stderr.push(d.toString()));
|
|
2051
|
-
child.on("error", (err) => allowFail ? resolve("") : reject(err));
|
|
2052
|
-
child.on("close", (code) => {
|
|
2053
|
-
if (code === 0 || allowFail) {
|
|
2054
|
-
resolve(stdout.join(""));
|
|
2055
|
-
} else {
|
|
2056
|
-
reject(new Error(stderr.join("") || `git exited with code ${code}`));
|
|
2057
|
-
}
|
|
2058
|
-
});
|
|
2059
|
-
});
|
|
2060
|
-
}
|
|
2061
|
-
async function processRepo(dir) {
|
|
2062
|
-
let entries;
|
|
2063
|
-
try {
|
|
2064
|
-
entries = await fs__namespace.readdir(dir, { withFileTypes: true });
|
|
2065
|
-
} catch (e) {
|
|
2066
|
-
return;
|
|
2067
|
-
}
|
|
2068
|
-
for (const entry of entries) {
|
|
2069
|
-
if (entry.name === ".git" || entry.name === "node_modules" || entry.name.endsWith(".__lfs_ptr_bak__"))
|
|
2070
|
-
continue;
|
|
2071
|
-
const fullPath = path__namespace.join(dir, entry.name);
|
|
2072
|
-
if (entry.isDirectory()) {
|
|
2073
|
-
await processRepo(fullPath);
|
|
2074
|
-
continue;
|
|
2075
|
-
}
|
|
2076
|
-
if (!entry.isFile()) continue;
|
|
2077
|
-
try {
|
|
2078
|
-
if (entry.name === ".gitattributes") {
|
|
2079
|
-
const content = await fs__namespace.readFile(fullPath, "utf8");
|
|
2080
|
-
if (content.includes("filter=lfs") || content.includes("lfs")) {
|
|
2081
|
-
cleanedAttrsFiles.push({ filePath: fullPath, original: content });
|
|
2082
|
-
const cleaned = content.split("\n").filter((line) => !line.toLowerCase().includes("lfs")).join("\n");
|
|
2083
|
-
await fs__namespace.writeFile(fullPath, cleaned);
|
|
2084
|
-
}
|
|
2085
|
-
continue;
|
|
2086
|
-
}
|
|
2087
|
-
const stat = await fs__namespace.stat(fullPath);
|
|
2088
|
-
if (stat.size < 4096 && stat.size > 20) {
|
|
2089
|
-
const buf = await fs__namespace.readFile(fullPath);
|
|
2090
|
-
const text = buf.toString("utf8");
|
|
2091
|
-
if (text.includes("version https://git-lfs.github.com/spec/v1") && text.includes("oid sha256:")) {
|
|
2092
|
-
const backupPath = fullPath + ".__lfs_ptr_bak__";
|
|
2093
|
-
await fs__namespace.rename(fullPath, backupPath);
|
|
2094
|
-
hiddenPointers.push({ original: fullPath, backup: backupPath });
|
|
2095
|
-
}
|
|
2096
|
-
}
|
|
2097
|
-
} catch (e) {
|
|
2098
|
-
}
|
|
2099
|
-
}
|
|
2100
|
-
}
|
|
2101
|
-
try {
|
|
2102
|
-
try {
|
|
2103
|
-
await git.raw(["lfs", "uninstall", "--local"]);
|
|
2104
|
-
} catch (e) {
|
|
2105
|
-
}
|
|
2106
|
-
try {
|
|
2107
|
-
await git.addConfig("filter.lfs.clean", "cat");
|
|
2108
|
-
await git.addConfig("filter.lfs.smudge", "cat");
|
|
2109
|
-
await git.addConfig("filter.lfs.process", "");
|
|
2110
|
-
await git.addConfig("filter.lfs.required", "false");
|
|
2111
|
-
} catch (e) {
|
|
2112
|
-
}
|
|
2113
|
-
await processRepo(repoPath);
|
|
2114
|
-
await runGit(["checkout", "--orphan", tempBranch]);
|
|
2115
|
-
await runGit(["add", "."]);
|
|
2116
|
-
try {
|
|
2117
|
-
const grepResult = await runGit(
|
|
2118
|
-
["grep", "--cached", "-l", "version https://git-lfs.github.com/spec/v1"],
|
|
2119
|
-
true
|
|
2120
|
-
);
|
|
2121
|
-
if (grepResult.trim()) {
|
|
2122
|
-
const lfsFiles = grepResult.trim().split("\n").filter(Boolean);
|
|
2123
|
-
for (const f of lfsFiles) {
|
|
2124
|
-
await runGit(["rm", "--cached", "--force", f.trim()], true);
|
|
2125
|
-
}
|
|
2126
|
-
}
|
|
2127
|
-
} catch (e) {
|
|
2128
|
-
}
|
|
2129
|
-
try {
|
|
2130
|
-
await runGit(["commit", "-m", "Master Override Push", "--no-verify"]);
|
|
2131
|
-
} catch (e) {
|
|
2132
|
-
}
|
|
2133
|
-
await runGit(["push", "--force", "--no-verify", authUrl, `${tempBranch}:${branch}`]);
|
|
2134
|
-
} finally {
|
|
2135
|
-
try {
|
|
2136
|
-
await runGit(["checkout", "-f", originalBranch], true);
|
|
2137
|
-
} catch (e) {
|
|
2138
|
-
try {
|
|
2139
|
-
await runGit(["checkout", "-f", branch], true);
|
|
2140
|
-
} catch (e2) {
|
|
2141
|
-
try {
|
|
2142
|
-
await runGit(["checkout", "-b", branch], true);
|
|
2143
|
-
} catch (e3) {
|
|
2144
|
-
}
|
|
2145
|
-
}
|
|
2146
|
-
}
|
|
2147
|
-
try {
|
|
2148
|
-
const branchList = await runGit(["branch", "--list", "__master_push_temp_*"], true);
|
|
2149
|
-
if (branchList.trim()) {
|
|
2150
|
-
const branches = branchList.trim().split("\n").map((b) => b.trim().replace(/^\*\s*/, "")).filter(Boolean);
|
|
2151
|
-
for (const b of branches) {
|
|
2152
|
-
await runGit(["branch", "-D", b], true);
|
|
2153
|
-
}
|
|
2154
|
-
}
|
|
2155
|
-
} catch (e) {
|
|
2156
|
-
}
|
|
2157
|
-
try {
|
|
2158
|
-
await runGit(["branch", "-D", tempBranch], true);
|
|
2159
|
-
} catch (e) {
|
|
2160
|
-
}
|
|
2161
|
-
for (const { original, backup } of hiddenPointers) {
|
|
2162
|
-
try {
|
|
2163
|
-
await fs__namespace.rename(backup, original);
|
|
2164
|
-
} catch (e) {
|
|
2165
|
-
}
|
|
2166
|
-
}
|
|
2167
|
-
for (const { filePath, original } of cleanedAttrsFiles) {
|
|
2168
|
-
try {
|
|
2169
|
-
await fs__namespace.writeFile(filePath, original);
|
|
2170
|
-
} catch (e) {
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2173
|
-
try {
|
|
2174
|
-
await git.raw(["lfs", "install", "--local"]);
|
|
2175
|
-
} catch (e) {
|
|
2176
|
-
}
|
|
2177
|
-
}
|
|
2178
|
-
}
|
|
2179
2075
|
const SYSTEM_PROMPT = `You are an autonomous Git Healer Agent for the "GitElectron" app.
|
|
2180
2076
|
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.
|
|
2181
2077
|
You will receive the Git Status and the Raw Error Message.
|
|
@@ -2296,10 +2192,14 @@ ${errorMsg}
|
|
|
2296
2192
|
]
|
|
2297
2193
|
};
|
|
2298
2194
|
}
|
|
2299
|
-
if (lowerError.includes("unmerged files") || lowerError.includes("you have unmerged paths")) {
|
|
2195
|
+
if (lowerError.includes("unmerged files") || lowerError.includes("you have unmerged paths") || lowerError.includes("unresolved conflict")) {
|
|
2300
2196
|
return {
|
|
2301
|
-
explanation: "Unmerged
|
|
2302
|
-
commandsToRun: [
|
|
2197
|
+
explanation: "Unmerged files detected. Resolving conflicts by keeping local changes...",
|
|
2198
|
+
commandsToRun: [
|
|
2199
|
+
"git checkout --ours .",
|
|
2200
|
+
"git add .",
|
|
2201
|
+
'git commit -m "Auto-resolved unmerged conflicts (kept local changes)"'
|
|
2202
|
+
]
|
|
2303
2203
|
};
|
|
2304
2204
|
}
|
|
2305
2205
|
if (lowerError.includes("please tell me who you are")) {
|
|
@@ -2932,15 +2832,15 @@ electron.app.whenReady().then(async () => {
|
|
|
2932
2832
|
}
|
|
2933
2833
|
return await pushToRemote(event.sender.id, remote, branch);
|
|
2934
2834
|
});
|
|
2835
|
+
electron.ipcMain.handle("master-push", async (event, remote, branch) => {
|
|
2836
|
+
return await masterForcePush(event.sender.id, remote, branch);
|
|
2837
|
+
});
|
|
2935
2838
|
electron.ipcMain.handle("pull-from-remote", async (event, remote, branch) => {
|
|
2936
2839
|
return await pullFromRemote(event.sender.id, remote, branch);
|
|
2937
2840
|
});
|
|
2938
2841
|
electron.ipcMain.handle("check-remote-updates", async (event) => {
|
|
2939
2842
|
return await checkRemoteUpdates(event.sender.id);
|
|
2940
2843
|
});
|
|
2941
|
-
electron.ipcMain.handle("master-push", async (event, remote, branch) => {
|
|
2942
|
-
return await masterPush(event.sender.id, remote, branch);
|
|
2943
|
-
});
|
|
2944
2844
|
electron.ipcMain.handle("reset-to-remote", async (event, remote, branch) => {
|
|
2945
2845
|
return await resetToRemote(event.sender.id, remote, branch);
|
|
2946
2846
|
});
|