gh-manager-cli 1.10.3 → 1.10.5

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,17 @@
1
+ ## [1.10.5](https://github.com/wiiiimm/gh-manager-cli/compare/v1.10.4...v1.10.5) (2025-09-01)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * prevent duplicate modal handlers and improve modal UI ([79281d3](https://github.com/wiiiimm/gh-manager-cli/commit/79281d34fe42d3345885cad257e6800e94eb2bb3))
7
+
8
+ ## [1.10.4](https://github.com/wiiiimm/gh-manager-cli/compare/v1.10.3...v1.10.4) (2025-09-01)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * eliminate duplicate sync handler to prevent double execution ([bf838b6](https://github.com/wiiiimm/gh-manager-cli/commit/bf838b66f5c8b7def294d3835278cd32254bce1f))
14
+
1
15
  ## [1.10.3](https://github.com/wiiiimm/gh-manager-cli/compare/v1.10.2...v1.10.3) (2025-09-01)
2
16
 
3
17
 
@@ -668,19 +668,6 @@ async function syncForkWithUpstream(token, owner, repo, branch = "main") {
668
668
  const body = await res.json();
669
669
  return body;
670
670
  }
671
- if (res.status === 422) {
672
- try {
673
- const body = await res.json();
674
- if (body && body.message && body.message.includes("There was a problem updating the branch")) {
675
- return {
676
- message: "Sync completed (with warnings)",
677
- merge_type: "merge",
678
- base_branch: branch
679
- };
680
- }
681
- } catch {
682
- }
683
- }
684
671
  let msg = `Fork sync failed (status ${res.status})`;
685
672
  try {
686
673
  const body = await res.json();
@@ -689,6 +676,9 @@ async function syncForkWithUpstream(token, owner, repo, branch = "main") {
689
676
  if (res.status === 409) {
690
677
  msg += " (conflicts detected - manual merge required)";
691
678
  }
679
+ if (res.status === 422) {
680
+ msg += " (branch could not be synced)";
681
+ }
692
682
  }
693
683
  } catch {
694
684
  }
@@ -17,7 +17,7 @@ import {
17
17
  updateCacheAfterArchive,
18
18
  updateCacheAfterDelete,
19
19
  updateCacheWithRepository
20
- } from "./chunk-KOZ6QCTU.js";
20
+ } from "./chunk-XCFI3TG5.js";
21
21
  export {
22
22
  archiveRepositoryById,
23
23
  deleteRepositoryRest,
package/dist/index.js CHANGED
@@ -16,14 +16,14 @@ import {
16
16
  updateCacheAfterArchive,
17
17
  updateCacheAfterDelete,
18
18
  updateCacheWithRepository
19
- } from "./chunk-KOZ6QCTU.js";
19
+ } from "./chunk-XCFI3TG5.js";
20
20
 
21
21
  // package.json
22
22
  var require_package = __commonJS({
23
23
  "package.json"(exports, module) {
24
24
  module.exports = {
25
25
  name: "gh-manager-cli",
26
- version: "1.10.3",
26
+ version: "1.10.5",
27
27
  private: false,
28
28
  description: "Interactive CLI to manage your GitHub repos (personal) with Ink",
29
29
  license: "MIT",
@@ -279,7 +279,7 @@ function OrgSwitcher({ token, currentContext, onSelect, onClose }) {
279
279
  const loadOrgs = async () => {
280
280
  try {
281
281
  setLoading(true);
282
- const client = await import("./github-HC6GZCKR.js").then((m) => m.makeClient(token));
282
+ const client = await import("./github-6IFMCQKW.js").then((m) => m.makeClient(token));
283
283
  const orgs = await fetchViewerOrganizations(client);
284
284
  setOrganizations(orgs);
285
285
  if (!isPersonalContext) {
@@ -486,6 +486,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
486
486
  const [syncing, setSyncing] = useState3(false);
487
487
  const [syncError, setSyncError] = useState3(null);
488
488
  const [syncFocus, setSyncFocus] = useState3("confirm");
489
+ const [syncTrigger, setSyncTrigger] = useState3(false);
489
490
  const [infoMode, setInfoMode] = useState3(false);
490
491
  const [infoRepo, setInfoRepo] = useState3(null);
491
492
  const [logoutMode, setLogoutMode] = useState3(false);
@@ -504,6 +505,67 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
504
505
  setSyncing(false);
505
506
  setSyncError(null);
506
507
  setSyncFocus("confirm");
508
+ setSyncTrigger(false);
509
+ }
510
+ async function executeSync() {
511
+ if (!syncTarget || syncing) return;
512
+ try {
513
+ setSyncing(true);
514
+ const [owner, repo] = syncTarget.nameWithOwner.split("/");
515
+ const branchName = syncTarget.defaultBranchRef?.name || "main";
516
+ const result = await syncForkWithUpstream(token, owner, repo, branchName);
517
+ const updatedRepo = {
518
+ ...syncTarget,
519
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
520
+ // If we're tracking fork commits and this is a fork with parent data, set commits to be in sync
521
+ ...forkTracking && syncTarget.isFork && syncTarget.parent && syncTarget.defaultBranchRef?.target?.history && syncTarget.parent.defaultBranchRef?.target?.history ? {
522
+ defaultBranchRef: {
523
+ ...syncTarget.defaultBranchRef,
524
+ target: {
525
+ ...syncTarget.defaultBranchRef.target,
526
+ history: {
527
+ // Set fork's commit count equal to parent's (0 commits behind)
528
+ totalCount: syncTarget.parent.defaultBranchRef.target.history.totalCount
529
+ }
530
+ }
531
+ }
532
+ } : {}
533
+ };
534
+ await updateCacheWithRepository(token, updatedRepo);
535
+ const updateSyncedRepo = (r) => {
536
+ if (r.id === syncTarget.id) {
537
+ return updatedRepo;
538
+ }
539
+ return r;
540
+ };
541
+ setItems((prev) => prev.map(updateSyncedRepo));
542
+ setSearchItems((prev) => prev.map(updateSyncedRepo));
543
+ closeSyncModal();
544
+ } catch (e) {
545
+ setSyncing(false);
546
+ setSyncError(e.message || "Failed to sync fork. Check permissions and network.");
547
+ }
548
+ }
549
+ async function executeArchive() {
550
+ if (!archiveTarget || archiving) return;
551
+ try {
552
+ setArchiving(true);
553
+ const isArchived = archiveTarget.isArchived;
554
+ const id = archiveTarget.id;
555
+ if (isArchived) {
556
+ await unarchiveRepositoryById(client, id);
557
+ } else {
558
+ await archiveRepositoryById(client, id);
559
+ }
560
+ await updateCacheAfterArchive(token, id, !isArchived);
561
+ const updateRepo = (r) => r.id === id ? { ...r, isArchived: !isArchived } : r;
562
+ setItems((prev) => prev.map(updateRepo));
563
+ setSearchItems((prev) => prev.map(updateRepo));
564
+ closeArchiveModal();
565
+ } catch (e) {
566
+ setArchiving(false);
567
+ setArchiveError("Failed to update archive state. Check permissions.");
568
+ }
507
569
  }
508
570
  function handleOrgContextChange(newContext) {
509
571
  setOwnerContext(newContext);
@@ -795,13 +857,12 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
795
857
  setConfirmFocus("cancel");
796
858
  return;
797
859
  }
798
- if (key.return) {
799
- if (confirmFocus === "delete") confirmDeleteNow();
800
- else cancelDeleteModal();
801
- return;
802
- }
803
860
  if (input && input.toUpperCase() === "Y") {
804
- confirmDeleteNow();
861
+ if (confirmFocus === "delete") {
862
+ confirmDeleteNow();
863
+ } else {
864
+ cancelDeleteModal();
865
+ }
805
866
  return;
806
867
  }
807
868
  }
@@ -820,29 +881,12 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
820
881
  setArchiveFocus("cancel");
821
882
  return;
822
883
  }
823
- if (key.return || input && input.toUpperCase() === "Y") {
884
+ if (input && input.toUpperCase() === "Y") {
824
885
  if (archiveFocus === "cancel") {
825
886
  closeArchiveModal();
826
887
  return;
827
888
  }
828
- if (!archiveTarget) return;
829
- (async () => {
830
- try {
831
- setArchiving(true);
832
- const isArchived = archiveTarget.isArchived;
833
- const id = archiveTarget.id;
834
- if (isArchived) await unarchiveRepositoryById(client, id);
835
- else await archiveRepositoryById(client, id);
836
- await updateCacheAfterArchive(token, id, !isArchived);
837
- const updateRepo = (r) => r.id === id ? { ...r, isArchived: !isArchived } : r;
838
- setItems((prev) => prev.map(updateRepo));
839
- setSearchItems((prev) => prev.map(updateRepo));
840
- closeArchiveModal();
841
- } catch (e) {
842
- setArchiving(false);
843
- setArchiveError("Failed to update archive state. Check permissions.");
844
- }
845
- })();
889
+ executeArchive();
846
890
  return;
847
891
  }
848
892
  return;
@@ -860,50 +904,12 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
860
904
  setSyncFocus("cancel");
861
905
  return;
862
906
  }
863
- if (key.return || input && input.toUpperCase() === "Y") {
907
+ if (input && input.toUpperCase() === "Y") {
864
908
  if (syncFocus === "cancel") {
865
909
  closeSyncModal();
866
- return;
910
+ } else {
911
+ executeSync();
867
912
  }
868
- if (!syncTarget) return;
869
- (async () => {
870
- try {
871
- setSyncing(true);
872
- const [owner, repo] = syncTarget.nameWithOwner.split("/");
873
- const branchName = syncTarget.defaultBranchRef?.name || "main";
874
- const result = await syncForkWithUpstream(token, owner, repo, branchName);
875
- const updatedRepo = {
876
- ...syncTarget,
877
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
878
- // If we're tracking fork commits and this is a fork with parent data, set commits to be in sync
879
- ...forkTracking && syncTarget.isFork && syncTarget.parent && syncTarget.defaultBranchRef?.target?.history && syncTarget.parent.defaultBranchRef?.target?.history ? {
880
- defaultBranchRef: {
881
- ...syncTarget.defaultBranchRef,
882
- target: {
883
- ...syncTarget.defaultBranchRef.target,
884
- history: {
885
- // Set fork's commit count equal to parent's (0 commits behind)
886
- totalCount: syncTarget.parent.defaultBranchRef.target.history.totalCount
887
- }
888
- }
889
- }
890
- } : {}
891
- };
892
- await updateCacheWithRepository(token, updatedRepo);
893
- const updateSyncedRepo = (r) => {
894
- if (r.id === syncTarget.id) {
895
- return updatedRepo;
896
- }
897
- return r;
898
- };
899
- setItems((prev) => prev.map(updateSyncedRepo));
900
- setSearchItems((prev) => prev.map(updateSyncedRepo));
901
- closeSyncModal();
902
- } catch (e) {
903
- setSyncing(false);
904
- setSyncError(e.message || "Failed to sync fork. Check permissions and network.");
905
- }
906
- })();
907
913
  return;
908
914
  }
909
915
  return;
@@ -1361,7 +1367,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
1361
1367
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, flexDirection: "row", justifyContent: "center", children: /* @__PURE__ */ jsxs5(Text6, { color: "gray", children: [
1362
1368
  "Press Enter to ",
1363
1369
  confirmFocus === "delete" ? "Delete" : "Cancel",
1364
- " \u2022 Y to confirm \u2022 C to cancel"
1370
+ " | Y to Delete | C to Cancel"
1365
1371
  ] }) }),
1366
1372
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx6(
1367
1373
  TextInput2,
@@ -1417,7 +1423,9 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
1417
1423
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, flexDirection: "row", justifyContent: "center", children: /* @__PURE__ */ jsxs5(Text6, { color: "gray", children: [
1418
1424
  "Press Enter to ",
1419
1425
  archiveFocus === "confirm" ? archiveTarget.isArchived ? "Unarchive" : "Archive" : "Cancel",
1420
- " \u2022 Y to confirm \u2022 C to cancel"
1426
+ " | Y to ",
1427
+ archiveTarget.isArchived ? "Unarchive" : "Archive",
1428
+ " | C to Cancel"
1421
1429
  ] }) }),
1422
1430
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx6(
1423
1431
  TextInput2,
@@ -1427,23 +1435,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
1427
1435
  },
1428
1436
  onSubmit: () => {
1429
1437
  if (archiveFocus === "confirm") {
1430
- (async () => {
1431
- try {
1432
- setArchiving(true);
1433
- const isArchived = archiveTarget.isArchived;
1434
- const id = archiveTarget.id;
1435
- if (isArchived) await unarchiveRepositoryById(client, id);
1436
- else await archiveRepositoryById(client, id);
1437
- await updateCacheAfterArchive(token, id, !isArchived);
1438
- const updateRepo = (r) => r.id === id ? { ...r, isArchived: !isArchived } : r;
1439
- setItems((prev) => prev.map(updateRepo));
1440
- setSearchItems((prev) => prev.map(updateRepo));
1441
- closeArchiveModal();
1442
- } catch (e) {
1443
- setArchiving(false);
1444
- setArchiveError("Failed to update archive state. Check permissions.");
1445
- }
1446
- })();
1438
+ executeArchive();
1447
1439
  } else {
1448
1440
  closeArchiveModal();
1449
1441
  }
@@ -1493,7 +1485,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
1493
1485
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, flexDirection: "row", justifyContent: "center", children: /* @__PURE__ */ jsxs5(Text6, { color: "gray", children: [
1494
1486
  "Press Enter to ",
1495
1487
  syncFocus === "confirm" ? "Sync" : "Cancel",
1496
- " \u2022 y to confirm \u2022 c to cancel"
1488
+ " | Y to Sync | C to Cancel"
1497
1489
  ] }) }),
1498
1490
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx6(
1499
1491
  TextInput2,
@@ -1503,44 +1495,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
1503
1495
  },
1504
1496
  onSubmit: () => {
1505
1497
  if (syncFocus === "confirm") {
1506
- (async () => {
1507
- try {
1508
- setSyncing(true);
1509
- const [owner, repo] = syncTarget.nameWithOwner.split("/");
1510
- const branchName = syncTarget.defaultBranchRef?.name || "main";
1511
- const result = await syncForkWithUpstream(token, owner, repo, branchName);
1512
- const updatedRepo = {
1513
- ...syncTarget,
1514
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1515
- // If we're tracking fork commits and this is a fork with parent data, set commits to be in sync
1516
- ...forkTracking && syncTarget.isFork && syncTarget.parent && syncTarget.defaultBranchRef?.target?.history && syncTarget.parent.defaultBranchRef?.target?.history ? {
1517
- defaultBranchRef: {
1518
- ...syncTarget.defaultBranchRef,
1519
- target: {
1520
- ...syncTarget.defaultBranchRef.target,
1521
- history: {
1522
- // Set fork's commit count equal to parent's (0 commits behind)
1523
- totalCount: syncTarget.parent.defaultBranchRef.target.history.totalCount
1524
- }
1525
- }
1526
- }
1527
- } : {}
1528
- };
1529
- await updateCacheWithRepository(token, updatedRepo);
1530
- const updateSyncedRepo = (r) => {
1531
- if (r.id === syncTarget.id) {
1532
- return updatedRepo;
1533
- }
1534
- return r;
1535
- };
1536
- setItems((prev) => prev.map(updateSyncedRepo));
1537
- setSearchItems((prev) => prev.map(updateSyncedRepo));
1538
- closeSyncModal();
1539
- } catch (e) {
1540
- setSyncing(false);
1541
- setSyncError(e.message || "Failed to sync fork. Check permissions and network.");
1542
- }
1543
- })();
1498
+ executeSync();
1544
1499
  } else {
1545
1500
  closeSyncModal();
1546
1501
  }
@@ -1583,7 +1538,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
1583
1538
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, flexDirection: "row", justifyContent: "center", children: /* @__PURE__ */ jsxs5(Text6, { color: "gray", children: [
1584
1539
  "Press Enter to ",
1585
1540
  logoutFocus === "confirm" ? "Logout" : "Cancel",
1586
- " \u2022 Y to confirm \u2022 C to cancel"
1541
+ " | Y to Logout | C to Cancel"
1587
1542
  ] }) })
1588
1543
  ] }) }) : orgSwitcherOpen ? /* @__PURE__ */ jsx6(Box5, { height: contentHeight, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsx6(
1589
1544
  OrgSwitcher,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gh-manager-cli",
3
- "version": "1.10.3",
3
+ "version": "1.10.5",
4
4
  "private": false,
5
5
  "description": "Interactive CLI to manage your GitHub repos (personal) with Ink",
6
6
  "license": "MIT",