github-search-cli 0.7.0 → 0.8.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/README.md +163 -183
- package/bin/ghfind.js +55 -0
- package/completions/{search-cli.bash → ghfind.bash} +4 -4
- package/completions/ghfind.fish +19 -0
- package/completions/{search-cli.zsh → ghfind.zsh} +4 -4
- package/demo.svg +65 -65
- package/package.json +20 -9
- package/src/bookmarks.ts +2 -2
- package/src/cli.ts +32 -45
- package/src/compare.ts +1 -1
- package/src/config.ts +8 -8
- package/src/deepdive.ts +4 -10
- package/src/errors.ts +1 -4
- package/src/explore.ts +0 -1
- package/src/export.ts +2 -3
- package/src/help.ts +112 -120
- package/src/history.ts +2 -2
- package/src/init.ts +6 -6
- package/src/notifications.ts +2 -6
- package/src/open-url.ts +16 -17
- package/src/output.ts +2 -9
- package/src/pipe.ts +2 -8
- package/src/saved-searches.ts +2 -2
- package/src/search.ts +555 -0
- package/src/session.ts +4 -5
- package/src/share.ts +27 -22
- package/src/trending.ts +10 -15
- package/src/tui.ts +408 -261
- package/src/types.ts +3 -11
- package/src/watch.ts +3 -6
- package/vendor/bun.exe +0 -0
- package/bin/search-cli.js +0 -17
- package/completions/search-cli.fish +0 -19
- package/src/cache.ts +0 -64
- package/src/normalizer.ts +0 -66
- package/src/provider.ts +0 -165
- package/src/query.ts +0 -249
- package/src/ranking.ts +0 -57
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "github-search-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Terminal-native GitHub
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"description": "Terminal-native GitHub search — search, trending, bookmarks, history, deep-dive, compare, export, and more. All keyboard-driven, no browser needed.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"
|
|
7
|
+
"ghfind": "bin/ghfind.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"bin/",
|
|
11
11
|
"src/",
|
|
12
|
+
"vendor/",
|
|
12
13
|
"completions/",
|
|
13
14
|
"demo.svg",
|
|
14
15
|
"LICENSE",
|
|
@@ -16,19 +17,29 @@
|
|
|
16
17
|
],
|
|
17
18
|
"scripts": {
|
|
18
19
|
"start": "bun run src/cli.ts",
|
|
19
|
-
"build": "
|
|
20
|
-
"prepublishOnly": "
|
|
21
|
-
"test": "
|
|
22
|
-
"
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"prepublishOnly": "npm run build",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:bun": "bun test",
|
|
24
|
+
"dev": "bun run --watch src/tui.ts",
|
|
25
|
+
"postinstall": "node scripts/postinstall.js",
|
|
26
|
+
"format:check": "prettier --check .",
|
|
27
|
+
"format": "prettier --write ."
|
|
23
28
|
},
|
|
24
29
|
"dependencies": {
|
|
25
30
|
"@opentui/core": "^0.4.3"
|
|
26
31
|
},
|
|
27
32
|
"devDependencies": {
|
|
28
|
-
"@types/bun": "latest"
|
|
33
|
+
"@types/bun": "latest",
|
|
34
|
+
"@types/node": "^20.0.0",
|
|
35
|
+
"prettier": "^3.2.0",
|
|
36
|
+
"tsup": "^8.0.0",
|
|
37
|
+
"tsx": "^4.0.0",
|
|
38
|
+
"typescript": "^5.3.0",
|
|
39
|
+
"vitest": "^1.2.0"
|
|
29
40
|
},
|
|
30
41
|
"engines": {
|
|
31
|
-
"
|
|
42
|
+
"node": ">=20.0.0"
|
|
32
43
|
},
|
|
33
44
|
"repository": {
|
|
34
45
|
"type": "git",
|
package/src/bookmarks.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
5
5
|
import { join } from "path";
|
|
6
|
-
import type { Bookmark, Repo } from "./types
|
|
7
|
-
import { stateDir } from "./config
|
|
6
|
+
import type { Bookmark, Repo } from "./types";
|
|
7
|
+
import { stateDir } from "./config";
|
|
8
8
|
|
|
9
9
|
const BOOKMARK_FILE = join(stateDir(), "bookmarks.json");
|
|
10
10
|
|
package/src/cli.ts
CHANGED
|
@@ -1,31 +1,18 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* search-cli "query" --csv Search + CSV output
|
|
9
|
-
* search-cli "query" --markdown Search + Markdown table
|
|
10
|
-
* search-cli "query" --count Just the result count
|
|
11
|
-
* search-cli --trending --json Trending repos as JSON
|
|
12
|
-
* search-cli init Setup wizard
|
|
13
|
-
* search-cli --watch "query" Periodic watch mode
|
|
14
|
-
* search-cli --completion bash Print shell completion
|
|
15
|
-
* search-cli --version Print version
|
|
16
|
-
* search-cli --help Print help
|
|
17
|
-
*/
|
|
18
|
-
import { parseQuery, applyFlagFilters } from "./query.ts";
|
|
19
|
-
import { GitHubSearchProvider } from "./provider.ts";
|
|
20
|
-
import { rankRepos } from "./ranking.ts";
|
|
21
|
-
import { formatRepos, type ExportFormat } from "./export.ts";
|
|
22
|
-
import { formatLines, pipeExec, type FormatLine } from "./pipe.ts";
|
|
23
|
-
import { runWatch } from "./watch.ts";
|
|
24
|
-
import { runInitWizard } from "./init.ts";
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/** CLI entry point — routes between TUI browser and non-interactive modes. */
|
|
3
|
+
import { parseQuery, applyFlagFilters, rankRepos, createGitHubSearch } from "./search";
|
|
4
|
+
import { formatRepos, type ExportFormat } from "./export";
|
|
5
|
+
import { formatLines, pipeExec, type FormatLine } from "./pipe";
|
|
6
|
+
import { runWatch } from "./watch";
|
|
7
|
+
import { runInitWizard } from "./init";
|
|
25
8
|
import { readFileSync } from "fs";
|
|
26
|
-
import { join } from "path";
|
|
27
|
-
import {
|
|
28
|
-
import
|
|
9
|
+
import { join, dirname } from "path";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
import { launchBrowser } from "./tui";
|
|
12
|
+
import type { SearchOptions } from "./types";
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const PKG_DIR = join(__dirname, "..");
|
|
29
16
|
|
|
30
17
|
interface CLIFlags {
|
|
31
18
|
query: string;
|
|
@@ -110,30 +97,30 @@ async function main() {
|
|
|
110
97
|
|
|
111
98
|
// Version
|
|
112
99
|
if (flags.version) {
|
|
113
|
-
const pkg = JSON.parse(readFileSync(join(
|
|
114
|
-
console.log(`
|
|
100
|
+
const pkg = JSON.parse(readFileSync(join(PKG_DIR, "package.json"), "utf-8"));
|
|
101
|
+
console.log(`ghfind v${pkg.version}`);
|
|
115
102
|
return;
|
|
116
103
|
}
|
|
117
104
|
|
|
118
105
|
// Help
|
|
119
106
|
if (flags.help) {
|
|
120
107
|
console.log(`
|
|
121
|
-
|
|
108
|
+
ghfind — Interactive GitHub repository browser
|
|
122
109
|
|
|
123
110
|
Usage:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
111
|
+
ghfind Launch interactive TUI
|
|
112
|
+
ghfind <query> --json Search, output JSON
|
|
113
|
+
ghfind <query> --csv Search, output CSV
|
|
114
|
+
ghfind <query> --markdown Search, output Markdown table
|
|
115
|
+
ghfind <query> --count Just the result count
|
|
116
|
+
ghfind <query> --format <fmt> Format lines (urls|names|ssh-urls|clone-commands|ids)
|
|
117
|
+
ghfind <query> --pipe <target> Pipe to clone/open
|
|
118
|
+
ghfind --trending --json Trending repos as JSON
|
|
119
|
+
ghfind --watch <query> Watch mode (poll every Ns)
|
|
120
|
+
ghfind init Run setup wizard
|
|
121
|
+
ghfind --completion <shell> Print completion script (bash|zsh|fish)
|
|
122
|
+
ghfind --version Print version
|
|
123
|
+
ghfind --help Print this help
|
|
137
124
|
|
|
138
125
|
Options:
|
|
139
126
|
--json, --csv, --markdown, --count Output format
|
|
@@ -155,7 +142,7 @@ Options:
|
|
|
155
142
|
if (flags.completion) {
|
|
156
143
|
const shell = flags.completion;
|
|
157
144
|
try {
|
|
158
|
-
const content = readFileSync(join(
|
|
145
|
+
const content = readFileSync(join(PKG_DIR, "completions", `ghfind.${shell}`), "utf-8");
|
|
159
146
|
console.log(content);
|
|
160
147
|
} catch {
|
|
161
148
|
console.error(`Completions not available for shell: ${shell}`);
|
|
@@ -187,7 +174,7 @@ Options:
|
|
|
187
174
|
|
|
188
175
|
async function runNonInteractive(flags: CLIFlags, format?: ExportFormat) {
|
|
189
176
|
const query = flags.query;
|
|
190
|
-
const provider =
|
|
177
|
+
const provider = createGitHubSearch(undefined, flags.token ? [flags.token] : []);
|
|
191
178
|
|
|
192
179
|
// --watch mode
|
|
193
180
|
if (flags.watch) {
|
package/src/compare.ts
CHANGED
package/src/config.ts
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* Config system: load/save config from XDG paths, merge with env vars.
|
|
3
3
|
*
|
|
4
4
|
* Lookup order:
|
|
5
|
-
* 1.
|
|
6
|
-
* 2. $XDG_CONFIG_HOME/
|
|
7
|
-
* 3. ~/.config/
|
|
5
|
+
* 1. GHFIND_CONFIG env var
|
|
6
|
+
* 2. $XDG_CONFIG_HOME/ghfind/config.json
|
|
7
|
+
* 3. ~/.config/ghfind/config.json
|
|
8
8
|
*/
|
|
9
|
-
import type { Config } from "./types
|
|
9
|
+
import type { Config } from "./types";
|
|
10
10
|
import { homedir } from "os";
|
|
11
11
|
import { join } from "path";
|
|
12
12
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -14,14 +14,14 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
|
14
14
|
/** Directory for persistent state (history, bookmarks, session). */
|
|
15
15
|
export function stateDir(): string {
|
|
16
16
|
const xdg = process.env.XDG_STATE_HOME;
|
|
17
|
-
const base = xdg ? join(xdg, "
|
|
17
|
+
const base = xdg ? join(xdg, "ghfind") : join(homedir(), ".local", "share", "ghfind");
|
|
18
18
|
return base;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/** Directory for cache files. */
|
|
22
22
|
export function cacheDir(): string {
|
|
23
23
|
const xdg = process.env.XDG_CACHE_HOME;
|
|
24
|
-
const base = xdg ? join(xdg, "
|
|
24
|
+
const base = xdg ? join(xdg, "ghfind") : join(homedir(), ".cache", "ghfind");
|
|
25
25
|
return base;
|
|
26
26
|
}
|
|
27
27
|
const DEFAULTS: Config = {
|
|
@@ -33,11 +33,11 @@ const DEFAULTS: Config = {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
export function configPath(): string {
|
|
36
|
-
const envPath = process.env.
|
|
36
|
+
const envPath = process.env.GHFIND_CONFIG;
|
|
37
37
|
if (envPath) return envPath;
|
|
38
38
|
|
|
39
39
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
40
|
-
const base = xdg ? join(xdg, "
|
|
40
|
+
const base = xdg ? join(xdg, "ghfind") : join(homedir(), ".config", "ghfind");
|
|
41
41
|
return join(base, "config.json");
|
|
42
42
|
}
|
|
43
43
|
|
package/src/deepdive.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* ponytail: single fetch-all function, no section tab navigation.
|
|
5
|
-
* Shows: summary, languages bar, top contributors, README excerpt.
|
|
6
|
-
* Skip: releases (YAGNI), dependency graph (auth-gated).
|
|
7
|
-
*/
|
|
8
|
-
import type { Repo } from "./types.ts";
|
|
9
|
-
import { NetworkError } from "./errors.ts";
|
|
1
|
+
/** Repo deep-dive — fetch and format rich repo details. */
|
|
2
|
+
import type { Repo } from "./types";
|
|
3
|
+
import { NetworkError } from "./errors";
|
|
10
4
|
|
|
11
|
-
const USER_AGENT = "
|
|
5
|
+
const USER_AGENT = "ghfind/1.0";
|
|
12
6
|
|
|
13
7
|
/** Language breakdown: { [lang]: bytes } */
|
|
14
8
|
type LanguageMap = Record<string, number>;
|
package/src/errors.ts
CHANGED
package/src/explore.ts
CHANGED
package/src/export.ts
CHANGED
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
* Export — format repos as JSON, CSV, Markdown, or plain text.
|
|
3
3
|
*/
|
|
4
4
|
import { writeFileSync } from "fs";
|
|
5
|
-
import type { Repo } from "./types
|
|
5
|
+
import type { Repo } from "./types";
|
|
6
6
|
|
|
7
7
|
export type ExportFormat = "json" | "csv" | "markdown" | "text";
|
|
8
8
|
|
|
9
|
-
/** Format repos as JSON string. */
|
|
10
9
|
export function formatJson(repos: Repo[]): string {
|
|
11
10
|
return JSON.stringify(repos, null, 2);
|
|
12
11
|
}
|
|
@@ -58,7 +57,7 @@ export function formatRepos(repos: Repo[], format: ExportFormat): string {
|
|
|
58
57
|
export function exportToFile(repos: Repo[], format: ExportFormat): string {
|
|
59
58
|
const ext = format === "markdown" ? "md" : format;
|
|
60
59
|
const ts = Date.now();
|
|
61
|
-
const path = `./
|
|
60
|
+
const path = `./ghfind-export-${ts}.${ext}`;
|
|
62
61
|
writeFileSync(path, formatRepos(repos, format), "utf-8");
|
|
63
62
|
return path;
|
|
64
63
|
}
|
package/src/help.ts
CHANGED
|
@@ -1,120 +1,112 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export interface
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{ keys: "
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
{ keys: "
|
|
44
|
-
{ keys: "
|
|
45
|
-
],
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
title: "
|
|
49
|
-
titleColor: "
|
|
50
|
-
rows: [
|
|
51
|
-
{ keys: "
|
|
52
|
-
{ keys: "
|
|
53
|
-
{ keys: "
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
{ keys: "
|
|
78
|
-
{ keys: "
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
{ keys: "
|
|
88
|
-
{ keys:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
{ keys: "
|
|
96
|
-
{ keys: "
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
{ keys: "
|
|
104
|
-
{ keys: "
|
|
105
|
-
],
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
],
|
|
114
|
-
note: "Set GITHUB_TOKEN in your environment or add to config.",
|
|
115
|
-
},
|
|
116
|
-
];
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** Column at which the action description starts (right-aligns keys). */
|
|
120
|
-
export const HELP_KEYS_COLUMN = 24;
|
|
1
|
+
/** Help screen — structured sections rendered by OpenTUI components. */
|
|
2
|
+
|
|
3
|
+
export interface HelpRow {
|
|
4
|
+
keys: string;
|
|
5
|
+
action: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface HelpSection {
|
|
9
|
+
title: string;
|
|
10
|
+
/** Theme color key or hex — used for Box title color */
|
|
11
|
+
titleColor: string;
|
|
12
|
+
rows: HelpRow[];
|
|
13
|
+
note?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function buildHelpSections(): HelpSection[] {
|
|
17
|
+
return [
|
|
18
|
+
{
|
|
19
|
+
title: " Navigation ",
|
|
20
|
+
titleColor: "blue",
|
|
21
|
+
rows: [
|
|
22
|
+
{ keys: "↑ ↓ / j k", action: "Move selection" },
|
|
23
|
+
{ keys: "Enter", action: "Open repo in browser" },
|
|
24
|
+
{ keys: "/", action: "Focus search input" },
|
|
25
|
+
{ keys: "Space", action: "Open command menu" },
|
|
26
|
+
{ keys: "? / Ctrl+H", action: "Toggle this help screen" },
|
|
27
|
+
{ keys: "q", action: "Quit" },
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
title: " Main View ",
|
|
32
|
+
titleColor: "green",
|
|
33
|
+
rows: [
|
|
34
|
+
{ keys: "Tab", action: "Auto-complete qualifier" },
|
|
35
|
+
{ keys: "PageDown", action: "Next page of results" },
|
|
36
|
+
{ keys: "PageUp", action: "Scroll to top of results" },
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
title: " Trending Mode ",
|
|
41
|
+
titleColor: "yellow",
|
|
42
|
+
rows: [
|
|
43
|
+
{ keys: "1-5", action: "Switch tab: Today → Week → Month → …" },
|
|
44
|
+
{ keys: "← → / h l", action: "Navigate tabs" },
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
title: " Command Menu (Space)",
|
|
49
|
+
titleColor: "purple",
|
|
50
|
+
rows: [
|
|
51
|
+
{ keys: "Sort", action: "Cycle sort: best-match → stars → …" },
|
|
52
|
+
{ keys: "Limit", action: "Cycle limit: 10 → 25 → 50 → 100" },
|
|
53
|
+
{ keys: "Refresh", action: "Re-run current search" },
|
|
54
|
+
{ keys: "Graph", action: "Toggle commit activity chart" },
|
|
55
|
+
{ keys: "Readme", action: "Full README viewer" },
|
|
56
|
+
{ keys: "Deep-dive", action: "Languages + contributors + excerpt" },
|
|
57
|
+
{ keys: "Bookmark", action: "Save / unsave selected repo" },
|
|
58
|
+
{ keys: "Compare", action: "Add to / remove from comparison" },
|
|
59
|
+
{ keys: "Trending", action: "Switch to trending browser" },
|
|
60
|
+
],
|
|
61
|
+
note: "Also: Open, History, Export, Share, Topics, Saved, Notifs, Help",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
title: " Overlay Keys ",
|
|
65
|
+
titleColor: "teal",
|
|
66
|
+
rows: [
|
|
67
|
+
{ keys: "Esc / q", action: "Close any overlay" },
|
|
68
|
+
{ keys: "Enter", action: "Confirm selection / run action" },
|
|
69
|
+
{ keys: "d", action: "Delete entry (history, bookmarks, saved)" },
|
|
70
|
+
{ keys: "↑ ↓ / j k", action: "Navigate overlay list" },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
title: " Search Syntax ",
|
|
75
|
+
titleColor: "teal",
|
|
76
|
+
rows: [
|
|
77
|
+
{ keys: "keywords", action: "Free-text search" },
|
|
78
|
+
{ keys: "key:value", action: "Qualifier filter" },
|
|
79
|
+
{ keys: "-key:value", action: "Negated qualifier" },
|
|
80
|
+
{ keys: '"phrase"', action: "Exact phrase match" },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
title: " Qualifiers ",
|
|
85
|
+
titleColor: "muted",
|
|
86
|
+
rows: [
|
|
87
|
+
{ keys: "language:", action: "Filter by language" },
|
|
88
|
+
{ keys: "stars:>N", action: "Minimum stars" },
|
|
89
|
+
{ keys: "fork:true", action: "Include forks" },
|
|
90
|
+
{ keys: "user:", action: "User's repos" },
|
|
91
|
+
{ keys: "org:", action: "Organization repos" },
|
|
92
|
+
{ keys: "repo:", action: "Specific repo" },
|
|
93
|
+
{ keys: "topic:", action: "Filter by topic" },
|
|
94
|
+
{ keys: "license:", action: "License type" },
|
|
95
|
+
{ keys: "pushed:>YYYY-MM-DD", action: "Last push date" },
|
|
96
|
+
{ keys: "archived:false", action: "Exclude archived" },
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
title: " Rate Limits ",
|
|
101
|
+
titleColor: "orange",
|
|
102
|
+
rows: [
|
|
103
|
+
{ keys: "No token", action: "10 req / min" },
|
|
104
|
+
{ keys: "GITHUB_TOKEN", action: "30 req / min (or your plan limit)" },
|
|
105
|
+
],
|
|
106
|
+
note: "Set GITHUB_TOKEN in your environment or add to config.",
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Column at which the action description starts (right-aligns keys). */
|
|
112
|
+
export const HELP_KEYS_COLUMN = 24;
|
package/src/history.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, appendFileSync, writeFileSync, unlinkSync } from "fs";
|
|
5
5
|
import { join } from "path";
|
|
6
|
-
import type { HistoryEntry } from "./types
|
|
7
|
-
import { stateDir } from "./config
|
|
6
|
+
import type { HistoryEntry } from "./types";
|
|
7
|
+
import { stateDir } from "./config";
|
|
8
8
|
|
|
9
9
|
const HISTORY_FILE = join(stateDir(), "history.jsonl");
|
|
10
10
|
const MAX_ENTRIES = 500;
|
package/src/init.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `
|
|
2
|
+
* `ghfind init` wizard — interactive one-time config setup.
|
|
3
3
|
*
|
|
4
4
|
* ponytail: simple stdin prompts, no curses/readline UI.
|
|
5
5
|
*/
|
|
6
6
|
import { createInterface } from "readline";
|
|
7
|
-
import { saveConfig } from "./config
|
|
8
|
-
import { listThemes } from "./themes
|
|
9
|
-
import type { Config, SortStrategy } from "./types
|
|
7
|
+
import { saveConfig } from "./config";
|
|
8
|
+
import { listThemes } from "./themes";
|
|
9
|
+
import type { Config, SortStrategy } from "./types";
|
|
10
10
|
|
|
11
11
|
function ask(query: string): Promise<string> {
|
|
12
12
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -20,7 +20,7 @@ function ask(query: string): Promise<string> {
|
|
|
20
20
|
|
|
21
21
|
export async function runInitWizard(): Promise<void> {
|
|
22
22
|
console.log("");
|
|
23
|
-
console.log("
|
|
23
|
+
console.log(" ghfind setup wizard");
|
|
24
24
|
console.log(" ──────────────────────");
|
|
25
25
|
console.log("");
|
|
26
26
|
|
|
@@ -50,6 +50,6 @@ export async function runInitWizard(): Promise<void> {
|
|
|
50
50
|
saveConfig(config);
|
|
51
51
|
const { configPath } = await import("./config.ts");
|
|
52
52
|
console.log(` ✓ Config saved to ${configPath()}`);
|
|
53
|
-
console.log(" Run '
|
|
53
|
+
console.log(" Run 'ghfind' to start browsing!");
|
|
54
54
|
console.log("");
|
|
55
55
|
}
|
package/src/notifications.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Notification center — ephemeral alerts for rate limits, watch changes, etc.
|
|
3
|
-
*
|
|
4
|
-
* ponytail: in-memory + last-session persistence. Skip 24h auto-clean.
|
|
5
|
-
*/
|
|
1
|
+
/** Notification center — ephemeral alerts for rate limits, watch changes, etc. */
|
|
6
2
|
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
7
3
|
import { join } from "path";
|
|
8
|
-
import { stateDir } from "./config
|
|
4
|
+
import { stateDir } from "./config";
|
|
9
5
|
|
|
10
6
|
export interface Notification {
|
|
11
7
|
id: number;
|
package/src/open-url.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Open a URL in the user's default browser — platform-aware.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (p === "
|
|
12
|
-
else
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Open a URL in the user's default browser — platform-aware.
|
|
3
|
+
*
|
|
4
|
+
* only if the open/xdg-open pattern fails somewhere.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export function openUrl(url: string): void {
|
|
8
|
+
try {
|
|
9
|
+
const p = process.platform;
|
|
10
|
+
if (p === "win32") Bun.spawn(["cmd", "/c", "start", "", url]);
|
|
11
|
+
else if (p === "darwin") Bun.spawn(["open", url]);
|
|
12
|
+
else Bun.spawn(["xdg-open", url]);
|
|
13
|
+
} catch {
|
|
14
|
+
// non-critical — user can copy the URL manually
|
|
15
|
+
}
|
|
16
|
+
}
|