opencodekit 0.15.12 → 0.15.13

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 CHANGED
@@ -80,8 +80,8 @@ Background Plugins:
80
80
  Supporting:
81
81
  • 30+ Skills (domain expertise loaded on-demand)
82
82
  • 26+ Commands (workflow shortcuts)
83
- • 3 MCP Services (context7, exa, gh_grep) + skill-embedded MCPs
84
- • Custom Tools (memory-*, observation, ast-grep, lsp-*)
83
+ • 3 MCP Services (context7, exa) + grep-search tool + skill-embedded MCPs
84
+ • Custom Tools (memory-*, observation, grep-search, lsp-*)
85
85
  • Beads task tracking (`bd` CLI for multi-session workflows)
86
86
  • Manual Handoffs (clean phase transitions)
87
87
  ```
@@ -223,9 +223,9 @@ You've successfully set up OpenCodeKit when:
223
223
  - ✅ Skills load on-demand (30+ skills)
224
224
  - ✅ Delegation is clear (build → specialized subagents)
225
225
  - ✅ `/handoff` creates portable bundles (.opencode/memory/handoffs/)
226
- - ✅ MCP services configured (context7, gh_grep + skill-embedded)
226
+ - ✅ Tools configured (context7, grep-search + skill-embedded MCP)
227
227
  - ✅ Background plugins active (enforcer, compactor, truncator)
228
- - ✅ Custom tools available (memory-_, observation, ast-grep, lsp-_)
228
+ - ✅ Custom tools available (memory-_, observation, grep-search, lsp-_)
229
229
  - ✅ Environment variables set (.opencode/.env with API keys)
230
230
 
231
231
  ---
package/dist/index.js CHANGED
@@ -750,7 +750,7 @@ var cac = (name = "") => new CAC(name);
750
750
  // package.json
751
751
  var package_default = {
752
752
  name: "opencodekit",
753
- version: "0.15.12",
753
+ version: "0.15.13",
754
754
  description: "CLI tool for bootstrapping and managing OpenCodeKit projects",
755
755
  keywords: ["agents", "cli", "mcp", "opencode", "opencodekit", "template"],
756
756
  license: "MIT",
@@ -180,16 +180,19 @@ Plugins run automatically in every session:
180
180
  **Enabled by default (3 total):**
181
181
 
182
182
  1. **context7** - Up-to-date library documentation (37.6k+ libraries)
183
- - Requires: CONTEXT7_API_KEY
184
- - GitHub: https://github.com/upstash/context7
183
+ - Native tools: `context7_resolve_library_id()` and `context7_query_docs()`
184
+ - Requires: CONTEXT7_API_KEY (optional - public libraries work without it)
185
+ - Step 1: Resolve library name → `/libraryId`
186
+ - Step 2: Query docs with the libraryId
185
187
 
186
188
  2. **exa** - Web search + code context (3.3k+ repos)
187
189
  - Requires: EXA_API_KEY
188
190
  - GitHub: https://github.com/exa-labs/exa-mcp-server
189
191
 
190
- 3. **gh_grep** - Search 1M+ public GitHub repositories
192
+ 3. **grep-search** - Search 1M+ public GitHub repositories via grep.app
193
+ - Native tool: `grep_search({ query: "...", language: [...] })`
191
194
  - No API key needed (public service)
192
- - GitHub: https://github.com/Shachlan/grep.app-mcp
195
+ - Direct HTTP wrapper (no MCP overhead)
193
196
 
194
197
  **Skill-Embedded MCP (load on-demand):**
195
198
 
@@ -93,7 +93,7 @@ Run 2-3 tool calls in parallel.
93
93
  **Triggers:** "how do others", "compare", "best practices", "production patterns"
94
94
  **Target:** Summary, 3-5 code examples, tradeoffs, recommendation
95
95
 
96
- 1. Search GitHub with gh_grep_searchGitHub (vary queries for different angles)
96
+ 1. Search GitHub with grep_search (vary queries for different angles)
97
97
  2. Compare 3-5 implementations from different repositories
98
98
  3. Synthesize common patterns
99
99
  4. Note tradeoffs and edge cases
@@ -104,30 +104,101 @@ Run 4-6 tool calls in parallel.
104
104
 
105
105
  Every code reference must include a GitHub permalink. Never link to a branch or tag that can change.
106
106
 
107
- To construct a permalink: use `gh_grep_searchGitHub` to find code, then build the URL from the repository and file path returned. Format: `https://github.com/owner/repo/blob/<sha>/path/to/file#L10-L20`.
107
+ To construct a permalink: use `grep_search` to find code, then build the URL from the repository and file path returned. Format: `https://github.com/owner/repo/blob/<sha>/path/to/file#L10-L20`.
108
108
 
109
109
  ## Tool Priority (External Sources Only)
110
110
 
111
- | Priority | Tool | Use Case | Speed |
112
- | -------- | -------------------- | ----------------------------------------- | ------- |
113
- | 1 | memory-search | Past research findings | Instant |
114
- | 2 | context7 | Official library docs | Fast |
115
- | 3 | codesearch | Exa Code API for SDK/library patterns | Fast |
116
- | 4 | gh_grep_searchGitHub | Cross-repo GitHub code search (1M+ repos) | Medium |
117
- | 5 | webfetch | Specific doc URLs, READMEs, changelogs | Medium |
118
- | 6 | opensrc + LSP | Clone & analyze source code | Slow |
119
- | 7 | websearch | Tutorials, blog posts, recent news | Slow |
111
+ | Priority | Tool | Use Case | Speed |
112
+ | -------- | ------------- | ----------------------------------------- | ------- |
113
+ | 1 | memory-search | Past research findings | Instant |
114
+ | 2 | context7 | Official library docs | Fast |
115
+ | 3 | codesearch | Exa Code API for SDK/library patterns | Fast |
116
+ | 4 | grep_search | Cross-repo GitHub code search (1M+ repos) | Medium |
117
+ | 5 | webfetch | Specific doc URLs, READMEs, changelogs | Medium |
118
+ | 6 | opensrc + LSP | Clone & analyze source code | Slow |
119
+ | 7 | websearch | Tutorials, blog posts, recent news | Slow |
120
120
 
121
121
  **Rule:** Exhaust faster tools before slower ones. Run tools in parallel when independent.
122
122
 
123
- ## gh_grep_searchGitHub Tool
123
+ ## context7 Tools
124
+
125
+ Use to access up-to-date library documentation (37.6k+ libraries).
126
+
127
+ ### Two-Step Process
128
+
129
+ **Step 1: Resolve Library ID**
130
+
131
+ ```typescript
132
+ context7_resolve_library_id({
133
+ libraryName: "react", // Required - package/library name
134
+ query?: "hooks composition", // Optional - search context
135
+ limit?: 5 // Optional - max results (default: 5)
136
+ })
137
+ ```
138
+
139
+ Returns library IDs like `/facebook/react`, `/nodejs/node`, etc.
140
+
141
+ **Step 2: Query Documentation**
142
+
143
+ ```typescript
144
+ context7_query_docs({
145
+ libraryId: "/facebook/react", // From resolve step
146
+ topic: "useState hook", // What you want to know
147
+ maxTokens?: 8000 // Optional - response size
148
+ })
149
+ ```
150
+
151
+ ### Query Patterns
152
+
153
+ **Good queries (specific features):**
154
+
155
+ - `useState hook` - Find React useState documentation
156
+ - `async/await` - Node.js async patterns
157
+ - `type decorators` - TypeScript types and decorators
158
+ - `setup instructions` - Getting started guides
159
+
160
+ **Bad queries (too vague):**
161
+
162
+ - `react` - Too broad
163
+ - `best practices` - Not a feature
164
+ - `how to use` - Natural language
165
+
166
+ ### Examples
167
+
168
+ ```typescript
169
+ // Find React docs
170
+ const reactId = context7_resolve_library_id({ libraryName: "react" });
171
+ context7_query_docs({ libraryId: reactId, topic: "useEffect cleanup" });
172
+
173
+ // Find TypeScript docs
174
+ const tsId = context7_resolve_library_id({
175
+ libraryName: "typescript",
176
+ query: "types",
177
+ });
178
+ context7_query_docs({ libraryId: tsId, topic: "generic types" });
179
+
180
+ // Find Node.js docs
181
+ const nodeId = context7_resolve_library_id({ libraryName: "nodejs" });
182
+ context7_query_docs({ libraryId: nodeId, topic: "streams API" });
183
+ ```
184
+
185
+ ### Failure Handling
186
+
187
+ | Problem | Solution |
188
+ | ----------------- | ---------------------------------------------- |
189
+ | Library not found | Check exact name; try shorter/different names |
190
+ | No docs for topic | Broaden query - search parent concepts instead |
191
+ | Empty results | Try related terms or "API reference" |
192
+ | API error | Verify CONTEXT7_API_KEY is set (optional) |
193
+
194
+ ## grep_search Tool
124
195
 
125
196
  Use for cross-repository code search across 1M+ public GitHub repositories.
126
197
 
127
198
  ### Schema
128
199
 
129
200
  ```typescript
130
- gh_grep_searchGitHub({
201
+ grep_search({
131
202
  query: string, // Required - search pattern (literal code, not keywords)
132
203
  repo?: string, // Optional - filter to specific repo (e.g., "vercel/ai")
133
204
  language?: string[], // Optional - e.g., ["TypeScript", "TSX"]
@@ -157,22 +228,22 @@ gh_grep_searchGitHub({
157
228
 
158
229
  ```typescript
159
230
  // Basic repo search
160
- gh_grep_searchGitHub({ query: "batch_tool", repo: "anomalyco/opencode" });
231
+ grep_search({ query: "batch_tool", repo: "anomalyco/opencode" });
161
232
 
162
233
  // With language filter
163
- gh_grep_searchGitHub({
234
+ grep_search({
164
235
  query: "getServerSession",
165
236
  language: ["TypeScript", "TSX"],
166
237
  });
167
238
 
168
239
  // Regex pattern (multi-line)
169
- gh_grep_searchGitHub({
240
+ grep_search({
170
241
  query: "(?s)useEffect\\(\\(\\) => {.*removeEventListener",
171
242
  useRegexp: true,
172
243
  });
173
244
 
174
245
  // Path filter for specific files
175
- gh_grep_searchGitHub({
246
+ grep_search({
176
247
  query: "CORS(",
177
248
  language: ["Python"],
178
249
  matchCase: true,
@@ -184,7 +255,7 @@ gh_grep_searchGitHub({
184
255
  | Problem | Solution |
185
256
  | ---------------- | ------------------------------------------------ |
186
257
  | Empty results | Broaden query - search concepts, not exact names |
187
- | MCP server error | Fall back to `codesearch` or `websearch` |
258
+ | API error | Fall back to `codesearch` or `websearch` |
188
259
  | Rate limited | Reduce parallel calls, go sequential |
189
260
  | Too many results | Add `language` or `path` filters |
190
261
 
@@ -316,8 +387,8 @@ Structure your response as:
316
387
 
317
388
  ```
318
389
  context7 fails → try codesearch for patterns
319
- codesearch empty → try gh_grep_searchGitHub with broader query
320
- gh_grep_searchGitHub empty → webfetch specific doc URLs if known
390
+ codesearch empty → try grep_search with broader query
391
+ grep_search empty → webfetch specific doc URLs if known
321
392
  still stuck → opensrc clone + LSP analysis
322
393
  last resort → websearch for tutorials/blogs
323
394
  ```
@@ -327,10 +398,10 @@ last resort → websearch for tutorials/blogs
327
398
  **context7 doesn't find library:**
328
399
 
329
400
  1. Try `codesearch({ query: "<library> <function> example" })`
330
- 2. Try `gh_grep_searchGitHub({ query: "import.*from.*<library>", language: ["TypeScript"] })`
401
+ 2. Try `grep_search({ query: "import.*from.*<library>", language: ["TypeScript"] })`
331
402
  3. Clone with `npx opensrc <library>` and read source
332
403
 
333
- **gh_grep_searchGitHub returns nothing:**
404
+ **grep_search returns nothing:**
334
405
 
335
406
  - Broaden query: search concepts, not exact function names
336
407
  - Remove specific repo filter to search across all repos
@@ -339,9 +410,9 @@ last resort → websearch for tutorials/blogs
339
410
  - Search for error messages, config patterns, or import statements
340
411
  - Fall back to `codesearch` for conceptual queries
341
412
 
342
- **gh_grep_searchGitHub MCP error:**
413
+ **grep_search API error:**
343
414
 
344
- - MCP server at `mcp.grep.app` may be temporarily down
415
+ - The grep.app API may be temporarily unavailable
345
416
  - Fall back to `codesearch` for similar functionality
346
417
  - Use `opensrc` to clone specific repos and search locally
347
418
  - Try `websearch` as last resort
@@ -368,6 +439,6 @@ NO URL GUESSING: Only use URLs from tools or user input.
368
439
  CITE EVERYTHING: No claims without source links.
369
440
 
370
441
  Quick: context7 → codesearch → websearch (2-3 parallel calls)
371
- Deep: gh_grep (4-6 parallel calls) → compare 3-5 repos → synthesize
372
- Fallback: context7 → codesearch → gh_grep → webfetch → opensrc → websearch
442
+ Deep: grep_search (4-6 parallel calls) → compare 3-5 repos → synthesize
443
+ Fallback: context7 → codesearch → grep_search → webfetch → opensrc → websearch
373
444
  ```
@@ -212,7 +212,7 @@ context7_resolve_library_id({
212
212
  });
213
213
 
214
214
  // Real-world implementations
215
- gh_grep_searchGitHub({
215
+ grep_search({
216
216
  query: "[pattern to find]",
217
217
  language: ["TypeScript", "TSX"],
218
218
  path: "components/",
@@ -95,7 +95,7 @@ If memory search fails (Ollama not running), continue to external sources.
95
95
  2. **Official docs** (high trust) - What does the library documentation say?
96
96
  3. **Context7** (high trust) - API usage and examples
97
97
  4. **Source code** (high trust) - Library implementation (use `source-code-research` skill)
98
- 5. **GitHub examples** (medium trust) - Real-world patterns via codesearch/gh_grep
98
+ 5. **GitHub examples** (medium trust) - Real-world patterns via codesearch/grep_search
99
99
  6. **Web search** (lower trust) - Only if tiers 1-5 don't answer
100
100
 
101
101
  ## Research
@@ -0,0 +1,21 @@
1
+ ---
2
+ type: decision
3
+ created: 2026-01-28T16:59:35.621Z
4
+ confidence: high
5
+ valid_until: null
6
+ superseded_by: null
7
+ concepts: ["grep-search", "MCP", "native tool", "architecture", "best practices"]
8
+ ---
9
+
10
+ # 🎯 gh-grep MCP wrapper vs native grep-search tool
11
+
12
+ 🟢 **Confidence:** high
13
+
14
+ Created two implementations for GitHub code search:
15
+
16
+ 1. **Native tool** (.opencode/tool/grep-search.ts): TypeScript wrapper around grep.app API - WORKING ✅
17
+ 2. **MCP skill** (.opencode/skill/gh-grep/): Skill wrapper that calls uvx grep-mcp server - BROKEN ❌
18
+
19
+ The MCP server has an argument parsing bug ('str' object has no attribute 'get') that prevents tool execution. Even the SKILL.md documentation admits: "Note: The MCP server (grep-mcp) may have bugs. The native grep_search tool is recommended."
20
+
21
+ **Key insight**: We already documented the problem and recommended against the MCP approach. The native tool works perfectly and doesn't require external process dependencies.
@@ -94,10 +94,13 @@ The bug is in **OpenCode's tool response handler**, not the MCP connection layer
94
94
  2. `opencode mcp debug` shows HTTP 200 OK responses
95
95
  3. The error happens only when the AI agent calls the tool
96
96
 
97
- ## Workaround
97
+ ## Resolution
98
98
 
99
- Use alternative tools that don't go through MCP:
99
+ **FIXED** - Replaced MCP tools with native HTTP wrappers:
100
100
 
101
+ - `context7_resolve-library-id` - Native HTTP wrapper (works)
102
+ - `context7_query-docs` - Native HTTP wrapper (works)
103
+ - `grep-search` - Native HTTP wrapper (works)
101
104
  - `codesearch` (Exa Code API) - works
102
105
  - `websearch` (Exa Web Search) - works
103
106
 
@@ -49,53 +49,22 @@
49
49
  "experimental": {},
50
50
  "formatter": {
51
51
  "biome": {
52
- "command": [
53
- "npx",
54
- "@biomejs/biome",
55
- "check",
56
- "--write",
57
- "$FILE"
58
- ],
59
- "extensions": [
60
- ".js",
61
- ".jsx",
62
- ".ts",
63
- ".tsx",
64
- ".json",
65
- ".jsonc"
66
- ]
52
+ "command": ["npx", "@biomejs/biome", "check", "--write", "$FILE"],
53
+ "extensions": [".js", ".jsx", ".ts", ".tsx", ".json", ".jsonc"]
67
54
  },
68
55
  "cargo-fmt": {
69
- "command": [
70
- "cargo",
71
- "fmt",
72
- "--",
73
- "$FILE"
74
- ],
75
- "extensions": [
76
- ".rs"
77
- ]
56
+ "command": ["cargo", "fmt", "--", "$FILE"],
57
+ "extensions": [".rs"]
78
58
  },
79
59
  "java-formatter": {
80
- "command": [
81
- "google-java-format",
82
- "--replace",
83
- "$FILE"
84
- ],
60
+ "command": ["google-java-format", "--replace", "$FILE"],
85
61
  "environment": {
86
62
  "JAVA_HOME": "{env:JAVA_HOME}"
87
63
  },
88
- "extensions": [
89
- ".java"
90
- ]
64
+ "extensions": [".java"]
91
65
  },
92
66
  "oxfmt": {
93
- "command": [
94
- "npx",
95
- "oxfmt",
96
- "--write",
97
- "$FILE"
98
- ],
67
+ "command": ["npx", "oxfmt", "--write", "$FILE"],
99
68
  "extensions": [
100
69
  ".js",
101
70
  ".jsx",
@@ -114,22 +83,11 @@
114
83
  ]
115
84
  },
116
85
  "laravel-pint": {
117
- "command": [
118
- "npx",
119
- "laravel-pint",
120
- "--preset",
121
- "psr12",
122
- "$FILE"
123
- ],
124
- "extensions": [
125
- ".php"
126
- ]
86
+ "command": ["npx", "laravel-pint", "--preset", "psr12", "$FILE"],
87
+ "extensions": [".php"]
127
88
  }
128
89
  },
129
- "instructions": [
130
- ".opencode/memory/user.md",
131
- ".opencode/memory/project/*.md"
132
- ],
90
+ "instructions": [".opencode/memory/user.md", ".opencode/memory/project/*.md"],
133
91
  "keybinds": {
134
92
  "command_list": ";",
135
93
  "leader": "`",
@@ -138,17 +96,6 @@
138
96
  "session_compact": "ctrl+k"
139
97
  },
140
98
  "mcp": {
141
- "context7": {
142
- "type": "remote",
143
- "url": "https://mcp.context7.com/mcp",
144
- "headers": {
145
- "CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}"
146
- }
147
- },
148
- "gh_grep": {
149
- "type": "remote",
150
- "url": "https://mcp.grep.app"
151
- },
152
99
  "stitch": {
153
100
  "enabled": false,
154
101
  "type": "remote",
@@ -195,6 +142,11 @@
195
142
  "@tarquinen/opencode-dcp@latest",
196
143
  "@franlol/opencode-md-table-formatter@0.0.3"
197
144
  ],
145
+ "tools": {
146
+ "grep-search": true,
147
+ "context7-resolve-library-id": true,
148
+ "context7-query-docs": true
149
+ },
198
150
  "provider": {
199
151
  "github-copilot": {
200
152
  "models": {
@@ -338,17 +290,13 @@
338
290
  "disabled": true
339
291
  },
340
292
  "high": {
341
- "include": [
342
- "reasoning.encrypted_content"
343
- ],
293
+ "include": ["reasoning.encrypted_content"],
344
294
  "reasoningEffort": "high",
345
295
  "reasoningSummary": "auto",
346
296
  "textVerbosity": "low"
347
297
  },
348
298
  "medium": {
349
- "include": [
350
- "reasoning.encrypted_content"
351
- ],
299
+ "include": ["reasoning.encrypted_content"],
352
300
  "reasoningEffort": "medium",
353
301
  "reasoningSummary": "auto",
354
302
  "textVerbosity": "low"
@@ -361,17 +309,13 @@
361
309
  "disabled": true
362
310
  },
363
311
  "high": {
364
- "include": [
365
- "reasoning.encrypted_content"
366
- ],
312
+ "include": ["reasoning.encrypted_content"],
367
313
  "reasoningEffort": "high",
368
314
  "reasoningSummary": "auto",
369
315
  "textVerbosity": "low"
370
316
  },
371
317
  "medium": {
372
- "include": [
373
- "reasoning.encrypted_content"
374
- ],
318
+ "include": ["reasoning.encrypted_content"],
375
319
  "reasoningEffort": "medium",
376
320
  "reasoningSummary": "auto",
377
321
  "textVerbosity": "low"
@@ -402,14 +346,8 @@
402
346
  },
403
347
  "name": "Gemini 2 5 Computer Use Preview 10 2025",
404
348
  "modalities": {
405
- "input": [
406
- "text",
407
- "image",
408
- "pdf"
409
- ],
410
- "output": [
411
- "text"
412
- ]
349
+ "input": ["text", "image", "pdf"],
350
+ "output": ["text"]
413
351
  }
414
352
  },
415
353
  "gemini-2.5-flash": {
@@ -419,14 +357,8 @@
419
357
  },
420
358
  "name": "Gemini 2 5 Flash",
421
359
  "modalities": {
422
- "input": [
423
- "text",
424
- "image",
425
- "pdf"
426
- ],
427
- "output": [
428
- "text"
429
- ]
360
+ "input": ["text", "image", "pdf"],
361
+ "output": ["text"]
430
362
  }
431
363
  },
432
364
  "gemini-2.5-flash-lite": {
@@ -436,14 +368,8 @@
436
368
  },
437
369
  "name": "Gemini 2 5 Flash Lite",
438
370
  "modalities": {
439
- "input": [
440
- "text",
441
- "image",
442
- "pdf"
443
- ],
444
- "output": [
445
- "text"
446
- ]
371
+ "input": ["text", "image", "pdf"],
372
+ "output": ["text"]
447
373
  }
448
374
  },
449
375
  "gemini-2.5-pro": {
@@ -453,14 +379,8 @@
453
379
  },
454
380
  "name": "Gemini 2 5 Pro",
455
381
  "modalities": {
456
- "input": [
457
- "text",
458
- "image",
459
- "pdf"
460
- ],
461
- "output": [
462
- "text"
463
- ]
382
+ "input": ["text", "image", "pdf"],
383
+ "output": ["text"]
464
384
  }
465
385
  },
466
386
  "gemini-3-flash-preview": {
@@ -470,14 +390,8 @@
470
390
  },
471
391
  "name": "Gemini 3 Flash Preview",
472
392
  "modalities": {
473
- "input": [
474
- "text",
475
- "image",
476
- "pdf"
477
- ],
478
- "output": [
479
- "text"
480
- ]
393
+ "input": ["text", "image", "pdf"],
394
+ "output": ["text"]
481
395
  },
482
396
  "variants": {
483
397
  "low": {
@@ -499,14 +413,8 @@
499
413
  },
500
414
  "name": "Gemini 3 Pro Image Preview",
501
415
  "modalities": {
502
- "input": [
503
- "text",
504
- "image",
505
- "pdf"
506
- ],
507
- "output": [
508
- "text"
509
- ]
416
+ "input": ["text", "image", "pdf"],
417
+ "output": ["text"]
510
418
  }
511
419
  },
512
420
  "gemini-3-pro-preview": {
@@ -516,14 +424,8 @@
516
424
  },
517
425
  "name": "Gemini 3 Pro Preview",
518
426
  "modalities": {
519
- "input": [
520
- "text",
521
- "image",
522
- "pdf"
523
- ],
524
- "output": [
525
- "text"
526
- ]
427
+ "input": ["text", "image", "pdf"],
428
+ "output": ["text"]
527
429
  },
528
430
  "variants": {
529
431
  "low": {
@@ -541,14 +443,8 @@
541
443
  "output": 64000
542
444
  },
543
445
  "modalities": {
544
- "input": [
545
- "text",
546
- "image",
547
- "pdf"
548
- ],
549
- "output": [
550
- "text"
551
- ]
446
+ "input": ["text", "image", "pdf"],
447
+ "output": ["text"]
552
448
  },
553
449
  "name": "Gemini Claude Opus 4 5 Thinking",
554
450
  "variants": {
@@ -571,14 +467,8 @@
571
467
  "output": 64000
572
468
  },
573
469
  "modalities": {
574
- "input": [
575
- "text",
576
- "image",
577
- "pdf"
578
- ],
579
- "output": [
580
- "text"
581
- ]
470
+ "input": ["text", "image", "pdf"],
471
+ "output": ["text"]
582
472
  },
583
473
  "name": "Gemini Claude Sonnet 4 5"
584
474
  },
@@ -588,14 +478,8 @@
588
478
  "output": 64000
589
479
  },
590
480
  "modalities": {
591
- "input": [
592
- "text",
593
- "image",
594
- "pdf"
595
- ],
596
- "output": [
597
- "text"
598
- ]
481
+ "input": ["text", "image", "pdf"],
482
+ "output": ["text"]
599
483
  },
600
484
  "name": "Gemini Claude Sonnet 4 5 Thinking",
601
485
  "variants": {
@@ -38,7 +38,16 @@ If memory returns high-confidence findings on this exact topic, synthesize and r
38
38
  | Priority | Tool | Use Case | Speed |
39
39
  |----------|------|----------|-------|
40
40
  | 1 | memory-search | Past research findings | Instant |
41
- | 2 | context7 | Official library docs | Fast |
41
+ | Priority | Tool | Use Case | Speed |
42
+ |----------|------|----------|-------|
43
+ | 1 | memory-search | Past research findings | Instant |
44
+ | 2 | context7_resolve-library-id | Resolve library names to IDs | Fast |
45
+ | 3 | context7_query-docs | Official library docs | Fast |
46
+ | 4 | codesearch | Exa Code API for SDK/library patterns | Fast |
47
+ | 5 | grep-search | Cross-repo GitHub code search | Medium |
48
+ | 6 | webfetch | Specific doc URLs, READMEs, changelogs | Medium |
49
+ | 7 | opensrc + LSP | Clone & analyze source code | Slow |
50
+ | 8 | websearch | Tutorials, blog posts, recent news | Slow |
42
51
  | 3 | codesearch | Usage patterns in real code | Fast |
43
52
  | 4 | gh_grep | Cross-repo deep code search | Medium |
44
53
  | 5 | webfetch | Specific doc URLs, READMEs, changelogs | Medium |
@@ -76,7 +85,8 @@ webfetch({ url: "https://docs.example.com/api/authentication", format: "markdown
76
85
  **When to use:**
77
86
 
78
87
  - User provides a specific URL
79
- - context7 returns a doc link worth fetching
88
+ - context7_resolve-library-id returns a library ID
89
+ - context7_query-docs returns a doc link worth fetching
80
90
  - Need CHANGELOG or release notes
81
91
  - GitHub README has details not in context7
82
92
 
@@ -362,20 +362,20 @@ If opensrc doesn't work:
362
362
 
363
363
  Source code research complements other tools:
364
364
 
365
- | Method | Best For | Source Code Adds |
366
- | -------------- | -------------------------- | ------------------------------ |
367
- | **Context7** | API docs, official guides | Implementation details |
368
- | **codesearch** | Usage patterns in the wild | Canonical implementation |
369
- | **gh_grep** | Real-world examples | How library itself works |
370
- | **Web search** | Tutorials, blog posts | Ground truth from source |
371
- | **Codebase** | Project-specific patterns | How dependencies actually work |
365
+ | Method | Best For | Source Code Adds |
366
+ | --------------- | -------------------------- | ------------------------------ |
367
+ | **Context7** | API docs, official guides | Implementation details |
368
+ | **codesearch** | Usage patterns in the wild | Canonical implementation |
369
+ | **grep_search** | Real-world examples | How library itself works |
370
+ | **Web search** | Tutorials, blog posts | Ground truth from source |
371
+ | **Codebase** | Project-specific patterns | How dependencies actually work |
372
372
 
373
373
  **Recommended flow:**
374
374
 
375
375
  1. Context7 - Check official docs
376
376
  2. Codebase - Check existing usage
377
377
  3. **Source code** - If still unclear, fetch source
378
- 4. codesearch/gh_grep - See how others use it
378
+ 4. codesearch/grep_search - See how others use it
379
379
  5. Web search - Last resort for context
380
380
 
381
381
  ## Cleanup
@@ -180,9 +180,11 @@ glob ["src/**/*.ts", "tests/**/*.ts"]
180
180
 
181
181
  ## Research Tools
182
182
 
183
- | Tool | Use When |
184
- | -------------- | ------------------------------------------------------- |
185
- | **context7** | Library docs (try first). Fast, external APIs. |
186
- | **websearch** | Docs not in Context7, recent releases, troubleshooting. |
187
- | **codesearch** | Real implementation patterns from GitHub. |
188
- | **webfetch** | Specific URL user provided. |
183
+ | Tool | Use When |
184
+ | ------------------------------- | ------------------------------------------------------- |
185
+ | **context7_resolve-library-id** | Resolve library names to IDs (try first). |
186
+ | **context7_query-docs** | Query official library documentation. Fast. |
187
+ | **websearch** | Docs not in Context7, recent releases, troubleshooting. |
188
+ | **codesearch** | Real implementation patterns from GitHub. |
189
+ | **grep-search** | Cross-repo code patterns via grep.app. |
190
+ | **webfetch** | Specific URL user provided. |
@@ -0,0 +1,89 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+
3
+ // Context7 API v2 - https://context7.com/docs/api-guide
4
+ const CONTEXT7_API = "https://context7.com/api/v2";
5
+
6
+ export default tool({
7
+ description: `Query library documentation from Context7 using a library ID.
8
+
9
+ Use when:
10
+ - You have a library ID (from context7_resolve_library_id)
11
+ - Need specific documentation about a library feature
12
+ - Looking for API reference, examples, or setup instructions
13
+
14
+ Always resolve library name to ID first with context7_resolve_library_id!
15
+
16
+ Examples:
17
+ context7_query_docs({ libraryId: "/reactjs/react.dev", topic: "hooks" })
18
+ context7_query_docs({ libraryId: "/vercel/next.js", topic: "middleware" })
19
+ context7_query_docs({ libraryId: "/microsoft/TypeScript", topic: "generics" })
20
+ `,
21
+ args: {
22
+ libraryId: tool.schema
23
+ .string()
24
+ .describe(
25
+ "Library ID from context7_resolve_library_id (e.g., '/reactjs/react.dev')",
26
+ ),
27
+ topic: tool.schema
28
+ .string()
29
+ .describe("Documentation topic or feature to search for"),
30
+ },
31
+ execute: async (args) => {
32
+ const { libraryId, topic } = args;
33
+
34
+ if (!libraryId || libraryId.trim() === "") {
35
+ return "Error: libraryId is required (use context7-resolve-library-id first)";
36
+ }
37
+
38
+ if (!topic || topic.trim() === "") {
39
+ return "Error: topic is required (e.g., 'hooks', 'setup', 'API reference')";
40
+ }
41
+
42
+ try {
43
+ // Query Context7 documentation - GET /api/v2/context
44
+ // Returns text format by default which is better for LLM consumption
45
+ const url = new URL(`${CONTEXT7_API}/context`);
46
+ url.searchParams.set("libraryId", libraryId);
47
+ url.searchParams.set("query", topic);
48
+
49
+ // Add API key if available (recommended for higher rate limits)
50
+ const apiKey = process.env.CONTEXT7_API_KEY;
51
+ const headers: HeadersInit = {
52
+ Accept: "text/plain",
53
+ "User-Agent": "OpenCode/1.0",
54
+ };
55
+
56
+ if (apiKey) {
57
+ headers.Authorization = `Bearer ${apiKey}`;
58
+ }
59
+
60
+ const response = await fetch(url.toString(), { headers });
61
+
62
+ if (!response.ok) {
63
+ if (response.status === 401) {
64
+ return `Error: Invalid CONTEXT7_API_KEY. Get a free key at https://context7.com/dashboard`;
65
+ }
66
+ if (response.status === 404) {
67
+ return `Error: Library not found: ${libraryId}\n\nUse context7-resolve-library-id first to find the correct ID.`;
68
+ }
69
+ if (response.status === 429) {
70
+ return `Error: Rate limit exceeded. Get a free API key at https://context7.com/dashboard for higher limits.`;
71
+ }
72
+ return `Error: Context7 API returned ${response.status}`;
73
+ }
74
+
75
+ const content = await response.text();
76
+
77
+ if (!content || content.trim() === "") {
78
+ return `No documentation found for "${topic}" in ${libraryId}.\n\nTry:\n- Simpler terms (e.g., "useState" instead of "state management")\n- Different topic spelling\n- Broader topics like "API reference" or "getting started"`;
79
+ }
80
+
81
+ return `# Documentation: ${topic} (${libraryId})
82
+
83
+ ${content}`;
84
+ } catch (error: unknown) {
85
+ const message = error instanceof Error ? error.message : String(error);
86
+ return `Error querying documentation: ${message}`;
87
+ }
88
+ },
89
+ });
@@ -0,0 +1,113 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+
3
+ // Context7 API v2 - https://context7.com/docs/api-guide
4
+ const CONTEXT7_API = "https://context7.com/api/v2";
5
+
6
+ interface LibraryInfo {
7
+ id: string;
8
+ title: string;
9
+ description?: string;
10
+ totalSnippets?: number;
11
+ trustScore?: number;
12
+ benchmarkScore?: number;
13
+ versions?: string[];
14
+ }
15
+
16
+ interface SearchResponse {
17
+ results: LibraryInfo[];
18
+ }
19
+
20
+ export default tool({
21
+ description: `Resolve a library name to its Context7 ID for documentation lookup.
22
+
23
+ Use when:
24
+ - You need to find the exact library ID format for a package
25
+ - Starting a documentation search (get the ID first, then query docs)
26
+ - Normalizing library names (e.g., "react" → "/reactjs/react.dev")
27
+
28
+ Examples:
29
+ context7_resolve_library_id({ libraryName: "react" })
30
+ context7_resolve_library_id({ libraryName: "vue", query: "composition API" })
31
+ context7_resolve_library_id({ libraryName: "nextjs" })
32
+ `,
33
+ args: {
34
+ libraryName: tool.schema
35
+ .string()
36
+ .describe(
37
+ "Library name to resolve (e.g., 'react', 'lodash', 'typescript')",
38
+ ),
39
+ query: tool.schema
40
+ .string()
41
+ .optional()
42
+ .describe("Optional context for the search (improves relevance ranking)"),
43
+ },
44
+ execute: async (args) => {
45
+ const { libraryName, query = "documentation" } = args;
46
+
47
+ if (!libraryName || libraryName.trim() === "") {
48
+ return "Error: libraryName is required";
49
+ }
50
+
51
+ try {
52
+ // Query Context7 library search - GET /api/v2/libs/search
53
+ const url = new URL(`${CONTEXT7_API}/libs/search`);
54
+ url.searchParams.set("libraryName", libraryName);
55
+ url.searchParams.set("query", query);
56
+
57
+ // Add API key if available (recommended for higher rate limits)
58
+ const apiKey = process.env.CONTEXT7_API_KEY;
59
+ const headers: HeadersInit = {
60
+ Accept: "application/json",
61
+ "User-Agent": "OpenCode/1.0",
62
+ };
63
+
64
+ if (apiKey) {
65
+ headers.Authorization = `Bearer ${apiKey}`;
66
+ }
67
+
68
+ const response = await fetch(url.toString(), { headers });
69
+
70
+ if (!response.ok) {
71
+ if (response.status === 401) {
72
+ return `Error: Invalid CONTEXT7_API_KEY. Get a free key at https://context7.com/dashboard`;
73
+ }
74
+ if (response.status === 429) {
75
+ return `Error: Rate limit exceeded. Get a free API key at https://context7.com/dashboard for higher limits.`;
76
+ }
77
+ return `Error: Context7 API returned ${response.status}`;
78
+ }
79
+
80
+ const data = (await response.json()) as SearchResponse;
81
+ const libraries = data.results || [];
82
+
83
+ if (!libraries || libraries.length === 0) {
84
+ return `No libraries found matching: ${libraryName}\n\nTry:\n- Different library name\n- Check spelling\n- Use official package name`;
85
+ }
86
+
87
+ const formatted = libraries
88
+ .slice(0, 5)
89
+ .map((lib, i) => {
90
+ const desc = lib.description
91
+ ? `\n ${lib.description.slice(0, 100)}...`
92
+ : "";
93
+ const snippets = lib.totalSnippets
94
+ ? ` (${lib.totalSnippets} snippets)`
95
+ : "";
96
+ const score = lib.benchmarkScore
97
+ ? ` [score: ${lib.benchmarkScore}]`
98
+ : "";
99
+ return `${i + 1}. **${lib.title}** → \`${lib.id}\`${snippets}${score}${desc}`;
100
+ })
101
+ .join("\n\n");
102
+
103
+ return `Found ${libraries.length} libraries matching "${libraryName}":
104
+
105
+ ${formatted}
106
+
107
+ **Next step**: Use \`context7-query-docs({ libraryId: "${libraries[0].id}", topic: "your topic" })\` to fetch documentation.`;
108
+ } catch (error: unknown) {
109
+ const message = error instanceof Error ? error.message : String(error);
110
+ return `Error resolving library: ${message}`;
111
+ }
112
+ },
113
+ });
@@ -0,0 +1,135 @@
1
+ import { tool } from "@opencode-ai/plugin";
2
+
3
+ const GREP_APP_API = "https://grep.app/api/search";
4
+
5
+ interface SearchResult {
6
+ repo: string;
7
+ path: string;
8
+ content: { snippet: string };
9
+ total_matches: string;
10
+ }
11
+
12
+ interface GrepResponse {
13
+ hits: { hits: SearchResult[] };
14
+ time: number;
15
+ }
16
+
17
+ export default tool({
18
+ description: `Search real-world code examples from GitHub repositories via grep.app.
19
+
20
+ Use when:
21
+ - Implementing unfamiliar APIs - see how others use a library
22
+ - Looking for production patterns - find real-world examples
23
+ - Understanding library integrations - see how things work together
24
+
25
+ IMPORTANT: Search for **literal code patterns**, not keywords:
26
+ ✅ Good: "useState(", "import React from", "async function"
27
+ ❌ Bad: "react tutorial", "best practices", "how to use"
28
+
29
+ Examples:
30
+ grep_search({ query: "getServerSession", language: "TypeScript" })
31
+ grep_search({ query: "CORS(", language: "Python", repo: "flask" })
32
+ grep_search({ query: "export async function POST", path: "route.ts" })
33
+ `,
34
+ args: {
35
+ query: tool.schema
36
+ .string()
37
+ .describe("Code pattern to search for (literal text)"),
38
+ language: tool.schema
39
+ .string()
40
+ .optional()
41
+ .describe("Filter by language: TypeScript, TSX, Python, Go, Rust, etc."),
42
+ repo: tool.schema
43
+ .string()
44
+ .optional()
45
+ .describe("Filter by repo: 'owner/repo' or partial match"),
46
+ path: tool.schema
47
+ .string()
48
+ .optional()
49
+ .describe("Filter by file path: 'src/', '.test.ts', etc."),
50
+ limit: tool.schema
51
+ .number()
52
+ .optional()
53
+ .describe("Max results to return (default: 10, max: 20)"),
54
+ },
55
+ execute: async (args) => {
56
+ const { query, language, repo, path, limit = 10 } = args;
57
+
58
+ if (!query || query.trim() === "") {
59
+ return "Error: query is required";
60
+ }
61
+
62
+ // Build URL with proper filter parameters
63
+ // grep.app uses filter[lang][0]=TypeScript format, NOT inline lang:TypeScript
64
+ const url = new URL(GREP_APP_API);
65
+ url.searchParams.set("q", query);
66
+
67
+ // Add language filter (grep.app uses filter[lang][0] format)
68
+ if (language) {
69
+ url.searchParams.set("filter[lang][0]", language);
70
+ }
71
+
72
+ // Add repo filter
73
+ if (repo) {
74
+ url.searchParams.set("filter[repo][0]", repo);
75
+ }
76
+
77
+ // Add path filter
78
+ if (path) {
79
+ url.searchParams.set("filter[path][0]", path);
80
+ }
81
+
82
+ try {
83
+ const response = await fetch(url.toString(), {
84
+ headers: {
85
+ Accept: "application/json",
86
+ "User-Agent": "OpenCode/1.0",
87
+ },
88
+ });
89
+
90
+ if (!response.ok) {
91
+ return `Error: grep.app API returned ${response.status}`;
92
+ }
93
+
94
+ const data = (await response.json()) as GrepResponse;
95
+
96
+ if (!data.hits?.hits?.length) {
97
+ return `No results found for: ${query}${language ? ` (${language})` : ""}`;
98
+ }
99
+
100
+ const maxResults = Math.min(limit, 20);
101
+ const results = data.hits.hits.slice(0, maxResults);
102
+
103
+ const formatted = results.map((hit, i) => {
104
+ const repoName = hit.repo || "unknown";
105
+ const filePath = hit.path || "unknown";
106
+ const snippet = hit.content?.snippet || "";
107
+
108
+ // Clean up HTML from snippet and extract text
109
+ const cleanCode = snippet
110
+ .replace(/<[^>]*>/g, "") // Remove HTML tags
111
+ .replace(/&lt;/g, "<")
112
+ .replace(/&gt;/g, ">")
113
+ .replace(/&amp;/g, "&")
114
+ .replace(/&quot;/g, '"')
115
+ .split("\n")
116
+ .slice(0, 8)
117
+ .join("\n")
118
+ .trim();
119
+
120
+ return `## ${i + 1}. ${repoName}
121
+ **File**: ${filePath}
122
+ \`\`\`
123
+ ${cleanCode}
124
+ \`\`\``;
125
+ });
126
+
127
+ return `Found ${data.hits.hits.length} results (showing ${results.length}) in ${data.time}ms:
128
+
129
+ ${formatted.join("\n\n")}`;
130
+ } catch (error: unknown) {
131
+ const message = error instanceof Error ? error.message : String(error);
132
+ return `Error searching grep.app: ${message}`;
133
+ }
134
+ },
135
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencodekit",
3
- "version": "0.15.12",
3
+ "version": "0.15.13",
4
4
  "description": "CLI tool for bootstrapping and managing OpenCodeKit projects",
5
5
  "keywords": ["agents", "cli", "mcp", "opencode", "opencodekit", "template"],
6
6
  "license": "MIT",