gh-manager-cli 1.18.1 → 1.19.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 +14 -0
- package/README.md +23 -0
- package/dist/index.js +133 -38
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [1.19.1](https://github.com/wiiiimm/gh-manager-cli/compare/v1.19.0...v1.19.1) (2025-09-02)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* clear repository list immediately on context switch ([73c75af](https://github.com/wiiiimm/gh-manager-cli/commit/73c75afd725fa2640acc03e8381c4bc0598c6bf1))
|
|
7
|
+
|
|
8
|
+
# [1.19.0](https://github.com/wiiiimm/gh-manager-cli/compare/v1.18.1...v1.19.0) (2025-09-02)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **cli:** add org (-o) and token (-t) flags ([#18](https://github.com/wiiiimm/gh-manager-cli/issues/18)) ([029376e](https://github.com/wiiiimm/gh-manager-cli/commit/029376e1465eb9376850c6e19ef2b514020a4542))
|
|
14
|
+
|
|
1
15
|
## [1.18.1](https://github.com/wiiiimm/gh-manager-cli/compare/v1.18.0...v1.18.1) (2025-09-02)
|
|
2
16
|
|
|
3
17
|
|
package/README.md
CHANGED
|
@@ -208,6 +208,29 @@ Notes:
|
|
|
208
208
|
|
|
209
209
|
Launch the app, then use the keys below:
|
|
210
210
|
|
|
211
|
+
### CLI Flags
|
|
212
|
+
|
|
213
|
+
- `--org, -o <slug>`: Start in a specific organisation context (if accessible). Ignores the flag if you don’t have access or if the slug isn’t an organisation.
|
|
214
|
+
- Examples:
|
|
215
|
+
- `gh-manager-cli --org acme`
|
|
216
|
+
- `gh-manager-cli -o acme`
|
|
217
|
+
- `npx gh-manager-cli --org=@acme`
|
|
218
|
+
- `npx gh-manager-cli -o=@acme`
|
|
219
|
+
- Notes:
|
|
220
|
+
- Leading `@` is optional.
|
|
221
|
+
- Personal usernames are not supported by `--org`/`-o` (use default personal context).
|
|
222
|
+
|
|
223
|
+
- `--token, -t <pat>`: Use a Personal Access Token just for this run. Does not persist to config.
|
|
224
|
+
- Examples:
|
|
225
|
+
- `gh-manager-cli --token ghp_XXXXXXXXXXXXXXXXXXXXXXXXXXXX`
|
|
226
|
+
- `gh-manager-cli -t=ghp_XXXXXXXXXXXXXXXXXXXXXXXXXXXX`
|
|
227
|
+
- Precedence: CLI token > `GITHUB_TOKEN`/`GH_TOKEN` env vars > stored config.
|
|
228
|
+
- Security: Supplying tokens on the command line may be captured in shell history. Prefer env vars or the interactive prompt when possible.
|
|
229
|
+
|
|
230
|
+
- `--help, -h`: Show usage information and exit.
|
|
231
|
+
|
|
232
|
+
- `--version, -v`: Print the current version and exit.
|
|
233
|
+
|
|
211
234
|
### Navigation & View Controls
|
|
212
235
|
- **Top/Bottom**: `Ctrl+G` (top), `G` (bottom)
|
|
213
236
|
- **Page Navigation**: ↑↓ Arrow keys, PageUp/PageDown
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ var require_package = __commonJS({
|
|
|
28
28
|
"package.json"(exports, module) {
|
|
29
29
|
module.exports = {
|
|
30
30
|
name: "gh-manager-cli",
|
|
31
|
-
version: "1.
|
|
31
|
+
version: "1.19.1",
|
|
32
32
|
private: false,
|
|
33
33
|
description: "Interactive CLI to manage your GitHub repos (personal) with Ink",
|
|
34
34
|
license: "MIT",
|
|
@@ -404,7 +404,7 @@ async function openGitHubAuthorizationPage() {
|
|
|
404
404
|
}
|
|
405
405
|
|
|
406
406
|
// src/ui/RepoList.tsx
|
|
407
|
-
import React10, { useEffect as useEffect7, useMemo, useState as useState10, useRef } from "react";
|
|
407
|
+
import React10, { useEffect as useEffect7, useMemo, useState as useState10, useRef, useCallback } from "react";
|
|
408
408
|
import { Box as Box13, Text as Text14, useApp, useInput as useInput10, useStdout } from "ink";
|
|
409
409
|
import TextInput4 from "ink-text-input";
|
|
410
410
|
import chalk11 from "chalk";
|
|
@@ -497,8 +497,8 @@ function OrgSwitcher({ token, currentContext, onSelect, onClose }) {
|
|
|
497
497
|
}
|
|
498
498
|
setEnterpriseOrgs(entOrgs);
|
|
499
499
|
if (!isPersonalContext) {
|
|
500
|
-
const
|
|
501
|
-
const index = orgs.findIndex((org) => org.login ===
|
|
500
|
+
const orgLogin = currentContext.login;
|
|
501
|
+
const index = orgs.findIndex((org) => org.login === orgLogin);
|
|
502
502
|
if (index !== -1) {
|
|
503
503
|
setCursor(index + 1);
|
|
504
504
|
}
|
|
@@ -1223,16 +1223,20 @@ var getPageSize = () => {
|
|
|
1223
1223
|
return 15;
|
|
1224
1224
|
};
|
|
1225
1225
|
var PAGE_SIZE = getPageSize();
|
|
1226
|
-
function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextChange }) {
|
|
1226
|
+
function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextChange, initialOrgSlug: initialOrgSlug2 }) {
|
|
1227
1227
|
const { exit } = useApp();
|
|
1228
1228
|
const { stdout } = useStdout();
|
|
1229
1229
|
const client = useMemo(() => makeClient(token), [token]);
|
|
1230
1230
|
const [debugMessages, setDebugMessages] = useState10([]);
|
|
1231
|
-
const addDebugMessage = (msg) => {
|
|
1231
|
+
const addDebugMessage = useCallback((msg) => {
|
|
1232
1232
|
if (process.env.GH_MANAGER_DEBUG === "1") {
|
|
1233
1233
|
setDebugMessages((prev) => [...prev.slice(-9), msg]);
|
|
1234
1234
|
}
|
|
1235
|
-
};
|
|
1235
|
+
}, []);
|
|
1236
|
+
const handleOrgContextChangeRef = useRef(onOrgContextChange);
|
|
1237
|
+
useEffect7(() => {
|
|
1238
|
+
handleOrgContextChangeRef.current = onOrgContextChange;
|
|
1239
|
+
}, [onOrgContextChange]);
|
|
1236
1240
|
React10.useEffect(() => {
|
|
1237
1241
|
addDebugMessage(`[RepoList] Component mounted`);
|
|
1238
1242
|
logger.info("RepoList component mounted", {
|
|
@@ -1299,6 +1303,35 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1299
1303
|
const [changingVisibility, setChangingVisibility] = useState10(false);
|
|
1300
1304
|
const [changeVisibilityError, setChangeVisibilityError] = useState10(null);
|
|
1301
1305
|
const [sortMode, setSortMode] = useState10(false);
|
|
1306
|
+
const appliedInitialOrg = useRef(false);
|
|
1307
|
+
useEffect7(() => {
|
|
1308
|
+
(async () => {
|
|
1309
|
+
if (appliedInitialOrg.current) return;
|
|
1310
|
+
if (!initialOrgSlug2) return;
|
|
1311
|
+
if (!token) return;
|
|
1312
|
+
if (!prefsLoaded) {
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
appliedInitialOrg.current = true;
|
|
1316
|
+
try {
|
|
1317
|
+
const orgs = await fetchViewerOrganizations(client);
|
|
1318
|
+
const slug = initialOrgSlug2.replace(/^@/, "");
|
|
1319
|
+
const match = orgs.find((o) => o.login.toLowerCase() === slug.toLowerCase());
|
|
1320
|
+
if (match) {
|
|
1321
|
+
await handleOrgContextChange({
|
|
1322
|
+
type: "organization",
|
|
1323
|
+
login: match.login,
|
|
1324
|
+
name: match.name || void 0
|
|
1325
|
+
});
|
|
1326
|
+
addDebugMessage(`[--org] Switched context to @${match.login}`);
|
|
1327
|
+
} else {
|
|
1328
|
+
addDebugMessage(`[--org] No access to org @${slug}, ignoring flag`);
|
|
1329
|
+
}
|
|
1330
|
+
} catch (e) {
|
|
1331
|
+
addDebugMessage(`[--org] Failed to apply org flag: ${e.message || e}`);
|
|
1332
|
+
}
|
|
1333
|
+
})();
|
|
1334
|
+
}, [initialOrgSlug2, token, prefsLoaded, client, addDebugMessage]);
|
|
1302
1335
|
function closeArchiveModal() {
|
|
1303
1336
|
setArchiveMode(false);
|
|
1304
1337
|
setArchiveTarget(null);
|
|
@@ -1413,6 +1446,10 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1413
1446
|
setOwnerContext(newContext);
|
|
1414
1447
|
setCursor(0);
|
|
1415
1448
|
setOrgSwitcherOpen(false);
|
|
1449
|
+
setItems([]);
|
|
1450
|
+
setSearchItems([]);
|
|
1451
|
+
setTotalCount(0);
|
|
1452
|
+
setSearchTotalCount(0);
|
|
1416
1453
|
setVisibilityFilter("all");
|
|
1417
1454
|
const newAffiliations = newContext === "personal" ? ["OWNER"] : ["ORGANIZATION_MEMBER"];
|
|
1418
1455
|
setOwnerAffiliations(newAffiliations);
|
|
@@ -1429,7 +1466,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1429
1466
|
visibilityFilter: "all"
|
|
1430
1467
|
});
|
|
1431
1468
|
if (onOrgContextChange) {
|
|
1432
|
-
|
|
1469
|
+
handleOrgContextChangeRef.current?.(newContext);
|
|
1433
1470
|
}
|
|
1434
1471
|
}
|
|
1435
1472
|
function cancelDeleteModal() {
|
|
@@ -1502,7 +1539,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1502
1539
|
field: sortFieldMap[sortKey],
|
|
1503
1540
|
direction: sortDir.toUpperCase()
|
|
1504
1541
|
};
|
|
1505
|
-
const
|
|
1542
|
+
const orgLogin = ownerContext !== "personal" ? ownerContext.login : void 0;
|
|
1506
1543
|
let privacy;
|
|
1507
1544
|
if (visibilityFilter === "public") privacy = "PUBLIC";
|
|
1508
1545
|
else if (visibilityFilter === "private") privacy = "PRIVATE";
|
|
@@ -1514,7 +1551,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1514
1551
|
overrideForkTracking ?? forkTracking,
|
|
1515
1552
|
policy ?? (after ? "network-only" : "cache-first"),
|
|
1516
1553
|
ownerAffiliations,
|
|
1517
|
-
|
|
1554
|
+
orgLogin,
|
|
1518
1555
|
privacy
|
|
1519
1556
|
);
|
|
1520
1557
|
setItems((prev) => reset || !after ? page.nodes : [...prev, ...page.nodes]);
|
|
@@ -1524,9 +1561,9 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1524
1561
|
if (page.nodes.some((repo) => repo.visibility === "INTERNAL")) {
|
|
1525
1562
|
setHasInternalRepos(true);
|
|
1526
1563
|
}
|
|
1527
|
-
if (!after &&
|
|
1564
|
+
if (!after && orgLogin) {
|
|
1528
1565
|
const client2 = makeClient(token);
|
|
1529
|
-
checkOrganizationIsEnterprise(client2,
|
|
1566
|
+
checkOrganizationIsEnterprise(client2, orgLogin).then((isEnt) => {
|
|
1530
1567
|
setIsEnterpriseOrg(isEnt);
|
|
1531
1568
|
});
|
|
1532
1569
|
}
|
|
@@ -1538,7 +1575,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1538
1575
|
sortDir,
|
|
1539
1576
|
pageSize: PAGE_SIZE,
|
|
1540
1577
|
forkTracking: overrideForkTracking ?? forkTracking,
|
|
1541
|
-
ownerContext:
|
|
1578
|
+
ownerContext: orgLogin ? `org:${orgLogin}` : "personal",
|
|
1542
1579
|
affiliations: ownerAffiliations.join(",")
|
|
1543
1580
|
});
|
|
1544
1581
|
markFetched(key);
|
|
@@ -1577,8 +1614,8 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1577
1614
|
setSearchLoading(true);
|
|
1578
1615
|
try {
|
|
1579
1616
|
const orderBy = { field: sortFieldMap[sortKey], direction: sortDir.toUpperCase() };
|
|
1580
|
-
const
|
|
1581
|
-
addDebugMessage(`[fetchSearchPage] Calling API with viewer="${viewerLogin}", orgLogin="${
|
|
1617
|
+
const orgLogin = ownerContext !== "personal" ? ownerContext.login : void 0;
|
|
1618
|
+
addDebugMessage(`[fetchSearchPage] Calling API with viewer="${viewerLogin}", orgLogin="${orgLogin || "none"}", query="${query.trim()}"`);
|
|
1582
1619
|
const page = await searchRepositoriesUnified(
|
|
1583
1620
|
token,
|
|
1584
1621
|
viewerLogin,
|
|
@@ -1589,7 +1626,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1589
1626
|
orderBy.direction,
|
|
1590
1627
|
forkTracking,
|
|
1591
1628
|
policy ?? (after ? "network-only" : "cache-first"),
|
|
1592
|
-
|
|
1629
|
+
orgLogin
|
|
1593
1630
|
);
|
|
1594
1631
|
addDebugMessage(`[fetchSearchPage] API returned ${page.nodes.length} results, totalCount=${page.totalCount}`);
|
|
1595
1632
|
if (page.nodes.length > 0) {
|
|
@@ -1642,7 +1679,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1642
1679
|
if (ui.ownerContext) {
|
|
1643
1680
|
setOwnerContext(ui.ownerContext);
|
|
1644
1681
|
if (onOrgContextChange) {
|
|
1645
|
-
|
|
1682
|
+
handleOrgContextChangeRef.current?.(ui.ownerContext);
|
|
1646
1683
|
}
|
|
1647
1684
|
if (ui.ownerContext !== "personal") {
|
|
1648
1685
|
const client2 = makeClient(token);
|
|
@@ -1659,7 +1696,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1659
1696
|
useEffect7(() => {
|
|
1660
1697
|
if (!prefsLoaded) return;
|
|
1661
1698
|
let policy = "cache-first";
|
|
1662
|
-
const
|
|
1699
|
+
const orgLogin = ownerContext !== "personal" ? ownerContext.login : void 0;
|
|
1663
1700
|
try {
|
|
1664
1701
|
const key = makeApolloKey({
|
|
1665
1702
|
viewer: viewerLogin || "unknown",
|
|
@@ -1667,7 +1704,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1667
1704
|
sortDir,
|
|
1668
1705
|
pageSize: PAGE_SIZE,
|
|
1669
1706
|
forkTracking,
|
|
1670
|
-
ownerContext:
|
|
1707
|
+
ownerContext: orgLogin ? `org:${orgLogin}` : "personal",
|
|
1671
1708
|
affiliations: ownerAffiliations.join(",")
|
|
1672
1709
|
});
|
|
1673
1710
|
policy = isFresh(key) ? "cache-first" : "network-only";
|
|
@@ -1680,7 +1717,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1680
1717
|
if (!searchActive) {
|
|
1681
1718
|
if (items.length > 0) {
|
|
1682
1719
|
let policy = "cache-first";
|
|
1683
|
-
const
|
|
1720
|
+
const orgLogin = ownerContext !== "personal" ? ownerContext.login : void 0;
|
|
1684
1721
|
try {
|
|
1685
1722
|
const key = makeApolloKey({
|
|
1686
1723
|
viewer: viewerLogin || "unknown",
|
|
@@ -1688,7 +1725,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1688
1725
|
sortDir,
|
|
1689
1726
|
pageSize: PAGE_SIZE,
|
|
1690
1727
|
forkTracking,
|
|
1691
|
-
ownerContext:
|
|
1728
|
+
ownerContext: orgLogin ? `org:${orgLogin}` : "personal",
|
|
1692
1729
|
affiliations: ownerAffiliations.join(",")
|
|
1693
1730
|
});
|
|
1694
1731
|
policy = isFresh(key) ? "cache-first" : "network-only";
|
|
@@ -1720,7 +1757,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1720
1757
|
if (!searchActive) {
|
|
1721
1758
|
if (items.length > 0) {
|
|
1722
1759
|
let policy = "network-only";
|
|
1723
|
-
const
|
|
1760
|
+
const orgLogin = ownerContext !== "personal" ? ownerContext.login : void 0;
|
|
1724
1761
|
fetchPage(null, true, true, void 0, policy);
|
|
1725
1762
|
}
|
|
1726
1763
|
} else {
|
|
@@ -1736,6 +1773,7 @@ function RepoList({ token, maxVisibleRows, onLogout, viewerLogin, onOrgContextCh
|
|
|
1736
1773
|
if (viewerLogin && searchActive && !searchLoading && searchItems.length === 0) {
|
|
1737
1774
|
let policy = "cache-first";
|
|
1738
1775
|
try {
|
|
1776
|
+
const orgLogin = ownerContext !== "personal" ? ownerContext.login : void 0;
|
|
1739
1777
|
const key = makeSearchKey({
|
|
1740
1778
|
viewer: viewerLogin || "unknown",
|
|
1741
1779
|
q: filter.trim(),
|
|
@@ -2841,7 +2879,7 @@ function OAuthProgress({ status, error, deviceCode }) {
|
|
|
2841
2879
|
// src/ui/App.tsx
|
|
2842
2880
|
import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2843
2881
|
var packageJson = require_package();
|
|
2844
|
-
function App() {
|
|
2882
|
+
function App({ initialOrgSlug: initialOrgSlug2, inlineToken: inlineToken2, inlineTokenEphemeral }) {
|
|
2845
2883
|
const { exit } = useApp2();
|
|
2846
2884
|
const { stdout } = useStdout2();
|
|
2847
2885
|
const [mode, setMode] = useState12("checking");
|
|
@@ -2855,6 +2893,7 @@ function App() {
|
|
|
2855
2893
|
const [authMethod, setAuthMethod] = useState12("pat");
|
|
2856
2894
|
const [oauthStatus, setOAuthStatus] = useState12("initializing");
|
|
2857
2895
|
const [tokenSource, setTokenSource] = useState12("pat");
|
|
2896
|
+
const [sessionTokenOrigin, setSessionTokenOrigin] = useState12("stored");
|
|
2858
2897
|
const [deviceCodeResponse, setDeviceCodeResponse] = useState12(null);
|
|
2859
2898
|
const [oauthDeviceCode, setOauthDeviceCode] = useState12(null);
|
|
2860
2899
|
const [dims, setDims] = useState12(() => {
|
|
@@ -2879,16 +2918,25 @@ function App() {
|
|
|
2879
2918
|
const stored = getStoredToken();
|
|
2880
2919
|
const source = getTokenSource();
|
|
2881
2920
|
setTokenSource(source);
|
|
2882
|
-
if (
|
|
2921
|
+
if (inlineToken2) {
|
|
2922
|
+
setToken(inlineToken2);
|
|
2923
|
+
setSessionTokenOrigin("cli");
|
|
2924
|
+
setTokenSource("pat");
|
|
2925
|
+
setMode("validating");
|
|
2926
|
+
} else if (env) {
|
|
2883
2927
|
setToken(env);
|
|
2928
|
+
setSessionTokenOrigin("env");
|
|
2929
|
+
setTokenSource("pat");
|
|
2884
2930
|
setMode("validating");
|
|
2885
2931
|
} else if (stored) {
|
|
2886
2932
|
setToken(stored);
|
|
2933
|
+
setSessionTokenOrigin("stored");
|
|
2887
2934
|
setMode("validating");
|
|
2888
2935
|
} else {
|
|
2936
|
+
setSessionTokenOrigin("prompt");
|
|
2889
2937
|
setMode("auth_method_selection");
|
|
2890
2938
|
}
|
|
2891
|
-
}, []);
|
|
2939
|
+
}, [inlineToken2]);
|
|
2892
2940
|
useEffect8(() => {
|
|
2893
2941
|
if (mode !== "oauth_flow") return;
|
|
2894
2942
|
(async () => {
|
|
@@ -2915,6 +2963,7 @@ function App() {
|
|
|
2915
2963
|
storeToken(tokenResult.token, "oauth");
|
|
2916
2964
|
setToken(tokenResult.token);
|
|
2917
2965
|
setTokenSource("oauth");
|
|
2966
|
+
setSessionTokenOrigin("oauth");
|
|
2918
2967
|
if (tokenResult.login) {
|
|
2919
2968
|
setViewer(tokenResult.login);
|
|
2920
2969
|
setOAuthStatus("success");
|
|
@@ -2953,16 +3002,18 @@ function App() {
|
|
|
2953
3002
|
const login = await getViewerLogin(client);
|
|
2954
3003
|
clearTimeout(timeoutId);
|
|
2955
3004
|
setViewer(login);
|
|
2956
|
-
logger.info("User authenticated successfully", {
|
|
2957
|
-
user: login,
|
|
2958
|
-
tokenSource,
|
|
2959
|
-
tokenStored: !getStoredToken()
|
|
2960
|
-
});
|
|
2961
3005
|
setWasRateLimited(false);
|
|
2962
3006
|
setRateLimitReset(null);
|
|
2963
|
-
|
|
3007
|
+
const hadStored = Boolean(getStoredToken());
|
|
3008
|
+
const shouldPersist = !hadStored && !inlineTokenEphemeral && (sessionTokenOrigin === "prompt" || sessionTokenOrigin === "oauth");
|
|
3009
|
+
if (shouldPersist) {
|
|
2964
3010
|
storeToken(token);
|
|
2965
3011
|
}
|
|
3012
|
+
logger.info("User authenticated successfully", {
|
|
3013
|
+
user: login,
|
|
3014
|
+
tokenOrigin: sessionTokenOrigin,
|
|
3015
|
+
willPersist: shouldPersist
|
|
3016
|
+
});
|
|
2966
3017
|
setInput("");
|
|
2967
3018
|
setMode("ready");
|
|
2968
3019
|
} catch (e) {
|
|
@@ -3015,7 +3066,12 @@ function App() {
|
|
|
3015
3066
|
setError(errorMessage);
|
|
3016
3067
|
setInput("");
|
|
3017
3068
|
setToken(null);
|
|
3018
|
-
|
|
3069
|
+
if (sessionTokenOrigin === "stored") {
|
|
3070
|
+
try {
|
|
3071
|
+
clearStoredToken();
|
|
3072
|
+
} catch {
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3019
3075
|
setMode("auth_method_selection");
|
|
3020
3076
|
}
|
|
3021
3077
|
}
|
|
@@ -3025,13 +3081,14 @@ function App() {
|
|
|
3025
3081
|
if (!input.trim()) return;
|
|
3026
3082
|
setToken(input.trim());
|
|
3027
3083
|
setTokenSource("pat");
|
|
3084
|
+
setSessionTokenOrigin("prompt");
|
|
3028
3085
|
setError(null);
|
|
3029
3086
|
setMode("validating");
|
|
3030
3087
|
};
|
|
3031
3088
|
const handleLogout = () => {
|
|
3032
3089
|
logger.info("User logged out", {
|
|
3033
3090
|
previousUser: viewer,
|
|
3034
|
-
|
|
3091
|
+
tokenOrigin: sessionTokenOrigin
|
|
3035
3092
|
});
|
|
3036
3093
|
try {
|
|
3037
3094
|
clearStoredToken();
|
|
@@ -3214,7 +3271,8 @@ function App() {
|
|
|
3214
3271
|
maxVisibleRows: dims.rows - verticalPadding * 2 - 4,
|
|
3215
3272
|
onLogout: handleLogout,
|
|
3216
3273
|
viewerLogin: viewer ?? void 0,
|
|
3217
|
-
onOrgContextChange: setOrgContext
|
|
3274
|
+
onOrgContextChange: setOrgContext,
|
|
3275
|
+
initialOrgSlug: initialOrgSlug2
|
|
3218
3276
|
}
|
|
3219
3277
|
)
|
|
3220
3278
|
] });
|
|
@@ -3223,6 +3281,31 @@ function App() {
|
|
|
3223
3281
|
// src/index.tsx
|
|
3224
3282
|
import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
3225
3283
|
var argv = process.argv.slice(2);
|
|
3284
|
+
var getFlagValue = (name) => {
|
|
3285
|
+
const idx = argv.findIndex((a) => a === `--${name}` || a.startsWith(`--${name}=`));
|
|
3286
|
+
if (idx === -1) return void 0;
|
|
3287
|
+
const at = argv[idx];
|
|
3288
|
+
if (at.includes("=")) {
|
|
3289
|
+
const [, v] = at.split("=");
|
|
3290
|
+
return v?.trim() || void 0;
|
|
3291
|
+
}
|
|
3292
|
+
const next = argv[idx + 1];
|
|
3293
|
+
if (next && !next.startsWith("-")) return next.trim();
|
|
3294
|
+
return void 0;
|
|
3295
|
+
};
|
|
3296
|
+
var getShortFlagValue = (short) => {
|
|
3297
|
+
const exact = `-${short}`;
|
|
3298
|
+
const idx = argv.findIndex((a) => a === exact || a.startsWith(`${exact}=`));
|
|
3299
|
+
if (idx === -1) return void 0;
|
|
3300
|
+
const at = argv[idx];
|
|
3301
|
+
if (at.includes("=")) {
|
|
3302
|
+
const [, v] = at.split("=");
|
|
3303
|
+
return v?.trim() || void 0;
|
|
3304
|
+
}
|
|
3305
|
+
const next = argv[idx + 1];
|
|
3306
|
+
if (next && !next.startsWith("-")) return next.trim();
|
|
3307
|
+
return void 0;
|
|
3308
|
+
};
|
|
3226
3309
|
if (argv.includes("--version") || argv.includes("-v")) {
|
|
3227
3310
|
const version = import_package.default?.version || "0.0.0";
|
|
3228
3311
|
process.stdout.write(`${version}
|
|
@@ -3234,9 +3317,11 @@ if (argv.includes("--help") || argv.includes("-h")) {
|
|
|
3234
3317
|
gh-manager-cli \u2014 GitHub repo manager (Ink TUI)
|
|
3235
3318
|
|
|
3236
3319
|
Usage:
|
|
3237
|
-
gh-manager-cli
|
|
3238
|
-
gh-manager-cli --
|
|
3239
|
-
gh-manager-cli --
|
|
3320
|
+
gh-manager-cli Launch the TUI
|
|
3321
|
+
gh-manager-cli --org, -o <slug> Start in an organisation context (if accessible)
|
|
3322
|
+
gh-manager-cli --token, -t <pat> Use a token just for this run (not persisted)
|
|
3323
|
+
gh-manager-cli --version Print version
|
|
3324
|
+
gh-manager-cli --help Show help
|
|
3240
3325
|
|
|
3241
3326
|
Env:
|
|
3242
3327
|
GITHUB_TOKEN / GH_TOKEN Personal Access Token
|
|
@@ -3277,10 +3362,20 @@ process.on("unhandledRejection", (reason) => {
|
|
|
3277
3362
|
console.error("Unhandled rejection:", reason?.message || reason);
|
|
3278
3363
|
process.exit(1);
|
|
3279
3364
|
});
|
|
3365
|
+
var initialOrgSlug = (() => {
|
|
3366
|
+
const v = getFlagValue("org") ?? getShortFlagValue("o");
|
|
3367
|
+
if (!v) return void 0;
|
|
3368
|
+
return v.replace(/^@/, "");
|
|
3369
|
+
})();
|
|
3370
|
+
var inlineToken = (() => {
|
|
3371
|
+
const v = getFlagValue("token") ?? getShortFlagValue("t");
|
|
3372
|
+
if (!v) return void 0;
|
|
3373
|
+
return v.trim();
|
|
3374
|
+
})();
|
|
3280
3375
|
logger.debug("Rendering UI");
|
|
3281
3376
|
var { unmount } = render(
|
|
3282
3377
|
/* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
|
|
3283
|
-
/* @__PURE__ */ jsx18(App, {}),
|
|
3378
|
+
/* @__PURE__ */ jsx18(App, { initialOrgSlug, inlineToken, inlineTokenEphemeral: Boolean(inlineToken) }),
|
|
3284
3379
|
/* @__PURE__ */ jsx18(Text18, { color: "gray" })
|
|
3285
3380
|
] })
|
|
3286
3381
|
);
|