Repository navigation
fix(github-mcp): pass each search word to gh as its own keyword - #18
Merged
Merged
Conversation
`gh search` quotes every keyword argument that contains whitespace, so search, search_repos, and search_commits, which passed the whole expression as one argument, ran every multi-word query as an exact phrase: `child_process timeout` in nodejs/node returned 2 issues instead of 74. gh also cuts an argument at its first colon, so a leading qualifier swallowed the rest: `is:open timeout hang` became `is:"open timeout hang"`. A new _gh_split_search_terms helper splits the expression on whitespace. A double-quoted span stays in one term with its quotes removed, so gh quotes it again: `"exact phrase"` stays a phrase and `label:"good first issue"` keeps working. The terms go after `--`, so a negated qualifier such as `-label:bug` is not read as a gh flag. An unbalanced quote, or an expression with no terms, fails before gh runs. search_code is unchanged, since its description promises an exact text match. A quoted phrase that contains a colon still does not reach GitHub as that phrase; gh has no argument form for it. Co-Authored-By: Claude <noreply@anthropic.com>
The per-character loop in _gh_split_search_terms took quadratic time in bash: a 60 KB search took 7 s under LC_ALL=C and 17 s under a UTF-8 locale before gh ran. The splitter now uses `read -a` with an explicit IFS, first to cut the expression at its double quotes and then to split it into words, and takes 0.09 s for the same input. The explicit IFS also makes the split independent of the locale, where `[[:space:]]` matched U+00A0 under UTF-8 only. Whitespace inside a quoted phrase now collapses to single spaces, since gh's quoting turned a tab into a literal `\t`. The split joins a phrase's words with a unit separator (U+001F) and turns it back into a space afterwards, so a search containing U+001F is rejected. search_repos accepts a search without words again and searches by its filters alone, as it did before the split was added. The search parameter descriptions in tools-read.json and REFERENCE.md now state the syntax: each word is its own keyword, double quotes keep a phrase together, and an unmatched quote fails the call. REFERENCE.md also lists what gh cannot pass through: a negated phrase (`-"exact phrase"`, use `NOT "exact phrase"` instead), a quoted single word such as `"OR"`, and a phrase containing a colon. Co-Authored-By: Claude <noreply@anthropic.com>
search_code put the search before its flags without `--`, so gh read a search that starts with `-`, such as the PHP code `->getId(`, as flags and failed with an unknown-flag error. The search now follows `--` as one argument, so gh still quotes it as the exact-text phrase the tool describes. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #10.
gh searchquotes every keyword argument that contains whitespace and reads the text before an argument's first:as a qualifier name (formatKeywords()andquote()in cli/clipkg/search/query.go).search,search_repos, andsearch_commitspassed the wholesearchvalue as one argument, so every multi-word query ran as an exact phrase, and a leading qualifier swallowed the rest:is:open timeout hangbecameis:"open timeout hang".child_process timeoutin nodejs/node returned 2 issues as a phrase and returns 74 as separate keywords.Changes
_gh_split_search_terms(lib/search.sh): splitssearchinto one argument per word. A double-quoted span stays inside its term, loses its quotes, and has its whitespace collapsed to single spaces, so gh quotes it again:"exact phrase"stays a phrase, andlabel:"good first issue"reaches gh aslabel:good first issue, which gh turns back intolabel:"good first issue". The split runs onread -awith an explicitIFS, so it takes linear time and does not depend on the locale. An unbalanced quote fails before gh runs, and so does asearchwithout words forsearchandsearch_commits;search_reposthen searches by its filters alone.--before the search:search,search_repos,search_commits, andsearch_codenow put the search after--, so a search that starts with-(-label:bug crash, the code->getId() is not read as a gh flag.search_codestill sends the whole search as one argument. Its description promises an exact text match, which gh's phrase quoting delivers.searchparameter descriptions intools-read.jsonandREFERENCE.mdstate the syntax: each word is its own keyword, double quotes keep a phrase together, and an unmatched quote fails the call.Known limitation
gh's keyword formatting cannot pass three forms through, so
REFERENCE.mdlists them:-"exact phrase"becomes a phrase that starts with-.NOT "exact phrase"works."OR"becomes the operator.::"error: timeout"reaches GitHub aserror:" timeout".