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 paths detected. Committing current state to proceed...",
2302
- commandsToRun: ["git add .", 'git commit -m "Auto-resolve unmerged paths"']
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
  });