gh-manager-cli 1.45.0 → 1.45.1

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [1.45.1](https://github.com/wiiiimm/gh-manager-cli/compare/v1.45.0...v1.45.1) (2026-06-07)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * ignore modal input while async actions are in flight, add guard tests (SWR-368) [semantic pr title] ([#64](https://github.com/wiiiimm/gh-manager-cli/issues/64)) ([97d2e4e](https://github.com/wiiiimm/gh-manager-cli/commit/97d2e4e25fc5d10cd2305ffb3f594b3f0b094e20)), closes [#65](https://github.com/wiiiimm/gh-manager-cli/issues/65)
7
+
1
8
  # [1.45.0](https://github.com/wiiiimm/gh-manager-cli/compare/v1.44.0...v1.45.0) (2026-06-07)
2
9
 
3
10
 
package/dist/index.js CHANGED
@@ -37,7 +37,7 @@ var require_package = __commonJS({
37
37
  "package.json"(exports, module) {
38
38
  module.exports = {
39
39
  name: "gh-manager-cli",
40
- version: "1.45.0",
40
+ version: "1.45.1",
41
41
  private: false,
42
42
  description: "TUI terminal app to manage GitHub repos. Clean up your account in 5 minutes. Archive, delete, rename repos with keyboard shortcuts. Alternative to clicking through github.com",
43
43
  license: "MIT",
@@ -411,7 +411,7 @@ async function openGitHubAuthorizationPage() {
411
411
  }
412
412
 
413
413
  // src/ui/views/RepoList.tsx
414
- import React19, { useEffect as useEffect13, useMemo as useMemo2, useState as useState19, useRef as useRef3, useCallback } from "react";
414
+ import React19, { useEffect as useEffect13, useMemo as useMemo2, useState as useState19, useRef as useRef7, useCallback } from "react";
415
415
  import { Box as Box22, Text as Text23, useApp, useInput as useInput19, useStdout } from "ink";
416
416
  import TextInput7 from "ink-text-input";
417
417
  import chalk15 from "chalk";
@@ -813,7 +813,7 @@ function ArchiveFilterModal({
813
813
  }
814
814
 
815
815
  // src/ui/components/modals/DeleteModal.tsx
816
- import { useState as useState4, useEffect as useEffect4 } from "react";
816
+ import { useEffect as useEffect4, useRef, useState as useState4 } from "react";
817
817
  import { Box as Box3, Text as Text4, useInput as useInput3 } from "ink";
818
818
  import TextInput from "ink-text-input";
819
819
  import chalk4 from "chalk";
@@ -838,13 +838,13 @@ function SlowSpinner({ interval = 500 } = {}) {
838
838
  import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
839
839
 
840
840
  // src/ui/components/modals/ArchiveModal.tsx
841
- import { useState as useState5 } from "react";
841
+ import { useRef as useRef2, useState as useState5 } from "react";
842
842
  import { Box as Box4, Text as Text5, useInput as useInput4 } from "ink";
843
843
  import chalk5 from "chalk";
844
844
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
845
845
 
846
846
  // src/ui/components/modals/SyncModal.tsx
847
- import { useState as useState6 } from "react";
847
+ import { useRef as useRef3, useState as useState6 } from "react";
848
848
  import { Box as Box5, Text as Text6, useInput as useInput5 } from "ink";
849
849
  import chalk6 from "chalk";
850
850
  import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
@@ -1370,6 +1370,7 @@ var ChangeVisibilityModal = ({
1370
1370
  }, [isOpen, isFork]);
1371
1371
  useInput11((input, key) => {
1372
1372
  if (!isOpen) return;
1373
+ if (changing) return;
1373
1374
  if (key.escape || input?.toLowerCase() === "c") {
1374
1375
  onClose();
1375
1376
  return;
@@ -1523,6 +1524,7 @@ var ChangeVisibilityModal = ({
1523
1524
  onChange: () => {
1524
1525
  },
1525
1526
  onSubmit: () => {
1527
+ if (changing) return;
1526
1528
  if (isFork || focusedButton === "cancel") {
1527
1529
  onClose();
1528
1530
  } else {
@@ -1666,7 +1668,7 @@ function CopyUrlModal({ repo, terminalWidth, onClose, onCopy, theme: themeProp }
1666
1668
  }
1667
1669
 
1668
1670
  // src/ui/components/modals/RenameModal.tsx
1669
- import { useState as useState13, useEffect as useEffect9 } from "react";
1671
+ import { useEffect as useEffect9, useRef as useRef4, useState as useState13 } from "react";
1670
1672
  import { Box as Box13, Text as Text14, useInput as useInput13 } from "ink";
1671
1673
  import TextInput3 from "ink-text-input";
1672
1674
  import { Fragment as Fragment6, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
@@ -1674,6 +1676,7 @@ function RenameModal({ repo, onRename, onCancel, theme: themeProp }) {
1674
1676
  const { theme } = useTheme(themeProp?.name ?? "default");
1675
1677
  const [newName, setNewName] = useState13("");
1676
1678
  const [renaming, setRenaming] = useState13(false);
1679
+ const renamingRef = useRef4(false);
1677
1680
  const [renameError, setRenameError] = useState13(null);
1678
1681
  useEffect9(() => {
1679
1682
  if (repo) {
@@ -1682,7 +1685,7 @@ function RenameModal({ repo, onRename, onCancel, theme: themeProp }) {
1682
1685
  }
1683
1686
  }, [repo]);
1684
1687
  useInput13((input, key) => {
1685
- if (renaming) return;
1688
+ if (renamingRef.current) return;
1686
1689
  if (key.escape) {
1687
1690
  onCancel();
1688
1691
  return;
@@ -1695,13 +1698,15 @@ function RenameModal({ repo, onRename, onCancel, theme: themeProp }) {
1695
1698
  }
1696
1699
  });
1697
1700
  const handleRenameConfirm = async () => {
1698
- if (!repo || renaming || !newName.trim() || newName === repo.name) return;
1701
+ if (!repo || renamingRef.current || !newName.trim() || newName === repo.name) return;
1699
1702
  try {
1703
+ renamingRef.current = true;
1700
1704
  setRenaming(true);
1701
1705
  setRenameError(null);
1702
1706
  await onRename(repo, newName.trim());
1703
1707
  } catch (e) {
1704
1708
  setRenameError(e.message || "Failed to rename repository");
1709
+ renamingRef.current = false;
1705
1710
  setRenaming(false);
1706
1711
  }
1707
1712
  };
@@ -1777,6 +1782,7 @@ function StarModal({
1777
1782
  const [focusedButton, setFocusedButton] = useState14("cancel");
1778
1783
  useInput14((input, key) => {
1779
1784
  if (!visible) return;
1785
+ if (isStarring) return;
1780
1786
  if (key.escape || input === "c" || input === "C") {
1781
1787
  onCancel();
1782
1788
  return;
@@ -1948,7 +1954,7 @@ function OpenInBrowserModal({ repo, onOpen, onCancel, theme: themeProp }) {
1948
1954
  }
1949
1955
 
1950
1956
  // src/ui/components/modals/CreateRepoModal.tsx
1951
- import { useState as useState16, useRef } from "react";
1957
+ import { useState as useState16, useRef as useRef5 } from "react";
1952
1958
  import { Box as Box16, Text as Text17, useInput as useInput16 } from "ink";
1953
1959
  import TextInput4 from "ink-text-input";
1954
1960
  import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
@@ -1958,10 +1964,10 @@ function CreateRepoModal({ ownerSlug, isOrg, isEnterprise, onCreate, onCancel, t
1958
1964
  const [visibility, setVisibility] = useState16("PRIVATE");
1959
1965
  const [creating, setCreating] = useState16(false);
1960
1966
  const [error, setError] = useState16(null);
1961
- const submittingRef = useRef(false);
1967
+ const submittingRef = useRef5(false);
1962
1968
  const visibilities = isOrg && isEnterprise ? ["PRIVATE", "PUBLIC", "INTERNAL"] : ["PRIVATE", "PUBLIC"];
1963
1969
  useInput16((input, key) => {
1964
- if (creating) return;
1970
+ if (submittingRef.current) return;
1965
1971
  if (key.escape) {
1966
1972
  onCancel();
1967
1973
  return;
@@ -2054,7 +2060,7 @@ function CreateRepoModal({ ownerSlug, isOrg, isEnterprise, onCreate, onCancel, t
2054
2060
  }
2055
2061
 
2056
2062
  // src/ui/components/modals/TransferModal.tsx
2057
- import { useState as useState17, useRef as useRef2, useEffect as useEffect11 } from "react";
2063
+ import { useState as useState17, useRef as useRef6, useEffect as useEffect11 } from "react";
2058
2064
  import { Box as Box17, Text as Text18, useInput as useInput17 } from "ink";
2059
2065
  import TextInput5 from "ink-text-input";
2060
2066
  import { Fragment as Fragment9, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
@@ -2067,7 +2073,7 @@ function TransferModal({ repo, onTransfer, onCancel, theme: themeProp }) {
2067
2073
  const [error, setError] = useState17(null);
2068
2074
  const [transferCode, setTransferCode] = useState17("");
2069
2075
  const [typedCode, setTypedCode] = useState17("");
2070
- const submittingRef = useRef2(false);
2076
+ const submittingRef = useRef6(false);
2071
2077
  const owner = repo ? repo.nameWithOwner.split("/")[0] : "";
2072
2078
  useEffect11(() => {
2073
2079
  if (repo) {
@@ -2084,7 +2090,7 @@ function TransferModal({ repo, onTransfer, onCancel, theme: themeProp }) {
2084
2090
  }
2085
2091
  }, [repo]);
2086
2092
  useInput17((input, key) => {
2087
- if (transferring || !repo) return;
2093
+ if (submittingRef.current || !repo) return;
2088
2094
  if (key.escape) {
2089
2095
  onCancel();
2090
2096
  return;
@@ -2299,6 +2305,7 @@ function UnstarModal({
2299
2305
  const [focusedButton, setFocusedButton] = useState18("cancel");
2300
2306
  useInput18((input, key) => {
2301
2307
  if (!visible) return;
2308
+ if (isUnstarring) return;
2302
2309
  if (key.escape || input === "c" || input === "C") {
2303
2310
  onCancel();
2304
2311
  return;
@@ -2528,7 +2535,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
2528
2535
  setDebugMessages((prev) => [...prev.slice(-9), msg]);
2529
2536
  }
2530
2537
  }, []);
2531
- const handleOrgContextChangeRef = useRef3(onOrgContextChange);
2538
+ const handleOrgContextChangeRef = useRef7(onOrgContextChange);
2532
2539
  useEffect13(() => {
2533
2540
  handleOrgContextChangeRef.current = onOrgContextChange;
2534
2541
  }, [onOrgContextChange]);
@@ -2562,7 +2569,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
2562
2569
  const [prefsLoaded, setPrefsLoaded] = useState19(false);
2563
2570
  const [themeName, setThemeName] = useState19("default");
2564
2571
  const [themeToast, setThemeToast] = useState19(null);
2565
- const themeToastTimerRef = useRef3(null);
2572
+ const themeToastTimerRef = useRef7(null);
2566
2573
  const { theme, c: tc } = useTheme(themeName);
2567
2574
  const [ownerContext, setOwnerContext] = useState19("personal");
2568
2575
  const [ownerAffiliations, setOwnerAffiliations] = useState19(["OWNER"]);
@@ -2628,8 +2635,8 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
2628
2635
  const [openInBrowserMode, setOpenInBrowserMode] = useState19(false);
2629
2636
  const [openInBrowserTarget, setOpenInBrowserTarget] = useState19(null);
2630
2637
  const [enrichingForks, setEnrichingForks] = useState19(false);
2631
- const enrichmentDoneRef = useRef3(/* @__PURE__ */ new Set());
2632
- const appliedInitialOrg = useRef3(false);
2638
+ const enrichmentDoneRef = useRef7(/* @__PURE__ */ new Set());
2639
+ const appliedInitialOrg = useRef7(false);
2633
2640
  useEffect13(() => {
2634
2641
  (async () => {
2635
2642
  if (appliedInitialOrg.current) return;
@@ -2923,7 +2930,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
2923
2930
  trackSuccessfulOperation();
2924
2931
  closeTransferModal();
2925
2932
  }
2926
- const copyToastTimerRef = useRef3(null);
2933
+ const copyToastTimerRef = useRef7(null);
2927
2934
  async function handleCopyUrl(url, type) {
2928
2935
  try {
2929
2936
  if (copyToastTimerRef.current) {
@@ -3127,8 +3134,8 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
3127
3134
  }
3128
3135
  }
3129
3136
  const [visibilityFilter, setVisibilityFilter] = useState19("all");
3130
- const previousVisibilityFilter = useRef3("all");
3131
- const pendingFocusRef = useRef3(null);
3137
+ const previousVisibilityFilter = useRef7("all");
3138
+ const pendingFocusRef = useRef7(null);
3132
3139
  const [archiveFilter, setArchiveFilter] = useState19("all");
3133
3140
  const sortFieldMap = {
3134
3141
  "updated": "UPDATED_AT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gh-manager-cli",
3
- "version": "1.45.0",
3
+ "version": "1.45.1",
4
4
  "private": false,
5
5
  "description": "TUI terminal app to manage GitHub repos. Clean up your account in 5 minutes. Archive, delete, rename repos with keyboard shortcuts. Alternative to clicking through github.com",
6
6
  "license": "MIT",