github-search-cli 9.1.0 → 9.1.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.
@@ -4,7 +4,7 @@ import {
4
4
  loadConfig,
5
5
  saveConfig,
6
6
  stateDir
7
- } from "./chunk-TUMYR2IC.js";
7
+ } from "./chunk-IVUU2KGR.js";
8
8
  export {
9
9
  cacheDir,
10
10
  configPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-search-cli",
3
- "version": "9.1.0",
3
+ "version": "9.1.1",
4
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
  "packageManager": "bun@1",
package/src/cli.ts CHANGED
@@ -1,6 +1,17 @@
1
- #!/usr/bin/env node
2
- /** CLI entry point — routes between TUI browser and non-interactive modes. */
1
+ // Prevent tui.ts auto-launch when imported from cli.ts
2
+ process.env.GHFIND_CLI_RUN = "1";
3
3
  import { parseQuery, applyFlagFilters, rankRepos, createGitHubSearch, createTrendingSearch } from "./search";
4
+ import {
5
+ createPackageSearch,
6
+ formatPackagesJson,
7
+ formatPackagesCsv,
8
+ formatPackagesMarkdown,
9
+ formatPackagesUrls,
10
+ formatPackagesNames,
11
+ sortPackages,
12
+ type PackageSortMode,
13
+ } from "./package";
14
+ import { launchPackageBrowser } from "./package-browser";
4
15
  import { format as formatOutput, exportToFile, pipeExec, type Format, type ExportFormat, type FormatLine } from "./output";
5
16
  import { runWatch } from "./watch";
6
17
  import { runInitWizard } from "./init";
@@ -32,6 +43,9 @@ interface CLIFlags {
32
43
  init: boolean;
33
44
  version: boolean;
34
45
  help: boolean;
46
+ pkg: boolean;
47
+ theme?: string;
48
+ registry: string;
35
49
  }
36
50
 
37
51
  function parseArgs(args: string[]): CLIFlags {
@@ -51,6 +65,8 @@ function parseArgs(args: string[]): CLIFlags {
51
65
  init: false,
52
66
  version: false,
53
67
  help: false,
68
+ pkg: false,
69
+ registry: "npm",
54
70
  };
55
71
 
56
72
  let queryParts: string[] = [];
@@ -81,12 +97,17 @@ function parseArgs(args: string[]): CLIFlags {
81
97
  case "--since": flags.since = args[++i]; break;
82
98
  case "--pipe": flags.pipe = args[++i]; break;
83
99
  case "--format": flags.format = args[++i]; break;
84
- case "--interval": flags.interval = parseInt(args[++i]) || 300; break;
100
+ case "--registry": flags.registry = args[++i] ?? "npm"; break;
101
+ case "--theme": flags.theme = args[++i] ?? "tokyo-night"; break;
85
102
  case "--completion": flags.completion = args[++i]; break;
86
103
  default:
87
104
  if (!arg.startsWith("-")) queryParts.push(arg);
88
105
  }
89
106
  }
107
+ if (queryParts[0] === "pkg") {
108
+ flags.pkg = true;
109
+ queryParts.shift();
110
+ }
90
111
  flags.query = queryParts.join(" ");
91
112
  return flags;
92
113
  }
@@ -115,6 +136,8 @@ Usage:
115
136
  ghfind <query> --format <fmt> Format lines (urls|names|ssh-urls|clone-commands|ids)
116
137
  ghfind <query> --pipe <target> Pipe to clone/open
117
138
  ghfind --trending --json Trending repos as JSON
139
+ ghfind pkg <query> --json Search npm packages, output JSON
140
+ ghfind pkg <query> Search npm packages, text list
118
141
  ghfind --watch <query> Watch mode (poll every Ns)
119
142
  ghfind init Run setup wizard
120
143
  ghfind --completion <shell> Print completion script (bash|zsh|fish)
@@ -125,11 +148,13 @@ Options:
125
148
  --json, --csv, --markdown, --count Output format
126
149
  --limit <n> Max results (default: 50)
127
150
  --sort <strategy> Sort: best-match|stars|updated|forks
128
- --token <token> GitHub API token
151
+ --theme <name> Theme: tokyo-night|premium-dark (default: tokyo-night)
129
152
  --trending Trending mode
130
153
  --since <period> Trending period: daily|weekly|monthly
131
154
  --pipe <target> Pipe target: clone|open
132
155
  --format <fmt> Line format: urls|names|ssh-urls|...
156
+ --registry <name> Registry for pkg: npm (default) | others TBD
157
+
133
158
  --watch Watch mode (re-run periodically)
134
159
  --interval <s> Watch interval in seconds (default: 300)
135
160
  --completion <shell> Generate completions
@@ -155,6 +180,17 @@ Options:
155
180
  await runInitWizard();
156
181
  return;
157
182
  }
183
+ // Package search (prototype, ticket 002-008)
184
+ if (flags.pkg) {
185
+ const interactive =
186
+ !flags.query && !flags.json && !flags.csv && !flags.markdown && !flags.count && !flags.format;
187
+ if (interactive) {
188
+ await launchPackageBrowser();
189
+ } else {
190
+ await runPackageSearch(flags);
191
+ }
192
+ return;
193
+ }
158
194
 
159
195
  // Determine output format
160
196
  const outputFormat: ExportFormat | undefined =
@@ -167,8 +203,7 @@ Options:
167
203
  return;
168
204
  }
169
205
 
170
- // Default: launch interactive TUI
171
- await launchBrowser();
206
+ await launchBrowser(flags.theme);
172
207
  }
173
208
 
174
209
  interface SearchContext {
@@ -186,6 +221,50 @@ function buildSearchContext(flags: CLIFlags): SearchContext {
186
221
  };
187
222
  }
188
223
 
224
+ /** `ghfind pkg "<query>"` — npm package search. Pass-through query to the registry. */
225
+ async function runPackageSearch(flags: CLIFlags): Promise<void> {
226
+ if (flags.registry !== "npm") {
227
+ console.error(`Registry "${flags.registry}" not yet supported (only npm).`);
228
+ process.exit(1);
229
+ }
230
+ const PKG_SORTS: PackageSortMode[] = ["best-match", "score", "downloads", "name"];
231
+ const pkgSort = flags.sort as PackageSortMode;
232
+ if (!PKG_SORTS.includes(pkgSort)) {
233
+ console.error(`Invalid sort for pkg: "${flags.sort}" (use best-match|score|downloads|name).`);
234
+ process.exit(1);
235
+ }
236
+ const search = createPackageSearch();
237
+ const query = flags.query.trim();
238
+ if (!query) {
239
+ console.error("Usage: ghfind pkg <query> [--json|--csv|--markdown|--count|--format urls|names] [--limit <n>]");
240
+ process.exit(1);
241
+ }
242
+ try {
243
+ const { totalCount, packages } = await search.searchPackage(query, flags.limit);
244
+ const sorted = sortPackages(packages, pkgSort);
245
+ if (flags.count) {
246
+ console.log(totalCount);
247
+ } else if (flags.json) {
248
+ console.log(formatPackagesJson(sorted));
249
+ } else if (flags.csv) {
250
+ console.log(formatPackagesCsv(sorted));
251
+ } else if (flags.markdown) {
252
+ console.log(formatPackagesMarkdown(sorted));
253
+ } else if (flags.format === "urls") {
254
+ console.log(formatPackagesUrls(sorted));
255
+ } else if (flags.format === "names") {
256
+ console.log(formatPackagesNames(sorted));
257
+ } else {
258
+ for (const p of sorted) {
259
+ console.log(`${p.name}@${p.version} ↓ ${p.downloads.toLocaleString()} ${p.score.toFixed(2)} ${p.description ?? ""}`);
260
+ }
261
+ }
262
+ } catch (err) {
263
+ console.error(err instanceof Error ? err.message : String(err));
264
+ process.exit(1);
265
+ }
266
+ }
267
+
189
268
  async function runNonInteractive(flags: CLIFlags, outputFormat?: ExportFormat) {
190
269
  // Dispatch table: each handler receives shared context + flags, returns void.
191
270
  const handlers: Record<string, (ctx: SearchContext) => Promise<void>> = {
@@ -262,7 +341,10 @@ async function runNonInteractive(flags: CLIFlags, outputFormat?: ExportFormat) {
262
341
  await handlers[key](ctx);
263
342
  }
264
343
 
344
+
345
+
265
346
  main().catch((err) => {
347
+ console.error('DEBUG: uncaught error:', err.message || err);
266
348
  console.error(err instanceof Error ? err.message : String(err));
267
349
  process.exit(1);
268
350
  });
package/src/config.ts CHANGED
@@ -27,7 +27,7 @@ export function cacheDir(): string {
27
27
  const DEFAULTS: Config = {
28
28
  defaultSort: "best-match",
29
29
  defaultLimit: 50,
30
- theme: "premium-dark", // New default: premium dark with sharp edges
30
+ theme: "tokyo-night",
31
31
  cacheTtlSeconds: 300,
32
32
  defaultTab: "search",
33
33
  };
package/src/help.ts CHANGED
@@ -1,112 +1,142 @@
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;
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" },
21
+ { keys: "? / h", action: "Toggle this help screen" },
22
+ { keys: "q", action: "Quit" },
23
+ ],
24
+ },
25
+ {
26
+ title: " Navigation ",
27
+ titleColor: "blue",
28
+ rows: [
29
+ { keys: "↑ ↓ / j k", action: "Move selection" },
30
+ { keys: "Enter", action: "Open repo in browser" },
31
+ { keys: "/", action: "Focus search input" },
32
+ { keys: "Space", action: "Open command menu" },
33
+ { keys: "? / Ctrl+H", action: "Toggle this help screen" },
34
+ { keys: "q", action: "Quit" },
35
+ ],
36
+ },
37
+ {
38
+ title: " Main View ",
39
+ titleColor: "green",
40
+ rows: [
41
+ { keys: "Tab", action: "Auto-complete qualifier" },
42
+ { keys: "PageDown", action: "Next page of results" },
43
+ { keys: "PageUp", action: "Scroll to top of results" },
44
+ ],
45
+ },
46
+ {
47
+ title: " Trending Mode ",
48
+ titleColor: "yellow",
49
+ rows: [
50
+ { keys: "1-5", action: "Switch tab: Today → Week → Month → …" },
51
+ { keys: "← → / h l", action: "Navigate tabs" },
52
+ ],
53
+ },
54
+ {
55
+ title: " Packages Mode ",
56
+ titleColor: "cyan",
57
+ rows: [
58
+ { keys: "/", action: "Search npm packages" },
59
+ { keys: "↑ ↓ / j k", action: "Move selection" },
60
+ { keys: "Enter", action: "View package details" },
61
+ { keys: "Space", action: "Open command menu" },
62
+ ],
63
+ note: "Search by name, description, or tags. Sort by downloads or score.",
64
+ },
65
+ {
66
+ title: " Command Menu (Space)",
67
+ titleColor: "purple",
68
+ rows: [
69
+ { keys: "Sort", action: "Cycle sort: best-match → stars → …" },
70
+ { keys: "Limit", action: "Cycle limit: 10 → 25 → 50 → 100" },
71
+ { keys: "Refresh", action: "Re-run current search" },
72
+ { keys: "Graph", action: "Toggle commit activity chart" },
73
+ { keys: "Readme", action: "Full README viewer" },
74
+ { keys: "Deep-dive", action: "Languages + contributors + excerpt" },
75
+ { keys: "Bookmark", action: "Save / unsave selected repo" },
76
+ { keys: "Compare", action: "Add to / remove from comparison" },
77
+ { keys: "Trending", action: "Switch to trending browser" },
78
+ { keys: "Packages", action: "Switch to npm packages" },
79
+ { keys: "Export", action: "Export results to file" },
80
+ { keys: "Share", action: "Share repo as text" },
81
+ { keys: "Topics", action: "Browse GitHub topics" },
82
+ { keys: "Saved", action: "View saved searches" },
83
+ { keys: "Notifs", action: "Check GitHub notifications" },
84
+ { keys: "History", action: "View search history" },
85
+ { keys: "Help", action: "Show this help screen" },
86
+ ],
87
+ note: "Navigate menu with ↑ ↓, select with Enter, back with ← / Esc",
88
+ },
89
+ {
90
+ title: " Overlay Keys ",
91
+ titleColor: "teal",
92
+ rows: [
93
+ { keys: "Esc / q", action: "Close any overlay" },
94
+ { keys: "Enter", action: "Confirm selection / run action" },
95
+ { keys: "d", action: "Delete entry (history, bookmarks, saved)" },
96
+ { keys: "↑ ↓ / j k", action: "Navigate overlay list" },
97
+ { keys: "← → / h l", action: "Navigate tabs / panels" },
98
+ ],
99
+ },
100
+ {
101
+ title: " Search Syntax ",
102
+ titleColor: "teal",
103
+ rows: [
104
+ { keys: "keywords", action: "Free-text search" },
105
+ { keys: "key:value", action: "Qualifier filter" },
106
+ { keys: "-key:value", action: "Negated qualifier" },
107
+ { keys: '"phrase"', action: "Exact phrase match" },
108
+ { keys: "language:TypeScript", action: "Filter by language" },
109
+ { keys: "stars:>1000", action: "Minimum stars" },
110
+ { keys: "fork:true", action: "Include forks" },
111
+ { keys: "user:octocat", action: "User's repos" },
112
+ { keys: "org:facebook", action: "Organization repos" },
113
+ { keys: "repo:facebook/react", action: "Specific repo" },
114
+ { keys: "topic:react", action: "Filter by topic" },
115
+ { keys: "license:mit", action: "License type" },
116
+ { keys: "pushed:>2024-01-01", action: "Last push date" },
117
+ { keys: "archived:false", action: "Exclude archived" },
118
+ ],
119
+ },
120
+ {
121
+ title: " Utility Keys ",
122
+ titleColor: "muted",
123
+ rows: [
124
+ { keys: "t", action: "Cycle theme (light / dark / solarized)" },
125
+ { keys: "Ctrl+X", action: "Copy repo URL to clipboard" },
126
+ { keys: "Ctrl+C", action: "Copy search query to clipboard" },
127
+ ],
128
+ },
129
+ {
130
+ title: " Rate Limits ",
131
+ titleColor: "orange",
132
+ rows: [
133
+ { keys: "No token", action: "10 req / min" },
134
+ { keys: "GITHUB_TOKEN", action: "30 req / min (or your plan limit)" },
135
+ ],
136
+ note: "Set GITHUB_TOKEN in your environment or add to config.",
137
+ },
138
+ ];
139
+ }
140
+
141
+ /** Column at which the action description starts (right-aligns keys). */
142
+ export const HELP_KEYS_COLUMN = 24;
package/src/init.ts CHANGED
@@ -40,7 +40,7 @@ export async function runInitWizard(): Promise<void> {
40
40
  ? sortStr
41
41
  : "best-match") as SortStrategy,
42
42
  defaultLimit: Math.min(100, Math.max(10, parseInt(limitStr) || 50)),
43
- theme: themes.includes(themeStr) ? themeStr : "tokyo-night",
43
+ theme: themes.includes(themeStr) ? themeStr : themes[0],
44
44
  cacheTtlSeconds: 300,
45
45
  defaultTab: "search",
46
46
  };