grepmax 0.16.2 → 0.16.4
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/dist/commands/diff.js +8 -140
- package/dist/commands/extract.js +20 -0
- package/dist/commands/log.js +231 -0
- package/dist/commands/peek.js +19 -0
- package/dist/commands/recent.js +7 -129
- package/dist/commands/related.js +73 -1
- package/dist/commands/search.js +71 -50
- package/dist/commands/test-find.js +10 -2
- package/dist/commands/trace.js +141 -4
- package/dist/index.js +2 -0
- package/dist/lib/graph/impact.js +51 -0
- package/dist/lib/utils/git.js +90 -0
- package/dist/lib/utils/tests-footer.js +78 -0
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
- package/plugins/grepmax/skills/grepmax/SKILL.md +22 -13
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.fetchTestsForFooter = fetchTestsForFooter;
|
|
13
|
+
exports.renderTestsFooterAgent = renderTestsFooterAgent;
|
|
14
|
+
exports.renderTestsFooterHuman = renderTestsFooterHuman;
|
|
15
|
+
const impact_1 = require("../graph/impact");
|
|
16
|
+
const FOOTER_TIMEOUT_MS = 1500;
|
|
17
|
+
const MAX_SHOWN = 5;
|
|
18
|
+
const useColors = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
19
|
+
const dim = (s) => (useColors ? `\x1b[2m${s}\x1b[22m` : s);
|
|
20
|
+
function withTimeout(p, ms) {
|
|
21
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
let timer;
|
|
23
|
+
const timeout = new Promise((resolve) => {
|
|
24
|
+
timer = setTimeout(() => resolve(null), ms);
|
|
25
|
+
});
|
|
26
|
+
try {
|
|
27
|
+
return yield Promise.race([p, timeout]);
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
if (timer)
|
|
31
|
+
clearTimeout(timer);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function fetchTestsForFooter(symbol, vectorDb, pathPrefix, excludePrefixes) {
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
return withTimeout((0, impact_1.findTests)([symbol], vectorDb, pathPrefix, 1, excludePrefixes), FOOTER_TIMEOUT_MS);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function relPath(p, projectRoot) {
|
|
41
|
+
return p.startsWith(`${projectRoot}/`) ? p.slice(projectRoot.length + 1) : p;
|
|
42
|
+
}
|
|
43
|
+
function hopLabelAgent(hops) {
|
|
44
|
+
if (hops === -1)
|
|
45
|
+
return "via-import";
|
|
46
|
+
if (hops === 0)
|
|
47
|
+
return "direct";
|
|
48
|
+
return `${hops}-hop`;
|
|
49
|
+
}
|
|
50
|
+
function hopLabelHuman(hops) {
|
|
51
|
+
if (hops === -1)
|
|
52
|
+
return "via import";
|
|
53
|
+
if (hops === 0)
|
|
54
|
+
return "direct";
|
|
55
|
+
return `${hops} hop${hops > 1 ? "s" : ""}`;
|
|
56
|
+
}
|
|
57
|
+
function renderTestsFooterAgent(tests, projectRoot) {
|
|
58
|
+
const lines = [];
|
|
59
|
+
for (const t of tests.slice(0, MAX_SHOWN)) {
|
|
60
|
+
lines.push(`t: ${relPath(t.file, projectRoot)}:${t.line + 1}\t${t.symbol}\t${hopLabelAgent(t.hops)}`);
|
|
61
|
+
}
|
|
62
|
+
if (tests.length > MAX_SHOWN) {
|
|
63
|
+
lines.push(`t: ... ${tests.length - MAX_SHOWN} more`);
|
|
64
|
+
}
|
|
65
|
+
return lines;
|
|
66
|
+
}
|
|
67
|
+
function renderTestsFooterHuman(tests, projectRoot) {
|
|
68
|
+
const lines = [];
|
|
69
|
+
lines.push("");
|
|
70
|
+
lines.push(`tests (${tests.length}):`);
|
|
71
|
+
for (const t of tests.slice(0, MAX_SHOWN)) {
|
|
72
|
+
lines.push(` ${t.symbol.padEnd(25)} ${dim(`${relPath(t.file, projectRoot)}:${t.line + 1}`)} ${dim(`(${hopLabelHuman(t.hops)})`)}`);
|
|
73
|
+
}
|
|
74
|
+
if (tests.length > MAX_SHOWN) {
|
|
75
|
+
lines.push(dim(` ... and ${tests.length - MAX_SHOWN} more`));
|
|
76
|
+
}
|
|
77
|
+
return lines;
|
|
78
|
+
}
|
package/package.json
CHANGED
|
@@ -53,7 +53,7 @@ gmax "auth" --root ~/other/project --agent # search a different project
|
|
|
53
53
|
gmax "auth" --imports --agent # show file imports per file
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
Output: `file:line symbol [ROLE] — signature_hint` (one line per result)
|
|
56
|
+
Output: `file:line symbol [ROLE] — signature_hint` (one line per result). When multiple hits land in the same file, they collapse under a `path/to/file.ts (N hits):` header with indented children — saves the repeated path prefix.
|
|
57
57
|
|
|
58
58
|
All search flags: `--agent --plain -m <n> --per-file <n> --min-score <n> --root <dir> --file <name> --exclude <prefix> --lang <ext> --role <role> --symbol --imports --name <regex> -C <n> --compact --content --scores --skeleton --explain --context-for-llm --budget <tokens>`
|
|
59
59
|
|
|
@@ -87,6 +87,9 @@ gmax trace handleAuth # 1-hop: callers + callees
|
|
|
87
87
|
gmax trace handleAuth -d 2 # 2-hop: callers-of-callers
|
|
88
88
|
gmax trace handleAuth --root ~/project # trace in a different project
|
|
89
89
|
gmax trace handleAuth --agent # compact: symbol\tpath:line, <- callers, -> callees
|
|
90
|
+
gmax trace handleAuth --inbound --agent # callers-only with call-site snippets (path:line\tsymbol\tsnippet)
|
|
91
|
+
gmax trace handleAuth --inbound --no-snippets # drop the snippet column
|
|
92
|
+
gmax trace handleAuth --inbound --limit 20 # show up to 20 callers (default 10, max 30)
|
|
90
93
|
```
|
|
91
94
|
|
|
92
95
|
### Extract — `gmax extract <symbol>`
|
|
@@ -95,7 +98,9 @@ gmax extract handleAuth # full function body with line number
|
|
|
95
98
|
gmax extract handleAuth --agent # compact: path:start-end then raw code
|
|
96
99
|
gmax extract handleAuth --imports # prepend file imports
|
|
97
100
|
gmax extract handleAuth --root ~/project # extract from different project
|
|
101
|
+
gmax extract handleAuth --no-tests # suppress tests footer (default-on)
|
|
98
102
|
```
|
|
103
|
+
Output ends with a `--- tests:` footer listing tests that exercise the symbol (default-on; opt-out with `--no-tests`).
|
|
99
104
|
|
|
100
105
|
### Peek — `gmax peek <symbol>`
|
|
101
106
|
```
|
|
@@ -103,7 +108,9 @@ gmax peek handleAuth # signature + callers + callees
|
|
|
103
108
|
gmax peek handleAuth --agent # compact TSV output
|
|
104
109
|
gmax peek handleAuth -d 2 # 2-hop callers
|
|
105
110
|
gmax peek handleAuth --root ~/project # peek in different project
|
|
111
|
+
gmax peek handleAuth --no-tests # suppress tests footer (default-on)
|
|
106
112
|
```
|
|
113
|
+
Agent output ends with `t: <test-file>:line\t<test-symbol>\t<hop-label>` rows where hop-label is `direct`, `N-hop`, or `via-import`.
|
|
107
114
|
|
|
108
115
|
### Skeleton — `gmax skeleton <target>`
|
|
109
116
|
```
|
|
@@ -124,10 +131,20 @@ gmax project --root ~/other/project # different project
|
|
|
124
131
|
gmax related src/lib/index/syncer.ts # dependencies + dependents
|
|
125
132
|
gmax related src/lib/index/syncer.ts --root ~/project
|
|
126
133
|
```
|
|
134
|
+
When both directions are empty, falls back to files mentioning the input file's basename. Generic basenames (`index`, `main`, `lib`, etc.) skip the fallback.
|
|
127
135
|
|
|
128
|
-
###
|
|
136
|
+
### Commit history — `gmax log <path-or-symbol>`
|
|
129
137
|
```
|
|
130
|
-
gmax
|
|
138
|
+
gmax log src/lib/auth.ts # commits touching this file
|
|
139
|
+
gmax log src/lib/ # commits touching this directory
|
|
140
|
+
gmax log handleAuth # commits across all files defining the symbol
|
|
141
|
+
gmax log handleAuth --in src/ # restrict symbol resolution to a sub-path
|
|
142
|
+
gmax log src/lib/auth.ts --limit 5 # last 5 commits
|
|
143
|
+
gmax log src/lib/auth.ts --from main # commits since main (range main..HEAD)
|
|
144
|
+
gmax log src/lib/auth.ts --since "2 weeks ago"
|
|
145
|
+
gmax log src/lib/auth.ts --author Robert
|
|
146
|
+
gmax log src/lib/auth.ts --no-follow # disable rename tracking (default: on for files)
|
|
147
|
+
gmax log src/lib/auth.ts --agent # TSV: hash\tisoDate\tauthor\tsubject\tfilesChanged\tins\tdel\ttouchedFiles
|
|
131
148
|
```
|
|
132
149
|
|
|
133
150
|
### Symbols — `gmax symbols`
|
|
@@ -137,22 +154,14 @@ gmax symbols auth -p src/ --root ~/proj # filter by name, path, project
|
|
|
137
154
|
gmax symbols --agent # compact: symbol\tpath:line\tcount
|
|
138
155
|
```
|
|
139
156
|
|
|
140
|
-
### Diff — `gmax diff [ref]`
|
|
141
|
-
```
|
|
142
|
-
gmax diff # uncommitted changes
|
|
143
|
-
gmax diff HEAD~5 # last 5 commits
|
|
144
|
-
gmax diff main # branch changes vs main
|
|
145
|
-
gmax diff main --query "auth changes" # semantic search within changed files
|
|
146
|
-
gmax diff --agent # compact output
|
|
147
|
-
```
|
|
148
|
-
|
|
149
157
|
### Test — `gmax test <symbol|file>`
|
|
150
158
|
```
|
|
151
|
-
gmax test handleAuth # tests calling handleAuth
|
|
159
|
+
gmax test handleAuth # tests calling handleAuth (call-graph + import-fallback)
|
|
152
160
|
gmax test src/lib/auth.ts # tests for symbols in this file
|
|
153
161
|
gmax test handleAuth -d 2 # 2-hop: tests calling callers too
|
|
154
162
|
gmax test handleAuth --agent # compact output
|
|
155
163
|
```
|
|
164
|
+
Hop labels: `direct` (calls the symbol), `N-hop` (calls a transitive caller), `via-import` (test references the symbol via import or mock when no call-graph match exists).
|
|
156
165
|
|
|
157
166
|
### Impact — `gmax impact <symbol|file>`
|
|
158
167
|
```
|