opencodekit 0.23.2 → 0.23.3

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.
@@ -3,19 +3,19 @@ import { tool } from "@opencode-ai/plugin";
3
3
  const GREP_APP_API = "https://grep.app/api/search";
4
4
 
5
5
  interface SearchResult {
6
- repo: string;
7
- path: string;
8
- content: { snippet: string };
9
- total_matches: string;
6
+ repo: string;
7
+ path: string;
8
+ content: { snippet: string };
9
+ total_matches: string;
10
10
  }
11
11
 
12
12
  interface GrepResponse {
13
- hits: { hits: SearchResult[] };
14
- time: number;
13
+ hits: { hits: SearchResult[] };
14
+ time: number;
15
15
  }
16
16
 
17
17
  export default tool({
18
- description: `Search real-world code examples from GitHub repositories via grep.app. Replaces asking "how do others use X?" — use this for finding production patterns and real-world API usage.
18
+ description: `Search real-world code examples from GitHub repositories via grep.app. Replaces asking "how do others use X?" — use this for finding production patterns and real-world API usage.
19
19
 
20
20
  WHEN: Implementing unfamiliar APIs, looking for production patterns, understanding library integrations.
21
21
  SKIP: Searching your own codebase (use grep/srcwalk), looking up docs (use context7), general research (use websearch).
@@ -31,113 +31,102 @@ Use when:
31
31
  - Understanding library integrations - see how things work together
32
32
 
33
33
  IMPORTANT: Search for **literal code patterns**, not keywords:
34
- Good: "useState(", "import React from", "async function"
35
- ❌ Bad: "react tutorial", "best practices", "how to use"
34
+ Good: "useState(", "import React from", "async function"
36
35
 
36
+ Bad: "react tutorial", "best practices", "how to use"
37
37
  Examples:
38
38
  grepsearch({ query: "getServerSession", language: "TypeScript" })
39
39
  grepsearch({ query: "CORS(", language: "Python", repo: "flask" })
40
40
  grepsearch({ query: "export async function POST", path: "route.ts" })
41
41
  `,
42
- args: {
43
- query: tool.schema
44
- .string()
45
- .describe("Code pattern to search for (literal text)"),
46
- language: tool.schema
47
- .string()
48
- .optional()
49
- .describe("Filter by language: TypeScript, TSX, Python, Go, Rust, etc."),
50
- repo: tool.schema
51
- .string()
52
- .optional()
53
- .describe("Filter by repo: 'owner/repo' or partial match"),
54
- path: tool.schema
55
- .string()
56
- .optional()
57
- .describe("Filter by file path: 'src/', '.test.ts', etc."),
58
- limit: tool.schema
59
- .number()
60
- .optional()
61
- .describe("Max results to return (default: 10, max: 20)"),
62
- },
63
- execute: async (args) => {
64
- const { query, language, repo, path, limit = 10 } = args;
65
-
66
- if (!query || query.trim() === "") {
67
- return "Error: query is required";
68
- }
69
-
70
- // Build URL with proper filter parameters
71
- // grep.app uses filter[lang][0]=TypeScript format, NOT inline lang:TypeScript
72
- const url = new URL(GREP_APP_API);
73
- url.searchParams.set("q", query);
74
-
75
- // Add language filter (grep.app uses filter[lang][0] format)
76
- if (language) {
77
- url.searchParams.set("filter[lang][0]", language);
78
- }
79
-
80
- // Add repo filter
81
- if (repo) {
82
- url.searchParams.set("filter[repo][0]", repo);
83
- }
84
-
85
- // Add path filter
86
- if (path) {
87
- url.searchParams.set("filter[path][0]", path);
88
- }
89
-
90
- try {
91
- const response = await fetch(url.toString(), {
92
- headers: {
93
- Accept: "application/json",
94
- "User-Agent": "OpenCode/1.0",
95
- },
96
- });
97
-
98
- if (!response.ok) {
99
- return `Error: grep.app API returned ${response.status}`;
100
- }
101
-
102
- const data = (await response.json()) as GrepResponse;
103
-
104
- if (!data.hits?.hits?.length) {
105
- return `No results found for: ${query}${language ? ` (${language})` : ""}`;
106
- }
107
-
108
- const maxResults = Math.min(limit, 20);
109
- const results = data.hits.hits.slice(0, maxResults);
110
-
111
- const formatted = results.map((hit, i) => {
112
- const repoName = hit.repo || "unknown";
113
- const filePath = hit.path || "unknown";
114
- const snippet = hit.content?.snippet || "";
115
-
116
- // Clean up HTML from snippet and extract text
117
- const cleanCode = snippet
118
- .replace(/<[^>]*>/g, "") // Remove HTML tags
119
- .replace(/&lt;/g, "<")
120
- .replace(/&gt;/g, ">")
121
- .replace(/&amp;/g, "&")
122
- .replace(/&quot;/g, '"')
123
- .split("\n")
124
- .slice(0, 8)
125
- .join("\n")
126
- .trim();
127
-
128
- return `## ${i + 1}. ${repoName}
42
+ args: {
43
+ query: tool.schema.string().describe("Code pattern to search for (literal text)"),
44
+ language: tool.schema
45
+ .string()
46
+ .optional()
47
+ .describe("Filter by language: TypeScript, TSX, Python, Go, Rust, etc."),
48
+ repo: tool.schema.string().optional().describe("Filter by repo: 'owner/repo' or partial match"),
49
+ path: tool.schema.string().optional().describe("Filter by file path: 'src/', '.test.ts', etc."),
50
+ limit: tool.schema.number().optional().describe("Max results to return (default: 10, max: 20)"),
51
+ },
52
+ execute: async (args) => {
53
+ const { query, language, repo, path, limit = 10 } = args;
54
+
55
+ if (!query || query.trim() === "") {
56
+ return "Error: query is required";
57
+ }
58
+
59
+ // Build URL with proper filter parameters
60
+ // grep.app uses filter[lang][0]=TypeScript format, NOT inline lang:TypeScript
61
+ const url = new URL(GREP_APP_API);
62
+ url.searchParams.set("q", query);
63
+
64
+ // Add language filter (grep.app uses filter[lang][0] format)
65
+ if (language) {
66
+ url.searchParams.set("filter[lang][0]", language);
67
+ }
68
+
69
+ // Add repo filter
70
+ if (repo) {
71
+ url.searchParams.set("filter[repo][0]", repo);
72
+ }
73
+
74
+ // Add path filter
75
+ if (path) {
76
+ url.searchParams.set("filter[path][0]", path);
77
+ }
78
+
79
+ try {
80
+ const response = await fetch(url.toString(), {
81
+ headers: {
82
+ Accept: "application/json",
83
+ "User-Agent": "OpenCode/1.0",
84
+ },
85
+ });
86
+
87
+ if (!response.ok) {
88
+ return `Error: grep.app API returned ${response.status}`;
89
+ }
90
+
91
+ const data = (await response.json()) as GrepResponse;
92
+
93
+ if (!data.hits?.hits?.length) {
94
+ return `No results found for: ${query}${language ? ` (${language})` : ""}`;
95
+ }
96
+
97
+ const maxResults = Math.min(limit, 20);
98
+ const results = data.hits.hits.slice(0, maxResults);
99
+
100
+ const formatted = results.map((hit, i) => {
101
+ const repoName = hit.repo || "unknown";
102
+ const filePath = hit.path || "unknown";
103
+ const snippet = hit.content?.snippet || "";
104
+
105
+ // Clean up HTML from snippet and extract text
106
+ const cleanCode = snippet
107
+ .replace(/<[^>]*>/g, "") // Remove HTML tags
108
+ .replace(/&lt;/g, "<")
109
+ .replace(/&gt;/g, ">")
110
+ .replace(/&amp;/g, "&")
111
+ .replace(/&quot;/g, '"')
112
+ .split("\n")
113
+ .slice(0, 8)
114
+ .join("\n")
115
+ .trim();
116
+
117
+ return `## ${i + 1}. ${repoName}
129
118
  **File**: ${filePath}
130
119
  \`\`\`
131
120
  ${cleanCode}
132
121
  \`\`\``;
133
- });
122
+ });
134
123
 
135
- return `Found ${data.hits.hits.length} results (showing ${results.length}) in ${data.time}ms:
124
+ return `Found ${data.hits.hits.length} results (showing ${results.length}) in ${data.time}ms:
136
125
 
137
126
  ${formatted.join("\n\n")}`;
138
- } catch (error: unknown) {
139
- const message = error instanceof Error ? error.message : String(error);
140
- return `Error searching grep.app: ${message}`;
141
- }
142
- },
127
+ } catch (error: unknown) {
128
+ const message = error instanceof Error ? error.message : String(error);
129
+ return `Error searching grep.app: ${message}`;
130
+ }
131
+ },
143
132
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencodekit",
3
- "version": "0.23.2",
3
+ "version": "0.23.3",
4
4
  "description": "CLI tool for bootstrapping and managing OpenCodeKit projects",
5
5
  "keywords": [
6
6
  "agents",