github-search-cli 9.5.1 → 9.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "github-search-cli",
3
- "version": "9.5.1",
3
+ "version": "9.7.0",
4
4
  "description": "Search GitHub from your terminal — repo search, trending repos, npm package search, bookmarks, deep-dive, compare, export. Keyboard-driven TUI + pipeable CLI.",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1",
@@ -0,0 +1,67 @@
1
+ # What's New in ghfind 9.6.0
2
+
3
+ ghfind now speaks the Model Context Protocol — your coding agent can search
4
+ GitHub through it — plus a curl installer and quieter output for `NO_COLOR`
5
+ users.
6
+
7
+ ### Added
8
+
9
+ **MCP server (beta) (`ghfind mcp`)** — ghfind as a tool server for coding agents
10
+
11
+ - Any MCP client (Claude Code, Cursor, Codex, …) can call GitHub search as
12
+ tools over stdio; zero new dependencies, a small JSON-RPC 2.0 layer over
13
+ the existing modules
14
+ - Nine tools: `ghfind_search_repos`, `ghfind_trending`, `ghfind_npm_packages`,
15
+ `ghfind_org_profile`, `ghfind_user_profile`, `ghfind_compare_repos`,
16
+ `ghfind_deep_dive`, `ghfind_bookmarked_releases`, `ghfind_skill`
17
+ - Implements the 2025-06-18 lifecycle (initialize → initialized notification →
18
+ operation); also speaks 2025-03-26 and 2024-11-05
19
+ - Tool failures report as `isError` results per spec — the agent sees the
20
+ error, not a hang
21
+ - Agent searches land in the TUI history like your own searches
22
+ - `ghfind mcp --token <t>` pins a token; otherwise config / `GITHUB_TOKEN`
23
+ applies as usual
24
+
25
+ **`ghfind skill [name]` (beta)** — a token-efficient usage guide for coding agents
26
+
27
+ - Search syntax, flags, rate limits, and token-efficiency tips, so agents
28
+ stop guessing from `--help`
29
+ - Bare `ghfind skill` lists the catalog; the registry (`src/agent-skill.ts`)
30
+ is generic, so third parties can register their own skills alongside the
31
+ built-in `ghfind-cli` one
32
+
33
+ **Trending language filter** — `ghfind trending` accepts a language slug
34
+ (`rust`, `python`, …), validated against the known language list; unknown
35
+ slugs are dropped instead of scraping an error page. Also exposed to agents
36
+ via the `ghfind_trending` MCP tool. _(The MCP server and agent skill are
37
+ beta — surface may still shift in 9.6.x patch releases.)_
38
+
39
+ **curl installer** — no Node.js needed
40
+
41
+ ```sh
42
+ curl -fsSL https://raw.githubusercontent.com/codersdfs/search-cli/main/scripts/install.sh | sh
43
+ ```
44
+
45
+ - Detects OS and arch, downloads the standalone `ghfind` binary from GitHub
46
+ Releases, verifies it against the release's `SHA256SUMS.txt`, and installs
47
+ to `~/.local/bin` (or `/usr/local/bin`, overridable with
48
+ `GHFIND_INSTALL_DIR`) — never needs sudo, prints a PATH hint if needed
49
+ - Every release now ships a merged `SHA256SUMS.txt` alongside the binaries,
50
+ so package maintainers can verify the same way
51
+
52
+ **`NO_COLOR` support** — `ghfind --doctor` stops emitting ANSI color codes
53
+ when `NO_COLOR` is set (any value, per no-color.org) or when stdout is not a
54
+ TTY. Piping `--doctor` into a file or CI log no longer drags escape codes
55
+ along.
56
+
57
+ ### Fixed
58
+
59
+ - **`scripts/brew.rb` was stale and broken** — pointed at the wrong repo
60
+ (`frank/search-cli`), version 0.1.0, and `search-cli-*` asset names that
61
+ never matched the release artifacts. Now targets `codersdfs/search-cli`
62
+ releases with the correct `ghfind-*` names (plus linux-arm64), a livecheck
63
+ block, and a version-pinning test.
64
+ - **Community health files** — `SECURITY.md` (private vulnerability
65
+ reporting), `CODE_OF_CONDUCT.md` (Contributor Covenant 2.1), and
66
+ `SUPPORT.md` (routes you to `--doctor` first) now exist, so security
67
+ reports and "it doesn't work" issues have proper homes.
@@ -0,0 +1,53 @@
1
+ # What's New in ghfind 9.7.0
2
+
3
+ CLI parity with the MCP tools — everything `ghfind mcp` exposes to coding
4
+ agents is now a first-class terminal command — plus two fixes: `ghfind mcp`
5
+ compiles again, and deep-dive shows real repo metadata.
6
+
7
+ ### Added
8
+
9
+ **`ghfind deep-dive <owner/repo>`** — the MCP-only deep dive, on the CLI
10
+
11
+ - Language breakdown with percentages, top contributors, and a README
12
+ excerpt (main → master → README.rst fallback)
13
+ - Previously the agent skill doc literally told agents to `curl` GitHub
14
+ instead — not anymore
15
+ - `--json` exposes a structured payload (language percents, contributor
16
+ counts, raw README) suitable for agents and scripting
17
+ - Resolves real repo metadata first: `ghfind deep-dive vercel/next.js
18
+ --json` reports actual stars, description, topics, and timestamps
19
+ - A 404 exits with `Repo not found: owner/name` instead of silently
20
+ printing empty sections; network failures still degrade gracefully
21
+
22
+ **`ghfind --compare` export formats** — `--json`, `--csv`, `--markdown`
23
+
24
+ - Compare was text-only ("no JSON formatter for it yet"); all three
25
+ formatters now exist, with columns matching the other export modes
26
+ - Repos that fail to resolve are reported in text output and excluded from
27
+ the table; fewer than 2 resolvable repos exits non-zero
28
+
29
+ **Trending language filter on the CLI**
30
+
31
+ - `ghfind trending rust` — the form the README already advertised but the
32
+ parser never handled — and `ghfind --trending rust` both work now
33
+ - `ghfind --trending --language <lang>` names the flag explicitly
34
+ - Unknown filters are rejected with the accepted list, the same validation
35
+ the `ghfind_trending` MCP tool applies
36
+
37
+ ### Changed
38
+
39
+ - The MCP server now shares its repo-ref parsing, trending-language
40
+ validation, and deep-dive data pipeline with the CLI (new seams in
41
+ `deepdive.ts` and `search.ts`) — one source of truth, no protocol
42
+ behavior change
43
+
44
+ ### Fixed
45
+
46
+ - **`ghfind mcp` failed to typecheck** — the id handed to
47
+ `respond`/`respondError` stayed `JsonRpcId | undefined` because
48
+ TypeScript's aliased-conditional narrowing does not apply through a `let`
49
+ binding; the id is now a `const`. Runtime behavior was already correct —
50
+ all 31 MCP tests pass unchanged.
51
+ - **Deep-dive ran on a zeroed repo stub** — stars, forks, description, and
52
+ topics were all empty in both the CLI and the `ghfind_deep_dive` MCP
53
+ tool; real metadata is now fetched first (see above).
package/scripts/brew.rb CHANGED
@@ -1,32 +1,53 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
- class SearchCli < Formula
5
- desc "Interactive GitHub repository browser for the terminal"
6
- homepage "https://github.com/frank/search-cli"
7
- version "0.1.0"
4
+ # Homebrew formula for ghfind.
5
+ #
6
+ # NOTE: this file is a template, kept in-tree for a future homebrew tap.
7
+ # Before use:
8
+ # 1. Replace VERSION with the released version tag.
9
+ # 2. Fill SHA256 placeholders from the SHA256SUMS.txt asset attached to
10
+ # the GitHub Release (the release workflow generates it).
11
+ # 3. Host it in a tap repo (e.g. codersdfs/tap) at Formula/ghfind.rb,
12
+ # then: brew install codersdfs/tap/ghfind
13
+ # See marketing/README.md (Track B) for the rollout order.
14
+
15
+ class Ghfind < Formula
16
+ desc "Search GitHub repos from your terminal — trending, bookmarks, deep-dive"
17
+ homepage "https://github.com/codersdfs/search-cli"
18
+ version "9.5.1"
8
19
  license "MIT"
9
20
 
21
+ livecheck do
22
+ url :stable
23
+ regex(/^v?(\d+(?:\.\d+)+)$/i)
24
+ end
25
+
10
26
  on_macos do
11
27
  if Hardware::CPU.arm?
12
- url "https://github.com/frank/search-cli/releases/download/v#{version}/search-cli-darwin-arm64"
28
+ url "https://github.com/codersdfs/search-cli/releases/download/v#{version}/ghfind-darwin-arm64"
13
29
  sha256 "SHA256_PLACEHOLDER"
14
30
  else
15
- url "https://github.com/frank/search-cli/releases/download/v#{version}/search-cli-darwin-x64"
31
+ url "https://github.com/codersdfs/search-cli/releases/download/v#{version}/ghfind-darwin-x64"
16
32
  sha256 "SHA256_PLACEHOLDER"
17
33
  end
18
34
  end
19
35
 
20
36
  on_linux do
21
- url "https://github.com/frank/search-cli/releases/download/v#{version}/search-cli-linux-x64"
22
- sha256 "SHA256_PLACEHOLDER"
37
+ if Hardware::CPU.arm? && Hardware::CPU.is_64_bit?
38
+ url "https://github.com/codersdfs/search-cli/releases/download/v#{version}/ghfind-linux-arm64"
39
+ sha256 "SHA256_PLACEHOLDER"
40
+ else
41
+ url "https://github.com/codersdfs/search-cli/releases/download/v#{version}/ghfind-linux-x64"
42
+ sha256 "SHA256_PLACEHOLDER"
43
+ end
23
44
  end
24
45
 
25
46
  def install
26
- bin.install "search-cli"
47
+ bin.install "ghfind" => "ghfind"
27
48
  end
28
49
 
29
50
  test do
30
- assert_match "search-cli", shell_output("#{bin}/search-cli --version")
51
+ assert_match version.to_s, shell_output("#{bin}/ghfind --version")
31
52
  end
32
53
  end
@@ -0,0 +1,118 @@
1
+ #!/bin/sh
2
+ # ghfind installer — https://github.com/codersdfs/search-cli
3
+ #
4
+ # Usage:
5
+ # curl -fsSL https://raw.githubusercontent.com/codersdfs/search-cli/main/scripts/install.sh | sh
6
+ #
7
+ # Downloads the standalone ghfind binary for your platform from GitHub
8
+ # Releases (no Node.js or Bun needed) into ~/.local/bin, /usr/local/bin,
9
+ # or a directory of your choice via GHFIND_INSTALL_DIR.
10
+ #
11
+ # Options via environment:
12
+ # GHFIND_VERSION a release tag without the leading v (default: latest)
13
+ # GHFIND_INSTALL_DIR target dir (default: ~/.local/bin if writable)
14
+ #
15
+ # The script never needs sudo: if the default dir is not writable it falls
16
+ # back to ~/.local/bin and prints a PATH reminder.
17
+
18
+ set -eu
19
+
20
+ REPO="codersdfs/search-cli"
21
+
22
+ printf '\n' # cosmetic spacing when piped
23
+
24
+ # ── Detect platform ────────────────────────────────────────────────────
25
+ os=$(uname -s)
26
+ arch=$(uname -m)
27
+
28
+ case "$os" in
29
+ Linux) plat="linux" ;;
30
+ Darwin) plat="darwin" ;;
31
+ *)
32
+ printf 'ghfind install: unsupported OS "%s".\n' "$os"
33
+ printf 'Windows: install with npm (npm i -g github-search-cli) or scoop/winget once listed.\n' >&2
34
+ exit 1
35
+ ;;
36
+ esac
37
+
38
+ case "$arch" in
39
+ x86_64 | amd64) arch="x64" ;;
40
+ aarch64 | arm64) arch="arm64" ;;
41
+ *)
42
+ printf 'ghfind install: unsupported architecture "%s".\n' "$arch" >&2
43
+ exit 1
44
+ ;;
45
+ esac
46
+
47
+ asset="ghfind-${plat}-${arch}"
48
+
49
+ # ── Resolve version ────────────────────────────────────────────────────
50
+ if [ -n "${GHFIND_VERSION:-}" ]; then
51
+ version="$GHFIND_VERSION"
52
+ else
53
+ # Latest release tag, following redirects; avoids a jq dependency.
54
+ version=$(curl -fsSLI -o /dev/null -w '%{url_effective}' \
55
+ "https://github.com/${REPO}/releases/latest" | sed 's|.*/tag/v||')
56
+ if [ -z "$version" ] || [ "$version" = "latest" ]; then
57
+ printf 'ghfind install: could not resolve the latest release version.\n' >&2
58
+ exit 1
59
+ fi
60
+ fi
61
+
62
+ base_url="https://github.com/${REPO}/releases/download/v${version}"
63
+
64
+ # ── Pick install dir (never requires sudo) ─────────────────────────────
65
+ if [ -n "${GHFIND_INSTALL_DIR:-}" ]; then
66
+ install_dir="$GHFIND_INSTALL_DIR"
67
+ elif [ -w /usr/local/bin ] 2>/dev/null; then
68
+ install_dir="/usr/local/bin"
69
+ else
70
+ install_dir="${HOME}/.local/bin"
71
+ fi
72
+
73
+ mkdir -p "$install_dir"
74
+
75
+ # ── Download binary + checksum ─────────────────────────────────────────
76
+ tmp=$(mktemp -d)
77
+ trap 'rm -rf "$tmp"' EXIT
78
+
79
+ printf 'Installing ghfind %s (%s) -> %s\n' "$version" "$asset" "$install_dir"
80
+
81
+ curl -fsSL --retry 3 -o "$tmp/ghfind" "${base_url}/${asset}"
82
+ curl -fsSL --retry 3 -o "$tmp/SHA256SUMS.txt" "${base_url}/SHA256SUMS.txt" ||
83
+ printf 'warning: could not download SHA256SUMS.txt; skipping checksum verification\n'
84
+
85
+ # ── Verify checksum when we have the sums file ─────────────────────────
86
+ if [ -f "$tmp/SHA256SUMS.txt" ]; then
87
+ expected=$(grep " ${asset}\$" "$tmp/SHA256SUMS.txt" | awk '{print $1}')
88
+ if [ -n "$expected" ]; then
89
+ if command -v sha256sum >/dev/null 2>&1; then
90
+ actual=$(sha256sum "$tmp/ghfind" | awk '{print $1}')
91
+ elif command -v shasum >/dev/null 2>&1; then
92
+ actual=$(shasum -a 256 "$tmp/ghfind" | awk '{print $1}')
93
+ else
94
+ actual=""
95
+ printf 'warning: no sha256sum/shasum found; skipping checksum verification\n'
96
+ fi
97
+ if [ -n "$actual" ] && [ "$actual" != "$expected" ]; then
98
+ printf 'ghfind install: checksum mismatch!\n expected %s\n actual %s\n' "$expected" "$actual" >&2
99
+ exit 1
100
+ fi
101
+ [ -n "$actual" ] && printf 'Checksum OK (%s)\n' "$actual"
102
+ fi
103
+ fi
104
+
105
+ # ── Install ────────────────────────────────────────────────────────────
106
+ mv "$tmp/ghfind" "${install_dir}/ghfind"
107
+ chmod +x "${install_dir}/ghfind"
108
+
109
+ # ── PATH hint ──────────────────────────────────────────────────────────
110
+ case ":$PATH:" in
111
+ *":${install_dir}:"*) ;;
112
+ *)
113
+ printf '\nNOTE: %s is not in your PATH.\n' "$install_dir"
114
+ printf 'Add it, e.g.:\n echo '"'"'export PATH="%s:$PATH"'"'"' >> ~/.bashrc # or ~/.zshrc\n' "$install_dir"
115
+ ;;
116
+ esac
117
+
118
+ printf 'Done. Run: ghfind --version\n'
@@ -0,0 +1,141 @@
1
+ /**
2
+ * agent-skill.ts — `ghfind skill`: a compact, token-efficient usage guide for
3
+ * AI coding agents, and the module that owns the skill registry.
4
+ *
5
+ * Coding agents (Claude Code, Cursor, Codex, ...) burn tokens reading
6
+ * `--help` output, most of which explains the interactive TUI they cannot
7
+ * drive. `ghfind skill` prints a distilled, agent-shaped guide covering only
8
+ * the non-interactive surface, so an agent gets everything it needs in ~2 KB.
9
+ *
10
+ * The registry is deliberately generic: the built-in ghfind skill is the
11
+ * seed, and third parties can register their own skills alongside it
12
+ * (`registerSkill`) — the foundation of ghfind-as-an-agent-ecosystem.
13
+ */
14
+ import { getVersion } from "./version";
15
+
16
+ /** One invocable skill in the registry. */
17
+ export interface Skill {
18
+ /** Unique id, e.g. "ghfind-cli". Also the `ghfind skill <id>` selector. */
19
+ name: string;
20
+ /** Human-readable display name. */
21
+ title: string;
22
+ /** When the agent should reach for this skill. */
23
+ description: string;
24
+ /** The full skill body, printed to stdout by `ghfind skill <name>`. */
25
+ content: string;
26
+ /** Registrations that are not the built-in ghfind skill. */
27
+ builtin?: boolean;
28
+ }
29
+
30
+ /** Build the built-in ghfind CLI skill. A function so the version is read lazily. */
31
+ function buildGhfindSkill(): Skill {
32
+ return {
33
+ name: "ghfind-cli",
34
+ title: "ghfind CLI for agents",
35
+ description:
36
+ "Search GitHub (repos, trending, npm packages, org/user profiles) from the terminal via the `ghfind` command. Use when the user asks to find, compare, or track GitHub repositories or npm packages.",
37
+ builtin: true,
38
+ content: `# ghfind — GitHub search for agents
39
+
40
+ ghfind searches GitHub from the terminal: repositories, trending, npm
41
+ packages, org/user profiles. This guide covers the non-interactive surface
42
+ only — ignore anything about a TUI in other docs; agents cannot drive it.
43
+
44
+ ## Search GitHub repositories
45
+
46
+ ghfind "QUERY" --json [--limit N] [--sort best-match|stars|updated|forks]
47
+
48
+ Query language (GitHub search qualifiers):
49
+ language:Rust stars:>1000 topic:cli org:vercel user:torvalds
50
+ repo:facebook/react pushed:>2026-01-01 license:mit archived:false
51
+ "exact phrase" -language:JavaScript # quotes, negation
52
+
53
+ Formats: --json | --csv | --markdown | --count | --format urls|names|ssh-urls|clone-commands|ids
54
+
55
+ ## Trending repositories
56
+
57
+ ghfind --trending --json [--since daily|weekly|monthly] [--language rust]
58
+ ghfind trending rust --json # subcommand form of the same thing
59
+
60
+ ## npm packages
61
+
62
+ ghfind pkg "QUERY" --json [--limit N] [--sort best-match|score|downloads|name]
63
+
64
+ ## Org & user profiles
65
+
66
+ ghfind org vercel --json
67
+ ghfind user torvalds --json
68
+
69
+ ## Compare repositories
70
+
71
+ ghfind --compare owner/a owner/b [--json|--csv|--markdown]
72
+ Errors if fewer than 2 of the requested repos resolve; unresolved names are
73
+ reported in text output and via the error message.
74
+
75
+ ## Deep-dive a repo (languages, contributors, README)
76
+
77
+ ghfind deep-dive owner/repo --json
78
+ Text output (no flag) prints the same sections formatted for the terminal.
79
+
80
+ ## Rate limits
81
+
82
+ 60 req/hr unauthenticated, 5,000 with GITHUB_TOKEN (env var or \`ghfind login\`).
83
+ Responses are cached ~5 min, so repeated identical queries are cheap.
84
+
85
+ ## Bookmarking & release tracking
86
+
87
+ Bookmarks live in ghfind's local state, not GitHub. An agent can read the
88
+ release feed with:
89
+ ghfind --releases --json
90
+ Marking releases seen and editing bookmarks is a TUI action; skip it.
91
+
92
+ ## Token efficiency
93
+
94
+ Prefer --count when only the number of results matters, --format names when
95
+ you only need fullNames, and --limit to cap payload size (default 50, max 100).
96
+ `,
97
+ };
98
+ }
99
+
100
+ // ─── Registry ───────────────────────────────────────────────────────────
101
+
102
+ const registry = new Map<string, Skill>();
103
+
104
+ /** Register a skill. Overwrites an existing skill with the same name. */
105
+ export function registerSkill(skill: Skill): void {
106
+ registry.set(skill.name, skill);
107
+ }
108
+
109
+ /** Get a skill by name, or undefined. */
110
+ export function getSkill(name: string): Skill | undefined {
111
+ return registry.get(name);
112
+ }
113
+
114
+ /** All registered skills, built-ins first, then alphabetical. */
115
+ export function listSkills(): Skill[] {
116
+ return [...registry.values()].sort((a, b) => {
117
+ if (a.builtin !== b.builtin) return a.builtin ? -1 : 1;
118
+ return a.name.localeCompare(b.name);
119
+ });
120
+ }
121
+
122
+ /** Load the built-in ghfind skill into the registry (idempotent). */
123
+ export function ensureBuiltinSkill(): void {
124
+ if (!registry.has("ghfind-cli")) {
125
+ registerSkill(buildGhfindSkill());
126
+ }
127
+ }
128
+
129
+ /** Print the skill catalog (one line per skill) for `ghfind skill` with no id. */
130
+ export function formatSkillCatalog(): string {
131
+ ensureBuiltinSkill();
132
+ const lines = listSkills().map(
133
+ (s) => ` ${s.name.padEnd(16)} ${s.description}`,
134
+ );
135
+ return [
136
+ "Available agent skills:",
137
+ ...lines,
138
+ "",
139
+ `Run \`ghfind skill <name>\` to print one (ghfind v${getVersion()}).`,
140
+ ].join("\n");
141
+ }