grepmax 0.11.2 → 0.11.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.
|
@@ -19,7 +19,8 @@ const node_os_1 = __importDefault(require("node:os"));
|
|
|
19
19
|
const node_path_1 = __importDefault(require("node:path"));
|
|
20
20
|
const commander_1 = require("commander");
|
|
21
21
|
const TOOL_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".config", "opencode", "tool", "gmax.ts");
|
|
22
|
-
const PLUGIN_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".config", "opencode", "
|
|
22
|
+
const PLUGIN_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".config", "opencode", "plugins", "gmax.ts");
|
|
23
|
+
const LEGACY_PLUGIN_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".config", "opencode", "plugin", "gmax.ts");
|
|
23
24
|
const CONFIG_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".config", "opencode", "opencode.json");
|
|
24
25
|
function resolveGmaxBin() {
|
|
25
26
|
try {
|
|
@@ -42,85 +43,65 @@ const SKILL = \`
|
|
|
42
43
|
---
|
|
43
44
|
name: gmax
|
|
44
45
|
description: Semantic code search. Use alongside grep - grep for exact strings, gmax for concepts.
|
|
45
|
-
allowed-tools: "Bash(gmax:*), Read"
|
|
46
46
|
---
|
|
47
47
|
|
|
48
|
-
##
|
|
48
|
+
## When to use what
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
50
|
+
- **Know the exact string/symbol?** → grep/ripgrep (fastest)
|
|
51
|
+
- **Know the file already?** → Read tool directly
|
|
52
|
+
- **Searching by concept/behavior?** → gmax "query" --agent (semantic search)
|
|
53
|
+
- **Need full function body?** → gmax extract <symbol> (complete source)
|
|
54
|
+
- **Quick symbol overview?** → gmax peek <symbol> (signature + callers + callees)
|
|
55
|
+
- **Need file structure?** → gmax skeleton <path>
|
|
56
|
+
- **Need call flow?** → gmax trace <symbol>
|
|
54
57
|
|
|
55
58
|
## Primary command
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Returns ~10 results with code snippets (15+ lines each). Usually enough to understand what's happening.
|
|
61
|
-
|
|
62
|
-
## Output explained
|
|
63
|
-
|
|
64
|
-
ORCHESTRATION src/auth/handler.ts:45
|
|
65
|
-
Defines: handleAuth | Calls: validate, checkRole, respond | Score: .94
|
|
66
|
-
|
|
67
|
-
export async function handleAuth(req: Request) {
|
|
68
|
-
const token = req.headers.get("Authorization");
|
|
69
|
-
const claims = await validateToken(token);
|
|
70
|
-
if (!claims) return unauthorized();
|
|
71
|
-
const allowed = await checkRole(claims.role, req.path);
|
|
72
|
-
...
|
|
73
|
-
|
|
74
|
-
- **ORCHESTRATION** = contains logic, coordinates other code
|
|
75
|
-
- **DEFINITION** = types, interfaces, classes
|
|
76
|
-
- **Score** = relevance (1 = best match)
|
|
77
|
-
- **Calls** = what this code calls (helps you trace flow)
|
|
78
|
-
|
|
79
|
-
## When to Read more
|
|
80
|
-
|
|
81
|
-
The snippet often has enough context. But if you need more:
|
|
82
|
-
|
|
83
|
-
# gmax found src/auth/handler.ts:45-90 as ORCH
|
|
84
|
-
Read src/auth/handler.ts:45-120
|
|
60
|
+
Use --agent for compact, token-efficient output (one line per result):
|
|
85
61
|
|
|
62
|
+
gmax "where do we handle authentication" --agent
|
|
63
|
+
gmax "database connection pooling" --role ORCHESTRATION --agent -m 5
|
|
64
|
+
gmax "error handling" --lang ts --exclude tests/ --agent
|
|
86
65
|
|
|
87
|
-
|
|
66
|
+
Output: file:line symbol [ROLE] — signature_hint
|
|
88
67
|
|
|
89
|
-
|
|
68
|
+
All search flags: --agent -m <n> --per-file <n> --root <dir> --file <name> --exclude <prefix> --lang <ext> --role <role> --symbol --imports --name <regex> -C <n> --skeleton --explain --context-for-llm --budget <tokens>
|
|
90
69
|
|
|
91
|
-
|
|
92
|
-
gmax trace handleAuth
|
|
70
|
+
## Commands
|
|
93
71
|
|
|
94
|
-
|
|
95
|
-
gmax
|
|
72
|
+
### Core
|
|
73
|
+
gmax "query" --agent # semantic search (compact output)
|
|
74
|
+
gmax extract <symbol> # full function body with line numbers
|
|
75
|
+
gmax peek <symbol> # signature + callers + callees
|
|
76
|
+
gmax trace <symbol> -d 2 # call graph (multi-hop)
|
|
77
|
+
gmax skeleton <path> # file structure (signatures only)
|
|
78
|
+
gmax symbols --agent # list all indexed symbols
|
|
96
79
|
|
|
97
|
-
|
|
98
|
-
gmax
|
|
80
|
+
### Analysis
|
|
81
|
+
gmax diff [ref] --agent # search scoped to git changes
|
|
82
|
+
gmax test <symbol> --agent # find tests via reverse call graph
|
|
83
|
+
gmax impact <symbol> --agent # dependents + affected tests
|
|
84
|
+
gmax similar <symbol> --agent # vector-to-vector similarity
|
|
85
|
+
gmax context "topic" --budget 4k # token-budgeted topic summary
|
|
99
86
|
|
|
87
|
+
### Project
|
|
88
|
+
gmax project --agent # languages, structure, key symbols
|
|
89
|
+
gmax related <file> --agent # dependencies + dependents
|
|
90
|
+
gmax recent --agent # recently modified files
|
|
91
|
+
gmax status --agent # all indexed projects
|
|
100
92
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
#
|
|
104
|
-
gmax
|
|
105
|
-
# Review the ORCH results - code is shown
|
|
106
|
-
|
|
107
|
-
# 2. If you need deeper context on a specific function
|
|
108
|
-
Read src/server/handler.ts:45-120
|
|
109
|
-
|
|
110
|
-
# 3. Trace to understand call flow
|
|
111
|
-
gmax trace handleRequest
|
|
93
|
+
### Management
|
|
94
|
+
gmax add # add + index current directory
|
|
95
|
+
gmax index # reindex current project
|
|
96
|
+
gmax doctor --fix # health check + auto-repair
|
|
112
97
|
|
|
113
98
|
## Tips
|
|
114
99
|
|
|
115
|
-
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
|
|
120
|
-
## If Index is Building
|
|
121
|
-
|
|
122
|
-
If you see "Indexing" or "Syncing": STOP. Tell the user the index is building. Ask if they want to wait or proceed with partial results.
|
|
123
|
-
|
|
100
|
+
- Be specific. "auth" is vague. "where does the server validate JWT tokens" is specific.
|
|
101
|
+
- Use --role ORCHESTRATION to skip type definitions and find actual logic.
|
|
102
|
+
- Use --symbol when the query is a function/class name — gets search + trace in one shot.
|
|
103
|
+
- Don't search for exact strings — use grep for that. gmax finds concepts.
|
|
104
|
+
- If search returns nothing, run: gmax add
|
|
124
105
|
\`;
|
|
125
106
|
|
|
126
107
|
const GMAX_BIN = "${gmaxBin}";
|
|
@@ -129,7 +110,7 @@ export default tool({
|
|
|
129
110
|
description: SKILL,
|
|
130
111
|
args: {
|
|
131
112
|
argv: tool.schema.array(tool.schema.string())
|
|
132
|
-
.describe("Arguments for gmax, e.g. ['search', 'user auth']")
|
|
113
|
+
.describe("Arguments for gmax, e.g. ['search', 'user auth', '--agent']")
|
|
133
114
|
},
|
|
134
115
|
async execute({ argv }) {
|
|
135
116
|
try {
|
|
@@ -142,7 +123,7 @@ export default tool({
|
|
|
142
123
|
Output so far:
|
|
143
124
|
\${text.trim()}
|
|
144
125
|
|
|
145
|
-
|
|
126
|
+
Please wait for indexing to complete before searching.\`;
|
|
146
127
|
}
|
|
147
128
|
return text.trim();
|
|
148
129
|
} catch (err) {
|
|
@@ -151,17 +132,62 @@ PLEASE READ THE "Indexing" WARNING IN MY SKILL DESCRIPTION.\`;
|
|
|
151
132
|
},
|
|
152
133
|
})`;
|
|
153
134
|
}
|
|
135
|
+
function buildPluginContent(gmaxBin) {
|
|
136
|
+
return `import { execFileSync } from "node:child_process";
|
|
137
|
+
import { readFileSync } from "node:fs";
|
|
138
|
+
import { join } from "node:path";
|
|
139
|
+
import { homedir } from "node:os";
|
|
140
|
+
|
|
141
|
+
const GMAX_BIN = "${gmaxBin}";
|
|
142
|
+
|
|
143
|
+
function isProjectRegistered() {
|
|
144
|
+
try {
|
|
145
|
+
const projectsPath = join(homedir(), ".gmax", "projects.json");
|
|
146
|
+
const projects = JSON.parse(readFileSync(projectsPath, "utf-8"));
|
|
147
|
+
const cwd = process.cwd();
|
|
148
|
+
return projects.some((p) => cwd.startsWith(p.root));
|
|
149
|
+
} catch {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export const GmaxPlugin = async () => {
|
|
155
|
+
// Start daemon on session creation if project is indexed
|
|
156
|
+
if (isProjectRegistered()) {
|
|
157
|
+
try {
|
|
158
|
+
execFileSync(GMAX_BIN, ["watch", "--daemon", "-b"], {
|
|
159
|
+
timeout: 5000,
|
|
160
|
+
stdio: "ignore",
|
|
161
|
+
});
|
|
162
|
+
} catch {}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
"session.created": async () => {
|
|
167
|
+
if (!isProjectRegistered()) return;
|
|
168
|
+
try {
|
|
169
|
+
execFileSync(GMAX_BIN, ["watch", "--daemon", "-b"], {
|
|
170
|
+
timeout: 5000,
|
|
171
|
+
stdio: "ignore",
|
|
172
|
+
});
|
|
173
|
+
} catch {}
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
`;
|
|
178
|
+
}
|
|
154
179
|
function install() {
|
|
155
180
|
return __awaiter(this, void 0, void 0, function* () {
|
|
181
|
+
var _a;
|
|
156
182
|
try {
|
|
157
183
|
// 1. Delete legacy plugin
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
184
|
+
for (const legacy of [LEGACY_PLUGIN_PATH]) {
|
|
185
|
+
if (node_fs_1.default.existsSync(legacy)) {
|
|
186
|
+
try {
|
|
187
|
+
node_fs_1.default.unlinkSync(legacy);
|
|
188
|
+
console.log("Deleted legacy plugin at", legacy);
|
|
189
|
+
}
|
|
190
|
+
catch (_b) { }
|
|
165
191
|
}
|
|
166
192
|
}
|
|
167
193
|
// 2. Resolve absolute path to gmax binary
|
|
@@ -171,23 +197,22 @@ function install() {
|
|
|
171
197
|
node_fs_1.default.mkdirSync(node_path_1.default.dirname(TOOL_PATH), { recursive: true });
|
|
172
198
|
node_fs_1.default.writeFileSync(TOOL_PATH, buildShimContent(gmaxBin));
|
|
173
199
|
console.log("✅ Created tool shim at", TOOL_PATH);
|
|
174
|
-
// 4.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
200
|
+
// 4. Create plugin for daemon startup
|
|
201
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(PLUGIN_PATH), { recursive: true });
|
|
202
|
+
node_fs_1.default.writeFileSync(PLUGIN_PATH, buildPluginContent(gmaxBin));
|
|
203
|
+
console.log("✅ Created plugin at", PLUGIN_PATH);
|
|
204
|
+
// 5. Clean up stale MCP registration if present
|
|
205
|
+
if (node_fs_1.default.existsSync(CONFIG_PATH)) {
|
|
206
|
+
try {
|
|
207
|
+
const config = JSON.parse(node_fs_1.default.readFileSync(CONFIG_PATH, "utf-8") || "{}");
|
|
208
|
+
if ((_a = config.mcp) === null || _a === void 0 ? void 0 : _a.gmax) {
|
|
209
|
+
delete config.mcp.gmax;
|
|
210
|
+
node_fs_1.default.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
211
|
+
console.log("✅ Removed stale MCP registration from", CONFIG_PATH);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch (_c) { }
|
|
178
215
|
}
|
|
179
|
-
const config = JSON.parse(node_fs_1.default.readFileSync(CONFIG_PATH, "utf-8") || "{}");
|
|
180
|
-
if (!config.$schema)
|
|
181
|
-
config.$schema = "https://opencode.ai/config.json";
|
|
182
|
-
if (!config.mcp)
|
|
183
|
-
config.mcp = {};
|
|
184
|
-
config.mcp.gmax = {
|
|
185
|
-
type: "local",
|
|
186
|
-
command: [gmaxBin, "mcp"],
|
|
187
|
-
enabled: true,
|
|
188
|
-
};
|
|
189
|
-
node_fs_1.default.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
190
|
-
console.log("✅ Registered MCP server in", CONFIG_PATH);
|
|
191
216
|
}
|
|
192
217
|
catch (err) {
|
|
193
218
|
console.error("❌ Installation failed:", err);
|
|
@@ -198,25 +223,30 @@ function uninstall() {
|
|
|
198
223
|
return __awaiter(this, void 0, void 0, function* () {
|
|
199
224
|
var _a;
|
|
200
225
|
try {
|
|
201
|
-
// 1. Remove shim
|
|
226
|
+
// 1. Remove tool shim
|
|
202
227
|
if (node_fs_1.default.existsSync(TOOL_PATH)) {
|
|
203
228
|
node_fs_1.default.unlinkSync(TOOL_PATH);
|
|
204
229
|
console.log("✅ Removed tool shim.");
|
|
205
230
|
}
|
|
206
|
-
// 2.
|
|
231
|
+
// 2. Remove plugin
|
|
232
|
+
if (node_fs_1.default.existsSync(PLUGIN_PATH)) {
|
|
233
|
+
node_fs_1.default.unlinkSync(PLUGIN_PATH);
|
|
234
|
+
console.log("✅ Removed plugin.");
|
|
235
|
+
}
|
|
236
|
+
// 3. Clean up legacy paths
|
|
237
|
+
if (node_fs_1.default.existsSync(LEGACY_PLUGIN_PATH)) {
|
|
238
|
+
node_fs_1.default.unlinkSync(LEGACY_PLUGIN_PATH);
|
|
239
|
+
console.log("✅ Cleaned up legacy plugin.");
|
|
240
|
+
}
|
|
241
|
+
// 4. Clean up MCP registration if present
|
|
207
242
|
if (node_fs_1.default.existsSync(CONFIG_PATH)) {
|
|
208
243
|
const config = JSON.parse(node_fs_1.default.readFileSync(CONFIG_PATH, "utf-8") || "{}");
|
|
209
244
|
if ((_a = config.mcp) === null || _a === void 0 ? void 0 : _a.gmax) {
|
|
210
245
|
delete config.mcp.gmax;
|
|
211
246
|
node_fs_1.default.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
212
|
-
console.log("✅
|
|
247
|
+
console.log("✅ Removed MCP registration.");
|
|
213
248
|
}
|
|
214
249
|
}
|
|
215
|
-
// Cleanup plugin just in case
|
|
216
|
-
if (node_fs_1.default.existsSync(PLUGIN_PATH)) {
|
|
217
|
-
node_fs_1.default.unlinkSync(PLUGIN_PATH);
|
|
218
|
-
console.log("✅ Cleaned up plugin file.");
|
|
219
|
-
}
|
|
220
250
|
}
|
|
221
251
|
catch (err) {
|
|
222
252
|
console.error("❌ Uninstall failed:", err);
|
package/package.json
CHANGED