gh-manager-cli 1.9.0 → 1.10.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,10 @@
|
|
|
1
|
+
# [1.10.0](https://github.com/wiiiimm/gh-manager-cli/compare/v1.9.0...v1.10.0) (2025-09-01)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* sync repository actions with Apollo cache and improve info view ([563d04a](https://github.com/wiiiimm/gh-manager-cli/commit/563d04a4ec931c27dff204d3b5e6e770e4b482e6))
|
|
7
|
+
|
|
1
8
|
# [1.9.0](https://github.com/wiiiimm/gh-manager-cli/compare/v1.8.2...v1.9.0) (2025-09-01)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -16,7 +16,11 @@ function makeClient(token) {
|
|
|
16
16
|
headers: { authorization: `token ${token}` }
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
+
var apolloClientInstance = null;
|
|
19
20
|
async function makeApolloClient(token) {
|
|
21
|
+
if (apolloClientInstance) {
|
|
22
|
+
return apolloClientInstance;
|
|
23
|
+
}
|
|
20
24
|
try {
|
|
21
25
|
if (typeof globalThis.fetch === "undefined") {
|
|
22
26
|
throw new Error("Fetch API not available. Node 18+ is required.");
|
|
@@ -63,7 +67,8 @@ async function makeApolloClient(token) {
|
|
|
63
67
|
headers: { authorization: `Bearer ${token}` }
|
|
64
68
|
});
|
|
65
69
|
const client = new ApolloClient({ cache, link });
|
|
66
|
-
|
|
70
|
+
apolloClientInstance = { client, gql };
|
|
71
|
+
return apolloClientInstance;
|
|
67
72
|
} catch (error) {
|
|
68
73
|
const debug = process.env.GH_MANAGER_DEBUG === "1";
|
|
69
74
|
if (debug) {
|
|
@@ -533,6 +538,61 @@ async function unarchiveRepositoryById(client, repositoryId) {
|
|
|
533
538
|
);
|
|
534
539
|
await client(mutation, { repositoryId });
|
|
535
540
|
}
|
|
541
|
+
async function getRepositoryFromCache(token, repositoryId) {
|
|
542
|
+
try {
|
|
543
|
+
const ap = await makeApolloClient(token);
|
|
544
|
+
if (!ap || !ap.client) return null;
|
|
545
|
+
const cached = ap.client.cache.readFragment({
|
|
546
|
+
id: `Repository:${repositoryId}`,
|
|
547
|
+
fragment: gql`
|
|
548
|
+
fragment CachedRepository on Repository {
|
|
549
|
+
id
|
|
550
|
+
name
|
|
551
|
+
nameWithOwner
|
|
552
|
+
description
|
|
553
|
+
url
|
|
554
|
+
pushedAt
|
|
555
|
+
updatedAt
|
|
556
|
+
isPrivate
|
|
557
|
+
isArchived
|
|
558
|
+
isFork
|
|
559
|
+
stargazerCount
|
|
560
|
+
forkCount
|
|
561
|
+
diskUsage
|
|
562
|
+
primaryLanguage {
|
|
563
|
+
name
|
|
564
|
+
color
|
|
565
|
+
}
|
|
566
|
+
parent {
|
|
567
|
+
nameWithOwner
|
|
568
|
+
defaultBranchRef {
|
|
569
|
+
target {
|
|
570
|
+
... on Commit {
|
|
571
|
+
history(first: 0) {
|
|
572
|
+
totalCount
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
defaultBranchRef {
|
|
579
|
+
name
|
|
580
|
+
target {
|
|
581
|
+
... on Commit {
|
|
582
|
+
history(first: 0) {
|
|
583
|
+
totalCount
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
`
|
|
590
|
+
});
|
|
591
|
+
return cached;
|
|
592
|
+
} catch {
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
536
596
|
async function fetchRepositoryById(client, repositoryId, includeForkTracking = true) {
|
|
537
597
|
const query = (
|
|
538
598
|
/* GraphQL */
|
|
@@ -643,6 +703,82 @@ async function purgeApolloCacheFiles() {
|
|
|
643
703
|
} catch {
|
|
644
704
|
}
|
|
645
705
|
}
|
|
706
|
+
async function updateCacheAfterDelete(token, repositoryId) {
|
|
707
|
+
try {
|
|
708
|
+
const ap = await makeApolloClient(token);
|
|
709
|
+
if (!ap || !ap.client) return;
|
|
710
|
+
ap.client.cache.evict({ id: `Repository:${repositoryId}` });
|
|
711
|
+
ap.client.cache.gc();
|
|
712
|
+
} catch {
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
async function updateCacheAfterArchive(token, repositoryId, isArchived) {
|
|
716
|
+
try {
|
|
717
|
+
const ap = await makeApolloClient(token);
|
|
718
|
+
if (!ap || !ap.client) return;
|
|
719
|
+
ap.client.cache.modify({
|
|
720
|
+
id: `Repository:${repositoryId}`,
|
|
721
|
+
fields: {
|
|
722
|
+
isArchived: () => isArchived
|
|
723
|
+
}
|
|
724
|
+
});
|
|
725
|
+
} catch {
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
async function updateCacheWithRepository(token, repository) {
|
|
729
|
+
try {
|
|
730
|
+
const ap = await makeApolloClient(token);
|
|
731
|
+
if (!ap || !ap.client) return;
|
|
732
|
+
ap.client.cache.writeFragment({
|
|
733
|
+
id: `Repository:${repository.id}`,
|
|
734
|
+
fragment: gql`
|
|
735
|
+
fragment UpdatedRepository on Repository {
|
|
736
|
+
id
|
|
737
|
+
name
|
|
738
|
+
nameWithOwner
|
|
739
|
+
description
|
|
740
|
+
url
|
|
741
|
+
pushedAt
|
|
742
|
+
updatedAt
|
|
743
|
+
isPrivate
|
|
744
|
+
isArchived
|
|
745
|
+
isFork
|
|
746
|
+
stargazerCount
|
|
747
|
+
forkCount
|
|
748
|
+
diskUsage
|
|
749
|
+
primaryLanguage {
|
|
750
|
+
name
|
|
751
|
+
color
|
|
752
|
+
}
|
|
753
|
+
parent {
|
|
754
|
+
nameWithOwner
|
|
755
|
+
defaultBranchRef {
|
|
756
|
+
target {
|
|
757
|
+
... on Commit {
|
|
758
|
+
history(first: 0) {
|
|
759
|
+
totalCount
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
defaultBranchRef {
|
|
766
|
+
name
|
|
767
|
+
target {
|
|
768
|
+
... on Commit {
|
|
769
|
+
history(first: 0) {
|
|
770
|
+
totalCount
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
`,
|
|
777
|
+
data: repository
|
|
778
|
+
});
|
|
779
|
+
} catch {
|
|
780
|
+
}
|
|
781
|
+
}
|
|
646
782
|
async function inspectCacheStatus() {
|
|
647
783
|
try {
|
|
648
784
|
const fs2 = await import("fs");
|
|
@@ -699,8 +835,12 @@ export {
|
|
|
699
835
|
deleteRepositoryRest,
|
|
700
836
|
archiveRepositoryById,
|
|
701
837
|
unarchiveRepositoryById,
|
|
838
|
+
getRepositoryFromCache,
|
|
702
839
|
fetchRepositoryById,
|
|
703
840
|
syncForkWithUpstream,
|
|
704
841
|
purgeApolloCacheFiles,
|
|
842
|
+
updateCacheAfterDelete,
|
|
843
|
+
updateCacheAfterArchive,
|
|
844
|
+
updateCacheWithRepository,
|
|
705
845
|
inspectCacheStatus
|
|
706
846
|
};
|
|
@@ -6,14 +6,18 @@ import {
|
|
|
6
6
|
fetchViewerOrganizations,
|
|
7
7
|
fetchViewerReposPage,
|
|
8
8
|
fetchViewerReposPageUnified,
|
|
9
|
+
getRepositoryFromCache,
|
|
9
10
|
getViewerLogin,
|
|
10
11
|
inspectCacheStatus,
|
|
11
12
|
makeClient,
|
|
12
13
|
purgeApolloCacheFiles,
|
|
13
14
|
searchRepositoriesUnified,
|
|
14
15
|
syncForkWithUpstream,
|
|
15
|
-
unarchiveRepositoryById
|
|
16
|
-
|
|
16
|
+
unarchiveRepositoryById,
|
|
17
|
+
updateCacheAfterArchive,
|
|
18
|
+
updateCacheAfterDelete,
|
|
19
|
+
updateCacheWithRepository
|
|
20
|
+
} from "./chunk-X5PZ5T27.js";
|
|
17
21
|
export {
|
|
18
22
|
archiveRepositoryById,
|
|
19
23
|
deleteRepositoryRest,
|
|
@@ -21,11 +25,15 @@ export {
|
|
|
21
25
|
fetchViewerOrganizations,
|
|
22
26
|
fetchViewerReposPage,
|
|
23
27
|
fetchViewerReposPageUnified,
|
|
28
|
+
getRepositoryFromCache,
|
|
24
29
|
getViewerLogin,
|
|
25
30
|
inspectCacheStatus,
|
|
26
31
|
makeClient,
|
|
27
32
|
purgeApolloCacheFiles,
|
|
28
33
|
searchRepositoriesUnified,
|
|
29
34
|
syncForkWithUpstream,
|
|
30
|
-
unarchiveRepositoryById
|
|
35
|
+
unarchiveRepositoryById,
|
|
36
|
+
updateCacheAfterArchive,
|
|
37
|
+
updateCacheAfterDelete,
|
|
38
|
+
updateCacheWithRepository
|
|
31
39
|
};
|
package/dist/index.js
CHANGED
|
@@ -6,21 +6,25 @@ import {
|
|
|
6
6
|
fetchRepositoryById,
|
|
7
7
|
fetchViewerOrganizations,
|
|
8
8
|
fetchViewerReposPageUnified,
|
|
9
|
+
getRepositoryFromCache,
|
|
9
10
|
getViewerLogin,
|
|
10
11
|
inspectCacheStatus,
|
|
11
12
|
makeClient,
|
|
12
13
|
purgeApolloCacheFiles,
|
|
13
14
|
searchRepositoriesUnified,
|
|
14
15
|
syncForkWithUpstream,
|
|
15
|
-
unarchiveRepositoryById
|
|
16
|
-
|
|
16
|
+
unarchiveRepositoryById,
|
|
17
|
+
updateCacheAfterArchive,
|
|
18
|
+
updateCacheAfterDelete,
|
|
19
|
+
updateCacheWithRepository
|
|
20
|
+
} from "./chunk-X5PZ5T27.js";
|
|
17
21
|
|
|
18
22
|
// package.json
|
|
19
23
|
var require_package = __commonJS({
|
|
20
24
|
"package.json"(exports, module) {
|
|
21
25
|
module.exports = {
|
|
22
26
|
name: "gh-manager-cli",
|
|
23
|
-
version: "1.
|
|
27
|
+
version: "1.10.0",
|
|
24
28
|
private: false,
|
|
25
29
|
description: "Interactive CLI to manage your GitHub repos (personal) with Ink",
|
|
26
30
|
license: "MIT",
|
|
@@ -276,7 +280,7 @@ function OrgSwitcher({ token, currentContext, onSelect, onClose }) {
|
|
|
276
280
|
const loadOrgs = async () => {
|
|
277
281
|
try {
|
|
278
282
|
setLoading(true);
|
|
279
|
-
const client = await import("./github-
|
|
283
|
+
const client = await import("./github-OM6QOCRV.js").then((m) => m.makeClient(token));
|
|
280
284
|
const orgs = await fetchViewerOrganizations(client);
|
|
281
285
|
setOrganizations(orgs);
|
|
282
286
|
if (!isPersonalContext) {
|
|
@@ -484,6 +488,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
484
488
|
const [syncError, setSyncError] = useState3(null);
|
|
485
489
|
const [syncFocus, setSyncFocus] = useState3("confirm");
|
|
486
490
|
const [infoMode, setInfoMode] = useState3(false);
|
|
491
|
+
const [infoRepo, setInfoRepo] = useState3(null);
|
|
487
492
|
const [logoutMode, setLogoutMode] = useState3(false);
|
|
488
493
|
const [logoutFocus, setLogoutFocus] = useState3("confirm");
|
|
489
494
|
const [logoutError, setLogoutError] = useState3(null);
|
|
@@ -529,6 +534,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
529
534
|
const [owner, repo] = (deleteTarget.nameWithOwner || "").split("/");
|
|
530
535
|
await deleteRepositoryRest(token, owner, repo);
|
|
531
536
|
const targetId = deleteTarget.id;
|
|
537
|
+
await updateCacheAfterDelete(token, targetId);
|
|
532
538
|
setItems((prev) => prev.filter((r) => r.id !== targetId));
|
|
533
539
|
setSearchItems((prev) => prev.filter((r) => r.id !== targetId));
|
|
534
540
|
setTotalCount((c) => Math.max(0, c - 1));
|
|
@@ -828,6 +834,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
828
834
|
const id = archiveTarget.id;
|
|
829
835
|
if (isArchived) await unarchiveRepositoryById(client, id);
|
|
830
836
|
else await archiveRepositoryById(client, id);
|
|
837
|
+
await updateCacheAfterArchive(token, id, !isArchived);
|
|
831
838
|
const updateRepo = (r) => r.id === id ? { ...r, isArchived: !isArchived } : r;
|
|
832
839
|
setItems((prev) => prev.map(updateRepo));
|
|
833
840
|
setSearchItems((prev) => prev.map(updateRepo));
|
|
@@ -868,6 +875,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
868
875
|
const result = await syncForkWithUpstream(token, owner, repo, branchName);
|
|
869
876
|
const updatedRepo = await fetchRepositoryById(client, syncTarget.id, forkTracking);
|
|
870
877
|
if (updatedRepo) {
|
|
878
|
+
await updateCacheWithRepository(token, updatedRepo);
|
|
871
879
|
const updateSyncedRepo = (r) => {
|
|
872
880
|
if (r.id === syncTarget.id) {
|
|
873
881
|
return updatedRepo;
|
|
@@ -939,6 +947,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
939
947
|
if (infoMode) {
|
|
940
948
|
if (key.escape || input && input.toUpperCase() === "I") {
|
|
941
949
|
setInfoMode(false);
|
|
950
|
+
setInfoRepo(null);
|
|
942
951
|
return;
|
|
943
952
|
}
|
|
944
953
|
return;
|
|
@@ -1077,6 +1086,17 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1077
1086
|
return;
|
|
1078
1087
|
}
|
|
1079
1088
|
if (input && input.toUpperCase() === "I") {
|
|
1089
|
+
const repo = visibleItems[cursor];
|
|
1090
|
+
if (repo) {
|
|
1091
|
+
(async () => {
|
|
1092
|
+
const cachedRepo = await getRepositoryFromCache(token, repo.id);
|
|
1093
|
+
if (cachedRepo) {
|
|
1094
|
+
setInfoRepo(cachedRepo);
|
|
1095
|
+
} else {
|
|
1096
|
+
setInfoRepo(repo);
|
|
1097
|
+
}
|
|
1098
|
+
})();
|
|
1099
|
+
}
|
|
1080
1100
|
setInfoMode(true);
|
|
1081
1101
|
return;
|
|
1082
1102
|
}
|
|
@@ -1421,6 +1441,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1421
1441
|
const id = archiveTarget.id;
|
|
1422
1442
|
if (isArchived) await unarchiveRepositoryById(client, id);
|
|
1423
1443
|
else await archiveRepositoryById(client, id);
|
|
1444
|
+
await updateCacheAfterArchive(token, id, !isArchived);
|
|
1424
1445
|
const updateRepo = (r) => r.id === id ? { ...r, isArchived: !isArchived } : r;
|
|
1425
1446
|
setItems((prev) => prev.map(updateRepo));
|
|
1426
1447
|
setSearchItems((prev) => prev.map(updateRepo));
|
|
@@ -1497,6 +1518,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1497
1518
|
const result = await syncForkWithUpstream(token, owner, repo, branchName);
|
|
1498
1519
|
const updatedRepo = await fetchRepositoryById(client, syncTarget.id, forkTracking);
|
|
1499
1520
|
if (updatedRepo) {
|
|
1521
|
+
await updateCacheWithRepository(token, updatedRepo);
|
|
1500
1522
|
const updateSyncedRepo = (r) => {
|
|
1501
1523
|
if (r.id === syncTarget.id) {
|
|
1502
1524
|
return updatedRepo;
|
|
@@ -1585,12 +1607,15 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1585
1607
|
onClose: () => setOrgSwitcherOpen(false)
|
|
1586
1608
|
}
|
|
1587
1609
|
) }) : infoMode ? /* @__PURE__ */ jsx6(Box5, { height: contentHeight, alignItems: "center", justifyContent: "center", children: (() => {
|
|
1588
|
-
const repo = visibleItems[cursor];
|
|
1610
|
+
const repo = infoRepo || visibleItems[cursor];
|
|
1589
1611
|
if (!repo) return /* @__PURE__ */ jsx6(Text6, { color: "red", children: "No repository selected." });
|
|
1590
1612
|
const langName = repo.primaryLanguage?.name || "N/A";
|
|
1591
1613
|
const langColor = repo.primaryLanguage?.color || "#666666";
|
|
1592
1614
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 3, paddingY: 2, width: Math.min(terminalWidth - 8, 90), children: [
|
|
1593
|
-
/* @__PURE__ */
|
|
1615
|
+
/* @__PURE__ */ jsxs5(Text6, { bold: true, children: [
|
|
1616
|
+
"Repository Info ",
|
|
1617
|
+
infoRepo ? chalk3.dim("(cached)") : ""
|
|
1618
|
+
] }),
|
|
1594
1619
|
/* @__PURE__ */ jsx6(Box5, { height: 1, children: /* @__PURE__ */ jsx6(Text6, { children: " " }) }),
|
|
1595
1620
|
/* @__PURE__ */ jsx6(Text6, { children: chalk3.bold(repo.nameWithOwner) }),
|
|
1596
1621
|
repo.description && /* @__PURE__ */ jsx6(Text6, { color: "gray", children: repo.description }),
|