@gkoreli/ghx 2.0.2 → 2.1.5
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 +25 -4
- package/npm/bin/ghx +22 -0
- package/package.json +11 -14
- package/postinstall.js +0 -59
- package/v2/MCP-SKILL.md +0 -175
- package/v2/SKILL.md +0 -129
package/README.md
CHANGED
|
@@ -17,18 +17,39 @@ ghx eliminates this by encoding the right defaults into every command. One call
|
|
|
17
17
|
## Install
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
#
|
|
21
|
-
|
|
20
|
+
# Zero install — just run it
|
|
21
|
+
npx @gkoreli/ghx explore vercel/next.js
|
|
22
22
|
|
|
23
23
|
# Homebrew
|
|
24
24
|
brew install gkoreli/tap/ghx
|
|
25
25
|
|
|
26
|
-
#
|
|
27
|
-
|
|
26
|
+
# npm (global)
|
|
27
|
+
npm install -g @gkoreli/ghx
|
|
28
|
+
|
|
29
|
+
# Go
|
|
30
|
+
go install github.com/gkoreli/ghx/v2@latest
|
|
31
|
+
|
|
32
|
+
# Build from source
|
|
33
|
+
cd v2 && go build -o ghx .
|
|
28
34
|
```
|
|
29
35
|
|
|
30
36
|
Requires: [gh CLI](https://cli.github.com/) authenticated (`gh auth login`).
|
|
31
37
|
|
|
38
|
+
### MCP Config (Claude Desktop, Cursor)
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"mcpServers": {
|
|
43
|
+
"ghx": {
|
|
44
|
+
"command": "npx",
|
|
45
|
+
"args": ["@gkoreli/ghx", "serve"]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
No install step — npx downloads and caches the binary on first run.
|
|
52
|
+
|
|
32
53
|
## Commands
|
|
33
54
|
|
|
34
55
|
```bash
|
package/npm/bin/ghx
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { platform, arch } = process;
|
|
3
|
+
|
|
4
|
+
const PLATFORMS = {
|
|
5
|
+
darwin: { arm64: "@gkoreli/ghx-darwin-arm64/ghx", x64: "@gkoreli/ghx-darwin-x64/ghx" },
|
|
6
|
+
linux: { arm64: "@gkoreli/ghx-linux-arm64/ghx", x64: "@gkoreli/ghx-linux-x64/ghx" },
|
|
7
|
+
win32: { arm64: "@gkoreli/ghx-win32-arm64/ghx.exe", x64: "@gkoreli/ghx-win32-x64/ghx.exe" },
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const bin = PLATFORMS[platform]?.[arch];
|
|
11
|
+
if (!bin) {
|
|
12
|
+
console.error(`ghx: unsupported platform ${platform}/${arch}`);
|
|
13
|
+
process.exitCode = 1;
|
|
14
|
+
} else {
|
|
15
|
+
const result = require("child_process").spawnSync(
|
|
16
|
+
require.resolve(bin),
|
|
17
|
+
process.argv.slice(2),
|
|
18
|
+
{ shell: false, stdio: "inherit" }
|
|
19
|
+
);
|
|
20
|
+
if (result.error) throw result.error;
|
|
21
|
+
process.exitCode = result.status;
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gkoreli/ghx",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.5",
|
|
4
4
|
"description": "Agent-first GitHub code exploration. GraphQL batching, code maps, codemode TypeScript sandbox, MCP server.",
|
|
5
5
|
"bin": {
|
|
6
|
-
"ghx": "
|
|
6
|
+
"ghx": "npm/bin/ghx"
|
|
7
7
|
},
|
|
8
8
|
"keywords": [
|
|
9
9
|
"github",
|
|
@@ -16,25 +16,22 @@
|
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "https://github.com/gkoreli/ghx"
|
|
19
|
+
"url": "git+https://github.com/gkoreli/ghx.git"
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
|
-
"ghx",
|
|
23
|
-
"postinstall.js",
|
|
24
|
-
"v2/SKILL.md",
|
|
25
|
-
"v2/MCP-SKILL.md",
|
|
22
|
+
"npm/bin/ghx",
|
|
26
23
|
"README.md",
|
|
27
24
|
"LICENSE"
|
|
28
25
|
],
|
|
29
|
-
"os": [
|
|
30
|
-
"darwin",
|
|
31
|
-
"linux",
|
|
32
|
-
"win32"
|
|
33
|
-
],
|
|
34
26
|
"engines": {
|
|
35
27
|
"node": ">=16"
|
|
36
28
|
},
|
|
37
|
-
"
|
|
38
|
-
"
|
|
29
|
+
"optionalDependencies": {
|
|
30
|
+
"@gkoreli/ghx-darwin-arm64": "2.1.5",
|
|
31
|
+
"@gkoreli/ghx-darwin-x64": "2.1.5",
|
|
32
|
+
"@gkoreli/ghx-linux-arm64": "2.1.5",
|
|
33
|
+
"@gkoreli/ghx-linux-x64": "2.1.5",
|
|
34
|
+
"@gkoreli/ghx-win32-arm64": "2.1.5",
|
|
35
|
+
"@gkoreli/ghx-win32-x64": "2.1.5"
|
|
39
36
|
}
|
|
40
37
|
}
|
package/postinstall.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Downloads the ghx Go binary from GitHub releases on npm install
|
|
3
|
-
const { execSync } = require("child_process");
|
|
4
|
-
const fs = require("fs");
|
|
5
|
-
const path = require("path");
|
|
6
|
-
const https = require("https");
|
|
7
|
-
|
|
8
|
-
const REPO = "gkoreli/ghx";
|
|
9
|
-
const BIN = path.join(__dirname, "ghx");
|
|
10
|
-
|
|
11
|
-
const PLATFORM_MAP = { darwin: "darwin", linux: "linux", win32: "windows" };
|
|
12
|
-
const ARCH_MAP = { x64: "amd64", arm64: "arm64" };
|
|
13
|
-
|
|
14
|
-
const os = PLATFORM_MAP[process.platform];
|
|
15
|
-
const arch = ARCH_MAP[process.arch];
|
|
16
|
-
if (!os || !arch) {
|
|
17
|
-
console.error(`Unsupported platform: ${process.platform}/${process.arch}`);
|
|
18
|
-
process.exit(1);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const ext = os === "windows" ? "zip" : "tar.gz";
|
|
22
|
-
const url = `https://github.com/${REPO}/releases/latest/download/ghx_${os}_${arch}.${ext}`;
|
|
23
|
-
|
|
24
|
-
function download(url, dest) {
|
|
25
|
-
return new Promise((resolve, reject) => {
|
|
26
|
-
https.get(url, (res) => {
|
|
27
|
-
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
28
|
-
return download(res.headers.location, dest).then(resolve, reject);
|
|
29
|
-
}
|
|
30
|
-
if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode} for ${url}`));
|
|
31
|
-
const file = fs.createWriteStream(dest);
|
|
32
|
-
res.pipe(file);
|
|
33
|
-
file.on("finish", () => file.close(resolve));
|
|
34
|
-
}).on("error", reject);
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async function main() {
|
|
39
|
-
const tmp = path.join(__dirname, `ghx-download.${ext}`);
|
|
40
|
-
try {
|
|
41
|
-
console.log(`Downloading ghx (${os}/${arch})...`);
|
|
42
|
-
await download(url, tmp);
|
|
43
|
-
if (ext === "tar.gz") {
|
|
44
|
-
execSync(`tar xzf "${tmp}" -C "${__dirname}" ghx`, { stdio: "pipe" });
|
|
45
|
-
} else {
|
|
46
|
-
execSync(`unzip -o "${tmp}" ghx.exe -d "${__dirname}"`, { stdio: "pipe" });
|
|
47
|
-
}
|
|
48
|
-
fs.chmodSync(BIN, 0o755);
|
|
49
|
-
console.log("ghx installed successfully");
|
|
50
|
-
} finally {
|
|
51
|
-
try { fs.unlinkSync(tmp); } catch {}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
main().catch((e) => {
|
|
56
|
-
console.error(`Failed to install ghx: ${e.message}`);
|
|
57
|
-
console.error("Install manually: https://github.com/gkoreli/ghx#install");
|
|
58
|
-
process.exit(1);
|
|
59
|
-
});
|
package/v2/MCP-SKILL.md
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: ghx-mcp
|
|
3
|
-
description: GitHub code exploration via MCP. 7 tools — 5 direct + code meta-tool + search_tools. The code tool lets you write JS programs that compose operations in one round-trip.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# ghx MCP — GitHub Code Exploration via MCP
|
|
7
|
-
|
|
8
|
-
7 tools for GitHub exploration. 5 direct tools for simple queries. 1 `code` meta-tool for complex multi-step operations. 1 `search_tools` for discovery.
|
|
9
|
-
|
|
10
|
-
## Tools
|
|
11
|
-
|
|
12
|
-
### Direct Tools (simple one-shot queries)
|
|
13
|
-
|
|
14
|
-
| Tool | Input | What it does |
|
|
15
|
-
|------|-------|-------------|
|
|
16
|
-
| `explore` | `repo` (required), `path` | Branch, file tree, README in 1 API call |
|
|
17
|
-
| `read` | `repo` + `paths` (required), `grep`, `lines`, `map` | Read 1-10 files in 1 API call. `map` = signatures only (~92% reduction) |
|
|
18
|
-
| `search` | `query` (required), `limit`, `full` | Code search with AND matching + matching lines |
|
|
19
|
-
| `repos` | `query` (required), `limit` | Search repos with README preview |
|
|
20
|
-
| `tree` | `repo` (required), `path` | Full recursive file tree |
|
|
21
|
-
|
|
22
|
-
### Meta-Tools (compose operations)
|
|
23
|
-
|
|
24
|
-
| Tool | Input | What it does |
|
|
25
|
-
|------|-------|-------------|
|
|
26
|
-
| `code` | `code` (required) | Execute JS that calls any combination of the 5 tools above |
|
|
27
|
-
| `search_tools` | `query` (optional) | List available tools with TypeScript type stubs |
|
|
28
|
-
|
|
29
|
-
## When to Use `code` vs Direct Tools
|
|
30
|
-
|
|
31
|
-
**Direct tools** — simple, single-operation queries:
|
|
32
|
-
```
|
|
33
|
-
explore({ repo: "vercel/next.js" }) → one call, one result
|
|
34
|
-
read({ repo: "vercel/next.js", paths: "README.md" }) → one call, one result
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
**`code` tool** — multi-step, filtering, conditional logic:
|
|
38
|
-
```javascript
|
|
39
|
-
// Explore → filter → read in ONE round-trip (not three)
|
|
40
|
-
var repo = codemode.explore({ repo: "vercel/next.js" });
|
|
41
|
-
var tsFiles = repo.files.filter(f => f.name.endsWith(".ts")).slice(0, 5);
|
|
42
|
-
var contents = codemode.read({ repo: "vercel/next.js", files: tsFiles.map(f => f.name), map: true });
|
|
43
|
-
return contents;
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
**Rule of thumb:** If you need the result of tool A to decide what to call for tool B → use `code`. Otherwise use direct tools.
|
|
47
|
-
|
|
48
|
-
## The `code` Tool
|
|
49
|
-
|
|
50
|
-
### Available API
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
53
|
-
type ExploreInput = { repo: string; path?: string }
|
|
54
|
-
type ReadInput = { repo: string; files: string[]; grep?: string; map?: boolean }
|
|
55
|
-
type ReposInput = { query: string; limit?: number }
|
|
56
|
-
type SearchInput = { query: string; limit?: number; fullMode?: boolean }
|
|
57
|
-
type TreeInput = { repo: string; path?: string }
|
|
58
|
-
|
|
59
|
-
declare const codemode: {
|
|
60
|
-
explore: (input: ExploreInput) => any;
|
|
61
|
-
read: (input: ReadInput) => any;
|
|
62
|
-
repos: (input: ReposInput) => any;
|
|
63
|
-
search: (input: SearchInput) => any;
|
|
64
|
-
tree: (input: TreeInput) => any;
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Use `search_tools` to get the latest type stubs at runtime.
|
|
69
|
-
|
|
70
|
-
### Writing Code
|
|
71
|
-
|
|
72
|
-
```javascript
|
|
73
|
-
// ✅ Correct: plain JavaScript, synchronous calls, return a value
|
|
74
|
-
var repo = codemode.explore({ repo: "dop251/goja" });
|
|
75
|
-
return { branch: repo.branch, fileCount: repo.files.length };
|
|
76
|
-
|
|
77
|
-
// ❌ Wrong: await (tools are synchronous, await causes transpile error)
|
|
78
|
-
const r = await codemode.explore(...) // top-level await not supported
|
|
79
|
-
|
|
80
|
-
// ❌ Wrong: TypeScript syntax
|
|
81
|
-
const r: ExploreResult = codemode.explore(...) // no type annotations
|
|
82
|
-
|
|
83
|
-
// ❌ Wrong: no return value
|
|
84
|
-
codemode.explore({ repo: "dop251/goja" }); // result is lost
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Rules
|
|
88
|
-
|
|
89
|
-
- Write plain JavaScript, not TypeScript (no type annotations, interfaces, generics)
|
|
90
|
-
- `codemode.*` calls are synchronous — do NOT use `await`
|
|
91
|
-
- Must `return` a value — the return value is what you see in the response
|
|
92
|
-
- `console.log()` output appears in the response under "Console:" (useful for debugging)
|
|
93
|
-
- Max 20 tool calls per execution
|
|
94
|
-
- Max 64KB code size
|
|
95
|
-
- Response truncated at 24K chars (use `map: true` or `grep` to reduce output)
|
|
96
|
-
|
|
97
|
-
### Patterns
|
|
98
|
-
|
|
99
|
-
**Explore and filter:**
|
|
100
|
-
```javascript
|
|
101
|
-
var repo = codemode.explore({ repo: "owner/repo" });
|
|
102
|
-
var goFiles = repo.files.filter(f => f.name.endsWith(".go"));
|
|
103
|
-
return goFiles.map(f => f.name);
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
**Map multiple files (understand structure before reading):**
|
|
107
|
-
```javascript
|
|
108
|
-
var repo = codemode.explore({ repo: "owner/repo" });
|
|
109
|
-
var srcFiles = repo.files.filter(f => f.name.startsWith("src/") && f.type === "blob").slice(0, 8);
|
|
110
|
-
return codemode.read({ repo: "owner/repo", files: srcFiles.map(f => f.name), map: true });
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
**Search then read matches:**
|
|
114
|
-
```javascript
|
|
115
|
-
var hits = codemode.search({ query: "GraphQL repo:owner/repo", limit: 5 });
|
|
116
|
-
var files = hits.results.map(r => r.path);
|
|
117
|
-
return codemode.read({ repo: "owner/repo", files: files });
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
**Conditional logic:**
|
|
121
|
-
```javascript
|
|
122
|
-
var repo = codemode.explore({ repo: "owner/repo" });
|
|
123
|
-
var hasGo = repo.files.some(f => f.name === "go.mod");
|
|
124
|
-
var hasPython = repo.files.some(f => f.name === "requirements.txt");
|
|
125
|
-
if (hasGo) {
|
|
126
|
-
return { lang: "go", mod: codemode.read({ repo: "owner/repo", files: ["go.mod"] }) };
|
|
127
|
-
} else if (hasPython) {
|
|
128
|
-
return { lang: "python", reqs: codemode.read({ repo: "owner/repo", files: ["requirements.txt"] }) };
|
|
129
|
-
}
|
|
130
|
-
return { lang: "unknown", files: repo.files.slice(0, 10) };
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## Chain of Thought
|
|
134
|
-
|
|
135
|
-
**Always start surgical, escalate only when needed.**
|
|
136
|
-
|
|
137
|
-
```
|
|
138
|
-
1. explore({ repo: "owner/repo" }) → What's in this repo?
|
|
139
|
-
2. read({ repo: "...", paths: "f1,f2", map: true }) → What do these files define? (92% fewer tokens)
|
|
140
|
-
3. read({ repo: "...", paths: "f1", grep: "pattern" }) → Where exactly is X?
|
|
141
|
-
4. read({ repo: "...", paths: "f1" }) → Full file (only when needed)
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
**When to escalate to `code`:**
|
|
145
|
-
- Step 1 result determines what to do in step 2 → use `code` (one round-trip)
|
|
146
|
-
- Need to filter/transform results before returning → use `code`
|
|
147
|
-
- Simple single query → use direct tool
|
|
148
|
-
|
|
149
|
-
## Search Query Syntax
|
|
150
|
-
|
|
151
|
-
Same as GitHub REST code search API. Multi-word = AND matching.
|
|
152
|
-
|
|
153
|
-
**Valid qualifiers:** `repo:`, `org:`, `path:`, `filename:`, `extension:`, `language:`, `in:file`, `in:path`
|
|
154
|
-
|
|
155
|
-
**DO NOT USE (web-only, silently wrong):** `OR`, `NOT`, `symbol:`, `content:`, `is:`, regex
|
|
156
|
-
|
|
157
|
-
**Rate limit:** 9 req/min for code search. Refine queries, don't paginate.
|
|
158
|
-
|
|
159
|
-
## Gotchas
|
|
160
|
-
|
|
161
|
-
1. **`read` paths are comma-separated.** `paths: "f1.go,f2.go"` not `paths: ["f1.go", "f2.go"]`.
|
|
162
|
-
2. **Response truncation at 24K chars.** Use `map: true` or `grep` to keep results small. The `code` tool is especially prone to this when reading multiple full files.
|
|
163
|
-
3. **`search` uses AND matching.** `"foo bar"` finds files with both words anywhere. For exact phrase, wrap in escaped quotes: `"\"foo bar\""`.
|
|
164
|
-
4. **Web-only qualifiers silently degrade.** `symbol:`, `OR`, `NOT` are treated as literal text in the REST API.
|
|
165
|
-
5. **`code` tool: no TypeScript.** Type stubs are for your reference. Write plain JS.
|
|
166
|
-
6. **`code` tool: return is required.** Bare expressions don't auto-return (except simple identifiers). Always use `return`.
|
|
167
|
-
|
|
168
|
-
## Anti-Patterns
|
|
169
|
-
|
|
170
|
-
- ❌ Three sequential tool calls when `code` can do it in one
|
|
171
|
-
- ❌ Reading full files when you need 10 lines — use `grep` or `map: true`
|
|
172
|
-
- ❌ Paginating broad searches — refine with `repo:`, `language:`, `path:`
|
|
173
|
-
- ❌ Writing TypeScript in the `code` tool — stripped by transpiler but may cause subtle issues
|
|
174
|
-
- ❌ Forgetting `return` in `code` — you get `undefined` back
|
|
175
|
-
- ❌ Reading 10 full files in `code` — hits 24K truncation. Use `map: true` first
|
package/v2/SKILL.md
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: ghx
|
|
3
|
-
description: GitHub code exploration for AI agents. CLI + codemode. One command does what takes 3-5 API calls. Write JS programs that compose operations in one round-trip.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# ghx — GitHub Code Exploration for AI Agents
|
|
7
|
-
|
|
8
|
-
Use `ghx` via `execute_bash` for anything on GitHub — repos, files, code search, codemode. Authenticated via `gh` CLI, structured output, zero context overhead.
|
|
9
|
-
|
|
10
|
-
## Commands
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
ghx explore <owner/repo> # Branch + tree + README in 1 API call
|
|
14
|
-
ghx explore <owner/repo> <path> # Subdirectory listing
|
|
15
|
-
ghx read <owner/repo> <f1> [f2] [f3] # Read 1-10 files in 1 API call (GraphQL batching)
|
|
16
|
-
ghx read <owner/repo> --map <f1> [f2] # Structural map: signatures, imports, types (~92% token reduction)
|
|
17
|
-
ghx read <owner/repo> --grep "pat" <f> # Read file, show only matching lines (2 lines context)
|
|
18
|
-
ghx read <owner/repo> --lines 42-80 <f> # Read specific line range
|
|
19
|
-
ghx repos "<query>" # Search repos with README preview in 1 GraphQL call
|
|
20
|
-
ghx search "<query>" # Code search (AND matching, shows matching lines)
|
|
21
|
-
ghx search --full "<query>" # Code search without line truncation
|
|
22
|
-
ghx tree <owner/repo> [path] # Full recursive tree listing
|
|
23
|
-
ghx code "<js>" # Execute JS with access to all ghx tools
|
|
24
|
-
ghx code - # Read code from stdin
|
|
25
|
-
ghx code --list # List available tools with type stubs
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
**Exit codes:** 0 = success, 1 = no results, 2 = usage error.
|
|
29
|
-
|
|
30
|
-
## Chain of Thought: Progressive Disclosure
|
|
31
|
-
|
|
32
|
-
**Start surgical, escalate only when needed.**
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
1. ghx explore owner/repo → What's in this repo? (structure + README)
|
|
36
|
-
2. ghx read owner/repo --map *.ts → What do these files define? (signatures only, 92% fewer tokens)
|
|
37
|
-
3. ghx read owner/repo --grep "X" f → Where exactly is X in this file? (targeted lines)
|
|
38
|
-
4. ghx read owner/repo f → Show me the full file (only when needed)
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
At 92% reduction, `--map` lets you scan 7 files in the space of reading 1 full file.
|
|
42
|
-
|
|
43
|
-
## When to Use `ghx code`
|
|
44
|
-
|
|
45
|
-
Use direct commands for simple one-shot queries. Use `ghx code` when you need to:
|
|
46
|
-
- **Chain operations** — explore → filter → read in one shot
|
|
47
|
-
- **Filter results** — JS logic runs locally, not in the LLM
|
|
48
|
-
- **Conditional logic** — read different files based on what you find
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
# Simple: use direct command
|
|
52
|
-
ghx explore vercel/next.js
|
|
53
|
-
|
|
54
|
-
# Complex: use ghx code (one round-trip instead of three)
|
|
55
|
-
ghx code "
|
|
56
|
-
var repo = codemode.explore({ repo: 'vercel/next.js' });
|
|
57
|
-
var goFiles = repo.files.filter(f => f.name.endsWith('.go'));
|
|
58
|
-
var contents = codemode.read({ repo: 'vercel/next.js', files: goFiles.map(f => f.name) });
|
|
59
|
-
return contents;
|
|
60
|
-
"
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### Codemode API
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
ghx code --list # See all available tools with type stubs
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
70
|
-
declare const codemode: {
|
|
71
|
-
explore: (input: { repo: string; path?: string }) => any;
|
|
72
|
-
read: (input: { repo: string; files: string[]; grep?: string; map?: boolean }) => any;
|
|
73
|
-
repos: (input: { query: string; limit?: number }) => any;
|
|
74
|
-
search: (input: { query: string; limit?: number; fullMode?: boolean }) => any;
|
|
75
|
-
tree: (input: { repo: string; path?: string }) => any;
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### Codemode Rules
|
|
80
|
-
|
|
81
|
-
- Write plain JavaScript, not TypeScript (no type annotations)
|
|
82
|
-
- `codemode.*` calls are synchronous — no `await` needed
|
|
83
|
-
- Must `return` a value — bare expressions don't auto-return (except simple identifiers)
|
|
84
|
-
- Must `return` a value — bare expressions don't auto-return (except simple identifiers)
|
|
85
|
-
- Console output goes to stderr, return value goes to stdout
|
|
86
|
-
- Max 20 tool calls per execution, 64KB code size limit
|
|
87
|
-
|
|
88
|
-
## Search Query Syntax
|
|
89
|
-
|
|
90
|
-
`ghx search` uses GitHub REST code search API. Multi-word = AND matching (both words anywhere in file).
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
ghx search "addClass repo:jquery/jquery" # Scoped to repo
|
|
94
|
-
ghx search "useState language:typescript" # Language filter
|
|
95
|
-
ghx search "filename:package.json repo:owner/repo" # Find specific filename
|
|
96
|
-
ghx search '"exact phrase" repo:plausible/analytics' # Exact phrase (shell quotes)
|
|
97
|
-
ghx search "path:llms.txt" # Find files by name
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**Valid qualifiers:** `repo:`, `org:`, `path:`, `filename:`, `extension:`, `language:`, `in:file`, `in:path`, `size:`, `fork:true`
|
|
101
|
-
|
|
102
|
-
**DO NOT USE (web-only, silently wrong):** `OR`, `NOT`, `symbol:`, `content:`, `is:`, regex
|
|
103
|
-
|
|
104
|
-
**Rate limit:** 9 req/min for code search. Refine queries, don't paginate.
|
|
105
|
-
|
|
106
|
-
## Gotchas
|
|
107
|
-
|
|
108
|
-
1. **Web-only qualifiers silently degrade.** `symbol:`, `OR`, `NOT` are treated as literal text. ghx warns on stderr.
|
|
109
|
-
2. **`gh search code` wraps in quotes.** `gh search code "foo bar"` = exact phrase. `ghx search "foo bar"` = AND. Use ghx.
|
|
110
|
-
3. **Flag ordering in `read`.** `ghx read owner/repo file --map` works. `ghx read --map owner/repo file` does NOT.
|
|
111
|
-
4. **Not all repos use `main`.** ghx handles this automatically.
|
|
112
|
-
5. **Unknown flags are rejected.** Exit 2 with clear error. Intentional — prevents silent query corruption.
|
|
113
|
-
|
|
114
|
-
## Anti-Patterns
|
|
115
|
-
|
|
116
|
-
- ❌ `web_fetch` on github.com — HTML noise, zero useful info
|
|
117
|
-
- ❌ Reading entire large files when you need 10 lines — use `--grep` or `--lines`
|
|
118
|
-
- ❌ Multiple `gh api` calls for explore — use `ghx explore` (1 call)
|
|
119
|
-
- ❌ Using web-only qualifiers in search — silently wrong results
|
|
120
|
-
- ❌ Paginating broad searches — refine with `repo:`, `language:`, `path:` instead
|
|
121
|
-
- ❌ `gh search code` for multi-word queries — silently wraps in quotes, returns nothing
|
|
122
|
-
|
|
123
|
-
## Best Practices
|
|
124
|
-
|
|
125
|
-
- **Batch reads.** `ghx read repo f1 f2 f3` = 1 API call. Three separate reads = 3 calls.
|
|
126
|
-
- **Map before reading.** `--map` first, then `--grep` or `--lines` for specifics.
|
|
127
|
-
- **Refine search, don't paginate.** Add qualifiers instead of fetching page 2.
|
|
128
|
-
- **Use `ghx code` for multi-step workflows.** One round-trip beats three sequential commands.
|
|
129
|
-
- **Check exit codes.** 0 = results, 1 = no results (broaden query), 2 = usage error (fix command).
|