gitxelectron 1.4.2 → 1.4.4

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.
@@ -14346,7 +14346,7 @@ function ContributorsModal({ onClose, remoteUrl }) {
14346
14346
  const [suggestions, setSuggestions] = reactExports.useState([]);
14347
14347
  const [showSuggestions, setShowSuggestions] = reactExports.useState(false);
14348
14348
  const debounceTimeoutRef = reactExports.useRef(null);
14349
- const fetchData = async () => {
14349
+ const fetchData = reactExports.useCallback(async () => {
14350
14350
  if (!remoteUrl) {
14351
14351
  setLoading(false);
14352
14352
  setErrorMsg(
@@ -14366,13 +14366,16 @@ function ContributorsModal({ onClose, remoteUrl }) {
14366
14366
  } finally {
14367
14367
  setLoading(false);
14368
14368
  }
14369
- };
14369
+ }, [remoteUrl]);
14370
14370
  reactExports.useEffect(() => {
14371
- fetchData();
14371
+ const timer = setTimeout(() => {
14372
+ fetchData();
14373
+ }, 0);
14372
14374
  return () => {
14375
+ clearTimeout(timer);
14373
14376
  if (debounceTimeoutRef.current) clearTimeout(debounceTimeoutRef.current);
14374
14377
  };
14375
- }, []);
14378
+ }, [fetchData]);
14376
14379
  const handleSelectUser = async (user) => {
14377
14380
  setNewUsername(user.login);
14378
14381
  setShowSuggestions(false);
@@ -14811,7 +14814,7 @@ function ContributorsModal({ onClose, remoteUrl }) {
14811
14814
  {
14812
14815
  src: user.avatar_url,
14813
14816
  alt: user.login,
14814
- className: "w-8 h-8 rounded-full bg-canvas"
14817
+ className: "w-8 h-8 rounded-full bg-canvas object-cover"
14815
14818
  }
14816
14819
  ),
14817
14820
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-sm font-medium text-primary flex items-center gap-2", children: [
@@ -14849,7 +14852,7 @@ function ContributorsModal({ onClose, remoteUrl }) {
14849
14852
  {
14850
14853
  src: user.avatar_url,
14851
14854
  alt: user.login,
14852
- className: "w-8 h-8 rounded-full bg-canvas mr-3"
14855
+ className: "w-8 h-8 rounded-full bg-canvas mr-3 object-cover"
14853
14856
  }
14854
14857
  ),
14855
14858
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
@@ -14870,8 +14873,45 @@ function ContributorsModal({ onClose, remoteUrl }) {
14870
14873
  ] })
14871
14874
  ] }) });
14872
14875
  }
14873
- const AIHealerOverlay = ({ message, attempt, maxAttempts, originalError }) => {
14874
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute inset-0 bg-black/80 backdrop-blur-sm flex flex-col items-center justify-center z-[200] animate-fade-in", children: [
14876
+ const AIHealerOverlay = ({ message, attempt, maxAttempts, originalError, onMinimize, onClose }) => {
14877
+ const cleanedError = originalError ? originalError.replace(/^Error invoking remote method '[^']+':\s*/i, "").replace(/^Error:\s*/i, "").replace(/^fatal:\s*/i, "") : "";
14878
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute inset-0 bg-black/85 backdrop-blur-md flex flex-col items-center justify-center z-[200] p-6 animate-fade-in", children: [
14879
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute top-6 right-6 flex items-center gap-2 z-20", children: [
14880
+ onMinimize && /* @__PURE__ */ jsxRuntimeExports.jsx(
14881
+ "button",
14882
+ {
14883
+ onClick: onMinimize,
14884
+ className: "p-2 rounded-full bg-surface/60 hover:bg-surface border border-border text-secondary hover:text-primary transition-all active:scale-95 shadow-md flex items-center gap-1",
14885
+ title: "Minimize to Bottom Dock (Runs in background)",
14886
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
14887
+ "path",
14888
+ {
14889
+ strokeLinecap: "round",
14890
+ strokeLinejoin: "round",
14891
+ strokeWidth: 2,
14892
+ d: "M19 14l-7 7m0 0l-7-7m7 7V3"
14893
+ }
14894
+ ) })
14895
+ }
14896
+ ),
14897
+ onClose && /* @__PURE__ */ jsxRuntimeExports.jsx(
14898
+ "button",
14899
+ {
14900
+ onClick: onClose,
14901
+ className: "p-2 rounded-full bg-surface/60 hover:bg-surface border border-border text-secondary hover:text-danger transition-all active:scale-95 shadow-md",
14902
+ title: "Permanently Stop & Close Healer",
14903
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
14904
+ "path",
14905
+ {
14906
+ strokeLinecap: "round",
14907
+ strokeLinejoin: "round",
14908
+ strokeWidth: 2,
14909
+ d: "M6 18L18 6M6 6l12 12"
14910
+ }
14911
+ ) })
14912
+ }
14913
+ )
14914
+ ] }),
14875
14915
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative flex items-center justify-center mb-6", children: [
14876
14916
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 bg-brand/20 blur-xl rounded-full scale-150 animate-pulse" }),
14877
14917
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -14905,17 +14945,43 @@ const AIHealerOverlay = ({ message, attempt, maxAttempts, originalError }) => {
14905
14945
  )
14906
14946
  ] }),
14907
14947
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-xl font-bold text-white tracking-wide mb-2 animate-pulse", children: "AI Auto-Healer Active" }),
14908
- originalError && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4 max-w-lg w-full px-6", children: [
14948
+ cleanedError && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4 max-w-lg w-full px-4", children: [
14909
14949
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-secondary/80 mb-1 text-center font-semibold", children: "Resolving Error:" }),
14910
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-red-900/20 border border-red-500/30 rounded-md p-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-red-200/90 font-mono text-center break-words max-h-24 overflow-y-auto custom-scrollbar", children: originalError }) })
14950
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-red-900/20 border border-red-500/30 rounded-xl p-3.5 shadow-inner", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-red-200/90 font-mono text-center break-words max-h-28 overflow-y-auto custom-scrollbar", children: cleanedError }) })
14911
14951
  ] }),
14912
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium text-brand/90 mb-6 bg-brand/10 border border-brand/20 px-4 py-2 rounded-full shadow-inner", children: message }),
14913
- attempt > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-secondary/70", children: [
14952
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-medium text-brand/90 mb-4 bg-brand/10 border border-brand/20 px-4 py-2 rounded-full shadow-inner max-w-md text-center", children: message }),
14953
+ attempt > 1 && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-secondary/70 mb-5", children: [
14914
14954
  "Attempt ",
14915
14955
  attempt,
14916
14956
  " of ",
14917
14957
  maxAttempts,
14918
14958
  "..."
14959
+ ] }),
14960
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
14961
+ onMinimize && /* @__PURE__ */ jsxRuntimeExports.jsxs(
14962
+ "button",
14963
+ {
14964
+ onClick: onMinimize,
14965
+ className: "px-4 py-2 bg-surface hover:bg-surface-hover border border-border text-secondary hover:text-primary rounded-xl text-xs font-semibold transition-all active:scale-95 shadow-md flex items-center gap-1.5",
14966
+ title: "Minimize to Bottom Dock",
14967
+ children: [
14968
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "⤓" }),
14969
+ " Minimize to Background"
14970
+ ]
14971
+ }
14972
+ ),
14973
+ onClose && /* @__PURE__ */ jsxRuntimeExports.jsxs(
14974
+ "button",
14975
+ {
14976
+ onClick: onClose,
14977
+ className: "px-4 py-2 bg-danger/15 hover:bg-danger/25 border border-danger/40 text-danger rounded-xl text-xs font-semibold transition-all active:scale-95 shadow-md flex items-center gap-1.5",
14978
+ title: "Permanently cancel and stop AI healer",
14979
+ children: [
14980
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "✕" }),
14981
+ " Stop & Close"
14982
+ ]
14983
+ }
14984
+ )
14919
14985
  ] })
14920
14986
  ] });
14921
14987
  };
@@ -25821,6 +25887,28 @@ const THEMES = [
25821
25887
  { id: "turbo-cpp-classic", name: "Turbo C++ Classic" },
25822
25888
  { id: "game-rpg", name: "RPG Game UI" }
25823
25889
  ];
25890
+ const formatErrorMessage = (msg) => {
25891
+ if (!msg) return "";
25892
+ let cleaned = msg.replace(/^Error invoking remote method '[^']+':\s*/i, "").replace(/^Error:\s*/i, "").replace(/^error:\s*/i, "").replace(/^fatal:\s*/i, "");
25893
+ cleaned = cleaned.replace(
25894
+ /(?:Enumerating|Counting|Compressing|Writing)\s+objects:\s*\d+%(?:\s*\([^)]+\))?,?/gi,
25895
+ ""
25896
+ ).replace(/Delta compression using up to \d+ threads,?/gi, "").replace(/Total \d+ \(delta \d+\), reused \d+/gi, "").replace(/POST git-(?:receive|upload)-pack \([^)]+\)/gi, "").replace(/To https:\/\/github\.com[^\r\n]*/gi, "").replace(/[\r\n]{2,}/g, "\n").trim();
25897
+ if (cleaned.includes("Protected branch update failed") || cleaned.includes("GH006") || cleaned.includes("Cannot force-push to a protected branch")) {
25898
+ return "GitHub rejected push: Protected branch policy is enabled. Force-pushing to this branch is blocked in your GitHub repository settings.";
25899
+ }
25900
+ if (cleaned.includes("GH001") || cleaned.includes("exceeds GitHub's file size limit")) {
25901
+ const match = cleaned.match(/File\s+([^\s]+)\s+is\s+([0-9.]+)\s+MB/i);
25902
+ if (match) {
25903
+ return `Large file rejected: "${match[1]}" is ${match[2]} MB (exceeds GitHub's 100 MB limit). Please track it with Git LFS or add it to .gitignore.`;
25904
+ }
25905
+ return "Large file rejected: Files exceeding GitHub's 100 MB limit must use Git LFS or be added to .gitignore.";
25906
+ }
25907
+ if (cleaned.includes("RPC failed") || cleaned.includes("the remote end hung up unexpectedly") || cleaned.includes("early EOF") || cleaned.includes("curl 55")) {
25908
+ return "Push connection interrupted or payload too large. (Buffer configured to 1GB). Check network stability or use Git LFS for large assets.";
25909
+ }
25910
+ return cleaned || "An unexpected Git error occurred.";
25911
+ };
25824
25912
  function App() {
25825
25913
  const [repoPath, setRepoPath] = reactExports.useState(null);
25826
25914
  const [collaboratedRepos, setCollaboratedRepos] = reactExports.useState([]);
@@ -26031,6 +26119,8 @@ function App() {
26031
26119
  const [history, setHistory] = reactExports.useState(null);
26032
26120
  const [deletedHistory, setDeletedHistory] = reactExports.useState(null);
26033
26121
  const [isPulling, setIsPulling] = reactExports.useState(false);
26122
+ const [showForcePullModal, setShowForcePullModal] = reactExports.useState(false);
26123
+ const [showMasterPushModal, setShowMasterPushModal] = reactExports.useState(false);
26034
26124
  const [expandedCommits, setExpandedCommits] = reactExports.useState({});
26035
26125
  const toggleCommit = (hash) => {
26036
26126
  setExpandedCommits((prev) => ({ ...prev, [hash]: !prev[hash] }));
@@ -26059,9 +26149,49 @@ function App() {
26059
26149
  const [showAutoSyncLogs, setShowAutoSyncLogs] = reactExports.useState(false);
26060
26150
  const [isRefreshing, setIsRefreshing] = reactExports.useState(false);
26061
26151
  const [gitProgress, setGitProgress] = reactExports.useState(0);
26152
+ const [gitProgressStage, setGitProgressStage] = reactExports.useState("");
26153
+ const [syncElapsedSeconds, setSyncElapsedSeconds] = reactExports.useState(0);
26062
26154
  const refreshLockRef = reactExports.useRef(false);
26155
+ const isSyncActive = isPushing || isPulling || isExecutingForcePush;
26063
26156
  reactExports.useEffect(() => {
26064
- }, [gitProgress]);
26157
+ if (!isSyncActive) return;
26158
+ const startTime = Date.now();
26159
+ const timer = setInterval(() => {
26160
+ setSyncElapsedSeconds(Math.floor((Date.now() - startTime) / 1e3));
26161
+ }, 1e3);
26162
+ return () => {
26163
+ clearInterval(timer);
26164
+ setSyncElapsedSeconds(0);
26165
+ setGitProgress(0);
26166
+ setGitProgressStage("");
26167
+ };
26168
+ }, [isSyncActive]);
26169
+ const formatTimerDisplay = (totalSec) => {
26170
+ const mins = Math.floor(totalSec / 60);
26171
+ const secs = totalSec % 60;
26172
+ return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
26173
+ };
26174
+ const computeRemainingEta = (progress2, elapsed, massiveEta) => {
26175
+ if (massiveEta && massiveEta !== "calculating..." && !massiveEta.includes("Uploading Chunk")) {
26176
+ return massiveEta;
26177
+ }
26178
+ if (progress2 >= 100) return "Finalizing sync with GitHub...";
26179
+ if (progress2 > 0 && elapsed > 0) {
26180
+ const rate = progress2 / elapsed;
26181
+ const remainingPercent = 100 - progress2;
26182
+ const remainingSeconds = Math.max(1, Math.round(remainingPercent / rate));
26183
+ if (remainingSeconds < 60) {
26184
+ return `~${remainingSeconds}s remaining`;
26185
+ }
26186
+ const mins = Math.floor(remainingSeconds / 60);
26187
+ const secs = remainingSeconds % 60;
26188
+ return `~${mins}m ${secs}s remaining`;
26189
+ }
26190
+ if (elapsed > 0) {
26191
+ return `Estimating time remaining...`;
26192
+ }
26193
+ return "Calculating...";
26194
+ };
26065
26195
  reactExports.useEffect(() => {
26066
26196
  const activeTheme = showSettings ? draftTheme : theme;
26067
26197
  document.documentElement.setAttribute("data-theme", activeTheme);
@@ -26074,14 +26204,17 @@ function App() {
26074
26204
  const [healerMessage, setHealerMessage] = reactExports.useState("");
26075
26205
  const [healerOriginalError, setHealerOriginalError] = reactExports.useState("");
26076
26206
  const [healerAttempt, setHealerAttempt] = reactExports.useState(0);
26207
+ const [isHealerMinimized, setIsHealerMinimized] = reactExports.useState(false);
26208
+ const isHealingCancelledRef = reactExports.useRef(false);
26077
26209
  const [showBranchModal, setShowBranchModal] = reactExports.useState(false);
26078
26210
  const [toasts, setToasts] = reactExports.useState([]);
26079
26211
  const showToast = (msg, type = "info") => {
26080
26212
  const id2 = Date.now() + Math.random();
26081
- setToasts((prev) => [...prev, { id: id2, msg, type }]);
26213
+ const sanitizedMsg = type === "error" ? formatErrorMessage(msg) : msg;
26214
+ setToasts((prev) => [...prev, { id: id2, msg: sanitizedMsg, type }]);
26082
26215
  setTimeout(() => {
26083
26216
  setToasts((prev) => prev.filter((t2) => t2.id !== id2));
26084
- }, 4e3);
26217
+ }, 5e3);
26085
26218
  };
26086
26219
  const loadRepo = async (targetPath) => {
26087
26220
  try {
@@ -26297,6 +26430,9 @@ function App() {
26297
26430
  window.api.onGitProgress((data) => {
26298
26431
  if (data && typeof data.progress === "number") {
26299
26432
  setGitProgress(data.progress);
26433
+ if (data.stage) {
26434
+ setGitProgressStage(data.stage);
26435
+ }
26300
26436
  }
26301
26437
  });
26302
26438
  window.api.onAutoSyncErrorApproval((payload) => {
@@ -26773,9 +26909,50 @@ Are you SURE you want to link "${repoName}" to this folder?`
26773
26909
  setIsPulling(false);
26774
26910
  }
26775
26911
  };
26776
- const formatErrorMessage = (msg) => {
26777
- if (!msg) return "";
26778
- return msg.replace(/^Error invoking remote method '[^']+':\s*/i, "").replace(/^Error:\s*/i, "").replace(/^error:\s*/i, "").trim();
26912
+ const handleForcePull = () => {
26913
+ setShowForcePullModal(true);
26914
+ };
26915
+ const executeForcePull = async () => {
26916
+ setShowForcePullModal(false);
26917
+ setIsPulling(true);
26918
+ try {
26919
+ const remotes = await window.api.getRemotes();
26920
+ if (remotes.length > 0) {
26921
+ showToast("⚡ Executing Force Pull directly from GitHub...", "info");
26922
+ const targetRemote = remotes[0].name;
26923
+ const targetBranch = branches?.current || status?.current || "main";
26924
+ const result = await window.api.masterPull(targetRemote, targetBranch);
26925
+ await refreshRepoState();
26926
+ setPushFailureData(null);
26927
+ showToast(
26928
+ `⚡ ${result.message || "Force Pull completed! Project is 100% synced with GitHub."}`,
26929
+ "success"
26930
+ );
26931
+ } else {
26932
+ setShowSetupWizard(true);
26933
+ }
26934
+ } catch (e) {
26935
+ showToast(`Force Pull failed: ${formatErrorMessage(e.message)}`, "error");
26936
+ } finally {
26937
+ setIsPulling(false);
26938
+ }
26939
+ };
26940
+ const executeMasterPush = async () => {
26941
+ setShowMasterPushModal(false);
26942
+ try {
26943
+ const remotes = await window.api.getRemotes();
26944
+ if (!remotes || remotes.length === 0) {
26945
+ showToast("No remote configured to push to.", "error");
26946
+ return;
26947
+ }
26948
+ showToast("Executing Master Push override...", "info");
26949
+ await window.api.masterPush(remotes[0].name, status?.current || "main");
26950
+ showToast("Master Push successful!", "success");
26951
+ refreshRepoState();
26952
+ cancelSettings();
26953
+ } catch (err) {
26954
+ showToast("Master Push failed: " + (err.message || "Unknown error"), "error");
26955
+ }
26779
26956
  };
26780
26957
  const handleResolveConflictOurs = async () => {
26781
26958
  try {
@@ -26848,14 +27025,18 @@ Are you SURE you want to link "${repoName}" to this folder?`
26848
27025
  let attempts = 0;
26849
27026
  const maxAttempts = 5;
26850
27027
  const targetRepoPath = overrideRepoPath || repoPath;
27028
+ isHealingCancelledRef.current = false;
27029
+ setIsHealerMinimized(false);
26851
27030
  setShowHealerOverlay(true);
26852
27031
  setHealerOriginalError(initialError);
26853
27032
  setHealerMessage(`Analyzing initial ${operation} failure...`);
26854
27033
  setHealerAttempt(1);
26855
27034
  while (attempts < maxAttempts) {
27035
+ if (isHealingCancelledRef.current) break;
26856
27036
  attempts++;
26857
27037
  setHealerAttempt(attempts);
26858
27038
  try {
27039
+ if (isHealingCancelledRef.current) break;
26859
27040
  if (overrideRepoPath) {
26860
27041
  await window.api.setRepoPath(overrideRepoPath);
26861
27042
  }
@@ -26931,15 +27112,34 @@ Are you SURE you want to link "${repoName}" to this folder?`
26931
27112
  setHealerMessage(result.explanation || `Applying fix...`);
26932
27113
  if (result.commandsToRun && result.commandsToRun.length > 0) {
26933
27114
  for (const cmd of result.commandsToRun) {
26934
- const parts = cmd.split(" ").filter((p) => p.trim() !== "");
26935
- if (parts[0] === "git") parts.shift();
26936
- await window.api.executeRawGit(parts);
27115
+ const regex = /[^\s"']+|"([^"]*)"|'([^']*)'/g;
27116
+ const parts = [];
27117
+ let match;
27118
+ while ((match = regex.exec(cmd)) !== null) {
27119
+ if (match[1] !== void 0) {
27120
+ parts.push(match[1]);
27121
+ } else if (match[2] !== void 0) {
27122
+ parts.push(match[2]);
27123
+ } else {
27124
+ parts.push(match[0]);
27125
+ }
27126
+ }
27127
+ if (parts.length > 0 && parts[0] === "git") {
27128
+ parts.shift();
27129
+ }
27130
+ if (parts.length > 0) {
27131
+ try {
27132
+ await window.api.executeRawGit(parts);
27133
+ } catch (cmdErr) {
27134
+ console.warn(`Command "${cmd}" returned notice:`, cmdErr?.message);
27135
+ }
27136
+ }
26937
27137
  }
26938
27138
  }
26939
27139
  const remotes = await window.api.getRemotes();
26940
27140
  if (remotes.length > 0) {
27141
+ const targetBranch = overrideBranch || branches?.current || status?.current || "main";
26941
27142
  if (operation === "push") {
26942
- const targetBranch = overrideBranch || branches.current;
26943
27143
  if (pushAllBranches && !overrideBranch)
26944
27144
  await window.api.pushAllBranches(remotes[0].name);
26945
27145
  else await window.api.pushToRemote(remotes[0].name, targetBranch);
@@ -26955,7 +27155,7 @@ Are you SURE you want to link "${repoName}" to this folder?`
26955
27155
  } else {
26956
27156
  const wasConflict = currentError.includes("unmerged files") || currentError.includes("unresolved conflict") || currentError.includes("automatic merge failed") || currentError.includes("you have unmerged paths");
26957
27157
  if (!wasConflict) {
26958
- await window.api.pullFromRemote(remotes[0].name, overrideBranch || branches.current);
27158
+ await window.api.pullFromRemote(remotes[0].name, targetBranch);
26959
27159
  }
26960
27160
  }
26961
27161
  setHealerMessage(`Successfully auto-healed and reconciled!`);
@@ -26975,6 +27175,23 @@ Are you SURE you want to link "${repoName}" to this folder?`
26975
27175
  setHealerMessage(`Attempt ${attempts} failed. Analyzing new error...`);
26976
27176
  }
26977
27177
  }
27178
+ if (overrideRepoPath && repoPath) {
27179
+ await window.api.setRepoPath(repoPath);
27180
+ }
27181
+ setShowHealerOverlay(false);
27182
+ setIsHealerMinimized(false);
27183
+ if (!isHealingCancelledRef.current) {
27184
+ showToast(
27185
+ `AI Healer could not resolve error automatically: ${formatErrorMessage(currentError)}`,
27186
+ "error"
27187
+ );
27188
+ setPushFailureData({
27189
+ reason: currentError,
27190
+ operation,
27191
+ overrideRepoPath,
27192
+ overrideBranch
27193
+ });
27194
+ }
26978
27195
  return false;
26979
27196
  };
26980
27197
  const confirmPush = async () => {
@@ -28183,29 +28400,7 @@ Are you SURE you want to link "${repoName}" to this folder?`
28183
28400
  "button",
28184
28401
  {
28185
28402
  type: "button",
28186
- onClick: async () => {
28187
- const confirmAction = window.confirm(
28188
- "Are you sure? This will force push all current files, overriding remote history and bypassing all safety checks."
28189
- );
28190
- if (!confirmAction) return;
28191
- try {
28192
- const remotes = await window.api.getRemotes();
28193
- if (!remotes || remotes.length === 0) {
28194
- showToast("No remote configured to push to.", "error");
28195
- return;
28196
- }
28197
- showToast("Executing Master Push override...", "info");
28198
- await window.api.masterPush(remotes[0].name, status?.current || "main");
28199
- showToast("Master Push successful!", "success");
28200
- refreshRepoState();
28201
- cancelSettings();
28202
- } catch (err) {
28203
- showToast(
28204
- "Master Push failed: " + (err.message || "Unknown error"),
28205
- "error"
28206
- );
28207
- }
28208
- },
28403
+ onClick: () => setShowMasterPushModal(true),
28209
28404
  className: "shrink-0 px-5 py-2.5 bg-danger hover:bg-danger/80 text-white text-xs font-bold rounded-xl transition-all shadow-sm",
28210
28405
  children: "Execute Force Push"
28211
28406
  }
@@ -28651,19 +28846,248 @@ Are you SURE you want to link "${repoName}" to this folder?`
28651
28846
  )
28652
28847
  ] })
28653
28848
  ] }) }),
28849
+ showForcePullModal && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-[150] transition-opacity p-4 animate-in fade-in duration-200", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative bg-surface/95 backdrop-blur-xl p-6 rounded-2xl shadow-2xl border border-amber-500/30 w-full max-w-[480px] mx-4 flex flex-col gap-4 animate-in zoom-in-95 duration-200", children: [
28850
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute -inset-0.5 bg-gradient-to-r from-amber-500/15 via-orange-500/10 to-amber-500/15 rounded-2xl blur-xl -z-10 pointer-events-none" }),
28851
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
28852
+ "button",
28853
+ {
28854
+ onClick: () => setShowForcePullModal(false),
28855
+ className: "absolute top-4 right-4 text-secondary hover:text-primary transition-colors p-1.5 rounded-lg hover:bg-surface-hover",
28856
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
28857
+ "path",
28858
+ {
28859
+ strokeLinecap: "round",
28860
+ strokeLinejoin: "round",
28861
+ strokeWidth: 2,
28862
+ d: "M6 18L18 6M6 6l12 12"
28863
+ }
28864
+ ) })
28865
+ }
28866
+ ),
28867
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3.5 pr-8", children: [
28868
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-11 h-11 rounded-xl bg-amber-500/10 border border-amber-500/30 flex items-center justify-center text-amber-400 flex-shrink-0 shadow-inner", children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
28869
+ "path",
28870
+ {
28871
+ strokeLinecap: "round",
28872
+ strokeLinejoin: "round",
28873
+ strokeWidth: 2,
28874
+ d: "M13 10V3L4 14h7v7l9-11h-7z"
28875
+ }
28876
+ ) }) }),
28877
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
28878
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-base font-bold text-primary flex items-center gap-2", children: "Force Pull (Hard Sync from GitHub)" }),
28879
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-secondary mt-0.5", children: "Synchronize local repository to 100% match GitHub" })
28880
+ ] })
28881
+ ] }),
28882
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-canvas/60 border border-border/80 rounded-xl p-3.5 flex flex-col gap-2.5 text-xs text-secondary", children: [
28883
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between text-[11px] pb-2 border-b border-border/60", children: [
28884
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-secondary/80", children: "Target Branch:" }),
28885
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-primary font-semibold bg-surface px-2 py-0.5 rounded border border-border", children: [
28886
+ "origin / ",
28887
+ branches?.current || status?.current || "main"
28888
+ ] })
28889
+ ] }),
28890
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "leading-relaxed", children: "This will pull all commits directly from GitHub. Any untracked temporary conflicts or desynchronized files will be safely aligned to match the GitHub remote." }),
28891
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start gap-2 pt-1 text-amber-400/90 bg-amber-500/5 p-2 rounded-lg border border-amber-500/20", children: [
28892
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm leading-none mt-0.5", children: "⚠️" }),
28893
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] leading-tight", children: "Local uncommitted changes will be automatically aligned so your local folder is completely in sync with your team on GitHub." })
28894
+ ] })
28895
+ ] }),
28896
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-end gap-3 pt-2", children: [
28897
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
28898
+ "button",
28899
+ {
28900
+ type: "button",
28901
+ onClick: () => setShowForcePullModal(false),
28902
+ className: "px-4 py-2.5 rounded-xl border border-border bg-surface hover:bg-surface-hover text-secondary hover:text-primary text-xs font-medium transition-all",
28903
+ children: "Cancel"
28904
+ }
28905
+ ),
28906
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
28907
+ "button",
28908
+ {
28909
+ type: "button",
28910
+ onClick: executeForcePull,
28911
+ disabled: isPulling,
28912
+ className: "px-5 py-2.5 rounded-xl bg-gradient-to-r from-amber-500 to-orange-600 hover:from-amber-600 hover:to-orange-700 text-white text-xs font-semibold shadow-lg shadow-amber-500/20 flex items-center gap-2 transition-all active:scale-[0.98] disabled:opacity-50",
28913
+ children: isPulling ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
28914
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
28915
+ "svg",
28916
+ {
28917
+ className: "w-4 h-4 animate-spin text-white",
28918
+ fill: "none",
28919
+ viewBox: "0 0 24 24",
28920
+ children: [
28921
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
28922
+ "circle",
28923
+ {
28924
+ className: "opacity-25",
28925
+ cx: "12",
28926
+ cy: "12",
28927
+ r: "10",
28928
+ stroke: "currentColor",
28929
+ strokeWidth: "4"
28930
+ }
28931
+ ),
28932
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
28933
+ "path",
28934
+ {
28935
+ className: "opacity-75",
28936
+ fill: "currentColor",
28937
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
28938
+ }
28939
+ )
28940
+ ]
28941
+ }
28942
+ ),
28943
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Force Pulling..." })
28944
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "⚡ Confirm Force Pull" }) })
28945
+ }
28946
+ )
28947
+ ] })
28948
+ ] }) }),
28949
+ showMasterPushModal && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-[150] transition-opacity p-4 animate-in fade-in duration-200", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative bg-surface/95 backdrop-blur-xl p-6 rounded-2xl shadow-2xl border border-danger/30 w-full max-w-[480px] mx-4 flex flex-col gap-4 animate-in zoom-in-95 duration-200", children: [
28950
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute -inset-0.5 bg-gradient-to-r from-red-500/15 via-rose-500/10 to-red-500/15 rounded-2xl blur-xl -z-10 pointer-events-none" }),
28951
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
28952
+ "button",
28953
+ {
28954
+ onClick: () => setShowMasterPushModal(false),
28955
+ className: "absolute top-4 right-4 text-secondary hover:text-primary transition-colors p-1.5 rounded-lg hover:bg-surface-hover",
28956
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
28957
+ "path",
28958
+ {
28959
+ strokeLinecap: "round",
28960
+ strokeLinejoin: "round",
28961
+ strokeWidth: 2,
28962
+ d: "M6 18L18 6M6 6l12 12"
28963
+ }
28964
+ ) })
28965
+ }
28966
+ ),
28967
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3.5 pr-8", children: [
28968
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-11 h-11 rounded-xl bg-danger/10 border border-danger/30 flex items-center justify-center text-danger flex-shrink-0 shadow-inner", children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-6 h-6", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
28969
+ "path",
28970
+ {
28971
+ strokeLinecap: "round",
28972
+ strokeLinejoin: "round",
28973
+ strokeWidth: 2,
28974
+ d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
28975
+ }
28976
+ ) }) }),
28977
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
28978
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-base font-bold text-primary flex items-center gap-2", children: "Master Force Push Override" }),
28979
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-secondary mt-0.5", children: "Force overwrite remote branch on GitHub" })
28980
+ ] })
28981
+ ] }),
28982
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-canvas/60 border border-border/80 rounded-xl p-3.5 flex flex-col gap-2.5 text-xs text-secondary", children: [
28983
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "leading-relaxed", children: "This will force push all current files to GitHub, bypassing standard safety checks and overriding remote commit history." }),
28984
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start gap-2 pt-1 text-danger/90 bg-danger/5 p-2 rounded-lg border border-danger/20", children: [
28985
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm leading-none mt-0.5", children: "⚠️" }),
28986
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] leading-tight font-medium", children: "Use caution: Any commits on GitHub not present in your local branch will be permanently overwritten." })
28987
+ ] })
28988
+ ] }),
28989
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-end gap-3 pt-2", children: [
28990
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
28991
+ "button",
28992
+ {
28993
+ type: "button",
28994
+ onClick: () => setShowMasterPushModal(false),
28995
+ className: "px-4 py-2.5 rounded-xl border border-border bg-surface hover:bg-surface-hover text-secondary hover:text-primary text-xs font-medium transition-all",
28996
+ children: "Cancel"
28997
+ }
28998
+ ),
28999
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29000
+ "button",
29001
+ {
29002
+ type: "button",
29003
+ onClick: executeMasterPush,
29004
+ className: "px-5 py-2.5 rounded-xl bg-danger hover:bg-danger/90 text-white text-xs font-semibold shadow-lg shadow-danger/20 flex items-center gap-2 transition-all active:scale-[0.98]",
29005
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Execute Force Push" })
29006
+ }
29007
+ )
29008
+ ] })
29009
+ ] }) }),
28654
29010
  isCloning && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute inset-0 bg-black/80 backdrop-blur-sm flex flex-col items-center justify-center z-[200]", children: [
28655
29011
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 border-4 border-brand border-t-transparent rounded-full animate-spin mb-4 shadow-[0_0_15px_rgba(var(--brand-color),0.5)]" }),
28656
29012
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-white font-medium tracking-wide text-lg", children: "Cloning Repository..." })
28657
29013
  ] }),
28658
- showHealerOverlay && /* @__PURE__ */ jsxRuntimeExports.jsx(
29014
+ showHealerOverlay && !isHealerMinimized && /* @__PURE__ */ jsxRuntimeExports.jsx(
28659
29015
  AIHealerOverlay,
28660
29016
  {
28661
29017
  message: healerMessage,
28662
29018
  attempt: healerAttempt,
28663
29019
  maxAttempts: 5,
28664
- originalError: healerOriginalError
29020
+ originalError: healerOriginalError,
29021
+ onMinimize: () => setIsHealerMinimized(true),
29022
+ onClose: () => setIsHealerMinimized(true)
28665
29023
  }
28666
29024
  ),
29025
+ showHealerOverlay && isHealerMinimized && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fixed bottom-6 right-6 z-[250] bg-surface/95 border border-brand/50 backdrop-blur-2xl rounded-2xl p-3.5 shadow-2xl flex items-center gap-3.5 max-w-md animate-slideUp", children: [
29026
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
29027
+ "div",
29028
+ {
29029
+ onClick: () => setIsHealerMinimized(false),
29030
+ className: "relative flex items-center justify-center flex-shrink-0 cursor-pointer group",
29031
+ title: "Click to expand AI Healer window",
29032
+ children: [
29033
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 bg-brand/30 blur-md rounded-full scale-125 animate-pulse" }),
29034
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8 h-8 rounded-full bg-brand/20 border border-brand/40 flex items-center justify-center text-brand font-bold text-xs relative z-10 group-hover:scale-105 transition-transform", children: "✨" })
29035
+ ]
29036
+ }
29037
+ ),
29038
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
29039
+ "div",
29040
+ {
29041
+ onClick: () => setIsHealerMinimized(false),
29042
+ className: "flex-1 min-w-0 cursor-pointer",
29043
+ title: "Click to expand AI Healer window",
29044
+ children: [
29045
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
29046
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-primary flex items-center gap-1.5", children: "AI Auto-Healer Active" }),
29047
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] bg-brand/15 text-brand px-1.5 py-0.5 rounded font-mono font-semibold", children: [
29048
+ "Attempt ",
29049
+ healerAttempt,
29050
+ " of 5"
29051
+ ] })
29052
+ ] }),
29053
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-secondary truncate mt-0.5 font-mono", children: healerMessage || "Analyzing repository state..." })
29054
+ ]
29055
+ }
29056
+ ),
29057
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 flex-shrink-0 border-l border-border/60 pl-2.5", children: [
29058
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29059
+ "button",
29060
+ {
29061
+ onClick: () => setIsHealerMinimized(false),
29062
+ className: "px-2 py-1 text-secondary hover:text-primary bg-surface-hover hover:bg-surface border border-border rounded-lg text-xs font-semibold transition-all active:scale-95",
29063
+ title: "Expand full AI Healer window",
29064
+ children: "⛶ Expand"
29065
+ }
29066
+ ),
29067
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29068
+ "button",
29069
+ {
29070
+ onClick: () => {
29071
+ isHealingCancelledRef.current = true;
29072
+ setShowHealerOverlay(false);
29073
+ setIsHealerMinimized(false);
29074
+ showToast("AI Auto-Healer permanently stopped.", "info");
29075
+ },
29076
+ className: "p-1.5 text-secondary hover:text-danger bg-surface-hover hover:bg-danger/20 border border-border hover:border-danger/40 rounded-lg transition-all active:scale-95",
29077
+ title: "Permanently cancel and stop AI Healer",
29078
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
29079
+ "path",
29080
+ {
29081
+ strokeLinecap: "round",
29082
+ strokeLinejoin: "round",
29083
+ strokeWidth: 2,
29084
+ d: "M6 18L18 6M6 6l12 12"
29085
+ }
29086
+ ) })
29087
+ }
29088
+ )
29089
+ ] })
29090
+ ] }),
28667
29091
  showAutoSyncLogs && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-[110] transition-opacity", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-surface/95 backdrop-blur-xl p-8 rounded-xl shadow-2xl border border-border w-full max-w-[600px] mx-4 flex flex-col max-h-[80vh]", children: [
28668
29092
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-6 border-b border-border pb-4", children: [
28669
29093
  /* @__PURE__ */ jsxRuntimeExports.jsxs("h2", { className: "text-xl font-bold text-primary flex items-center gap-2", children: [
@@ -29021,10 +29445,11 @@ Are you SURE you want to link "${repoName}" to this folder?`
29021
29445
  onClick: async () => {
29022
29446
  const data = pushFailureData;
29023
29447
  setPushFailureData(null);
29448
+ setIsExecutingForcePush(true);
29024
29449
  try {
29025
29450
  const remotes = await window.api.getRemotes();
29026
29451
  const targetRemote = data?.overrideRepoPath || remotes[0]?.name || "origin";
29027
- const targetBranch = data?.overrideBranch || "main";
29452
+ const targetBranch = data?.overrideBranch || branches?.current || status?.current || "main";
29028
29453
  await window.api.masterPush(targetRemote, targetBranch);
29029
29454
  setPushSuccessData({
29030
29455
  files: "All",
@@ -29038,12 +29463,23 @@ Are you SURE you want to link "${repoName}" to this folder?`
29038
29463
  overrideRepoPath: data?.overrideRepoPath,
29039
29464
  overrideBranch: data?.overrideBranch
29040
29465
  });
29466
+ } finally {
29467
+ setIsExecutingForcePush(false);
29041
29468
  }
29042
29469
  },
29043
29470
  className: "w-full mt-2 py-2.5 bg-danger/20 hover:bg-danger/30 border border-danger/50 text-danger rounded-md font-bold transition-all text-sm flex items-center justify-center gap-2 shadow-lg shadow-danger/10 active:scale-[0.99]",
29044
29471
  title: "Force push everything (including ignored files) bypassing all rules",
29045
29472
  children: "⚡ Master Force Push (Override All)"
29046
29473
  }
29474
+ ),
29475
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29476
+ "button",
29477
+ {
29478
+ onClick: handleForcePull,
29479
+ className: "w-full mt-2 py-2.5 bg-amber-500/20 hover:bg-amber-500/30 border border-amber-500/50 text-amber-400 rounded-md font-bold transition-all text-sm flex items-center justify-center gap-2 shadow-lg shadow-amber-500/10 active:scale-[0.99]",
29480
+ title: "Force pull all files directly from GitHub (discards local divergence)",
29481
+ children: "⚡ Master Force Pull (Hard Sync from GitHub)"
29482
+ }
29047
29483
  )
29048
29484
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3", children: [
29049
29485
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [
@@ -29090,10 +29526,11 @@ Are you SURE you want to link "${repoName}" to this folder?`
29090
29526
  onClick: async () => {
29091
29527
  const data = pushFailureData;
29092
29528
  setPushFailureData(null);
29529
+ setIsExecutingForcePush(true);
29093
29530
  try {
29094
29531
  const remotes = await window.api.getRemotes();
29095
29532
  const targetRemote = data?.overrideRepoPath || remotes[0]?.name || "origin";
29096
- const targetBranch = data?.overrideBranch || "main";
29533
+ const targetBranch = data?.overrideBranch || branches?.current || status?.current || "main";
29097
29534
  await window.api.masterPush(targetRemote, targetBranch);
29098
29535
  setPushSuccessData({
29099
29536
  files: "All",
@@ -29107,12 +29544,23 @@ Are you SURE you want to link "${repoName}" to this folder?`
29107
29544
  overrideRepoPath: data?.overrideRepoPath,
29108
29545
  overrideBranch: data?.overrideBranch
29109
29546
  });
29547
+ } finally {
29548
+ setIsExecutingForcePush(false);
29110
29549
  }
29111
29550
  },
29112
29551
  className: "w-full py-2 bg-danger/20 hover:bg-danger/30 border border-danger/50 text-danger rounded-md font-bold transition-all text-sm flex items-center justify-center gap-2 active:scale-[0.99]",
29113
29552
  title: "Force push everything (including ignored files) bypassing all rules",
29114
29553
  children: "⚡ Master Force Push (Override All)"
29115
29554
  }
29555
+ ),
29556
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29557
+ "button",
29558
+ {
29559
+ onClick: handleForcePull,
29560
+ className: "w-full py-2 bg-amber-500/20 hover:bg-amber-500/30 border border-amber-500/50 text-amber-400 rounded-md font-bold transition-all text-sm flex items-center justify-center gap-2 active:scale-[0.99]",
29561
+ title: "Force pull all files directly from GitHub (discards local divergence)",
29562
+ children: "⚡ Master Force Pull (Hard Sync from GitHub)"
29563
+ }
29116
29564
  )
29117
29565
  ] })
29118
29566
  ]
@@ -29234,36 +29682,48 @@ Are you SURE you want to link "${repoName}" to this folder?`
29234
29682
  ]
29235
29683
  }
29236
29684
  ),
29237
- repoPath && /* @__PURE__ */ jsxRuntimeExports.jsxs(
29238
- "button",
29239
- {
29240
- onClick: handlePull,
29241
- disabled: isPulling,
29242
- className: `w-full font-medium py-2 px-4 rounded-md transition-all border text-sm flex items-center justify-center gap-2 shadow-sm ${(status?.behind ?? 0) > 0 ? "bg-blue-600/25 text-blue-300 border-blue-500/50 hover:bg-blue-600/35 ring-1 ring-blue-500/30 animate-pulse" : "bg-surface-hover hover:brightness-110 text-primary border-border hover:border-brand/40"}`,
29243
- title: "Download and update all new files pushed by team members on GitHub to your local folder",
29244
- children: [
29245
- /* @__PURE__ */ jsxRuntimeExports.jsx(
29246
- "svg",
29247
- {
29248
- className: "w-4 h-4 text-accent",
29249
- fill: "none",
29250
- stroke: "currentColor",
29251
- viewBox: "0 0 24 24",
29252
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
29253
- "path",
29254
- {
29255
- strokeLinecap: "round",
29256
- strokeLinejoin: "round",
29257
- strokeWidth: 2,
29258
- d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
29259
- }
29260
- )
29261
- }
29262
- ),
29263
- isPulling ? "Pulling..." : (status?.behind ?? 0) > 0 ? `Pull (${status.behind})` : "Pull"
29264
- ]
29265
- }
29266
- )
29685
+ repoPath && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 w-full", children: [
29686
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
29687
+ "button",
29688
+ {
29689
+ onClick: handlePull,
29690
+ disabled: isPulling,
29691
+ className: `flex-1 font-medium py-2 px-3 rounded-md transition-all border text-sm flex items-center justify-center gap-1.5 shadow-sm ${(status?.behind ?? 0) > 0 ? "bg-blue-600/25 text-blue-300 border-blue-500/50 hover:bg-blue-600/35 ring-1 ring-blue-500/30 animate-pulse" : "bg-surface-hover hover:brightness-110 text-primary border-border hover:border-brand/40"}`,
29692
+ title: "Download and update all new files pushed by team members on GitHub to your local folder",
29693
+ children: [
29694
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29695
+ "svg",
29696
+ {
29697
+ className: "w-4 h-4 text-accent",
29698
+ fill: "none",
29699
+ stroke: "currentColor",
29700
+ viewBox: "0 0 24 24",
29701
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
29702
+ "path",
29703
+ {
29704
+ strokeLinecap: "round",
29705
+ strokeLinejoin: "round",
29706
+ strokeWidth: 2,
29707
+ d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
29708
+ }
29709
+ )
29710
+ }
29711
+ ),
29712
+ isPulling ? "Pulling..." : (status?.behind ?? 0) > 0 ? `Pull (${status.behind})` : "Pull"
29713
+ ]
29714
+ }
29715
+ ),
29716
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
29717
+ "button",
29718
+ {
29719
+ onClick: handleForcePull,
29720
+ disabled: isPulling,
29721
+ className: "px-3 py-2 bg-amber-500/15 hover:bg-amber-500/25 border border-amber-500/40 text-amber-400 hover:text-amber-300 rounded-md font-bold text-xs transition-all flex items-center justify-center gap-1 shadow-sm active:scale-[0.98]",
29722
+ title: "⚡ Force Pull: Instantly force-sync all files 1:1 with GitHub (overrides any divergence or missing files)",
29723
+ children: "⚡ Force Pull"
29724
+ }
29725
+ )
29726
+ ] })
29267
29727
  ] }),
29268
29728
  collaboratedRepos.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-4", children: [
29269
29729
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-secondary font-semibold mb-2 uppercase tracking-wider px-1", children: t("collaborationRepo") }),
@@ -29977,6 +30437,16 @@ Are you SURE you want to link "${repoName}" to this folder?`
29977
30437
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: (status?.behind ?? 0) > 0 ? `Pull (${status.behind})` : "Pull" })
29978
30438
  ] })
29979
30439
  }
30440
+ ),
30441
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
30442
+ "button",
30443
+ {
30444
+ onClick: handleForcePull,
30445
+ disabled: isPulling,
30446
+ title: "⚡ Force Pull: Instantly force-sync all files 1:1 with GitHub (overrides any divergence or missing files)",
30447
+ className: "ml-1.5 px-2.5 py-1.5 bg-amber-500/15 hover:bg-amber-500/25 border border-amber-500/40 text-amber-400 hover:text-amber-300 rounded-lg font-bold text-xs transition-all flex items-center gap-1 shadow-sm active:scale-[0.98] disabled:opacity-50",
30448
+ children: "⚡ Force Pull"
30449
+ }
29980
30450
  )
29981
30451
  ] })
29982
30452
  ] }),
@@ -30859,10 +31329,53 @@ Are you SURE you want to link "${repoName}" to this folder?`
30859
31329
  }
30860
31330
  }
30861
31331
  ),
30862
- (isPushing || isPulling || isUnlocking) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute inset-0 bg-black/80 backdrop-blur-md flex flex-col items-center justify-center z-[100] transition-opacity", children: [
30863
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-3/4 max-w-[600px]", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Loader, {}) }),
30864
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center text-primary mt-8 font-mono text-lg animate-pulse tracking-wide drop-shadow-md", children: isPushing ? "Pushing to remote..." : isPulling ? "Pulling from remote..." : unlockingText })
30865
- ] }),
31332
+ (isSyncActive || isUnlocking) && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 bg-black/85 backdrop-blur-md flex flex-col items-center justify-center z-[100] transition-opacity p-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full max-w-[540px] flex flex-col items-center", children: [
31333
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full max-w-[460px] mb-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Loader, {}) }),
31334
+ isUnlocking ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center text-primary mt-4 font-mono text-lg animate-pulse tracking-wide drop-shadow-md", children: unlockingText }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full bg-surface/90 border border-border/80 rounded-2xl p-6 shadow-2xl backdrop-blur-xl flex flex-col items-center text-center", children: [
31335
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2 mb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
31336
+ "span",
31337
+ {
31338
+ className: `inline-flex items-center px-2.5 py-1 rounded-full text-xs font-bold uppercase tracking-wider ${isExecutingForcePush ? "bg-danger/20 text-danger border border-danger/40 animate-pulse" : isPulling ? "bg-amber-500/20 text-amber-400 border border-amber-500/40" : "bg-brand/20 text-brand border border-brand/40"}`,
31339
+ children: isExecutingForcePush ? "⚡ Master Force Push" : isPulling ? "📥 Pull / Force Pull" : "🚀 Live Push"
31340
+ }
31341
+ ) }),
31342
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-bold text-primary mb-1", children: isExecutingForcePush ? "Force Overriding Remote Repository" : isPulling ? "Syncing Team Files from GitHub" : "Uploading Changes to Remote" }),
31343
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-secondary font-mono mb-4", children: gitProgressStage ? `${gitProgressStage}...` : "Streaming files and objects securely to repository" }),
31344
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full bg-canvas/80 border border-border rounded-full h-3 overflow-hidden p-0.5 mb-4 shadow-inner", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
31345
+ "div",
31346
+ {
31347
+ className: "h-full rounded-full bg-gradient-to-r from-brand via-cyan-400 to-brand transition-all duration-300 shadow-md shadow-brand/30",
31348
+ style: {
31349
+ width: `${Math.min(
31350
+ 100,
31351
+ Math.max(
31352
+ gitProgress > 0 ? gitProgress : massivePushData?.percentage || 8,
31353
+ 8
31354
+ )
31355
+ )}%`
31356
+ }
31357
+ }
31358
+ ) }),
31359
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full grid grid-cols-3 gap-2 py-3 px-4 bg-canvas/60 rounded-xl border border-border/60 text-center mb-3", children: [
31360
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [
31361
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-secondary uppercase font-semibold tracking-wider", children: "Progress" }),
31362
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-base font-bold text-primary font-mono mt-0.5", children: gitProgress > 0 ? `${Math.round(gitProgress)}%` : massivePushData?.percentage ? `${Math.round(massivePushData.percentage)}%` : "Syncing..." })
31363
+ ] }),
31364
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col border-x border-border/60", children: [
31365
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-secondary uppercase font-semibold tracking-wider", children: "⏱️ Elapsed" }),
31366
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-base font-bold text-cyan-400 font-mono mt-0.5", children: formatTimerDisplay(syncElapsedSeconds) })
31367
+ ] }),
31368
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [
31369
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-secondary uppercase font-semibold tracking-wider", children: "⏳ Time Left" }),
31370
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-base font-bold text-amber-400 font-mono mt-0.5", children: computeRemainingEta(gitProgress, syncElapsedSeconds, massivePushData?.eta) })
31371
+ ] })
31372
+ ] }),
31373
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-[11px] text-secondary", children: [
31374
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-emerald-400 inline-block" }),
31375
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: gitProgress > 0 && syncElapsedSeconds > 0 ? `Speed: ~${(gitProgress / syncElapsedSeconds).toFixed(1)}% per second • Safe sync active` : "Live sync engine active • Safe transfer in progress" })
31376
+ ] })
31377
+ ] })
31378
+ ] }) }),
30866
31379
  showInvitationsModal && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-50 p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-surface border border-border p-6 rounded-2xl w-full max-w-md shadow-2xl", children: [
30867
31380
  /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-xl font-bold text-primary mb-4", children: "Pending Invitations" }),
30868
31381
  invitations.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center py-6 text-secondary", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "You have no pending invitations." }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-3 max-h-96 overflow-y-auto pr-2 custom-scrollbar", children: invitations.map((inv) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
@@ -31303,7 +31816,14 @@ Are you SURE you want to link "${repoName}" to this folder?`
31303
31816
  )
31304
31817
  }
31305
31818
  ),
31306
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold text-sm drop-shadow-md text-white/95", children: toast.msg }),
31819
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
31820
+ "span",
31821
+ {
31822
+ className: "font-semibold text-sm drop-shadow-md text-white/95 max-w-xl truncate inline-block",
31823
+ title: toast.msg,
31824
+ children: toast.msg
31825
+ }
31826
+ ),
31307
31827
  /* @__PURE__ */ jsxRuntimeExports.jsx(
31308
31828
  "button",
31309
31829
  {