gh-manager-cli 1.10.4 → 1.10.6

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.6](https://github.com/wiiiimm/gh-manager-cli/compare/v1.10.5...v1.10.6) (2025-09-01)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * clear token input field after logout and successful login ([243d963](https://github.com/wiiiimm/gh-manager-cli/commit/243d963a8603580c921d01c8380a23c0e511c113))
7
+
8
+ ## [1.10.5](https://github.com/wiiiimm/gh-manager-cli/compare/v1.10.4...v1.10.5) (2025-09-01)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * prevent duplicate modal handlers and improve modal UI ([79281d3](https://github.com/wiiiimm/gh-manager-cli/commit/79281d34fe42d3345885cad257e6800e94eb2bb3))
14
+
1
15
  ## [1.10.4](https://github.com/wiiiimm/gh-manager-cli/compare/v1.10.3...v1.10.4) (2025-09-01)
2
16
 
3
17
 
package/README.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # gh-manager-cli
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/gh-manager-cli.svg)](https://www.npmjs.com/package/gh-manager-cli)
4
+ [![GitHub release](https://img.shields.io/github/release/wiiiimm/gh-manager-cli.svg)](https://github.com/wiiiimm/gh-manager-cli/releases)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![Node.js Version](https://img.shields.io/node/v/gh-manager-cli.svg)](https://nodejs.org)
7
+ [![GitHub Stars](https://img.shields.io/github/stars/wiiiimm/gh-manager-cli.svg)](https://github.com/wiiiimm/gh-manager-cli/stargazers)
8
+ [![Context Engineered with Claude Opus 4.1](https://img.shields.io/badge/Context%20Engineered%20with-Claude%20Opus%204.1-blue)](https://www.anthropic.com)
9
+ [![Context Engineered with Codex GPT-5](https://img.shields.io/badge/Context%20Engineered%20with-Codex%20GPT--5-green)](https://openai.com)
10
+
3
11
  Interactive terminal app to browse and manage your personal GitHub repositories. Built with Ink (React for CLIs) and the GitHub GraphQL API.
4
12
 
5
13
  ## Screenshots
@@ -27,7 +35,7 @@ Safe repository deletion with two-step confirmation process.
27
35
 
28
36
  ```bash
29
37
  # Run with npx (no install)
30
- npx gh-manager
38
+ npx gh-manager-cli
31
39
  ```
32
40
 
33
41
  On first run, you'll be prompted for a GitHub Personal Access Token.
@@ -68,30 +76,30 @@ On first run, you'll be prompted for a GitHub Personal Access Token.
68
76
  Run instantly without installing:
69
77
 
70
78
  ```bash
71
- npx gh-manager
79
+ npx gh-manager-cli
72
80
  ```
73
81
 
74
82
  ### NPM Global Install
75
83
 
76
- Install globally for persistent `gh-manager` command:
84
+ Install globally for persistent `gh-manager-cli` command:
77
85
 
78
86
  ```bash
79
87
  npm install -g gh-manager-cli
80
- gh-manager
88
+ gh-manager-cli
81
89
  ```
82
90
 
83
91
  ### Pre-built Binaries (No Node.js Required)
84
92
 
85
93
  Download standalone executables from [GitHub Releases](https://github.com/wiiiimm/gh-manager-cli/releases):
86
94
 
87
- - **Linux**: `gh-manager-linux-x64`
88
- - **macOS**: `gh-manager-macos-x64`
89
- - **Windows**: `gh-manager-windows-x64.exe`
95
+ - **Linux**: `gh-manager-cli-linux-x64`
96
+ - **macOS**: `gh-manager-cli-macos-x64`
97
+ - **Windows**: `gh-manager-cli-windows-x64.exe`
90
98
 
91
99
  Make the binary executable (Linux/macOS):
92
100
  ```bash
93
- chmod +x gh-manager-*
94
- ./gh-manager-*
101
+ chmod +x gh-manager-cli-*
102
+ ./gh-manager-cli-*
95
103
  ```
96
104
 
97
105
  ### From Source
@@ -113,7 +121,7 @@ Run locally:
113
121
  node dist/index.js
114
122
  # Or add to PATH for dev
115
123
  pnpm link
116
- gh-manager
124
+ gh-manager-cli
117
125
  ```
118
126
 
119
127
  ## Token & Security
@@ -162,8 +170,8 @@ Status bar shows loaded count vs total. A rate-limit line displays `remaining/li
162
170
  ## Pagination Details
163
171
 
164
172
  - Uses GitHub GraphQL `viewer.repositories` with `ownerAffiliations: OWNER`, ordered by `UPDATED_AT DESC`.
165
- - Fetches 50 repos per page and updates `totalCount` each time.
166
- - Prefetches the next page when your selection nears the end of the loaded list.
173
+ - Fetches 15 repos per page by default (configurable via `REPOS_PER_FETCH` environment variable, 1-50).
174
+ - Updates `totalCount` each time and prefetches the next page when selection nears the end of loaded list.
167
175
 
168
176
  ## Development
169
177
 
@@ -180,11 +188,14 @@ Scripts:
180
188
  pnpm build # build to dist/
181
189
  pnpm build:binaries # build cross-platform binaries to ./binaries/
182
190
  pnpm dev # watch mode
183
- pnpm start # node dist/index.js
191
+ pnpm start # run normally
192
+ pnpm start:debug # run with debug mode enabled
193
+ pnpm start:dev # run with 5 repos per page and debug mode
184
194
  ```
185
195
 
186
- Notes:
187
- - In development mode (set `NODE_ENV=development` or `GH_MANAGER_DEV=1`), the app fetches 5 repos per page to speed iteration.
196
+ Environment variables:
197
+ - `REPOS_PER_FETCH`: Number of repositories to fetch per page (1-50, default: 15)
198
+ - `GH_MANAGER_DEBUG=1`: Enables debug mode with performance metrics and detailed errors
188
199
 
189
200
  Project layout:
190
201
  - `src/index.tsx` — CLI entry and error handling
@@ -209,7 +220,7 @@ gh-manager-cli includes built-in Apollo Client caching to reduce GitHub API call
209
220
 
210
221
  Run with `GH_MANAGER_DEBUG=1` to enable debugging features:
211
222
  ```bash
212
- GH_MANAGER_DEBUG=1 npx gh-manager
223
+ GH_MANAGER_DEBUG=1 npx gh-manager-cli
213
224
  ```
214
225
 
215
226
  Debug mode provides:
@@ -241,14 +252,20 @@ Even with caching enabled, API credits may decrease due to:
241
252
  - **Cache-and-network policy**: Updates stale cache data in background
242
253
  - **Sorting changes**: Different sort orders create new cache entries
243
254
 
244
- ### Cache Configuration
255
+ ### Configuration
245
256
 
246
257
  ```bash
258
+ # Number of repositories to fetch per page (1-50, default: 15)
259
+ REPOS_PER_FETCH=10 npx gh-manager-cli
260
+
247
261
  # Custom cache TTL (milliseconds) - default: 30 minutes
248
- APOLLO_TTL_MS=1800000 npx gh-manager
262
+ APOLLO_TTL_MS=1800000 npx gh-manager-cli
249
263
 
250
264
  # Enable debug mode to see cache performance
251
- GH_MANAGER_DEBUG=1 npx gh-manager
265
+ GH_MANAGER_DEBUG=1 npx gh-manager-cli
266
+
267
+ # Combine multiple environment variables
268
+ REPOS_PER_FETCH=5 GH_MANAGER_DEBUG=1 npx gh-manager-cli-cli
252
269
  ```
253
270
 
254
271
  ## Troubleshooting
@@ -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,20 +16,20 @@ 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.4",
26
+ version: "1.10.6",
27
27
  private: false,
28
28
  description: "Interactive CLI to manage your GitHub repos (personal) with Ink",
29
29
  license: "MIT",
30
30
  main: "dist/index.js",
31
31
  bin: {
32
- "gh-manager": "dist/index.js"
32
+ "gh-manager-cli": "dist/index.js"
33
33
  },
34
34
  files: [
35
35
  "dist/",
@@ -52,10 +52,12 @@ var require_package = __commonJS({
52
52
  "build:binaries": "npm run build && pkg dist/index.js --targets node18-linux-x64,node18-macos-x64,node18-windows-x64 --out-path ./binaries",
53
53
  dev: "tsup --watch",
54
54
  start: "node dist/index.js",
55
- "start:cache": "GH_MANAGER_APOLLO=1 GH_MANAGER_DEBUG=1 node dist/index.js",
56
- "start:no-cache": "GH_MANAGER_APOLLO=0 GH_MANAGER_DEBUG=1 node dist/index.js",
57
- "test:cache": "pnpm build && pnpm start:cache",
58
- prepublishOnly: "pnpm run build"
55
+ "start:debug": "GH_MANAGER_DEBUG=1 node dist/index.js",
56
+ "start:dev": "REPOS_PER_FETCH=5 GH_MANAGER_DEBUG=1 node dist/index.js",
57
+ prepublishOnly: "pnpm run build",
58
+ test: "vitest run",
59
+ "test:watch": "vitest",
60
+ "test:coverage": "vitest run --coverage"
59
61
  },
60
62
  engines: {
61
63
  node: ">=18"
@@ -78,10 +80,13 @@ var require_package = __commonJS({
78
80
  "@semantic-release/git": "^10.0.1",
79
81
  "@types/node": "^24.3.0",
80
82
  "@types/react": "^19.1.12",
83
+ "ink-testing-library": "^3.0.0",
81
84
  pkg: "^5.8.1",
82
85
  "semantic-release": "^24.2.7",
83
86
  tsup: "^8.5.0",
84
- typescript: "^5.9.2"
87
+ typescript: "^5.9.2",
88
+ vitest: "^2.1.3",
89
+ "@vitest/coverage-v8": "^2.1.3"
85
90
  },
86
91
  repository: {
87
92
  type: "git",
@@ -115,18 +120,18 @@ var require_package = __commonJS({
115
120
  {
116
121
  assets: [
117
122
  {
118
- path: "binaries/gh-manager-linux-x64/gh-manager-linux-x64",
119
- name: "gh-manager-linux-x64",
123
+ path: "binaries/gh-manager-cli-linux-x64/gh-manager-cli-linux-x64",
124
+ name: "gh-manager-cli-linux-x64",
120
125
  label: "Linux x64 Binary"
121
126
  },
122
127
  {
123
- path: "binaries/gh-manager-macos-x64/gh-manager-macos-x64",
124
- name: "gh-manager-macos-x64",
128
+ path: "binaries/gh-manager-cli-macos-x64/gh-manager-cli-macos-x64",
129
+ name: "gh-manager-cli-macos-x64",
125
130
  label: "macOS x64 Binary"
126
131
  },
127
132
  {
128
- path: "binaries/gh-manager-windows-x64/gh-manager-windows-x64.exe",
129
- name: "gh-manager-windows-x64.exe",
133
+ path: "binaries/gh-manager-cli-windows-x64/gh-manager-cli-windows-x64.exe",
134
+ name: "gh-manager-cli-windows-x64.exe",
130
135
  label: "Windows x64 Binary"
131
136
  }
132
137
  ]
@@ -279,7 +284,7 @@ function OrgSwitcher({ token, currentContext, onSelect, onClose }) {
279
284
  const loadOrgs = async () => {
280
285
  try {
281
286
  setLoading(true);
282
- const client = await import("./github-HC6GZCKR.js").then((m) => m.makeClient(token));
287
+ const client = await import("./github-6IFMCQKW.js").then((m) => m.makeClient(token));
283
288
  const orgs = await fetchViewerOrganizations(client);
284
289
  setOrganizations(orgs);
285
290
  if (!isPersonalContext) {
@@ -430,7 +435,17 @@ import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
430
435
 
431
436
  // src/ui/RepoList.tsx
432
437
  import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
433
- var PAGE_SIZE = process.env.GH_MANAGER_DEV === "1" || process.env.NODE_ENV === "development" ? 5 : 15;
438
+ var getPageSize = () => {
439
+ const envValue = process.env.REPOS_PER_FETCH;
440
+ if (envValue) {
441
+ const parsed = parseInt(envValue, 10);
442
+ if (!isNaN(parsed) && parsed >= 1 && parsed <= 50) {
443
+ return parsed;
444
+ }
445
+ }
446
+ return 15;
447
+ };
448
+ var PAGE_SIZE = getPageSize();
434
449
  function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextChange }) {
435
450
  const { exit } = useApp();
436
451
  const { stdout } = useStdout();
@@ -546,6 +561,27 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
546
561
  setSyncError(e.message || "Failed to sync fork. Check permissions and network.");
547
562
  }
548
563
  }
564
+ async function executeArchive() {
565
+ if (!archiveTarget || archiving) return;
566
+ try {
567
+ setArchiving(true);
568
+ const isArchived = archiveTarget.isArchived;
569
+ const id = archiveTarget.id;
570
+ if (isArchived) {
571
+ await unarchiveRepositoryById(client, id);
572
+ } else {
573
+ await archiveRepositoryById(client, id);
574
+ }
575
+ await updateCacheAfterArchive(token, id, !isArchived);
576
+ const updateRepo = (r) => r.id === id ? { ...r, isArchived: !isArchived } : r;
577
+ setItems((prev) => prev.map(updateRepo));
578
+ setSearchItems((prev) => prev.map(updateRepo));
579
+ closeArchiveModal();
580
+ } catch (e) {
581
+ setArchiving(false);
582
+ setArchiveError("Failed to update archive state. Check permissions.");
583
+ }
584
+ }
549
585
  function handleOrgContextChange(newContext) {
550
586
  setOwnerContext(newContext);
551
587
  storeUIPrefs({ ownerContext: newContext });
@@ -836,13 +872,12 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
836
872
  setConfirmFocus("cancel");
837
873
  return;
838
874
  }
839
- if (key.return) {
840
- if (confirmFocus === "delete") confirmDeleteNow();
841
- else cancelDeleteModal();
842
- return;
843
- }
844
875
  if (input && input.toUpperCase() === "Y") {
845
- confirmDeleteNow();
876
+ if (confirmFocus === "delete") {
877
+ confirmDeleteNow();
878
+ } else {
879
+ cancelDeleteModal();
880
+ }
846
881
  return;
847
882
  }
848
883
  }
@@ -861,29 +896,12 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
861
896
  setArchiveFocus("cancel");
862
897
  return;
863
898
  }
864
- if (key.return || input && input.toUpperCase() === "Y") {
899
+ if (input && input.toUpperCase() === "Y") {
865
900
  if (archiveFocus === "cancel") {
866
901
  closeArchiveModal();
867
902
  return;
868
903
  }
869
- if (!archiveTarget) return;
870
- (async () => {
871
- try {
872
- setArchiving(true);
873
- const isArchived = archiveTarget.isArchived;
874
- const id = archiveTarget.id;
875
- if (isArchived) await unarchiveRepositoryById(client, id);
876
- else await archiveRepositoryById(client, id);
877
- await updateCacheAfterArchive(token, id, !isArchived);
878
- const updateRepo = (r) => r.id === id ? { ...r, isArchived: !isArchived } : r;
879
- setItems((prev) => prev.map(updateRepo));
880
- setSearchItems((prev) => prev.map(updateRepo));
881
- closeArchiveModal();
882
- } catch (e) {
883
- setArchiving(false);
884
- setArchiveError("Failed to update archive state. Check permissions.");
885
- }
886
- })();
904
+ executeArchive();
887
905
  return;
888
906
  }
889
907
  return;
@@ -909,9 +927,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
909
927
  }
910
928
  return;
911
929
  }
912
- if (!key.return) {
913
- return;
914
- }
930
+ return;
915
931
  }
916
932
  if (logoutMode) {
917
933
  if (key.escape || input && input.toUpperCase() === "C") {
@@ -1366,7 +1382,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
1366
1382
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, flexDirection: "row", justifyContent: "center", children: /* @__PURE__ */ jsxs5(Text6, { color: "gray", children: [
1367
1383
  "Press Enter to ",
1368
1384
  confirmFocus === "delete" ? "Delete" : "Cancel",
1369
- " \u2022 Y to confirm \u2022 C to cancel"
1385
+ " | Y to Delete | C to Cancel"
1370
1386
  ] }) }),
1371
1387
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx6(
1372
1388
  TextInput2,
@@ -1422,7 +1438,9 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
1422
1438
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, flexDirection: "row", justifyContent: "center", children: /* @__PURE__ */ jsxs5(Text6, { color: "gray", children: [
1423
1439
  "Press Enter to ",
1424
1440
  archiveFocus === "confirm" ? archiveTarget.isArchived ? "Unarchive" : "Archive" : "Cancel",
1425
- " \u2022 Y to confirm \u2022 C to cancel"
1441
+ " | Y to ",
1442
+ archiveTarget.isArchived ? "Unarchive" : "Archive",
1443
+ " | C to Cancel"
1426
1444
  ] }) }),
1427
1445
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx6(
1428
1446
  TextInput2,
@@ -1432,23 +1450,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
1432
1450
  },
1433
1451
  onSubmit: () => {
1434
1452
  if (archiveFocus === "confirm") {
1435
- (async () => {
1436
- try {
1437
- setArchiving(true);
1438
- const isArchived = archiveTarget.isArchived;
1439
- const id = archiveTarget.id;
1440
- if (isArchived) await unarchiveRepositoryById(client, id);
1441
- else await archiveRepositoryById(client, id);
1442
- await updateCacheAfterArchive(token, id, !isArchived);
1443
- const updateRepo = (r) => r.id === id ? { ...r, isArchived: !isArchived } : r;
1444
- setItems((prev) => prev.map(updateRepo));
1445
- setSearchItems((prev) => prev.map(updateRepo));
1446
- closeArchiveModal();
1447
- } catch (e) {
1448
- setArchiving(false);
1449
- setArchiveError("Failed to update archive state. Check permissions.");
1450
- }
1451
- })();
1453
+ executeArchive();
1452
1454
  } else {
1453
1455
  closeArchiveModal();
1454
1456
  }
@@ -1498,7 +1500,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
1498
1500
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, flexDirection: "row", justifyContent: "center", children: /* @__PURE__ */ jsxs5(Text6, { color: "gray", children: [
1499
1501
  "Press Enter to ",
1500
1502
  syncFocus === "confirm" ? "Sync" : "Cancel",
1501
- " \u2022 y to confirm \u2022 c to cancel"
1503
+ " | Y to Sync | C to Cancel"
1502
1504
  ] }) }),
1503
1505
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx6(
1504
1506
  TextInput2,
@@ -1551,7 +1553,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
1551
1553
  /* @__PURE__ */ jsx6(Box5, { marginTop: 1, flexDirection: "row", justifyContent: "center", children: /* @__PURE__ */ jsxs5(Text6, { color: "gray", children: [
1552
1554
  "Press Enter to ",
1553
1555
  logoutFocus === "confirm" ? "Logout" : "Cancel",
1554
- " \u2022 Y to confirm \u2022 C to cancel"
1556
+ " | Y to Logout | C to Cancel"
1555
1557
  ] }) })
1556
1558
  ] }) }) : orgSwitcherOpen ? /* @__PURE__ */ jsx6(Box5, { height: contentHeight, alignItems: "center", justifyContent: "center", children: /* @__PURE__ */ jsx6(
1557
1559
  OrgSwitcher,
@@ -1764,6 +1766,7 @@ function App() {
1764
1766
  if (!getStoredToken()) {
1765
1767
  storeToken(token);
1766
1768
  }
1769
+ setInput("");
1767
1770
  setMode("ready");
1768
1771
  } catch (e) {
1769
1772
  clearTimeout(timeoutId);
@@ -1831,6 +1834,7 @@ function App() {
1831
1834
  }
1832
1835
  setToken(null);
1833
1836
  setViewer(null);
1837
+ setInput("");
1834
1838
  setMode("prompt");
1835
1839
  };
1836
1840
  useInput3((input2, key) => {
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "gh-manager-cli",
3
- "version": "1.10.4",
3
+ "version": "1.10.6",
4
4
  "private": false,
5
5
  "description": "Interactive CLI to manage your GitHub repos (personal) with Ink",
6
6
  "license": "MIT",
7
7
  "main": "dist/index.js",
8
8
  "bin": {
9
- "gh-manager": "dist/index.js"
9
+ "gh-manager-cli": "dist/index.js"
10
10
  },
11
11
  "files": [
12
12
  "dist/",
@@ -29,10 +29,12 @@
29
29
  "build:binaries": "npm run build && pkg dist/index.js --targets node18-linux-x64,node18-macos-x64,node18-windows-x64 --out-path ./binaries",
30
30
  "dev": "tsup --watch",
31
31
  "start": "node dist/index.js",
32
- "start:cache": "GH_MANAGER_APOLLO=1 GH_MANAGER_DEBUG=1 node dist/index.js",
33
- "start:no-cache": "GH_MANAGER_APOLLO=0 GH_MANAGER_DEBUG=1 node dist/index.js",
34
- "test:cache": "pnpm build && pnpm start:cache",
35
- "prepublishOnly": "pnpm run build"
32
+ "start:debug": "GH_MANAGER_DEBUG=1 node dist/index.js",
33
+ "start:dev": "REPOS_PER_FETCH=5 GH_MANAGER_DEBUG=1 node dist/index.js",
34
+ "prepublishOnly": "pnpm run build",
35
+ "test": "vitest run",
36
+ "test:watch": "vitest",
37
+ "test:coverage": "vitest run --coverage"
36
38
  },
37
39
  "engines": {
38
40
  "node": ">=18"
@@ -55,10 +57,13 @@
55
57
  "@semantic-release/git": "^10.0.1",
56
58
  "@types/node": "^24.3.0",
57
59
  "@types/react": "^19.1.12",
60
+ "ink-testing-library": "^3.0.0",
58
61
  "pkg": "^5.8.1",
59
62
  "semantic-release": "^24.2.7",
60
63
  "tsup": "^8.5.0",
61
- "typescript": "^5.9.2"
64
+ "typescript": "^5.9.2",
65
+ "vitest": "^2.1.3",
66
+ "@vitest/coverage-v8": "^2.1.3"
62
67
  },
63
68
  "repository": {
64
69
  "type": "git",
@@ -92,18 +97,18 @@
92
97
  {
93
98
  "assets": [
94
99
  {
95
- "path": "binaries/gh-manager-linux-x64/gh-manager-linux-x64",
96
- "name": "gh-manager-linux-x64",
100
+ "path": "binaries/gh-manager-cli-linux-x64/gh-manager-cli-linux-x64",
101
+ "name": "gh-manager-cli-linux-x64",
97
102
  "label": "Linux x64 Binary"
98
103
  },
99
104
  {
100
- "path": "binaries/gh-manager-macos-x64/gh-manager-macos-x64",
101
- "name": "gh-manager-macos-x64",
105
+ "path": "binaries/gh-manager-cli-macos-x64/gh-manager-cli-macos-x64",
106
+ "name": "gh-manager-cli-macos-x64",
102
107
  "label": "macOS x64 Binary"
103
108
  },
104
109
  {
105
- "path": "binaries/gh-manager-windows-x64/gh-manager-windows-x64.exe",
106
- "name": "gh-manager-windows-x64.exe",
110
+ "path": "binaries/gh-manager-cli-windows-x64/gh-manager-cli-windows-x64.exe",
111
+ "name": "gh-manager-cli-windows-x64.exe",
107
112
  "label": "Windows x64 Binary"
108
113
  }
109
114
  ]