github-search-cli 9.4.1 → 9.4.3
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 +65 -1
- package/README.md +268 -237
- package/bin/ghfind.js +98 -89
- package/completions/ghfind.bash +1 -1
- package/completions/ghfind.fish +3 -1
- package/completions/ghfind.zsh +6 -0
- package/dist/{chunk-IVUU2KGR.js → chunk-GYIL4S5X.js} +4 -1
- package/dist/cli.js +1179 -403
- package/dist/{config-GNZOQRTH.js → config-OCIPF2IF.js} +1 -1
- package/package.json +16 -5
- package/release-notes/9.3.0.md +32 -29
- package/scripts/build.ts +34 -19
- package/scripts/generate-svg-demo.js +218 -168
- package/scripts/postinstall.js +176 -176
- package/src/bookmarks.ts +69 -69
- package/src/cli.ts +650 -566
- package/src/compare.ts +69 -47
- package/src/config.ts +70 -65
- package/src/deepdive.ts +149 -118
- package/src/doctor.ts +287 -287
- package/src/error-report.ts +8 -12
- package/src/errors.ts +62 -59
- package/src/explore.ts +34 -29
- package/src/export.ts +73 -63
- package/src/help.ts +157 -157
- package/src/history.ts +69 -55
- package/src/init.ts +60 -55
- package/src/landing.ts +106 -104
- package/src/login.ts +186 -0
- package/src/markdown-render.ts +1 -6
- package/src/notifications.ts +75 -59
- package/src/open-url.ts +16 -16
- package/src/org.ts +299 -0
- package/src/output.ts +153 -137
- package/src/package-browser.ts +317 -305
- package/src/package.ts +149 -137
- package/src/pipe.ts +60 -54
- package/src/releases.ts +182 -144
- package/src/saved-searches.ts +72 -50
- package/src/search-state.ts +283 -229
- package/src/search.ts +678 -653
- package/src/session.ts +26 -24
- package/src/share.ts +61 -54
- package/src/status.ts +68 -61
- package/src/storage.ts +136 -106
- package/src/themes.ts +259 -116
- package/src/tips.ts +42 -42
- package/src/toast.ts +70 -69
- package/src/trending-parser.ts +104 -0
- package/src/trending.ts +481 -462
- package/src/tui.ts +3015 -2867
- package/src/types.ts +160 -158
- package/src/update-check.ts +231 -215
- package/src/version.ts +33 -0
- package/src/watch.ts +95 -74
package/src/errors.ts
CHANGED
|
@@ -1,59 +1,62 @@
|
|
|
1
|
-
/** Structured error types with user-facing messages. */
|
|
2
|
-
|
|
3
|
-
export class SearchCliError extends Error {
|
|
4
|
-
constructor(
|
|
5
|
-
message: string,
|
|
6
|
-
public readonly userMessage: string,
|
|
7
|
-
public readonly recoverable: boolean = true,
|
|
8
|
-
) {
|
|
9
|
-
super(message);
|
|
10
|
-
this.name = "SearchCliError";
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export class NetworkError extends SearchCliError {
|
|
15
|
-
constructor() {
|
|
16
|
-
super(
|
|
17
|
-
"Network request failed",
|
|
18
|
-
"⚠ Network error — check your connection. Retrying in 5s... [r]etry now",
|
|
19
|
-
);
|
|
20
|
-
this.name = "NetworkError";
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class RateLimitError extends SearchCliError {
|
|
25
|
-
constructor(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
1
|
+
/** Structured error types with user-facing messages. */
|
|
2
|
+
|
|
3
|
+
export class SearchCliError extends Error {
|
|
4
|
+
constructor(
|
|
5
|
+
message: string,
|
|
6
|
+
public readonly userMessage: string,
|
|
7
|
+
public readonly recoverable: boolean = true,
|
|
8
|
+
) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "SearchCliError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class NetworkError extends SearchCliError {
|
|
15
|
+
constructor() {
|
|
16
|
+
super(
|
|
17
|
+
"Network request failed",
|
|
18
|
+
"⚠ Network error — check your connection. Retrying in 5s... [r]etry now",
|
|
19
|
+
);
|
|
20
|
+
this.name = "NetworkError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class RateLimitError extends SearchCliError {
|
|
25
|
+
constructor(
|
|
26
|
+
public readonly hasToken: boolean,
|
|
27
|
+
resetSeconds?: number,
|
|
28
|
+
) {
|
|
29
|
+
const msg = hasToken
|
|
30
|
+
? `⚠ API rate limit exceeded (5,000/hr). Resets in ${resetSeconds ?? "?"}s. [r]etry [c]hange token`
|
|
31
|
+
: "⚠ Rate limited (60/hr). Set GITHUB_TOKEN for 5,000/hr. [r]etry";
|
|
32
|
+
super(msg, msg);
|
|
33
|
+
this.name = "RateLimitError";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class BadQueryError extends SearchCliError {
|
|
38
|
+
constructor(public readonly detail: string) {
|
|
39
|
+
super(`Invalid query: ${detail}`, `⚠ Invalid query: ${detail}`);
|
|
40
|
+
this.name = "BadQueryError";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class NoResultsError extends SearchCliError {
|
|
45
|
+
constructor(public readonly query: string) {
|
|
46
|
+
super(
|
|
47
|
+
`No results for "${query}"`,
|
|
48
|
+
`🔍 No results for "${query}". Tips: check spelling, try fewer qualifiers, or [b]rowse trending`,
|
|
49
|
+
);
|
|
50
|
+
this.name = "NoResultsError";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export class ParseError extends SearchCliError {
|
|
55
|
+
constructor(source: string, detail: string) {
|
|
56
|
+
super(
|
|
57
|
+
`Parse error from ${source}: ${detail}`,
|
|
58
|
+
`⚠ Could not parse ${source}. GitHub may have changed the layout. [r]etry`,
|
|
59
|
+
);
|
|
60
|
+
this.name = "ParseError";
|
|
61
|
+
}
|
|
62
|
+
}
|
package/src/explore.ts
CHANGED
|
@@ -1,29 +1,34 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Topic explorer — browse popular GitHub topics.
|
|
3
|
-
*
|
|
4
|
-
* Selecting a topic triggers a search.
|
|
5
|
-
*/
|
|
6
|
-
export interface TopicItem {
|
|
7
|
-
name: string;
|
|
8
|
-
description: string;
|
|
9
|
-
repoCount: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/** Fetch popular topics from GitHub search API.
|
|
13
|
-
* Requires the `mercy-preview` media type for the /search/topics endpoint.
|
|
14
|
-
*/
|
|
15
|
-
export async function fetchTopics(): Promise<TopicItem[]> {
|
|
16
|
-
const res = await fetch(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Topic explorer — browse popular GitHub topics.
|
|
3
|
+
*
|
|
4
|
+
* Selecting a topic triggers a search.
|
|
5
|
+
*/
|
|
6
|
+
export interface TopicItem {
|
|
7
|
+
name: string;
|
|
8
|
+
description: string;
|
|
9
|
+
repoCount: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Fetch popular topics from GitHub search API.
|
|
13
|
+
* Requires the `mercy-preview` media type for the /search/topics endpoint.
|
|
14
|
+
*/
|
|
15
|
+
export async function fetchTopics(): Promise<TopicItem[]> {
|
|
16
|
+
const res = await fetch(
|
|
17
|
+
"https://api.github.com/search/topics?q=popular&per_page=30",
|
|
18
|
+
{
|
|
19
|
+
headers: {
|
|
20
|
+
Accept: "application/vnd.github.mercy-preview+json",
|
|
21
|
+
"User-Agent": "search-cli",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
);
|
|
25
|
+
if (!res.ok) throw new Error(`Topics API: HTTP ${res.status}`);
|
|
26
|
+
const data = (await res.json()) as {
|
|
27
|
+
items?: Array<{ name: string; description?: string; score?: number }>;
|
|
28
|
+
};
|
|
29
|
+
return (data.items ?? []).map((item) => ({
|
|
30
|
+
name: item.name,
|
|
31
|
+
description: item.description || "",
|
|
32
|
+
repoCount: item.score || 0,
|
|
33
|
+
}));
|
|
34
|
+
}
|
package/src/export.ts
CHANGED
|
@@ -1,63 +1,73 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Export — format repos as JSON, CSV, Markdown, or plain text.
|
|
3
|
-
*/
|
|
4
|
-
import { writeFileSync } from "fs";
|
|
5
|
-
import type { Repo } from "./types";
|
|
6
|
-
|
|
7
|
-
export type ExportFormat = "json" | "csv" | "markdown" | "text";
|
|
8
|
-
|
|
9
|
-
export function formatJson(repos: Repo[]): string {
|
|
10
|
-
return JSON.stringify(repos, null, 2);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function csvEscape(val: unknown): string {
|
|
14
|
-
const str = String(val ?? "");
|
|
15
|
-
if (str.includes('"') || str.includes(",") || str.includes("\n")) {
|
|
16
|
-
return `"${str.replace(/"/g, '""')}"`;
|
|
17
|
-
}
|
|
18
|
-
return str;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Format repos as CSV string. */
|
|
22
|
-
export function formatCsv(repos: Repo[]): string {
|
|
23
|
-
const header = "rank,full_name,stars,forks,language,url";
|
|
24
|
-
const rows = repos.map(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Export — format repos as JSON, CSV, Markdown, or plain text.
|
|
3
|
+
*/
|
|
4
|
+
import { writeFileSync } from "fs";
|
|
5
|
+
import type { Repo } from "./types";
|
|
6
|
+
|
|
7
|
+
export type ExportFormat = "json" | "csv" | "markdown" | "text";
|
|
8
|
+
|
|
9
|
+
export function formatJson(repos: Repo[]): string {
|
|
10
|
+
return JSON.stringify(repos, null, 2);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function csvEscape(val: unknown): string {
|
|
14
|
+
const str = String(val ?? "");
|
|
15
|
+
if (str.includes('"') || str.includes(",") || str.includes("\n")) {
|
|
16
|
+
return `"${str.replace(/"/g, '""')}"`;
|
|
17
|
+
}
|
|
18
|
+
return str;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Format repos as CSV string. */
|
|
22
|
+
export function formatCsv(repos: Repo[]): string {
|
|
23
|
+
const header = "rank,full_name,stars,forks,language,url";
|
|
24
|
+
const rows = repos.map(
|
|
25
|
+
(r, i) =>
|
|
26
|
+
`${i + 1},${csvEscape(r.fullName)},${r.stars},${r.forks},${csvEscape(r.language ?? "")},${csvEscape(r.url)}`,
|
|
27
|
+
);
|
|
28
|
+
return [header, ...rows].join("\n");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Format repos as Markdown table. */
|
|
32
|
+
export function formatMarkdown(repos: Repo[]): string {
|
|
33
|
+
const header = "| # | Repo | Stars | Forks | Language |";
|
|
34
|
+
const sep = "|---|------|-------|-------|----------|";
|
|
35
|
+
const rows = repos.map(
|
|
36
|
+
(r, i) =>
|
|
37
|
+
`| ${i + 1} | [${r.fullName}](${r.url}) | ${r.stars.toLocaleString()} | ${r.forks.toLocaleString()} | ${r.language ?? "—"} |`,
|
|
38
|
+
);
|
|
39
|
+
return [header, sep, ...rows].join("\n");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Format repos as plain text, one per line. */
|
|
43
|
+
export function formatText(repos: Repo[]): string {
|
|
44
|
+
return repos
|
|
45
|
+
.map(
|
|
46
|
+
(r, i) =>
|
|
47
|
+
`${i + 1}. ${r.fullName} ★ ${r.stars.toLocaleString()} ${r.url}`,
|
|
48
|
+
)
|
|
49
|
+
.join("\n");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Format repos in the given format. */
|
|
53
|
+
export function formatRepos(repos: Repo[], format: ExportFormat): string {
|
|
54
|
+
switch (format) {
|
|
55
|
+
case "json":
|
|
56
|
+
return formatJson(repos);
|
|
57
|
+
case "csv":
|
|
58
|
+
return formatCsv(repos);
|
|
59
|
+
case "markdown":
|
|
60
|
+
return formatMarkdown(repos);
|
|
61
|
+
case "text":
|
|
62
|
+
return formatText(repos);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Export repos to a file. Returns the file path. */
|
|
67
|
+
export function exportToFile(repos: Repo[], format: ExportFormat): string {
|
|
68
|
+
const ext = format === "markdown" ? "md" : format;
|
|
69
|
+
const ts = Date.now();
|
|
70
|
+
const path = `./ghfind-export-${ts}.${ext}`;
|
|
71
|
+
writeFileSync(path, formatRepos(repos, format), "utf-8");
|
|
72
|
+
return path;
|
|
73
|
+
}
|
package/src/help.ts
CHANGED
|
@@ -1,157 +1,157 @@
|
|
|
1
|
-
/** Help screen — structured sections rendered by OpenTUI components. */
|
|
2
|
-
export interface HelpRow {
|
|
3
|
-
keys: string;
|
|
4
|
-
action: string;
|
|
5
|
-
}
|
|
6
|
-
export interface HelpSection {
|
|
7
|
-
title: string;
|
|
8
|
-
/** Theme color key or hex — used for Box title color */
|
|
9
|
-
titleColor: string;
|
|
10
|
-
rows: HelpRow[];
|
|
11
|
-
note?: string;
|
|
12
|
-
}
|
|
13
|
-
export function buildHelpSections(): HelpSection[] {
|
|
14
|
-
return [
|
|
15
|
-
{
|
|
16
|
-
title: " Landing ",
|
|
17
|
-
titleColor: "blue",
|
|
18
|
-
rows: [
|
|
19
|
-
{ keys: "↑ ↓ / j k", action: "Navigate menu cards" },
|
|
20
|
-
{ keys: "Enter", action: "Select mode / open Bookmarks" },
|
|
21
|
-
{ keys: "b", action: "Jump straight to Bookmarks" },
|
|
22
|
-
{ keys: "? / h", action: "Toggle this help screen" },
|
|
23
|
-
{ keys: "q", action: "Quit" },
|
|
24
|
-
],
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
title: " Navigation ",
|
|
28
|
-
titleColor: "blue",
|
|
29
|
-
rows: [
|
|
30
|
-
{ keys: "↑ ↓ / j k", action: "Move selection" },
|
|
31
|
-
{ keys: "Enter", action: "Open repo in browser" },
|
|
32
|
-
{ keys: "/", action: "Focus search input" },
|
|
33
|
-
{ keys: "Space", action: "Open command menu" },
|
|
34
|
-
{ keys: "? / Ctrl+H", action: "Toggle this help screen" },
|
|
35
|
-
{ keys: "q", action: "Quit" },
|
|
36
|
-
],
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
title: " Main View ",
|
|
40
|
-
titleColor: "green",
|
|
41
|
-
rows: [
|
|
42
|
-
{ keys: "Tab", action: "Auto-complete qualifier" },
|
|
43
|
-
{ keys: "b", action: "Bookmark / unbookmark selected repo" },
|
|
44
|
-
{ keys: "c", action: "Compare selected repo" },
|
|
45
|
-
{ keys: "t", action: "Cycle theme" },
|
|
46
|
-
{ keys: "PageDown", action: "Next page of results" },
|
|
47
|
-
{ keys: "PageUp", action: "Scroll to top of results" },
|
|
48
|
-
],
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
title: " Trending Mode ",
|
|
52
|
-
titleColor: "yellow",
|
|
53
|
-
rows: [
|
|
54
|
-
{ keys: "1-5", action: "Switch tab: Today → Week → Month → …" },
|
|
55
|
-
{ keys: "← → / h l", action: "Navigate tabs" },
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
title: " Packages Mode ",
|
|
60
|
-
titleColor: "cyan",
|
|
61
|
-
rows: [
|
|
62
|
-
{ keys: "/", action: "Search npm packages" },
|
|
63
|
-
{ keys: "↑ ↓ / j k", action: "Move selection" },
|
|
64
|
-
{ keys: "Enter", action: "View package details" },
|
|
65
|
-
{ keys: "Space", action: "Open command menu" },
|
|
66
|
-
],
|
|
67
|
-
note: "Search by name, description, or tags. Sort by downloads or score.",
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
title: " Command Menu (Space)",
|
|
71
|
-
titleColor: "purple",
|
|
72
|
-
rows: [
|
|
73
|
-
{ keys: "Sort", action: "Cycle sort: best-match → stars → …" },
|
|
74
|
-
{ keys: "Limit", action: "Cycle limit: 10 → 25 → 50 → 100" },
|
|
75
|
-
{ keys: "Refresh", action: "Re-run current search" },
|
|
76
|
-
{ keys: "Graph", action: "Toggle commit activity chart" },
|
|
77
|
-
{ keys: "Readme", action: "Full README viewer" },
|
|
78
|
-
{ keys: "Deep-dive", action: "Languages + contributors + excerpt" },
|
|
79
|
-
{ keys: "Bookmark", action: "Save / unsave selected repo" },
|
|
80
|
-
{ keys: "Compare", action: "Add to / remove from comparison" },
|
|
81
|
-
{ keys: "Trending", action: "Switch to trending browser" },
|
|
82
|
-
{ keys: "Packages", action: "Switch to npm packages" },
|
|
83
|
-
{ keys: "Export", action: "Export results to file" },
|
|
84
|
-
{ keys: "Share", action: "Share repo as text" },
|
|
85
|
-
{ keys: "Topics", action: "Browse GitHub topics" },
|
|
86
|
-
{ keys: "Saved", action: "View saved searches" },
|
|
87
|
-
{ keys: "Notifs", action: "Check GitHub notifications" },
|
|
88
|
-
{ keys: "History", action: "View search history" },
|
|
89
|
-
{ keys: "Help", action: "Show this help screen" },
|
|
90
|
-
],
|
|
91
|
-
note: "Navigate menu with ↑ ↓, select with Enter, back with ← / Esc",
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
title: " Bookmarks Page ",
|
|
95
|
-
titleColor: "green",
|
|
96
|
-
rows: [
|
|
97
|
-
{ keys: "↑ ↓ / j k", action: "Move selection" },
|
|
98
|
-
{ keys: "Enter", action: "Open bookmark in browser" },
|
|
99
|
-
{ keys: "d", action: "Remove bookmark" },
|
|
100
|
-
{ keys: "Esc / ←", action: "Back to landing" },
|
|
101
|
-
],
|
|
102
|
-
note: "A full page, not an overlay — Esc returns to the mode menu.",
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
title: " Overlay Keys ",
|
|
106
|
-
titleColor: "teal",
|
|
107
|
-
rows: [
|
|
108
|
-
{ keys: "Esc / q", action: "Close any overlay" },
|
|
109
|
-
{ keys: "Enter", action: "Confirm selection / run action" },
|
|
110
|
-
{ keys: "d", action: "Delete entry (history, saved)" },
|
|
111
|
-
{ keys: "↑ ↓ / j k", action: "Navigate overlay list" },
|
|
112
|
-
{ keys: "← → / h l", action: "Navigate tabs / panels" },
|
|
113
|
-
],
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
title: " Search Syntax ",
|
|
117
|
-
titleColor: "teal",
|
|
118
|
-
rows: [
|
|
119
|
-
{ keys: "keywords", action: "Free-text search" },
|
|
120
|
-
{ keys: "key:value", action: "Qualifier filter" },
|
|
121
|
-
{ keys: "-key:value", action: "Negated qualifier" },
|
|
122
|
-
{ keys: '"phrase"', action: "Exact phrase match" },
|
|
123
|
-
{ keys: "language:TypeScript", action: "Filter by language" },
|
|
124
|
-
{ keys: "stars:>1000", action: "Minimum stars" },
|
|
125
|
-
{ keys: "fork:true", action: "Include forks" },
|
|
126
|
-
{ keys: "user:octocat", action: "User's repos" },
|
|
127
|
-
{ keys: "org:facebook", action: "Organization repos" },
|
|
128
|
-
{ keys: "repo:facebook/react", action: "Specific repo" },
|
|
129
|
-
{ keys: "topic:react", action: "Filter by topic" },
|
|
130
|
-
{ keys: "license:mit", action: "License type" },
|
|
131
|
-
{ keys: "pushed:>2024-01-01", action: "Last push date" },
|
|
132
|
-
{ keys: "archived:false", action: "Exclude archived" },
|
|
133
|
-
],
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
title: " Utility Keys ",
|
|
137
|
-
titleColor: "muted",
|
|
138
|
-
rows: [
|
|
139
|
-
{ keys: "t", action: "Cycle theme (light / dark / solarized)" },
|
|
140
|
-
{ keys: "Ctrl+X", action: "Copy repo URL to clipboard" },
|
|
141
|
-
{ keys: "Ctrl+C", action: "Copy search query to clipboard" },
|
|
142
|
-
],
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
title: " Rate Limits ",
|
|
146
|
-
titleColor: "orange",
|
|
147
|
-
rows: [
|
|
148
|
-
{ keys: "No token", action: "10 req / min" },
|
|
149
|
-
{ keys: "GITHUB_TOKEN", action: "30 req / min (or your plan limit)" },
|
|
150
|
-
],
|
|
151
|
-
note: "Set GITHUB_TOKEN in your environment or add to config.",
|
|
152
|
-
},
|
|
153
|
-
];
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/** Column at which the action description starts (right-aligns keys). */
|
|
157
|
-
export const HELP_KEYS_COLUMN = 24;
|
|
1
|
+
/** Help screen — structured sections rendered by OpenTUI components. */
|
|
2
|
+
export interface HelpRow {
|
|
3
|
+
keys: string;
|
|
4
|
+
action: string;
|
|
5
|
+
}
|
|
6
|
+
export interface HelpSection {
|
|
7
|
+
title: string;
|
|
8
|
+
/** Theme color key or hex — used for Box title color */
|
|
9
|
+
titleColor: string;
|
|
10
|
+
rows: HelpRow[];
|
|
11
|
+
note?: string;
|
|
12
|
+
}
|
|
13
|
+
export function buildHelpSections(): HelpSection[] {
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
title: " Landing ",
|
|
17
|
+
titleColor: "blue",
|
|
18
|
+
rows: [
|
|
19
|
+
{ keys: "↑ ↓ / j k", action: "Navigate menu cards" },
|
|
20
|
+
{ keys: "Enter", action: "Select mode / open Bookmarks" },
|
|
21
|
+
{ keys: "b", action: "Jump straight to Bookmarks" },
|
|
22
|
+
{ keys: "? / h", action: "Toggle this help screen" },
|
|
23
|
+
{ keys: "q", action: "Quit" },
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
title: " Navigation ",
|
|
28
|
+
titleColor: "blue",
|
|
29
|
+
rows: [
|
|
30
|
+
{ keys: "↑ ↓ / j k", action: "Move selection" },
|
|
31
|
+
{ keys: "Enter", action: "Open repo in browser" },
|
|
32
|
+
{ keys: "/", action: "Focus search input" },
|
|
33
|
+
{ keys: "Space", action: "Open command menu" },
|
|
34
|
+
{ keys: "? / Ctrl+H", action: "Toggle this help screen" },
|
|
35
|
+
{ keys: "q", action: "Quit" },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
title: " Main View ",
|
|
40
|
+
titleColor: "green",
|
|
41
|
+
rows: [
|
|
42
|
+
{ keys: "Tab", action: "Auto-complete qualifier" },
|
|
43
|
+
{ keys: "b", action: "Bookmark / unbookmark selected repo" },
|
|
44
|
+
{ keys: "c", action: "Compare selected repo" },
|
|
45
|
+
{ keys: "t", action: "Cycle theme" },
|
|
46
|
+
{ keys: "PageDown", action: "Next page of results" },
|
|
47
|
+
{ keys: "PageUp", action: "Scroll to top of results" },
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
title: " Trending Mode ",
|
|
52
|
+
titleColor: "yellow",
|
|
53
|
+
rows: [
|
|
54
|
+
{ keys: "1-5", action: "Switch tab: Today → Week → Month → …" },
|
|
55
|
+
{ keys: "← → / h l", action: "Navigate tabs" },
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
title: " Packages Mode ",
|
|
60
|
+
titleColor: "cyan",
|
|
61
|
+
rows: [
|
|
62
|
+
{ keys: "/", action: "Search npm packages" },
|
|
63
|
+
{ keys: "↑ ↓ / j k", action: "Move selection" },
|
|
64
|
+
{ keys: "Enter", action: "View package details" },
|
|
65
|
+
{ keys: "Space", action: "Open command menu" },
|
|
66
|
+
],
|
|
67
|
+
note: "Search by name, description, or tags. Sort by downloads or score.",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
title: " Command Menu (Space)",
|
|
71
|
+
titleColor: "purple",
|
|
72
|
+
rows: [
|
|
73
|
+
{ keys: "Sort", action: "Cycle sort: best-match → stars → …" },
|
|
74
|
+
{ keys: "Limit", action: "Cycle limit: 10 → 25 → 50 → 100" },
|
|
75
|
+
{ keys: "Refresh", action: "Re-run current search" },
|
|
76
|
+
{ keys: "Graph", action: "Toggle commit activity chart" },
|
|
77
|
+
{ keys: "Readme", action: "Full README viewer" },
|
|
78
|
+
{ keys: "Deep-dive", action: "Languages + contributors + excerpt" },
|
|
79
|
+
{ keys: "Bookmark", action: "Save / unsave selected repo" },
|
|
80
|
+
{ keys: "Compare", action: "Add to / remove from comparison" },
|
|
81
|
+
{ keys: "Trending", action: "Switch to trending browser" },
|
|
82
|
+
{ keys: "Packages", action: "Switch to npm packages" },
|
|
83
|
+
{ keys: "Export", action: "Export results to file" },
|
|
84
|
+
{ keys: "Share", action: "Share repo as text" },
|
|
85
|
+
{ keys: "Topics", action: "Browse GitHub topics" },
|
|
86
|
+
{ keys: "Saved", action: "View saved searches" },
|
|
87
|
+
{ keys: "Notifs", action: "Check GitHub notifications" },
|
|
88
|
+
{ keys: "History", action: "View search history" },
|
|
89
|
+
{ keys: "Help", action: "Show this help screen" },
|
|
90
|
+
],
|
|
91
|
+
note: "Navigate menu with ↑ ↓, select with Enter, back with ← / Esc",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
title: " Bookmarks Page ",
|
|
95
|
+
titleColor: "green",
|
|
96
|
+
rows: [
|
|
97
|
+
{ keys: "↑ ↓ / j k", action: "Move selection" },
|
|
98
|
+
{ keys: "Enter", action: "Open bookmark in browser" },
|
|
99
|
+
{ keys: "d", action: "Remove bookmark" },
|
|
100
|
+
{ keys: "Esc / ←", action: "Back to landing" },
|
|
101
|
+
],
|
|
102
|
+
note: "A full page, not an overlay — Esc returns to the mode menu.",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
title: " Overlay Keys ",
|
|
106
|
+
titleColor: "teal",
|
|
107
|
+
rows: [
|
|
108
|
+
{ keys: "Esc / q", action: "Close any overlay" },
|
|
109
|
+
{ keys: "Enter", action: "Confirm selection / run action" },
|
|
110
|
+
{ keys: "d", action: "Delete entry (history, saved)" },
|
|
111
|
+
{ keys: "↑ ↓ / j k", action: "Navigate overlay list" },
|
|
112
|
+
{ keys: "← → / h l", action: "Navigate tabs / panels" },
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
title: " Search Syntax ",
|
|
117
|
+
titleColor: "teal",
|
|
118
|
+
rows: [
|
|
119
|
+
{ keys: "keywords", action: "Free-text search" },
|
|
120
|
+
{ keys: "key:value", action: "Qualifier filter" },
|
|
121
|
+
{ keys: "-key:value", action: "Negated qualifier" },
|
|
122
|
+
{ keys: '"phrase"', action: "Exact phrase match" },
|
|
123
|
+
{ keys: "language:TypeScript", action: "Filter by language" },
|
|
124
|
+
{ keys: "stars:>1000", action: "Minimum stars" },
|
|
125
|
+
{ keys: "fork:true", action: "Include forks" },
|
|
126
|
+
{ keys: "user:octocat", action: "User's repos" },
|
|
127
|
+
{ keys: "org:facebook", action: "Organization repos" },
|
|
128
|
+
{ keys: "repo:facebook/react", action: "Specific repo" },
|
|
129
|
+
{ keys: "topic:react", action: "Filter by topic" },
|
|
130
|
+
{ keys: "license:mit", action: "License type" },
|
|
131
|
+
{ keys: "pushed:>2024-01-01", action: "Last push date" },
|
|
132
|
+
{ keys: "archived:false", action: "Exclude archived" },
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
title: " Utility Keys ",
|
|
137
|
+
titleColor: "muted",
|
|
138
|
+
rows: [
|
|
139
|
+
{ keys: "t", action: "Cycle theme (light / dark / solarized)" },
|
|
140
|
+
{ keys: "Ctrl+X", action: "Copy repo URL to clipboard" },
|
|
141
|
+
{ keys: "Ctrl+C", action: "Copy search query to clipboard" },
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
title: " Rate Limits ",
|
|
146
|
+
titleColor: "orange",
|
|
147
|
+
rows: [
|
|
148
|
+
{ keys: "No token", action: "10 req / min" },
|
|
149
|
+
{ keys: "GITHUB_TOKEN", action: "30 req / min (or your plan limit)" },
|
|
150
|
+
],
|
|
151
|
+
note: "Set GITHUB_TOKEN in your environment or add to config.",
|
|
152
|
+
},
|
|
153
|
+
];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Column at which the action description starts (right-aligns keys). */
|
|
157
|
+
export const HELP_KEYS_COLUMN = 24;
|