github-search-cli 9.8.0 → 9.8.2
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 +109 -0
- package/LICENSE +21 -21
- package/README.md +81 -22
- package/completions/ghfind.bash +55 -51
- package/completions/ghfind.fish +29 -24
- package/completions/ghfind.zsh +52 -39
- package/demo.svg +71 -71
- package/dist/cli.js +1336 -551
- package/package.json +1 -1
- package/release-notes/9.8.1.md +74 -0
- package/release-notes/9.8.2.md +65 -0
- package/scripts/brew.rb +53 -53
- package/scripts/postinstall.js +38 -0
- package/src/agent-skill.ts +14 -0
- package/src/cli.ts +450 -20
- package/src/config.ts +12 -2
- package/src/deepdive.ts +70 -66
- package/src/doctor.ts +3 -2
- package/src/error-report.ts +81 -11
- package/src/errors.ts +0 -1
- package/src/history.ts +2 -5
- package/src/image-loader.ts +30 -1
- package/src/init.ts +1 -2
- package/src/markdown-view.ts +20 -4
- package/src/mcp-server.ts +65 -10
- package/src/notifications.ts +9 -3
- package/src/org.ts +15 -14
- package/src/output.ts +1 -13
- package/src/readme.ts +70 -0
- package/src/releases.ts +29 -27
- package/src/search.ts +4 -0
- package/src/skill-finder.ts +476 -0
- package/src/storage.ts +22 -47
- package/src/tui.ts +17 -33
- package/src/user.ts +15 -14
- package/dist/chunk-GYIL4S5X.js +0 -59
- package/dist/config-OCIPF2IF.js +0 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "github-search-cli",
|
|
3
|
-
"version": "9.8.
|
|
3
|
+
"version": "9.8.2",
|
|
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,74 @@
|
|
|
1
|
+
# What's New in ghfind 9.8.1
|
|
2
|
+
|
|
3
|
+
Agent skills and read-only CLI views for scripts.
|
|
4
|
+
|
|
5
|
+
This is a patch release. It also corrects the v9.8.0 release notes, which
|
|
6
|
+
claimed README image rendering worked. It does not, and this release does not
|
|
7
|
+
fix it — see the note at the end.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
**`ghfind skill search <query>`**
|
|
12
|
+
|
|
13
|
+
- Finds agent skills by keyword and prints why each one matched.
|
|
14
|
+
- Scans `SKILL.md` files under `~/.codex/skills`, `~/.agents/skills`,
|
|
15
|
+
`<project>/.codex/skills` and `<project>/.github/skills`, in that
|
|
16
|
+
priority order, de-duplicated by name.
|
|
17
|
+
- `--remote` queries the public [skills.sh](https://skills.sh) ecosystem
|
|
18
|
+
instead, returning each hit's install count and `npx skills add` command.
|
|
19
|
+
- `GHFIND_SKILL_ROOTS` overrides which directories are scanned.
|
|
20
|
+
|
|
21
|
+
**MCP tool `ghfind_skill_search`**
|
|
22
|
+
|
|
23
|
+
- Agents can search skills as soon as they connect: `source: "local"` (the
|
|
24
|
+
default) searches installed skills, `source: "registry"` searches
|
|
25
|
+
skills.sh. Read-only — it returns install commands and never writes to disk.
|
|
26
|
+
|
|
27
|
+
**Read-only CLI views of local state**
|
|
28
|
+
|
|
29
|
+
- `ghfind bookmarks [query]`, `ghfind history [query]`, `ghfind saved`
|
|
30
|
+
and `ghfind topics`, each with `--json` for agents. They print what the
|
|
31
|
+
TUI has stored and never modify it.
|
|
32
|
+
|
|
33
|
+
**`ghfind readme <owner/repo>` and `ghfind share <owner/repo>`**
|
|
34
|
+
|
|
35
|
+
- `ghfind readme` prints a repository's README (`--raw` skips the header,
|
|
36
|
+
`--json` returns `{ owner, name, sourceUrl, text }`), bringing the TUI's
|
|
37
|
+
README viewer to scripts and agents.
|
|
38
|
+
- `ghfind share` prints a share snippet (`--as markdown|plain|gh-cli|short`),
|
|
39
|
+
with `--copy` to also put it on the clipboard.
|
|
40
|
+
|
|
41
|
+
**Shell completions**
|
|
42
|
+
|
|
43
|
+
- bash, zsh and fish completions cover every new subcommand and flag.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- The bundled `ghfind-cli` agent skill documents skill search and the new
|
|
48
|
+
read-only commands, so CLI-first agents discover them without reading
|
|
49
|
+
`--help`.
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
**README image rendering is not working — please read this before upgrading**
|
|
54
|
+
|
|
55
|
+
The 9.8.0 README viewer added inline image support. On real repositories it
|
|
56
|
+
does not work reliably, and this release does not fix it. Known failures, all
|
|
57
|
+
verified against live READMEs:
|
|
58
|
+
|
|
59
|
+
- **An image wrapped in a link renders nothing.** `[](url)`
|
|
60
|
+
is a common way to write a linked screenshot. The whole block is treated as
|
|
61
|
+
prose and the image is dropped. This affects repositories such as
|
|
62
|
+
`sst/opencode`.
|
|
63
|
+
- **A README with hundreds of small images is unusable.** `openclaw/openclaw`
|
|
64
|
+
has 661 `<img>` tags, 648 of them 48x48 sponsor avatars. Each becomes a
|
|
65
|
+
full screen of terminal cells, so the document is 15,552 rows tall.
|
|
66
|
+
- **An image smaller than 100px is skipped**, judged by the `width`/`height`
|
|
67
|
+
its `<img>` tag declares. A README that understates an image's size hides
|
|
68
|
+
that image.
|
|
69
|
+
- **SVG is not rendered.**
|
|
70
|
+
|
|
71
|
+
Plain `![]()` images and large banners do render, correctly and quickly. The
|
|
72
|
+
v9.8.0 notes described image rendering as working; that was wrong, and it is
|
|
73
|
+
corrected here. Measurements, root causes and the remaining work are tracked
|
|
74
|
+
in `.issues/tickets/readme-image-rendering.md`.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# v9.8.2
|
|
2
|
+
|
|
3
|
+
A maintenance release: twenty-three fixes from a full static audit of the
|
|
4
|
+
codebase, most of them invisible until something went wrong. Nothing user-facing
|
|
5
|
+
was added or removed — every flag, key and command behaves as it did in 9.8.1.
|
|
6
|
+
|
|
7
|
+
## The one that mattered
|
|
8
|
+
|
|
9
|
+
A GitHub token passed as `--token` could end up in a public URL. When ghfind
|
|
10
|
+
crashed, it built a GitHub issue link straight from `process.argv` — argv
|
|
11
|
+
included your token — and opened it in a browser. The docblock claimed the
|
|
12
|
+
command line was redacted; it was not. Every field that reaches the issue now
|
|
13
|
+
goes through redaction first, and when ghfind sees a credential it prints the
|
|
14
|
+
URL for you to copy instead of opening a browser tab automatically.
|
|
15
|
+
|
|
16
|
+
## Security, in full
|
|
17
|
+
|
|
18
|
+
- Tokens are no longer sent to `raw.githubusercontent.com` when fetching a
|
|
19
|
+
README — only to `api.github.com`, and only for a private repository.
|
|
20
|
+
- Skill sources and ids from the public skills.sh registry are validated before
|
|
21
|
+
they can reach a shell command or a URL, so a hostile registry entry cannot
|
|
22
|
+
smuggle `;`, `$(`, backticks or a path traversal into `npx skills add`.
|
|
23
|
+
- The config file that stores your token is now written with `0600`
|
|
24
|
+
permissions. On Windows the file still inherits the directory ACL, so this
|
|
25
|
+
closes the hole on POSIX only.
|
|
26
|
+
- `--doctor` masks the token rather than printing a raw prefix.
|
|
27
|
+
|
|
28
|
+
## Reliability
|
|
29
|
+
|
|
30
|
+
The most user-visible correctness fix: recoverable errors were treated as
|
|
31
|
+
crashes. The top-level catch tested `err.name === "SearchCliError"`, a string
|
|
32
|
+
that is never true, so a rate limit, a network blip or a layout change on
|
|
33
|
+
GitHub's trending page all opened a browser tab asking you to file a bug. That
|
|
34
|
+
branch now works, and those errors print a short explanation and exit.
|
|
35
|
+
|
|
36
|
+
`--compare` and the `ghfind_compare_repos` MCP tool both resolved repository
|
|
37
|
+
names through a free-text search with no `repo:` qualifier and never checked
|
|
38
|
+
the `fullName` that came back, so `ghfind --compare oven/bun oven-sh/bun` could
|
|
39
|
+
quietly compare the wrong two repositories. Both now resolve exactly.
|
|
40
|
+
|
|
41
|
+
State files — bookmarks, history, sessions, saved searches, notifications —
|
|
42
|
+
were written directly to their live path. A crash, a full disk, or a reader
|
|
43
|
+
caught mid-write left a truncated JSON file, which the loader then silently
|
|
44
|
+
replaced with defaults: your data was gone with no error. Writes are now atomic
|
|
45
|
+
(temp file plus rename).
|
|
46
|
+
|
|
47
|
+
## Smaller fixes
|
|
48
|
+
|
|
49
|
+
Notification IDs restarted after "dismiss all"; `history --delete` removed
|
|
50
|
+
every duplicate entry instead of one; an invalid `--sort` value degraded
|
|
51
|
+
silently instead of erroring; a failed "load more" in the TUI wiped the results
|
|
52
|
+
already on screen; `--markdown` did not escape `|` in cells while `--csv`
|
|
53
|
+
did; the in-memory cache was not a real LRU; local skill scanning re-walked the
|
|
54
|
+
filesystem on every keystroke; and skill ids containing `_` — common on GitHub
|
|
55
|
+
— were wrongly rejected.
|
|
56
|
+
|
|
57
|
+
## Verification
|
|
58
|
+
|
|
59
|
+
482 tests, plus `typecheck`, `lint`, `format:check` and `build` all green.
|
|
60
|
+
The security fixes were additionally verified with runnable probes that assert
|
|
61
|
+
no token substring survives URL encoding in the generated crash-report URL, that
|
|
62
|
+
none of twelve `raw.githubusercontent.com` requests carries an `Authorization`
|
|
63
|
+
header, and that seven of eight hostile skill payloads are rejected.
|
|
64
|
+
|
|
65
|
+
`README.md` test count updated to match the real suite.
|
package/scripts/brew.rb
CHANGED
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
# typed: true
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
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"
|
|
19
|
-
license "MIT"
|
|
20
|
-
|
|
21
|
-
livecheck do
|
|
22
|
-
url :stable
|
|
23
|
-
regex(/^v?(\d+(?:\.\d+)+)$/i)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
on_macos do
|
|
27
|
-
if Hardware::CPU.arm?
|
|
28
|
-
url "https://github.com/codersdfs/search-cli/releases/download/v#{version}/ghfind-darwin-arm64"
|
|
29
|
-
sha256 "SHA256_PLACEHOLDER"
|
|
30
|
-
else
|
|
31
|
-
url "https://github.com/codersdfs/search-cli/releases/download/v#{version}/ghfind-darwin-x64"
|
|
32
|
-
sha256 "SHA256_PLACEHOLDER"
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
on_linux do
|
|
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
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def install
|
|
47
|
-
bin.install "ghfind" => "ghfind"
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
test do
|
|
51
|
-
assert_match version.to_s, shell_output("#{bin}/ghfind --version")
|
|
52
|
-
end
|
|
53
|
-
end
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
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"
|
|
19
|
+
license "MIT"
|
|
20
|
+
|
|
21
|
+
livecheck do
|
|
22
|
+
url :stable
|
|
23
|
+
regex(/^v?(\d+(?:\.\d+)+)$/i)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
on_macos do
|
|
27
|
+
if Hardware::CPU.arm?
|
|
28
|
+
url "https://github.com/codersdfs/search-cli/releases/download/v#{version}/ghfind-darwin-arm64"
|
|
29
|
+
sha256 "SHA256_PLACEHOLDER"
|
|
30
|
+
else
|
|
31
|
+
url "https://github.com/codersdfs/search-cli/releases/download/v#{version}/ghfind-darwin-x64"
|
|
32
|
+
sha256 "SHA256_PLACEHOLDER"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
on_linux do
|
|
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
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def install
|
|
47
|
+
bin.install "ghfind" => "ghfind"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
test do
|
|
51
|
+
assert_match version.to_s, shell_output("#{bin}/ghfind --version")
|
|
52
|
+
end
|
|
53
|
+
end
|
package/scripts/postinstall.js
CHANGED
|
@@ -18,6 +18,7 @@ import { join, dirname } from "node:path";
|
|
|
18
18
|
import { fileURLToPath } from "node:url";
|
|
19
19
|
import { platform, arch } from "node:os";
|
|
20
20
|
import { spawnSync } from "node:child_process";
|
|
21
|
+
import { createHash } from "node:crypto";
|
|
21
22
|
import { inflateRawSync } from "node:zlib";
|
|
22
23
|
|
|
23
24
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -96,6 +97,35 @@ const key = `${platform()}-${arch}`;
|
|
|
96
97
|
const assetName = map[key];
|
|
97
98
|
const version = "1.3.14";
|
|
98
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Pinned SHA256 of every Bun release asset this script can install, taken
|
|
102
|
+
* from that release's own SHASUMS256.txt. The download is verified before
|
|
103
|
+
* anything is written, so a tampered or truncated archive can never become
|
|
104
|
+
* an executable in vendor/.
|
|
105
|
+
*
|
|
106
|
+
* ponytail: hand-pinned per Bun release — regenerate this table (and bump
|
|
107
|
+
* `version`) whenever the release is bumped; the check is what makes the
|
|
108
|
+
* hardcoded `version` above trustworthy.
|
|
109
|
+
*/
|
|
110
|
+
const SHA256 = {
|
|
111
|
+
"bun-windows-x64.zip":
|
|
112
|
+
"0a0620930b6675d7ba440e81f4e0e00d3cfbe096c4b140d3fff02205e9e18922",
|
|
113
|
+
"bun-windows-aarch64.zip":
|
|
114
|
+
"89841f5a57f2348b67ec0839b718f4bf4ea7d07c371c9ba4b77b6c790f918953",
|
|
115
|
+
"bun-darwin-x64.zip":
|
|
116
|
+
"4183df3374623e5bab315c547cfa0974533cd457d86b73b639f7a87974cd6633",
|
|
117
|
+
"bun-darwin-aarch64.zip":
|
|
118
|
+
"d8b96221828ad6f97ac7ac0ab7e95872341af763001e8803e8267652c2652620",
|
|
119
|
+
"bun-linux-x64.zip":
|
|
120
|
+
"951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f",
|
|
121
|
+
"bun-linux-x64-musl.zip":
|
|
122
|
+
"14bd9aedeebf1dba67e8def9531c89bc989ecfdf1de42e5bfcaf1b8cd9294719",
|
|
123
|
+
"bun-linux-aarch64.zip":
|
|
124
|
+
"a27ffb63a8310375836e0d6f668ae17fa8d8d18b88c37c821c65331973a19a3b",
|
|
125
|
+
"bun-linux-aarch64-musl.zip":
|
|
126
|
+
"b98e0ad3625c5c00d1d5b5ff55605c7adddbfae151861e68ade57b2d3b8703bb",
|
|
127
|
+
};
|
|
128
|
+
|
|
99
129
|
if (!assetName) {
|
|
100
130
|
console.error(
|
|
101
131
|
`[ghfind] Unsupported platform: ${key}. Install Bun manually: https://bun.sh`,
|
|
@@ -116,6 +146,14 @@ try {
|
|
|
116
146
|
|
|
117
147
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
118
148
|
|
|
149
|
+
const expected = SHA256[assetName];
|
|
150
|
+
const actual = createHash("sha256").update(buffer).digest("hex");
|
|
151
|
+
if (expected !== actual) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`checksum mismatch for ${assetName} (expected ${expected}, got ${actual})`,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
119
157
|
// Find the central directory file header signature (PK\x01\x02)
|
|
120
158
|
const cdSig = "PK\x01\x02";
|
|
121
159
|
let cdOffset = buffer.indexOf(cdSig, 0);
|
package/src/agent-skill.ts
CHANGED
|
@@ -77,6 +77,12 @@ reported in text output and via the error message.
|
|
|
77
77
|
ghfind deep-dive owner/repo --json
|
|
78
78
|
Text output (no flag) prints the same sections formatted for the terminal.
|
|
79
79
|
|
|
80
|
+
## Finding skills
|
|
81
|
+
ghfind skill search QUERY # skills installed on this machine
|
|
82
|
+
ghfind skill search QUERY --remote # the public skills.sh ecosystem
|
|
83
|
+
Results carry path+description (local) or install command (registry, read-only --
|
|
84
|
+
nothing is installed). The MCP server exposes the same search as
|
|
85
|
+
ghfind_skill_search.
|
|
80
86
|
## Rate limits
|
|
81
87
|
|
|
82
88
|
60 req/hr unauthenticated, 5,000 with GITHUB_TOKEN (env var or \`ghfind login\`).
|
|
@@ -88,6 +94,14 @@ Bookmarks live in ghfind's local state, not GitHub. An agent can read the
|
|
|
88
94
|
release feed with:
|
|
89
95
|
ghfind --releases --json
|
|
90
96
|
Marking releases seen and editing bookmarks is a TUI action; skip it.
|
|
97
|
+
## Local state (read-only)
|
|
98
|
+
ghfind bookmarks [QUERY] --json # saved repos, newest first
|
|
99
|
+
ghfind history [QUERY] --json # past searches
|
|
100
|
+
ghfind saved --json # named searches
|
|
101
|
+
ghfind topics --json # popular GitHub topics
|
|
102
|
+
ghfind readme owner/repo # print a repo README
|
|
103
|
+
ghfind share owner/repo --as gh-cli|markdown|plain|short
|
|
104
|
+
These never write local state; skip them when nothing needs reading.
|
|
91
105
|
|
|
92
106
|
## Token efficiency
|
|
93
107
|
|