gh-manager-cli 1.39.0 → 1.40.0

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.40.0](https://github.com/wiiiimm/gh-manager-cli/compare/v1.39.1...v1.40.0) (2026-06-05)
2
+
3
+
4
+ ### Features
5
+
6
+ * background fetch-all pagination with light bulk query ([#50](https://github.com/wiiiimm/gh-manager-cli/issues/50)) ([932deb8](https://github.com/wiiiimm/gh-manager-cli/commit/932deb85736bf999bde3c6f4d9bab02aaece8610))
7
+
8
+ ## [1.39.1](https://github.com/wiiiimm/gh-manager-cli/compare/v1.39.0...v1.39.1) (2026-06-05)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * restore changelog body in GitHub release notes [semantic pr title] ([#46](https://github.com/wiiiimm/gh-manager-cli/issues/46)) ([62e20ad](https://github.com/wiiiimm/gh-manager-cli/commit/62e20ad795abb38cc370e25738182a1ba99fd6f7))
14
+
1
15
  # [1.39.0](https://github.com/wiiiimm/gh-manager-cli/compare/v1.38.1...v1.39.0) (2026-06-05)
2
16
 
3
17
 
package/README.md CHANGED
@@ -22,7 +22,7 @@ Interactive terminal app to browse and manage your personal GitHub repositories.
22
22
  `gh-manager-cli` replaces tedious web clicking with powerful terminal commands:
23
23
 
24
24
  ### ❌ GitHub Website Pain Points → ✅ Our Solution
25
- - **Slow pagination** (20 repos/page) → View all repos instantly with smooth scrolling
25
+ - **Slow pagination** (page-by-page) → Whole account loaded in the background, browse and search everything instantly
26
26
  - **Multiple clicks per action** → Single keypress for any operation
27
27
  - **No bulk operations** → Archive, delete, or modify multiple repos at once
28
28
  - **Buried settings menus** → Direct keyboard shortcuts for everything
@@ -73,7 +73,7 @@ On first run, you'll be prompted to authenticate with GitHub (OAuth recommended)
73
73
  ### Core Repository Management
74
74
  - **Authentication**: GitHub OAuth (recommended) or Personal Access Token with secure storage
75
75
  - **Repository Listing**: Browse all your personal repositories with metadata (stars, forks, language, etc.)
76
- - **Live Pagination**: Infinite scroll with automatic page prefetching
76
+ - **Background Fetch-All**: Loads your entire account in the background after the first page, so filtering/sorting/search are instant and complete
77
77
  - **Interactive Sorting**: Modal-based sort selection (updated, pushed, name, stars) with modal-based direction selection
78
78
  - **Smart Search**: Server-side search through repository names and descriptions (3+ characters)
79
79
  - **Visibility Filter**: Modal-based visibility filter (All, Public, Private/Internal for enterprise) with smart filtering
@@ -305,8 +305,9 @@ Status bar shows loaded count vs total. A rate-limit line displays `remaining/li
305
305
  ## Pagination Details
306
306
 
307
307
  - Uses GitHub GraphQL `viewer.repositories` with `ownerAffiliations: OWNER`, ordered by `UPDATED_AT DESC`.
308
- - Fetches 15 repos per page by default (configurable via `REPOS_PER_FETCH` environment variable, 1-50).
309
- - Updates `totalCount` each time and prefetches the next page when selection nears the end of loaded list.
308
+ - **Background fetch-all:** the first page renders immediately, then the remaining repositories load in the background until the whole account is cached locally. Filtering, sorting, and search then operate over the complete set, client-side and instant.
309
+ - Fetches 100 repos per page by default (configurable via `REPOS_PER_FETCH` environment variable, 1-100).
310
+ - Reads `totalCount` from the first page and shows background-load progress (`loaded/total`) while filling. The list stays usable from the first page throughout; very large accounts simply take longer to finish loading.
310
311
 
311
312
  ## Development
312
313
 
@@ -621,11 +621,8 @@ async function fetchViewerReposPageUnified(token, first, after, orderBy, include
621
621
  updatedAt
622
622
  pushedAt
623
623
  diskUsage
624
- ${includeForkTracking ? `
625
- parent { nameWithOwner defaultBranchRef { name target { ... on Commit { history(first: 0) { totalCount } } } } }
626
- defaultBranchRef { name target { ... on Commit { history(first: 0) { totalCount } } } }` : `
627
624
  parent { nameWithOwner }
628
- defaultBranchRef { name }`}
625
+ defaultBranchRef { name }
629
626
  }
630
627
  }
631
628
  }
@@ -657,11 +654,8 @@ async function fetchViewerReposPageUnified(token, first, after, orderBy, include
657
654
  updatedAt
658
655
  pushedAt
659
656
  diskUsage
660
- ${includeForkTracking ? `
661
- parent { nameWithOwner defaultBranchRef { name target { ... on Commit { history(first: 0) { totalCount } } } } }
662
- defaultBranchRef { name target { ... on Commit { history(first: 0) { totalCount } } } }` : `
663
657
  parent { nameWithOwner }
664
- defaultBranchRef { name }`}
658
+ defaultBranchRef { name }
665
659
  }
666
660
  }
667
661
  }
@@ -742,11 +736,8 @@ async function searchRepositoriesUnified(token, viewer, text, first, after, sort
742
736
  updatedAt
743
737
  pushedAt
744
738
  diskUsage
745
- ${includeForkTracking ? `
746
- parent { nameWithOwner defaultBranchRef { name target { ... on Commit { history(first: 0) { totalCount } } } } }
747
- defaultBranchRef { name target { ... on Commit { history(first: 0) { totalCount } } } }` : `
748
739
  parent { nameWithOwner }
749
- defaultBranchRef { name }`}
740
+ defaultBranchRef { name }
750
741
  }
751
742
  }
752
743
  }
@@ -26,7 +26,7 @@ import {
26
26
  updateCacheAfterRename,
27
27
  updateCacheAfterVisibilityChange,
28
28
  updateCacheWithRepository
29
- } from "./chunk-EZP4YBHA.js";
29
+ } from "./chunk-UOGN2QJU.js";
30
30
  export {
31
31
  archiveRepositoryById,
32
32
  changeRepositoryVisibility,
package/dist/index.js CHANGED
@@ -27,14 +27,14 @@ import {
27
27
  updateCacheAfterRename,
28
28
  updateCacheAfterVisibilityChange,
29
29
  updateCacheWithRepository
30
- } from "./chunk-EZP4YBHA.js";
30
+ } from "./chunk-UOGN2QJU.js";
31
31
 
32
32
  // package.json
33
33
  var require_package = __commonJS({
34
34
  "package.json"(exports, module) {
35
35
  module.exports = {
36
36
  name: "gh-manager-cli",
37
- version: "1.39.0",
37
+ version: "1.40.0",
38
38
  private: false,
39
39
  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",
40
40
  license: "MIT",
@@ -487,7 +487,7 @@ function OrgSwitcher({ token, currentContext, onSelect, onClose }) {
487
487
  try {
488
488
  setLoading(true);
489
489
  setError(null);
490
- const client = await import("./github-HIF7MTPO.js").then((m) => m.makeClient(token));
490
+ const client = await import("./github-ASGTM4ZX.js").then((m) => m.makeClient(token));
491
491
  const orgs = await fetchViewerOrganizations(client);
492
492
  setOrganizations(orgs);
493
493
  const entOrgs = /* @__PURE__ */ new Set();
@@ -1967,11 +1967,11 @@ var getPageSize = () => {
1967
1967
  const envValue = process.env.REPOS_PER_FETCH;
1968
1968
  if (envValue) {
1969
1969
  const parsed = parseInt(envValue, 10);
1970
- if (!isNaN(parsed) && parsed >= 1 && parsed <= 50) {
1970
+ if (!isNaN(parsed) && parsed >= 1 && parsed <= 100) {
1971
1971
  return parsed;
1972
1972
  }
1973
1973
  }
1974
- return 15;
1974
+ return 100;
1975
1975
  };
1976
1976
  var PAGE_SIZE = getPageSize();
1977
1977
  function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextChange, initialOrgSlug: initialOrgSlug2 }) {
@@ -2678,26 +2678,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
2678
2678
  fetchPage(null, true, false, void 0, policy);
2679
2679
  }, [client, prefsLoaded, ownerContext, ownerAffiliations]);
2680
2680
  useEffect12(() => {
2681
- if (!searchActive) {
2682
- if (items.length > 0) {
2683
- let policy = "cache-first";
2684
- const orgLogin = ownerContext !== "personal" ? ownerContext.login : void 0;
2685
- try {
2686
- const key = makeApolloKey({
2687
- viewer: viewerLogin || "unknown",
2688
- sortKey,
2689
- sortDir,
2690
- pageSize: PAGE_SIZE,
2691
- forkTracking,
2692
- ownerContext: orgLogin ? `org:${orgLogin}` : "personal",
2693
- affiliations: ownerAffiliations.join(",")
2694
- });
2695
- policy = isFresh(key) ? "cache-first" : "network-only";
2696
- } catch {
2697
- }
2698
- fetchPage(null, true, true, void 0, policy);
2699
- }
2700
- } else {
2681
+ if (searchActive) {
2701
2682
  if (!searchLoading && filter.trim().length >= 3) {
2702
2683
  let policy = "cache-first";
2703
2684
  try {
@@ -3284,20 +3265,16 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
3284
3265
  const nearEnd = visibleItems.length > 0 && cursor >= prefetchThreshold;
3285
3266
  const rawItemsLength = starsMode ? starredItems.length : searchActive ? searchItems.length : items.length;
3286
3267
  const filterDrainedPage = visibleItems.length === 0 && archiveFilter !== "all" && rawItemsLength > 0;
3287
- const shouldFetch = nearEnd || filterDrainedPage;
3288
3268
  if (starsMode) {
3289
- if (!starredLoading && starredHasNextPage && shouldFetch) {
3290
- addDebugMessage(`[Infinite Scroll] Prefetching starred repos at ${cursor}/${visibleItems.length} (80% threshold: ${prefetchThreshold})`);
3269
+ if (!starredLoading && starredHasNextPage) {
3291
3270
  fetchStarredRepositories(starredEndCursor);
3292
3271
  }
3293
3272
  } else if (searchActive) {
3294
- if (!searchLoading && searchHasNextPage && shouldFetch) {
3295
- addDebugMessage(`[Infinite Scroll] Prefetching search results at ${cursor}/${visibleItems.length} (80% threshold: ${prefetchThreshold})`);
3273
+ if (!searchLoading && searchHasNextPage && (nearEnd || filterDrainedPage)) {
3296
3274
  fetchSearchPage(searchEndCursor);
3297
3275
  }
3298
3276
  } else {
3299
- if (!loading && !loadingMore && hasNextPage && shouldFetch) {
3300
- addDebugMessage(`[Infinite Scroll] Prefetching repos at ${cursor}/${visibleItems.length} (80% threshold: ${prefetchThreshold})`);
3277
+ if (!loading && !loadingMore && hasNextPage) {
3301
3278
  fetchPage(endCursor);
3302
3279
  }
3303
3280
  }
@@ -3324,7 +3301,8 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
3324
3301
  searchActive ? searchTotalCount : totalCount,
3325
3302
  ")"
3326
3303
  ] }),
3327
- (loading || searchLoading) && /* @__PURE__ */ jsx20(Box19, { width: 2, flexShrink: 0, flexGrow: 0, marginLeft: 1, children: /* @__PURE__ */ jsx20(Text20, { color: "yellow", children: /* @__PURE__ */ jsx20(SlowSpinner, {}) }) })
3304
+ loadingMore && hasNextPage && !starsMode && !searchActive && totalCount > 0 && /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: ` \xB7 loading ${items.length}/${totalCount}` }),
3305
+ (loading || searchLoading || loadingMore) && /* @__PURE__ */ jsx20(Box19, { width: 2, flexShrink: 0, flexGrow: 0, marginLeft: 1, children: /* @__PURE__ */ jsx20(Text20, { color: "yellow", children: /* @__PURE__ */ jsx20(SlowSpinner, {}) }) })
3328
3306
  ] }),
3329
3307
  (rateLimit || restRateLimit) && /* @__PURE__ */ jsxs19(Text20, { color: lowRate ? "yellow" : "gray", children: [
3330
3308
  "GraphQL: ",
@@ -3856,7 +3834,14 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
3856
3834
  repo.nameWithOwner
3857
3835
  );
3858
3836
  }),
3859
- loadingMore && hasNextPage && /* @__PURE__ */ jsx20(Box19, { justifyContent: "center", alignItems: "center", marginTop: 1, children: /* @__PURE__ */ jsxs19(Box19, { flexDirection: "row", children: [
3837
+ loadingMore && hasNextPage && !starsMode && !searchActive && /* @__PURE__ */ jsx20(Box19, { justifyContent: "center", alignItems: "center", marginTop: 1, children: /* @__PURE__ */ jsxs19(Box19, { flexDirection: "row", children: [
3838
+ /* @__PURE__ */ jsx20(Box19, { width: 2, flexShrink: 0, flexGrow: 0, marginRight: 1, children: /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: /* @__PURE__ */ jsx20(SlowSpinner, {}) }) }),
3839
+ /* @__PURE__ */ jsxs19(Text20, { color: "cyan", children: [
3840
+ "Loading repositories\u2026 ",
3841
+ totalCount > 0 ? `(${items.length}/${totalCount})` : `(${items.length})`
3842
+ ] })
3843
+ ] }) }),
3844
+ loadingMore && hasNextPage && (starsMode || searchActive) && /* @__PURE__ */ jsx20(Box19, { justifyContent: "center", alignItems: "center", marginTop: 1, children: /* @__PURE__ */ jsxs19(Box19, { flexDirection: "row", children: [
3860
3845
  /* @__PURE__ */ jsx20(Box19, { width: 2, flexShrink: 0, flexGrow: 0, marginRight: 1, children: /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: /* @__PURE__ */ jsx20(SlowSpinner, {}) }) }),
3861
3846
  /* @__PURE__ */ jsx20(Text20, { color: "cyan", children: "Loading more repositories..." })
3862
3847
  ] }) }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gh-manager-cli",
3
- "version": "1.39.0",
3
+ "version": "1.40.0",
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",