gh-manager-cli 1.37.0 → 1.38.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,17 @@
1
+ ## [1.38.1](https://github.com/wiiiimm/gh-manager-cli/compare/v1.38.0...v1.38.1) (2026-06-05)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * add archive filter toggle for repositories [semantic pr title] ([#43](https://github.com/wiiiimm/gh-manager-cli/issues/43)) ([3b717a3](https://github.com/wiiiimm/gh-manager-cli/commit/3b717a345c6104a6b59e530eb7688bac9d8276ee))
7
+
8
+ # [1.38.0](https://github.com/wiiiimm/gh-manager-cli/compare/v1.37.0...v1.38.0) (2025-09-09)
9
+
10
+
11
+ ### Features
12
+
13
+ * add GitHub Sponsors integration ([b73a8c2](https://github.com/wiiiimm/gh-manager-cli/commit/b73a8c244aa6a336b249bc573a019c307b56bfc5))
14
+
1
15
  # [1.37.0](https://github.com/wiiiimm/gh-manager-cli/compare/v1.36.0...v1.37.0) (2025-09-09)
2
16
 
3
17
 
package/README.md CHANGED
@@ -7,6 +7,7 @@
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
  [![Node.js Version](https://img.shields.io/node/v/gh-manager-cli.svg)](https://nodejs.org)
9
9
  [![GitHub Stars](https://img.shields.io/github/stars/wiiiimm/gh-manager-cli.svg)](https://github.com/wiiiimm/gh-manager-cli/stargazers)
10
+ [![GitHub Sponsors](https://img.shields.io/badge/Sponsor-%E2%9D%A4-pink)](https://github.com/sponsors/wiiiimm)
10
11
  [![Context Engineered with Claude Opus 4.1](https://img.shields.io/badge/Context%20Engineered%20with-Claude%20Opus%204.1-blue)](https://www.anthropic.com)
11
12
  [![Context Engineered with Codex GPT-5](https://img.shields.io/badge/Context%20Engineered%20with-Codex%20GPT--5-green)](https://openai.com)
12
13
 
@@ -75,7 +76,8 @@ On first run, you'll be prompted to authenticate with GitHub (OAuth recommended)
75
76
  - **Live Pagination**: Infinite scroll with automatic page prefetching
76
77
  - **Interactive Sorting**: Modal-based sort selection (updated, pushed, name, stars) with modal-based direction selection
77
78
  - **Smart Search**: Server-side search through repository names and descriptions (3+ characters)
78
- - **Visibility Filtering**: Modal-based visibility filter (All, Public, Private/Internal for enterprise) with smart filtering
79
+ - **Visibility Filter**: Modal-based visibility filter (All, Public, Private/Internal for enterprise) with smart filtering
80
+ - **Archive Filter**: Toggle-based archive filter (`A` key cycles All → Unarchived → Archived) for quick filtering by archive status
79
81
  - **Fork Status Tracking**: Always shows commits behind upstream for forked repositories
80
82
  - **Stars Mode**: View and manage starred repositories (personal account only)
81
83
  - **Repository Actions**:
@@ -101,7 +103,7 @@ On first run, you'll be prompted to authenticate with GitHub (OAuth recommended)
101
103
  - **Rate Limit Monitoring**: Dual API rate limit display (GraphQL & REST) with real-time usage deltas and visual warnings
102
104
 
103
105
  ### Technical Features
104
- - **Preference Persistence**: UI settings (sort, density, visibility filter, fork tracking) saved between sessions
106
+ - **Preference Persistence**: UI settings (sort, density, visibility filter, archive filter, fork tracking) saved between sessions
105
107
  - **Server-side Filtering**: Visibility filtering performed at GitHub API level for accurate pagination
106
108
  - **Cross-platform**: Works on macOS, Linux, and Windows
107
109
  - **Secure Storage**: Token stored with proper file permissions (0600)
@@ -270,6 +272,7 @@ Launch the app, then use the keys below:
270
272
  - **Display Density**: `T` to toggle compact/cozy/comfy
271
273
  - **Fork Status**: Always enabled - shows commits behind upstream for all forks
272
274
  - **Visibility Filter**: `V` opens modal (All, Public, Private/Internal for enterprise)
275
+ - **Archive Filter**: `A` toggles archive filter (All → Unarchived → Archived)
273
276
  - **Stars Mode**: `Shift+S` (personal account only) to view starred repositories
274
277
 
275
278
  ### Navigation & Account
@@ -529,7 +532,8 @@ Highlights on deck:
529
532
 
530
533
  If you find gh-manager-cli useful, consider supporting its development:
531
534
 
532
- **[Buy Me a Coffee](https://buymeacoffee.com/wiiiimm)** - Support with coffee donations
535
+ 💖 **[GitHub Sponsors](https://github.com/sponsors/wiiiimm)** - Support directly through GitHub
536
+ ☕ **[Buy Me a Coffee](https://buymeacoffee.com/wiiiimm)** - One-time coffee donations
533
537
 
534
538
  Your support helps maintain and improve this project. Thank you! 🙏
535
539
 
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ var require_package = __commonJS({
34
34
  "package.json"(exports, module) {
35
35
  module.exports = {
36
36
  name: "gh-manager-cli",
37
- version: "1.37.0",
37
+ version: "1.38.1",
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",
@@ -115,7 +115,7 @@ var require_package = __commonJS({
115
115
  "semantic-release": "^24.2.7",
116
116
  tsup: "^8.5.0",
117
117
  typescript: "^5.9.2",
118
- vitest: "^2.1.3"
118
+ vitest: "^4.1.0"
119
119
  },
120
120
  repository: {
121
121
  type: "git",
@@ -1819,6 +1819,7 @@ function RepoListHeader({
1819
1819
  searchActive,
1820
1820
  searchLoading,
1821
1821
  visibilityFilter = "all",
1822
+ archiveFilter = "all",
1822
1823
  isEnterprise = false,
1823
1824
  starsMode = false
1824
1825
  }) {
@@ -1841,6 +1842,10 @@ function RepoListHeader({
1841
1842
  "Visibility: ",
1842
1843
  visibilityLabel
1843
1844
  ] }),
1845
+ archiveFilter !== "all" && /* @__PURE__ */ jsxs17(Text18, { color: "cyan", children: [
1846
+ "Archive: ",
1847
+ archiveFilter === "archived" ? "Archived" : "Unarchived"
1848
+ ] }),
1844
1849
  filter && !searchActive && /* @__PURE__ */ jsxs17(Text18, { color: "cyan", children: [
1845
1850
  'Filter: "',
1846
1851
  filter,
@@ -2362,6 +2367,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
2362
2367
  const [forkTracking, setForkTracking] = useState15(true);
2363
2368
  const [visibilityFilter, setVisibilityFilter] = useState15("all");
2364
2369
  const previousVisibilityFilter = useRef("all");
2370
+ const [archiveFilter, setArchiveFilter] = useState15("all");
2365
2371
  const sortFieldMap = {
2366
2372
  "updated": "UPDATED_AT",
2367
2373
  "pushed": "PUSHED_AT",
@@ -2534,6 +2540,9 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
2534
2540
  if (ui.visibilityFilter && ["all", "public", "private", "internal"].includes(ui.visibilityFilter)) {
2535
2541
  setVisibilityFilter(ui.visibilityFilter);
2536
2542
  }
2543
+ if (ui.archiveFilter && ["all", "unarchived", "archived"].includes(ui.archiveFilter)) {
2544
+ setArchiveFilter(ui.archiveFilter);
2545
+ }
2537
2546
  if (ui.ownerContext) {
2538
2547
  setOwnerContext(ui.ownerContext);
2539
2548
  if (onOrgContextChange) {
@@ -3064,6 +3073,15 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
3064
3073
  });
3065
3074
  return;
3066
3075
  }
3076
+ if (input && input.toUpperCase() === "A" && !key.ctrl) {
3077
+ setArchiveFilter((f) => {
3078
+ const next = f === "all" ? "unarchived" : f === "unarchived" ? "archived" : "all";
3079
+ storeUIPrefs({ archiveFilter: next });
3080
+ return next;
3081
+ });
3082
+ setCursor(0);
3083
+ return;
3084
+ }
3067
3085
  if (input && input.toUpperCase() === "V") {
3068
3086
  if (!starsMode) {
3069
3087
  setVisibilityMode(true);
@@ -3076,6 +3094,11 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
3076
3094
  if (visibilityFilter === "private") {
3077
3095
  result = result.filter((r) => r.visibility === "PRIVATE" || r.visibility === "INTERNAL");
3078
3096
  }
3097
+ if (archiveFilter === "archived") {
3098
+ result = result.filter((r) => r.isArchived);
3099
+ } else if (archiveFilter === "unarchived") {
3100
+ result = result.filter((r) => !r.isArchived);
3101
+ }
3079
3102
  const q = filter.trim().toLowerCase();
3080
3103
  if (q) {
3081
3104
  result = result.filter(
@@ -3083,7 +3106,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
3083
3106
  );
3084
3107
  }
3085
3108
  return result;
3086
- }, [items, filter, visibilityFilter]);
3109
+ }, [items, filter, visibilityFilter, archiveFilter]);
3087
3110
  const filteredAndSorted = useMemo(() => {
3088
3111
  const arr = [...filtered];
3089
3112
  const dir = sortDir === "asc" ? 1 : -1;
@@ -3112,15 +3135,28 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
3112
3135
  } else if (visibilityFilter === "public") {
3113
3136
  result = result.filter((r) => r.visibility === "PUBLIC");
3114
3137
  }
3138
+ if (archiveFilter === "archived") {
3139
+ result = result.filter((r) => r.isArchived);
3140
+ } else if (archiveFilter === "unarchived") {
3141
+ result = result.filter((r) => !r.isArchived);
3142
+ }
3115
3143
  return result;
3116
- }, [searchItems, visibilityFilter]);
3144
+ }, [searchItems, visibilityFilter, archiveFilter]);
3117
3145
  const filteredStarredItems = useMemo(() => {
3118
- if (!filter || filter.trim().length === 0) return starredItems;
3119
- const lowerFilter = filter.toLowerCase();
3120
- return starredItems.filter(
3121
- (repo) => repo.nameWithOwner.toLowerCase().includes(lowerFilter) || repo.description && repo.description.toLowerCase().includes(lowerFilter)
3122
- );
3123
- }, [starredItems, filter]);
3146
+ let result = starredItems;
3147
+ if (filter && filter.trim().length > 0) {
3148
+ const lowerFilter = filter.toLowerCase();
3149
+ result = result.filter(
3150
+ (repo) => repo.nameWithOwner.toLowerCase().includes(lowerFilter) || repo.description && repo.description.toLowerCase().includes(lowerFilter)
3151
+ );
3152
+ }
3153
+ if (archiveFilter === "archived") {
3154
+ result = result.filter((r) => r.isArchived);
3155
+ } else if (archiveFilter === "unarchived") {
3156
+ result = result.filter((r) => !r.isArchived);
3157
+ }
3158
+ return result;
3159
+ }, [starredItems, filter, archiveFilter]);
3124
3160
  const visibleItems = starsMode ? filteredStarredItems : searchActive ? filteredSearchItems : filteredAndSorted;
3125
3161
  useEffect11(() => {
3126
3162
  if (searchActive) {
@@ -3151,23 +3187,26 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
3151
3187
  useEffect11(() => {
3152
3188
  const prefetchThreshold = Math.floor(visibleItems.length * 0.8);
3153
3189
  const nearEnd = visibleItems.length > 0 && cursor >= prefetchThreshold;
3190
+ const rawItemsLength = starsMode ? starredItems.length : searchActive ? searchItems.length : items.length;
3191
+ const filterDrainedPage = visibleItems.length === 0 && archiveFilter !== "all" && rawItemsLength > 0;
3192
+ const shouldFetch = nearEnd || filterDrainedPage;
3154
3193
  if (starsMode) {
3155
- if (!starredLoading && starredHasNextPage && nearEnd) {
3194
+ if (!starredLoading && starredHasNextPage && shouldFetch) {
3156
3195
  addDebugMessage(`[Infinite Scroll] Prefetching starred repos at ${cursor}/${visibleItems.length} (80% threshold: ${prefetchThreshold})`);
3157
3196
  fetchStarredRepositories(starredEndCursor);
3158
3197
  }
3159
3198
  } else if (searchActive) {
3160
- if (!searchLoading && searchHasNextPage && nearEnd) {
3199
+ if (!searchLoading && searchHasNextPage && shouldFetch) {
3161
3200
  addDebugMessage(`[Infinite Scroll] Prefetching search results at ${cursor}/${visibleItems.length} (80% threshold: ${prefetchThreshold})`);
3162
3201
  fetchSearchPage(searchEndCursor);
3163
3202
  }
3164
3203
  } else {
3165
- if (!loading && !loadingMore && hasNextPage && nearEnd) {
3204
+ if (!loading && !loadingMore && hasNextPage && shouldFetch) {
3166
3205
  addDebugMessage(`[Infinite Scroll] Prefetching repos at ${cursor}/${visibleItems.length} (80% threshold: ${prefetchThreshold})`);
3167
3206
  fetchPage(endCursor);
3168
3207
  }
3169
3208
  }
3170
- }, [cursor, visibleItems.length, starsMode, starredLoading, starredHasNextPage, starredEndCursor, searchActive, searchLoading, searchHasNextPage, searchEndCursor, loading, loadingMore, hasNextPage, endCursor]);
3209
+ }, [cursor, visibleItems.length, archiveFilter, items.length, starredItems.length, searchItems.length, starsMode, starredLoading, starredHasNextPage, starredEndCursor, searchActive, searchLoading, searchHasNextPage, searchEndCursor, loading, loadingMore, hasNextPage, endCursor]);
3171
3210
  function openInBrowser(url) {
3172
3211
  const platform = process.platform;
3173
3212
  const cmd = platform === "darwin" ? `open "${url}"` : platform === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
@@ -3237,7 +3276,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
3237
3276
  showSponsorReminder && /* @__PURE__ */ jsx19(Box18, { marginX: 1, marginBottom: 1, children: /* @__PURE__ */ jsx19(Box18, { borderStyle: "single", borderColor: "yellow", paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", alignItems: "center", children: [
3238
3277
  /* @__PURE__ */ jsx19(Text19, { color: "yellow", children: "\u{1F49A} Thanks for using gh-manager-cli!" }),
3239
3278
  /* @__PURE__ */ jsx19(Text19, { color: "gray", children: "Your support helps craft more open-source tools" }),
3240
- /* @__PURE__ */ jsx19(Text19, { color: "cyan", children: "\u2615 buymeacoffee.com/wiiiimm" })
3279
+ /* @__PURE__ */ jsx19(Text19, { color: "cyan", children: "\u{1F496} github.com/sponsors/wiiiimm" })
3241
3280
  ] }) }) }),
3242
3281
  /* @__PURE__ */ jsx19(Box18, { borderStyle: "single", borderColor: modalOpen ? "gray" : "yellow", paddingX: 1, paddingY: 1, marginX: 1, height: contentHeight + containerPadding + 2, flexDirection: "column", children: deleteMode && deleteTarget ? (
3243
3282
  // Centered modal; hide list content while modal is open
@@ -3646,6 +3685,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
3646
3685
  searchActive,
3647
3686
  searchLoading,
3648
3687
  visibilityFilter,
3688
+ archiveFilter,
3649
3689
  isEnterprise: isEnterpriseOrg,
3650
3690
  starsMode
3651
3691
  }
@@ -3719,13 +3759,13 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
3719
3759
  /* @__PURE__ */ jsxs18(Box18, { marginTop: 1, paddingX: 1, flexDirection: "column", children: [
3720
3760
  /* @__PURE__ */ jsx19(Box18, { width: terminalWidth, justifyContent: "center", children: /* @__PURE__ */ jsx19(Text19, { color: "gray", dimColor: modalOpen ? true : void 0, children: "\u2191\u2193 Navigate \u2022 Ctrl+G Top \u2022 G Bottom \u2022 \u23CE/O Open \u2022 R Refresh" }) }),
3721
3761
  /* @__PURE__ */ jsx19(Box18, { width: terminalWidth, justifyContent: "center", children: /* @__PURE__ */ jsxs18(Text19, { color: "gray", dimColor: modalOpen ? true : void 0, children: [
3722
- "/ Search \u2022 S Sort \u2022 D Direction \u2022 T Density",
3723
- !starsMode && " \u2022 V Visibility",
3762
+ "/ Search \u2022 S Sort \u2022 D Direction \u2022 T Density \u2022 A Archive",
3763
+ !starsMode && " \u2022 V Visibility Filter",
3724
3764
  ownerContext === "personal" && " \u2022 Shift+S Stars"
3725
3765
  ] }) }),
3726
3766
  /* @__PURE__ */ jsx19(Box18, { width: terminalWidth, justifyContent: "center", children: /* @__PURE__ */ jsx19(Text19, { color: "gray", dimColor: modalOpen ? true : void 0, children: starsMode ? "I Info \u2022 C Copy URL \u2022 U Unstar Repository" : "I Info \u2022 C Copy URL \u2022 Ctrl+S Un/Star \u2022 Ctrl+R Rename \u2022 Ctrl+A Un/Archive \u2022 Ctrl+V Change Visibility \u2022 Ctrl+F Sync Fork" }) }),
3727
3767
  /* @__PURE__ */ jsx19(Box18, { width: terminalWidth, justifyContent: "center", children: /* @__PURE__ */ jsx19(Text19, { color: "gray", dimColor: modalOpen ? true : void 0, children: "K Cache Info \u2022 W Org Switch \u2022 Del/Backspace Delete \u2022 Ctrl+L Logout \u2022 Q Quit" }) }),
3728
- /* @__PURE__ */ jsx19(Box18, { width: terminalWidth, justifyContent: "center", marginTop: 1, children: /* @__PURE__ */ jsx19(Text19, { color: "yellow", dimColor: modalOpen ? true : void 0, children: "\u{1F49A} Support the project: buymeacoffee.com/wiiiimm" }) })
3768
+ /* @__PURE__ */ jsx19(Box18, { width: terminalWidth, justifyContent: "center", marginTop: 1, children: /* @__PURE__ */ jsx19(Text19, { color: "yellow", dimColor: modalOpen ? true : void 0, children: "\u{1F496} Sponsor on GitHub: github.com/sponsors/wiiiimm" }) })
3729
3769
  ] }),
3730
3770
  process.env.GH_MANAGER_DEBUG === "1" && /* @__PURE__ */ jsxs18(Box18, { marginTop: 1, borderStyle: "single", borderColor: "yellow", paddingX: 1, flexDirection: "column", children: [
3731
3771
  /* @__PURE__ */ jsx19(Text19, { bold: true, color: "yellow", children: "Debug Messages:" }),
@@ -4348,10 +4388,10 @@ var showSponsorshipMessage = () => {
4348
4388
  console.log("\n\u{1F49A} Thank you for using gh-manager-cli!\n");
4349
4389
  console.log("If this app saved you time, please consider supporting");
4350
4390
  console.log("the development of more open-source projects like this:\n");
4351
- console.log(" \u2615 Buy Me a Coffee: https://buymeacoffee.com/wiiiimm");
4391
+ console.log(" \u{1F496} Sponsor on GitHub: https://github.com/sponsors/wiiiimm");
4352
4392
  console.log(" \u{1F680} Visit my site: https://wiiiimm.codes");
4353
4393
  console.log(" \u{1F4AC} Leave feedback: https://github.com/wiiiimm/gh-manager-cli");
4354
- console.log("\nYour support and contributions make a difference! \u{1F64F}\n");
4394
+ console.log("\nYour support keeps this project alive! \u{1F64F}\n");
4355
4395
  console.log("\u2500".repeat(60) + "\n");
4356
4396
  };
4357
4397
  process.on("SIGINT", () => handleShutdown("SIGINT"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gh-manager-cli",
3
- "version": "1.37.0",
3
+ "version": "1.38.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",
@@ -81,7 +81,7 @@
81
81
  "semantic-release": "^24.2.7",
82
82
  "tsup": "^8.5.0",
83
83
  "typescript": "^5.9.2",
84
- "vitest": "^2.1.3"
84
+ "vitest": "^4.1.0"
85
85
  },
86
86
  "repository": {
87
87
  "type": "git",