gh-manager-cli 1.13.2 → 1.15.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 +24 -0
- package/README.md +49 -16
- package/dist/{chunk-BOS4OCY4.js → chunk-OKP742N4.js} +83 -2
- package/dist/{github-GO2ZQWZN.js → github-YDCON2PN.js} +7 -1
- package/dist/index.js +1184 -460
- package/package.json +6 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
# [1.15.0](https://github.com/wiiiimm/gh-manager-cli/compare/v1.14.0...v1.15.0) (2025-09-02)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* implement GitHub Device Authorization Grant flow ([#13](https://github.com/wiiiimm/gh-manager-cli/issues/13)) ([d259534](https://github.com/wiiiimm/gh-manager-cli/commit/d259534a8a0e5c21270da17df4256aec6b0b216c))
|
|
7
|
+
|
|
8
|
+
# [1.14.0](https://github.com/wiiiimm/gh-manager-cli/compare/v1.13.2...v1.14.0) (2025-09-02)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* correct TextInput import from ink-text-input package ([1040eca](https://github.com/wiiiimm/gh-manager-cli/commit/1040ecac07b0976eaf916ee5593d0bc867590eda))
|
|
14
|
+
* update both visibility and isPrivate fields when changing visibility ([4b96234](https://github.com/wiiiimm/gh-manager-cli/commit/4b962345a1e490b3a675575c8726e7040e0c0ed3))
|
|
15
|
+
* use REST API for changing repository visibility ([0bd1475](https://github.com/wiiiimm/gh-manager-cli/commit/0bd1475f22d5802d919491ad507d4b38f158da5e))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* add enterprise support with Internal visibility and Ctrl+V visibility change ([9f457af](https://github.com/wiiiimm/gh-manager-cli/commit/9f457af4558458a23f321c14b42f0701fefecc0f))
|
|
21
|
+
* add repository visibility change with Ctrl+V ([d51b5e8](https://github.com/wiiiimm/gh-manager-cli/commit/d51b5e8b28c78f6ba58056a3254fc1aa218d9838))
|
|
22
|
+
* add support for Internal visibility in enterprise accounts ([781575a](https://github.com/wiiiimm/gh-manager-cli/commit/781575aee55a70f869aad7d724fd50b6bd052221))
|
|
23
|
+
* respect visibility filter when changing repository visibility ([25c963c](https://github.com/wiiiimm/gh-manager-cli/commit/25c963ca89038c84e0c8711f69d71785eb3a7355))
|
|
24
|
+
|
|
1
25
|
## [1.13.2](https://github.com/wiiiimm/gh-manager-cli/compare/v1.13.1...v1.13.2) (2025-09-01)
|
|
2
26
|
|
|
3
27
|
|
package/README.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/logo-horizontal.png" alt="gh-manager-cli logo" width="400" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
# gh-manager-cli
|
|
2
6
|
|
|
3
7
|
[](https://www.npmjs.com/package/gh-manager-cli)
|
|
@@ -41,34 +45,36 @@ Interactive terminal app to browse and manage your personal GitHub repositories.
|
|
|
41
45
|
npx gh-manager-cli
|
|
42
46
|
```
|
|
43
47
|
|
|
44
|
-
On first run, you'll be prompted
|
|
48
|
+
On first run, you'll be prompted to authenticate with GitHub (OAuth recommended).
|
|
45
49
|
|
|
46
50
|
## Features
|
|
47
51
|
|
|
48
52
|
### Core Repository Management
|
|
49
|
-
- **
|
|
53
|
+
- **Authentication**: GitHub OAuth (recommended) or Personal Access Token with secure storage
|
|
50
54
|
- **Repository Listing**: Browse all your personal repositories with metadata (stars, forks, language, etc.)
|
|
51
55
|
- **Live Pagination**: Infinite scroll with automatic page prefetching
|
|
52
56
|
- **Interactive Sorting**: Modal-based sort selection (updated, pushed, name, stars) with direction toggle
|
|
53
57
|
- **Smart Search**: Server-side search through repository names and descriptions (3+ characters)
|
|
54
|
-
- **Visibility Filtering**: Modal-based visibility filter (All, Public, Private
|
|
58
|
+
- **Visibility Filtering**: Modal-based visibility filter (All, Public, Private/Internal for enterprise) with smart filtering
|
|
55
59
|
- **Fork Status Tracking**: Toggle display of commits behind upstream for forked repositories
|
|
56
60
|
- **Repository Actions**:
|
|
57
61
|
- View detailed info (`I`) - Shows repository metadata, language, size, and timestamps
|
|
58
62
|
- Open in browser (Enter/`O`)
|
|
59
63
|
- Delete repository (`Del` or `Backspace`) with secure two-step confirmation
|
|
60
64
|
- Archive/unarchive repositories (`Ctrl+A`) with confirmation prompts
|
|
65
|
+
- Change repository visibility (`Ctrl+V`) - Switch between Public, Private, and Internal (enterprise only)
|
|
61
66
|
- Sync forks with upstream (`Ctrl+S`) with automatic conflict detection
|
|
62
67
|
|
|
63
68
|
### User Interface & Experience
|
|
64
69
|
- **Keyboard Navigation**: Full keyboard control (arrow keys, PageUp/Down, `Ctrl+G`/`G`)
|
|
65
70
|
- **Display Density**: Toggle between compact/cozy/comfy spacing (`T`)
|
|
66
|
-
- **Visual Indicators**: Fork status, private/archived badges, language colors, visibility status
|
|
67
|
-
- **
|
|
71
|
+
- **Visual Indicators**: Fork status, private/internal/archived badges, language colors, visibility status
|
|
72
|
+
- **Enterprise Support**: Full support for GitHub Enterprise with Internal repository visibility
|
|
73
|
+
- **Organization Context**: Switch between personal and organization accounts with ENT badge for enterprise orgs
|
|
74
|
+
- **Interactive Modals**: Sort selection, visibility filtering, organization switching, and visibility change dialogs
|
|
68
75
|
- **Balanced Layout**: Repository items with spacing above and below for better visual hierarchy
|
|
69
76
|
- **Loading States**: Contextual loading screens for sorting and refreshing operations
|
|
70
77
|
- **Rate Limit Monitoring**: Live API usage display with visual warnings
|
|
71
|
-
- **Improved Layout**: Balanced spacing above and below repository items for better visual hierarchy
|
|
72
78
|
|
|
73
79
|
### Technical Features
|
|
74
80
|
- **Preference Persistence**: UI settings (sort, density, visibility filter, fork tracking) saved between sessions
|
|
@@ -140,18 +146,41 @@ pnpm link
|
|
|
140
146
|
gh-manager-cli
|
|
141
147
|
```
|
|
142
148
|
|
|
143
|
-
##
|
|
149
|
+
## Authentication
|
|
150
|
+
|
|
151
|
+
The app supports two authentication methods:
|
|
152
|
+
|
|
153
|
+
### 1. GitHub OAuth (Recommended) 🎯
|
|
154
|
+
|
|
155
|
+
The easiest and most secure way to authenticate:
|
|
144
156
|
|
|
145
|
-
|
|
157
|
+
- **Device Flow**: No need to handle callback URLs - just enter a code on GitHub's website
|
|
158
|
+
- **Browser-based**: Opens GitHub's authorization page automatically
|
|
159
|
+
- **Secure**: No client secrets or sensitive data in the app
|
|
160
|
+
- **Full Permissions**: Automatically requests all necessary scopes for complete functionality
|
|
161
|
+
- **User-friendly**: No manual token management required
|
|
162
|
+
|
|
163
|
+
When you first run the app, select **"GitHub OAuth (Recommended)"** from the authentication options. The app will:
|
|
164
|
+
1. Display a device code for you to enter on GitHub
|
|
165
|
+
2. Open your browser to GitHub's device authorization page
|
|
166
|
+
3. Wait for you to authorize the app
|
|
167
|
+
4. Securely store the OAuth token for future use
|
|
168
|
+
|
|
169
|
+
### 2. Personal Access Token (PAT)
|
|
170
|
+
|
|
171
|
+
Alternative method for users who prefer manual token management:
|
|
146
172
|
|
|
147
173
|
- Provide via env var: `GITHUB_TOKEN` or `GH_TOKEN`, or enter when prompted on first run.
|
|
148
|
-
- Recommended: classic PAT with `repo` scope for listing both public and private repos
|
|
174
|
+
- Recommended: classic PAT with `repo` scope for listing both public and private repos.
|
|
149
175
|
- Validation: a minimal `viewer { login }` request verifies the token.
|
|
150
|
-
|
|
176
|
+
|
|
177
|
+
### Token Storage & Security
|
|
178
|
+
|
|
179
|
+
- Storage: tokens are saved as JSON in your OS user config directory with POSIX perms `0600`.
|
|
151
180
|
- macOS: `~/Library/Preferences/gh-manager-cli/config.json`
|
|
152
181
|
- Linux: `~/.config/gh-manager-cli/config.json`
|
|
153
182
|
- Windows: `%APPDATA%\gh-manager-cli\config.json`
|
|
154
|
-
- Revocation: you can revoke
|
|
183
|
+
- Revocation: you can revoke tokens at any time in your GitHub settings.
|
|
155
184
|
|
|
156
185
|
Note: Tokens are stored in plaintext on disk with restricted permissions. Future work may add OS keychain support.
|
|
157
186
|
|
|
@@ -192,7 +221,7 @@ Launch the app, then use the keys below:
|
|
|
192
221
|
- **Sort Direction**: `D` to toggle ascending/descending
|
|
193
222
|
- **Display Density**: `T` to toggle compact/cozy/comfy
|
|
194
223
|
- **Fork Status**: `F` to toggle showing commits behind upstream
|
|
195
|
-
- **Visibility Filter**: `V` opens modal (All, Public, Private
|
|
224
|
+
- **Visibility Filter**: `V` opens modal (All, Public, Private/Internal for enterprise)
|
|
196
225
|
|
|
197
226
|
### Navigation & Account
|
|
198
227
|
- **Open in browser**: Enter or `O`
|
|
@@ -205,6 +234,7 @@ Launch the app, then use the keys below:
|
|
|
205
234
|
- **Repository info**: `I` to view detailed metadata (size, language, timestamps)
|
|
206
235
|
- **Cache info**: `K` to inspect Apollo cache status
|
|
207
236
|
- **Archive/Unarchive**: `Ctrl+A` with confirmation prompt
|
|
237
|
+
- **Change visibility**: `Ctrl+V` to change repository visibility (Public/Private/Internal)
|
|
208
238
|
- **Delete repository**: `Del` or `Backspace` (with two-step confirmation modal)
|
|
209
239
|
- Type confirmation code → confirm (Y/Enter)
|
|
210
240
|
- Cancel: press `C` or Esc
|
|
@@ -329,13 +359,16 @@ REPOS_PER_FETCH=5 GH_MANAGER_DEBUG=1 npx gh-manager-cli-cli
|
|
|
329
359
|
For the up-to-date task board, see [TODOs.md](./TODOs.md).
|
|
330
360
|
|
|
331
361
|
Recently implemented:
|
|
362
|
+
- ✅ OAuth login flow as an alternative to Personal Access Token
|
|
332
363
|
- ✅ Density toggle for row spacing (compact/cozy/comfy)
|
|
333
|
-
- ✅ Repo actions (archive/unarchive, delete) with confirmations
|
|
334
|
-
- ✅ Organization support and switching (press `W`)
|
|
335
|
-
- ✅ Enhanced server-side search with improved UX
|
|
364
|
+
- ✅ Repo actions (archive/unarchive, delete, change visibility) with confirmations
|
|
365
|
+
- ✅ Organization support and switching (press `W`) with enterprise detection
|
|
366
|
+
- ✅ Enhanced server-side search with improved UX and organization context support
|
|
336
367
|
- ✅ Smart infinite scroll with 80% prefetch trigger
|
|
337
368
|
- ✅ Modal-based sort and visibility filtering
|
|
338
|
-
- ✅
|
|
369
|
+
- ✅ GitHub Enterprise support with Internal repository visibility
|
|
370
|
+
- ✅ Change repository visibility modal (`Ctrl+V`)
|
|
371
|
+
- ✅ Compact filter modals for better screen space utilization
|
|
339
372
|
|
|
340
373
|
Highlights on deck:
|
|
341
374
|
- Optional OS keychain storage via `keytar`
|
|
@@ -139,6 +139,26 @@ async function fetchViewerOrganizations(client) {
|
|
|
139
139
|
const res = await client(query);
|
|
140
140
|
return res.viewer.organizations.nodes;
|
|
141
141
|
}
|
|
142
|
+
async function checkOrganizationIsEnterprise(client, orgLogin) {
|
|
143
|
+
try {
|
|
144
|
+
const query = (
|
|
145
|
+
/* GraphQL */
|
|
146
|
+
`
|
|
147
|
+
query CheckOrgEnterprise($orgLogin: String!) {
|
|
148
|
+
organization(login: $orgLogin) {
|
|
149
|
+
enterpriseOwners(first: 1) {
|
|
150
|
+
totalCount
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
`
|
|
155
|
+
);
|
|
156
|
+
const res = await client(query, { orgLogin });
|
|
157
|
+
return res.organization?.enterpriseOwners?.totalCount > 0;
|
|
158
|
+
} catch (error) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
142
162
|
async function fetchViewerReposPage(client, first, after, orderBy, includeForkTracking = true, ownerAffiliations = ["OWNER"], organizationLogin, privacy) {
|
|
143
163
|
const sortField = orderBy?.field || "UPDATED_AT";
|
|
144
164
|
const sortDirection = orderBy?.direction || "DESC";
|
|
@@ -453,8 +473,9 @@ async function fetchViewerReposPageUnified(token, first, after, orderBy, include
|
|
|
453
473
|
const octo = makeClient(token);
|
|
454
474
|
return fetchViewerReposPage(octo, first, after, orderBy, includeForkTracking, ownerAffiliations, organizationLogin, privacy);
|
|
455
475
|
}
|
|
456
|
-
async function searchRepositoriesUnified(token, viewer, text, first, after, sortKey = "UPDATED_AT", sortDir = "DESC", includeForkTracking = true, fetchPolicy = "network-only") {
|
|
457
|
-
const
|
|
476
|
+
async function searchRepositoriesUnified(token, viewer, text, first, after, sortKey = "UPDATED_AT", sortDir = "DESC", includeForkTracking = true, fetchPolicy = "network-only", organizationLogin) {
|
|
477
|
+
const searchContext = organizationLogin ? `org:${organizationLogin}` : `user:${viewer}`;
|
|
478
|
+
const q = `${text} ${searchContext} in:name,description fork:true`;
|
|
458
479
|
try {
|
|
459
480
|
const ap = await makeApolloClient(token);
|
|
460
481
|
const queryDoc = ap.gql`
|
|
@@ -565,6 +586,48 @@ async function unarchiveRepositoryById(client, repositoryId) {
|
|
|
565
586
|
);
|
|
566
587
|
await client(mutation, { repositoryId });
|
|
567
588
|
}
|
|
589
|
+
async function changeRepositoryVisibility(client, repositoryId, visibility, token) {
|
|
590
|
+
const query = (
|
|
591
|
+
/* GraphQL */
|
|
592
|
+
`
|
|
593
|
+
query GetRepoDetails($id: ID!) {
|
|
594
|
+
node(id: $id) {
|
|
595
|
+
... on Repository {
|
|
596
|
+
nameWithOwner
|
|
597
|
+
owner {
|
|
598
|
+
login
|
|
599
|
+
}
|
|
600
|
+
name
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
`
|
|
605
|
+
);
|
|
606
|
+
const result = await client(query, { id: repositoryId });
|
|
607
|
+
const repo = result.node;
|
|
608
|
+
if (!repo || !repo.nameWithOwner) {
|
|
609
|
+
throw new Error("Repository not found");
|
|
610
|
+
}
|
|
611
|
+
const [owner, name] = repo.nameWithOwner.split("/");
|
|
612
|
+
const response = await fetch(`https://api.github.com/repos/${owner}/${name}`, {
|
|
613
|
+
method: "PATCH",
|
|
614
|
+
headers: {
|
|
615
|
+
"Authorization": `token ${token}`,
|
|
616
|
+
"Accept": "application/vnd.github+json",
|
|
617
|
+
"Content-Type": "application/json",
|
|
618
|
+
"User-Agent": "gh-manager-cli"
|
|
619
|
+
},
|
|
620
|
+
body: JSON.stringify({
|
|
621
|
+
visibility: visibility.toLowerCase()
|
|
622
|
+
// API expects lowercase
|
|
623
|
+
})
|
|
624
|
+
});
|
|
625
|
+
if (!response.ok) {
|
|
626
|
+
const error = await response.text();
|
|
627
|
+
throw new Error(`Failed to change visibility: ${error}`);
|
|
628
|
+
}
|
|
629
|
+
return { nameWithOwner: repo.nameWithOwner };
|
|
630
|
+
}
|
|
568
631
|
async function getRepositoryFromCache(token, repositoryId) {
|
|
569
632
|
try {
|
|
570
633
|
const ap = await makeApolloClient(token);
|
|
@@ -755,6 +818,21 @@ async function updateCacheAfterArchive(token, repositoryId, isArchived) {
|
|
|
755
818
|
} catch {
|
|
756
819
|
}
|
|
757
820
|
}
|
|
821
|
+
async function updateCacheAfterVisibilityChange(token, repositoryId, visibility) {
|
|
822
|
+
try {
|
|
823
|
+
const ap = await makeApolloClient(token);
|
|
824
|
+
if (!ap || !ap.client) return;
|
|
825
|
+
const isPrivate = visibility === "PRIVATE";
|
|
826
|
+
ap.client.cache.modify({
|
|
827
|
+
id: `Repository:${repositoryId}`,
|
|
828
|
+
fields: {
|
|
829
|
+
visibility: () => visibility,
|
|
830
|
+
isPrivate: () => isPrivate
|
|
831
|
+
}
|
|
832
|
+
});
|
|
833
|
+
} catch {
|
|
834
|
+
}
|
|
835
|
+
}
|
|
758
836
|
async function updateCacheWithRepository(token, repository) {
|
|
759
837
|
try {
|
|
760
838
|
const ap = await makeApolloClient(token);
|
|
@@ -860,18 +938,21 @@ export {
|
|
|
860
938
|
makeClient,
|
|
861
939
|
getViewerLogin,
|
|
862
940
|
fetchViewerOrganizations,
|
|
941
|
+
checkOrganizationIsEnterprise,
|
|
863
942
|
fetchViewerReposPage,
|
|
864
943
|
fetchViewerReposPageUnified,
|
|
865
944
|
searchRepositoriesUnified,
|
|
866
945
|
deleteRepositoryRest,
|
|
867
946
|
archiveRepositoryById,
|
|
868
947
|
unarchiveRepositoryById,
|
|
948
|
+
changeRepositoryVisibility,
|
|
869
949
|
getRepositoryFromCache,
|
|
870
950
|
fetchRepositoryById,
|
|
871
951
|
syncForkWithUpstream,
|
|
872
952
|
purgeApolloCacheFiles,
|
|
873
953
|
updateCacheAfterDelete,
|
|
874
954
|
updateCacheAfterArchive,
|
|
955
|
+
updateCacheAfterVisibilityChange,
|
|
875
956
|
updateCacheWithRepository,
|
|
876
957
|
inspectCacheStatus
|
|
877
958
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
archiveRepositoryById,
|
|
4
|
+
changeRepositoryVisibility,
|
|
5
|
+
checkOrganizationIsEnterprise,
|
|
4
6
|
deleteRepositoryRest,
|
|
5
7
|
fetchRepositoryById,
|
|
6
8
|
fetchViewerOrganizations,
|
|
@@ -16,10 +18,13 @@ import {
|
|
|
16
18
|
unarchiveRepositoryById,
|
|
17
19
|
updateCacheAfterArchive,
|
|
18
20
|
updateCacheAfterDelete,
|
|
21
|
+
updateCacheAfterVisibilityChange,
|
|
19
22
|
updateCacheWithRepository
|
|
20
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-OKP742N4.js";
|
|
21
24
|
export {
|
|
22
25
|
archiveRepositoryById,
|
|
26
|
+
changeRepositoryVisibility,
|
|
27
|
+
checkOrganizationIsEnterprise,
|
|
23
28
|
deleteRepositoryRest,
|
|
24
29
|
fetchRepositoryById,
|
|
25
30
|
fetchViewerOrganizations,
|
|
@@ -35,5 +40,6 @@ export {
|
|
|
35
40
|
unarchiveRepositoryById,
|
|
36
41
|
updateCacheAfterArchive,
|
|
37
42
|
updateCacheAfterDelete,
|
|
43
|
+
updateCacheAfterVisibilityChange,
|
|
38
44
|
updateCacheWithRepository
|
|
39
45
|
};
|