grepmax 0.18.0 → 0.19.0
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 +27 -2
- package/dist/commands/add.js +4 -2
- package/dist/commands/claude-code.js +1 -1
- package/dist/commands/codex.js +3 -1
- package/dist/commands/dead.js +2 -6
- package/dist/commands/doctor.js +26 -7
- package/dist/commands/extract.js +3 -5
- package/dist/commands/impact.js +6 -4
- package/dist/commands/index.js +7 -2
- package/dist/commands/log.js +4 -2
- package/dist/commands/mcp.js +587 -715
- package/dist/commands/peek.js +15 -9
- package/dist/commands/plugin.js +1 -1
- package/dist/commands/project.js +15 -5
- package/dist/commands/related.js +8 -9
- package/dist/commands/review.js +1 -1
- package/dist/commands/search.js +1 -1
- package/dist/commands/similar.js +4 -4
- package/dist/commands/status.js +5 -3
- package/dist/commands/summarize.js +6 -4
- package/dist/commands/test-find.js +2 -2
- package/dist/commands/trace.js +51 -9
- package/dist/commands/watch.js +9 -5
- package/dist/eval-graph-nav.js +4 -1
- package/dist/eval-graph-recovery-probe.js +56 -14
- package/dist/eval-graph-spotcheck.js +10 -2
- package/dist/eval-graph-totals.js +5 -2
- package/dist/eval-oss.js +212 -37
- package/dist/eval-seed.js +13 -4
- package/dist/index.js +9 -9
- package/dist/lib/daemon/daemon.js +22 -13
- package/dist/lib/daemon/ipc-handler.js +18 -5
- package/dist/lib/daemon/mlx-server-manager.js +11 -3
- package/dist/lib/daemon/process-manager.js +1 -2
- package/dist/lib/daemon/watcher-manager.js +4 -4
- package/dist/lib/graph/callsites.js +151 -25
- package/dist/lib/help/agent-cheatsheet.js +1 -1
- package/dist/lib/index/batch-processor.js +6 -5
- package/dist/lib/index/chunker.js +2 -0
- package/dist/lib/index/syncer.js +7 -6
- package/dist/lib/llm/diff.js +56 -11
- package/dist/lib/llm/investigate.js +12 -5
- package/dist/lib/llm/review.js +21 -8
- package/dist/lib/llm/server.js +16 -7
- package/dist/lib/output/agent-search-formatter.js +25 -3
- package/dist/lib/output/index-state-footer.js +1 -1
- package/dist/lib/review/risk.js +2 -4
- package/dist/lib/search/searcher.js +37 -11
- package/dist/lib/search/seed-weight.js +4 -1
- package/dist/lib/skeleton/symbol-extractor.js +2 -1
- package/dist/lib/utils/cross-project.js +5 -1
- package/dist/lib/utils/daemon-client.js +5 -1
- package/dist/lib/utils/git.js +10 -2
- package/dist/lib/utils/project-registry.js +3 -2
- package/dist/lib/utils/scope-filter.js +3 -1
- package/dist/lib/utils/watcher-launcher.js +4 -1
- package/dist/lib/utils/watcher-store.js +2 -1
- package/dist/lib/workers/embeddings/mlx-client.js +7 -2
- package/dist/lib/workers/pool.js +9 -6
- package/dist/lib/workers/process-child.js +1 -1
- package/package.json +22 -19
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
- package/plugins/grepmax/hooks/cwd-changed.js +4 -1
- package/plugins/grepmax/hooks/pre-grep.js +2 -1
- package/plugins/grepmax/hooks/start.js +45 -10
- package/plugins/grepmax/hooks/subagent-start.js +1 -4
package/dist/commands/peek.js
CHANGED
|
@@ -53,8 +53,8 @@ const exit_1 = require("../lib/utils/exit");
|
|
|
53
53
|
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
54
54
|
const language_1 = require("../lib/utils/language");
|
|
55
55
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
56
|
-
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
57
56
|
const project_root_1 = require("../lib/utils/project-root");
|
|
57
|
+
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
58
58
|
const useColors = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
59
59
|
const style = {
|
|
60
60
|
bold: (s) => (useColors ? `\x1b[1m${s}\x1b[22m` : s),
|
|
@@ -117,8 +117,8 @@ exports.peek = new commander_1.Command("peek")
|
|
|
117
117
|
.argument("<symbol>", "The symbol to peek at")
|
|
118
118
|
.option("-d, --depth <n>", "Caller traversal depth (default 1, max 3)", "1")
|
|
119
119
|
.option("--root <dir>", "Project root directory")
|
|
120
|
-
.option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) =>
|
|
121
|
-
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) =>
|
|
120
|
+
.option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
121
|
+
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
122
122
|
.option("--agent", "Compact output for AI agents", false)
|
|
123
123
|
.option("--no-tests", "Suppress the tests footer")
|
|
124
124
|
.action((symbol, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -196,9 +196,7 @@ exports.peek = new commander_1.Command("peek")
|
|
|
196
196
|
return;
|
|
197
197
|
}
|
|
198
198
|
const center = graph.center;
|
|
199
|
-
const rel = (p) => p.startsWith(projectRoot)
|
|
200
|
-
? p.slice(projectRoot.length + 1)
|
|
201
|
-
: p;
|
|
199
|
+
const rel = (p) => p.startsWith(projectRoot) ? p.slice(projectRoot.length + 1) : p;
|
|
202
200
|
// Get chunk metadata for is_exported and end_line
|
|
203
201
|
const table = yield vectorDb.ensureTable();
|
|
204
202
|
const metaRows = yield table
|
|
@@ -208,8 +206,12 @@ exports.peek = new commander_1.Command("peek")
|
|
|
208
206
|
.limit(1)
|
|
209
207
|
.toArray();
|
|
210
208
|
const exported = metaRows.length > 0 && Boolean(metaRows[0].is_exported);
|
|
211
|
-
const startLine = metaRows.length > 0
|
|
212
|
-
|
|
209
|
+
const startLine = metaRows.length > 0
|
|
210
|
+
? Number(metaRows[0].start_line || 0)
|
|
211
|
+
: center.line;
|
|
212
|
+
const endLine = metaRows.length > 0
|
|
213
|
+
? Number(metaRows[0].end_line || 0)
|
|
214
|
+
: center.line;
|
|
213
215
|
// Get multi-hop callers if depth > 1
|
|
214
216
|
let callerList;
|
|
215
217
|
if (depth > 1) {
|
|
@@ -218,7 +220,11 @@ exports.peek = new commander_1.Command("peek")
|
|
|
218
220
|
const flat = [];
|
|
219
221
|
function walkCallers(tree) {
|
|
220
222
|
for (const t of tree) {
|
|
221
|
-
flat.push({
|
|
223
|
+
flat.push({
|
|
224
|
+
symbol: t.node.symbol,
|
|
225
|
+
file: t.node.file,
|
|
226
|
+
line: t.node.line,
|
|
227
|
+
});
|
|
222
228
|
walkCallers(t.callers);
|
|
223
229
|
}
|
|
224
230
|
}
|
package/dist/commands/plugin.js
CHANGED
|
@@ -107,7 +107,7 @@ function getClients() {
|
|
|
107
107
|
isInstalled: () => {
|
|
108
108
|
const p = path.join(os.homedir(), ".codex", "AGENTS.md");
|
|
109
109
|
try {
|
|
110
|
-
return fs.existsSync(p) && fs.readFileSync(p, "utf-8").includes("gmax");
|
|
110
|
+
return (fs.existsSync(p) && fs.readFileSync(p, "utf-8").includes("gmax"));
|
|
111
111
|
}
|
|
112
112
|
catch (_a) {
|
|
113
113
|
return false;
|
package/dist/commands/project.js
CHANGED
|
@@ -47,11 +47,11 @@ const path = __importStar(require("node:path"));
|
|
|
47
47
|
const commander_1 = require("commander");
|
|
48
48
|
const callsites_1 = require("../lib/graph/callsites");
|
|
49
49
|
const vector_db_1 = require("../lib/store/vector-db");
|
|
50
|
-
const
|
|
50
|
+
const arrow_1 = require("../lib/utils/arrow");
|
|
51
51
|
const exit_1 = require("../lib/utils/exit");
|
|
52
|
+
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
52
53
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
53
54
|
const project_root_1 = require("../lib/utils/project-root");
|
|
54
|
-
const arrow_1 = require("../lib/utils/arrow");
|
|
55
55
|
exports.project = new commander_1.Command("project")
|
|
56
56
|
.description("Show project overview — languages, structure, key symbols")
|
|
57
57
|
.option("--root <dir>", "Project root (defaults to current directory)")
|
|
@@ -122,7 +122,10 @@ exports.project = new commander_1.Command("project")
|
|
|
122
122
|
definedInProject.add(d);
|
|
123
123
|
for (const ref of refs)
|
|
124
124
|
symbolRefs.set(ref, (symbolRefs.get(ref) || 0) + 1);
|
|
125
|
-
if (exported &&
|
|
125
|
+
if (exported &&
|
|
126
|
+
role === "ORCHESTRATION" &&
|
|
127
|
+
complexity >= 5 &&
|
|
128
|
+
defs.length > 0) {
|
|
126
129
|
const epKey = `${defs[0]}:${p}`;
|
|
127
130
|
if (!seenEntryPoints.has(epKey)) {
|
|
128
131
|
seenEntryPoints.add(epKey);
|
|
@@ -152,12 +155,19 @@ exports.project = new commander_1.Command("project")
|
|
|
152
155
|
console.log(`files\t${files.size}`);
|
|
153
156
|
console.log(`last_indexed\t${(_b = proj === null || proj === void 0 ? void 0 : proj.lastIndexed) !== null && _b !== void 0 ? _b : "unknown"}`);
|
|
154
157
|
console.log(`languages\t${extEntries.map(([ext]) => ext).join(",")}`);
|
|
155
|
-
console.log(`top_dirs\t${Array.from(dirCounts.entries())
|
|
158
|
+
console.log(`top_dirs\t${Array.from(dirCounts.entries())
|
|
159
|
+
.sort((a, b) => b[1].chunks - a[1].chunks)
|
|
160
|
+
.slice(0, 8)
|
|
161
|
+
.map(([d]) => d)
|
|
162
|
+
.join(",")}`);
|
|
156
163
|
if (topSymbols.length > 0) {
|
|
157
164
|
console.log(`key_symbols\t${topSymbols.map(([s]) => s).join(",")}`);
|
|
158
165
|
}
|
|
159
166
|
if (entryPoints.length > 0) {
|
|
160
|
-
console.log(`entry_points\t${entryPoints
|
|
167
|
+
console.log(`entry_points\t${entryPoints
|
|
168
|
+
.slice(0, 10)
|
|
169
|
+
.map((e) => e.symbol)
|
|
170
|
+
.join(",")}`);
|
|
161
171
|
}
|
|
162
172
|
}
|
|
163
173
|
else {
|
package/dist/commands/related.js
CHANGED
|
@@ -47,20 +47,20 @@ const path = __importStar(require("node:path"));
|
|
|
47
47
|
const commander_1 = require("commander");
|
|
48
48
|
const vector_db_1 = require("../lib/store/vector-db");
|
|
49
49
|
const agent_errors_1 = require("../lib/utils/agent-errors");
|
|
50
|
-
const
|
|
50
|
+
const arrow_1 = require("../lib/utils/arrow");
|
|
51
51
|
const exit_1 = require("../lib/utils/exit");
|
|
52
|
+
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
52
53
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
53
54
|
const project_root_1 = require("../lib/utils/project-root");
|
|
54
55
|
const query_timeout_1 = require("../lib/utils/query-timeout");
|
|
55
56
|
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
56
|
-
const arrow_1 = require("../lib/utils/arrow");
|
|
57
57
|
exports.related = new commander_1.Command("related")
|
|
58
58
|
.description("Find files related by shared symbol references")
|
|
59
59
|
.argument("<file>", "File path relative to project root")
|
|
60
60
|
.option("-l, --limit <n>", "Max results per direction (default 10)", "10")
|
|
61
61
|
.option("--root <dir>", "Project root directory")
|
|
62
|
-
.option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) =>
|
|
63
|
-
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) =>
|
|
62
|
+
.option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
63
|
+
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
64
64
|
.option("--agent", "Compact output for AI agents", false)
|
|
65
65
|
.action((file, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
66
66
|
var _a;
|
|
@@ -158,13 +158,14 @@ exports.related = new commander_1.Command("related")
|
|
|
158
158
|
"common",
|
|
159
159
|
"shared",
|
|
160
160
|
]);
|
|
161
|
-
|
|
161
|
+
const mentions = [];
|
|
162
162
|
let basename = "";
|
|
163
163
|
let basenameRejected = false;
|
|
164
164
|
if (topDeps.length === 0 && topRevs.length === 0) {
|
|
165
165
|
const ext = path.extname(absPath);
|
|
166
166
|
basename = path.basename(absPath, ext);
|
|
167
|
-
if (basename.length < 4 ||
|
|
167
|
+
if (basename.length < 4 ||
|
|
168
|
+
GENERIC_BASENAMES.has(basename.toLowerCase())) {
|
|
168
169
|
basenameRejected = true;
|
|
169
170
|
}
|
|
170
171
|
else {
|
|
@@ -190,9 +191,7 @@ exports.related = new commander_1.Command("related")
|
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
193
|
if (opts.agent) {
|
|
193
|
-
const rel = (p) => p.startsWith(`${projectRoot}/`)
|
|
194
|
-
? p.slice(projectRoot.length + 1)
|
|
195
|
-
: p;
|
|
194
|
+
const rel = (p) => p.startsWith(`${projectRoot}/`) ? p.slice(projectRoot.length + 1) : p;
|
|
196
195
|
for (const [p, count] of topDeps) {
|
|
197
196
|
console.log(`dep: ${rel(p)}\t${count}`);
|
|
198
197
|
}
|
package/dist/commands/review.js
CHANGED
|
@@ -85,7 +85,7 @@ Subcommands:
|
|
|
85
85
|
const { VectorDB } = yield Promise.resolve().then(() => __importStar(require("../lib/store/vector-db")));
|
|
86
86
|
const { GraphBuilder } = yield Promise.resolve().then(() => __importStar(require("../lib/graph/graph-builder")));
|
|
87
87
|
const { ensureProjectPaths } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/project-root")));
|
|
88
|
-
const { gatherRiskInputs, computeRiskTable, formatRiskTable
|
|
88
|
+
const { gatherRiskInputs, computeRiskTable, formatRiskTable } = yield Promise.resolve().then(() => __importStar(require("../lib/review/risk")));
|
|
89
89
|
const paths = ensureProjectPaths(projectRoot);
|
|
90
90
|
const vectorDb = new VectorDB(paths.lancedbDir);
|
|
91
91
|
try {
|
package/dist/commands/search.js
CHANGED
|
@@ -63,7 +63,7 @@ exports.search = new commander_1.Command("search")
|
|
|
63
63
|
.option("--explain", "Show scoring breakdown per result", false)
|
|
64
64
|
.option("--context-for-llm", "Return full function body + imports per result", false)
|
|
65
65
|
.option("--budget <tokens>", "Max tokens for --context-for-llm output (default 8000)", "8000")
|
|
66
|
-
.option("--min-score <score>", "Minimum relevance score (0
|
|
66
|
+
.option("--min-score <score>", "Minimum relevance score to include. Scores are per-query-normalized (top hit = 1.0), so this is relative to the best match in THIS query, not an absolute confidence threshold.", "0")
|
|
67
67
|
.option("--compact", "Compact hits view (paths + line ranges + role/preview)", false)
|
|
68
68
|
.option("--plain", "Disable ANSI colors and use simpler formatting", false)
|
|
69
69
|
.option("-s, --sync", "Syncs the local files to the store before searching", false)
|
package/dist/commands/similar.js
CHANGED
|
@@ -47,20 +47,20 @@ const path = __importStar(require("node:path"));
|
|
|
47
47
|
const commander_1 = require("commander");
|
|
48
48
|
const vector_db_1 = require("../lib/store/vector-db");
|
|
49
49
|
const agent_errors_1 = require("../lib/utils/agent-errors");
|
|
50
|
-
const
|
|
50
|
+
const arrow_1 = require("../lib/utils/arrow");
|
|
51
51
|
const exit_1 = require("../lib/utils/exit");
|
|
52
|
+
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
52
53
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
53
54
|
const project_root_1 = require("../lib/utils/project-root");
|
|
54
55
|
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
55
|
-
const arrow_1 = require("../lib/utils/arrow");
|
|
56
56
|
exports.similar = new commander_1.Command("similar")
|
|
57
57
|
.description("Find semantically similar code to a symbol or file")
|
|
58
58
|
.argument("<target>", "Symbol name or file path")
|
|
59
59
|
.option("-m, --max-count <n>", "Max results (default 5)", "5")
|
|
60
60
|
.option("--threshold <score>", "Min similarity 0-1 (default 0)")
|
|
61
61
|
.option("--root <dir>", "Project root directory")
|
|
62
|
-
.option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) =>
|
|
63
|
-
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) =>
|
|
62
|
+
.option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
63
|
+
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
64
64
|
.option("--agent", "Compact output for AI agents", false)
|
|
65
65
|
.action((target, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
66
66
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
package/dist/commands/status.js
CHANGED
|
@@ -47,8 +47,8 @@ const os = __importStar(require("node:os"));
|
|
|
47
47
|
const commander_1 = require("commander");
|
|
48
48
|
const config_1 = require("../config");
|
|
49
49
|
const index_config_1 = require("../lib/index/index-config");
|
|
50
|
-
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
51
50
|
const exit_1 = require("../lib/utils/exit");
|
|
51
|
+
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
52
52
|
const lock_1 = require("../lib/utils/lock");
|
|
53
53
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
54
54
|
const project_root_1 = require("../lib/utils/project-root");
|
|
@@ -115,7 +115,9 @@ Examples:
|
|
|
115
115
|
const db = new VectorDB(config_1.PATHS.lancedbDir);
|
|
116
116
|
const table = yield db.ensureTable();
|
|
117
117
|
for (const project of projects) {
|
|
118
|
-
const prefix = project.root.endsWith("/")
|
|
118
|
+
const prefix = project.root.endsWith("/")
|
|
119
|
+
? project.root
|
|
120
|
+
: `${project.root}/`;
|
|
119
121
|
const rows = yield table
|
|
120
122
|
.query()
|
|
121
123
|
.select(["id"])
|
|
@@ -125,7 +127,7 @@ Examples:
|
|
|
125
127
|
}
|
|
126
128
|
yield db.close();
|
|
127
129
|
}
|
|
128
|
-
catch (
|
|
130
|
+
catch (_e) {
|
|
129
131
|
console.warn(`[status] Failed to query LanceDB for live chunk counts, using cached counts`);
|
|
130
132
|
}
|
|
131
133
|
if (projects.length === 0) {
|
|
@@ -56,15 +56,17 @@ exports.summarize = new commander_1.Command("summarize")
|
|
|
56
56
|
.action((options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
57
57
|
var _a, _b, _c;
|
|
58
58
|
const paths = (0, project_root_1.ensureProjectPaths)(process.cwd());
|
|
59
|
-
const rootPrefix = options.path
|
|
60
|
-
? `${path.resolve(options.path)}/`
|
|
61
|
-
: "";
|
|
59
|
+
const rootPrefix = options.path ? `${path.resolve(options.path)}/` : "";
|
|
62
60
|
const { spinner } = (0, sync_helpers_1.createIndexingSpinner)("", "Summarizing...");
|
|
63
61
|
const { isDaemonRunning, sendStreamingCommand } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/daemon-client")));
|
|
64
62
|
if (yield isDaemonRunning()) {
|
|
65
63
|
// Daemon mode: IPC streaming
|
|
66
64
|
try {
|
|
67
|
-
const done = yield sendStreamingCommand({
|
|
65
|
+
const done = yield sendStreamingCommand({
|
|
66
|
+
cmd: "summarize",
|
|
67
|
+
root: paths.root,
|
|
68
|
+
pathPrefix: rootPrefix || undefined,
|
|
69
|
+
}, (msg) => {
|
|
68
70
|
var _a, _b;
|
|
69
71
|
spinner.text = `Summarizing... (${(_a = msg.summarized) !== null && _a !== void 0 ? _a : 0}/${(_b = msg.total) !== null && _b !== void 0 ? _b : 0})`;
|
|
70
72
|
});
|
|
@@ -56,8 +56,8 @@ exports.testFind = new commander_1.Command("test")
|
|
|
56
56
|
.argument("<target>", "Symbol name or file path")
|
|
57
57
|
.option("-d, --depth <n>", "Caller traversal depth (default 1, max 3)", "1")
|
|
58
58
|
.option("--root <dir>", "Project root directory")
|
|
59
|
-
.option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) =>
|
|
60
|
-
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) =>
|
|
59
|
+
.option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
60
|
+
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
61
61
|
.option("--agent", "Compact output for AI agents", false)
|
|
62
62
|
.action((target, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
63
63
|
var _a;
|
package/dist/commands/trace.js
CHANGED
|
@@ -51,21 +51,60 @@ const vector_db_1 = require("../lib/store/vector-db");
|
|
|
51
51
|
const agent_errors_1 = require("../lib/utils/agent-errors");
|
|
52
52
|
const exit_1 = require("../lib/utils/exit");
|
|
53
53
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
54
|
-
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
55
54
|
const project_root_1 = require("../lib/utils/project-root");
|
|
55
|
+
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
56
56
|
const useColors = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
57
57
|
const dim = (s) => (useColors ? `\x1b[2m${s}\x1b[22m` : s);
|
|
58
58
|
const bold = (s) => (useColors ? `\x1b[1m${s}\x1b[22m` : s);
|
|
59
|
-
function formatTraceAgent(graph, projectRoot) {
|
|
59
|
+
function formatTraceAgent(graph, projectRoot, raw = false) {
|
|
60
60
|
if (!graph.center)
|
|
61
61
|
return "(not found)";
|
|
62
|
+
const center = graph.center;
|
|
62
63
|
const rel = (p) => p.startsWith(projectRoot) ? p.slice(projectRoot.length + 1) : p;
|
|
63
64
|
const lines = [];
|
|
64
|
-
lines.push(`${
|
|
65
|
+
lines.push(`${center.symbol}\t${rel(center.file)}:${center.line}\t${center.role}`);
|
|
66
|
+
// A "self edge" is the traced symbol referencing itself (recursion) or its own
|
|
67
|
+
// definition chunk surfacing as a caller — noise in nearly every trace. Hidden
|
|
68
|
+
// by default; --raw brings them back.
|
|
69
|
+
const isSelfEdge = (n) => n.symbol === center.symbol ||
|
|
70
|
+
(n.file === center.file && n.line === center.line);
|
|
65
71
|
function walkCallers(tree, depth) {
|
|
72
|
+
if (raw) {
|
|
73
|
+
for (const t of tree) {
|
|
74
|
+
lines.push(`${" ".repeat(depth)}<- ${t.node.symbol}\t${rel(t.node.file)}:${t.node.line}`);
|
|
75
|
+
walkCallers(t.callers, depth + 1);
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Collapse repeated callers: the common flood is ONE caller symbol matched at
|
|
80
|
+
// many call-sites (e.g. `mcp` ×9). Group by (symbol, file), merge their lines
|
|
81
|
+
// onto a single row, and recurse into the union of their sub-callers.
|
|
82
|
+
const groups = new Map();
|
|
83
|
+
const order = [];
|
|
66
84
|
for (const t of tree) {
|
|
67
|
-
|
|
68
|
-
|
|
85
|
+
if (isSelfEdge(t.node))
|
|
86
|
+
continue;
|
|
87
|
+
const key = `${t.node.symbol}\t${t.node.file}`;
|
|
88
|
+
let g = groups.get(key);
|
|
89
|
+
if (!g) {
|
|
90
|
+
g = {
|
|
91
|
+
symbol: t.node.symbol,
|
|
92
|
+
file: t.node.file,
|
|
93
|
+
lineSet: new Set(),
|
|
94
|
+
sub: [],
|
|
95
|
+
};
|
|
96
|
+
groups.set(key, g);
|
|
97
|
+
order.push(key);
|
|
98
|
+
}
|
|
99
|
+
g.lineSet.add(t.node.line);
|
|
100
|
+
g.sub.push(...t.callers);
|
|
101
|
+
}
|
|
102
|
+
for (const key of order) {
|
|
103
|
+
const g = groups.get(key);
|
|
104
|
+
const locs = [...g.lineSet].sort((a, b) => a - b).join(",");
|
|
105
|
+
const loc = g.file ? `${rel(g.file)}:${locs}` : "(not indexed)";
|
|
106
|
+
lines.push(`${" ".repeat(depth)}<- ${g.symbol}\t${loc}`);
|
|
107
|
+
walkCallers(g.sub, depth + 1);
|
|
69
108
|
}
|
|
70
109
|
}
|
|
71
110
|
walkCallers(graph.callerTree, 0);
|
|
@@ -115,7 +154,9 @@ function formatInboundAgent(center, tree, projectRoot, withSnippets) {
|
|
|
115
154
|
var _a, _b;
|
|
116
155
|
for (const n of nodes) {
|
|
117
156
|
const prefix = " ".repeat(depth);
|
|
118
|
-
const loc = n.file
|
|
157
|
+
const loc = n.file
|
|
158
|
+
? `${rel(n.file)}:${((_a = n.snippetLine) !== null && _a !== void 0 ? _a : n.line) + 1}`
|
|
159
|
+
: "(not indexed)";
|
|
119
160
|
const cols = withSnippets
|
|
120
161
|
? `${loc}\t${n.symbol}\t${(_b = n.snippet) !== null && _b !== void 0 ? _b : ""}`
|
|
121
162
|
: `${loc}\t${n.symbol}`;
|
|
@@ -168,12 +209,13 @@ exports.trace = new commander_1.Command("trace")
|
|
|
168
209
|
.argument("<symbol>", "The symbol to trace")
|
|
169
210
|
.option("-d, --depth <n>", "Caller traversal depth (default 1, max 3)", "1")
|
|
170
211
|
.option("--root <dir>", "Project root directory")
|
|
171
|
-
.option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) =>
|
|
172
|
-
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) =>
|
|
212
|
+
.option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
213
|
+
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
173
214
|
.option("--agent", "Compact output for AI agents", false)
|
|
174
215
|
.option("--inbound", "Show only callers, with call-site snippets", false)
|
|
175
216
|
.option("--no-snippets", "Suppress call-site snippets in --inbound output")
|
|
176
217
|
.option("--limit <n>", "Max callers shown per node in --inbound (default 10)", "10")
|
|
218
|
+
.option("--raw", "In --agent mode, list every call-site without collapsing repeated callers or hiding self-edges", false)
|
|
177
219
|
.action((symbol, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
178
220
|
var _a;
|
|
179
221
|
const depth = Math.min(Math.max(Number.parseInt(opts.depth || "1", 10), 1), 3);
|
|
@@ -214,7 +256,7 @@ exports.trace = new commander_1.Command("trace")
|
|
|
214
256
|
}
|
|
215
257
|
}
|
|
216
258
|
else if (opts.agent) {
|
|
217
|
-
console.log(formatTraceAgent(graph, projectRoot));
|
|
259
|
+
console.log(formatTraceAgent(graph, projectRoot, opts.raw));
|
|
218
260
|
if (!graph.center)
|
|
219
261
|
process.exitCode = 1;
|
|
220
262
|
}
|
package/dist/commands/watch.js
CHANGED
|
@@ -43,18 +43,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
43
43
|
};
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
45
|
exports.watch = void 0;
|
|
46
|
-
const fs = __importStar(require("node:fs"));
|
|
47
46
|
const node_child_process_1 = require("node:child_process");
|
|
47
|
+
const fs = __importStar(require("node:fs"));
|
|
48
48
|
const path = __importStar(require("node:path"));
|
|
49
49
|
const commander_1 = require("commander");
|
|
50
50
|
const config_1 = require("../config");
|
|
51
51
|
const index_config_1 = require("../lib/index/index-config");
|
|
52
|
-
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
53
52
|
const syncer_1 = require("../lib/index/syncer");
|
|
54
53
|
const watcher_1 = require("../lib/index/watcher");
|
|
55
54
|
const meta_cache_1 = require("../lib/store/meta-cache");
|
|
56
55
|
const vector_db_1 = require("../lib/store/vector-db");
|
|
57
56
|
const exit_1 = require("../lib/utils/exit");
|
|
57
|
+
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
58
58
|
const log_rotate_1 = require("../lib/utils/log-rotate");
|
|
59
59
|
const process_1 = require("../lib/utils/process");
|
|
60
60
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
@@ -148,7 +148,7 @@ exports.watch = new commander_1.Command("watch")
|
|
|
148
148
|
// --- Per-project mode ---
|
|
149
149
|
const projectRoot = options.path
|
|
150
150
|
? path.resolve(options.path)
|
|
151
|
-
: (_a = (0, project_root_1.findProjectRoot)(process.cwd())) !== null && _a !== void 0 ? _a : process.cwd();
|
|
151
|
+
: ((_a = (0, project_root_1.findProjectRoot)(process.cwd())) !== null && _a !== void 0 ? _a : process.cwd());
|
|
152
152
|
const projectName = path.basename(projectRoot);
|
|
153
153
|
// Check if watcher already running (exact match or parent covering this dir)
|
|
154
154
|
const existing = (_b = (0, watcher_store_1.getWatcherForProject)(projectRoot)) !== null && _b !== void 0 ? _b : (0, watcher_store_1.getWatcherCoveringPath)(projectRoot);
|
|
@@ -195,7 +195,9 @@ exports.watch = new commander_1.Command("watch")
|
|
|
195
195
|
// Initial sync if this directory isn't indexed yet
|
|
196
196
|
const vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
197
197
|
const table = yield vectorDb.ensureTable();
|
|
198
|
-
const prefix = projectRoot.endsWith("/")
|
|
198
|
+
const prefix = projectRoot.endsWith("/")
|
|
199
|
+
? projectRoot
|
|
200
|
+
: `${projectRoot}/`;
|
|
199
201
|
const indexed = yield table
|
|
200
202
|
.query()
|
|
201
203
|
.select(["id"])
|
|
@@ -325,7 +327,9 @@ exports.watch
|
|
|
325
327
|
let parentCmd = "?";
|
|
326
328
|
try {
|
|
327
329
|
const { execSync } = yield Promise.resolve().then(() => __importStar(require("node:child_process")));
|
|
328
|
-
parentCmd = execSync(`ps -o command= -p ${process.ppid}`, {
|
|
330
|
+
parentCmd = execSync(`ps -o command= -p ${process.ppid}`, {
|
|
331
|
+
encoding: "utf8",
|
|
332
|
+
}).trim();
|
|
329
333
|
}
|
|
330
334
|
catch (_c) { }
|
|
331
335
|
yield sendDaemonCommand({
|
package/dist/eval-graph-nav.js
CHANGED
|
@@ -93,7 +93,10 @@ const SELF = "src/eval-graph-nav.ts"; // exclude from grep + graph (self-referen
|
|
|
93
93
|
// grep can't tell those apart from genuine uses, so they would manufacture
|
|
94
94
|
// phantom "expected callers" that no correct graph ever surfaces. Excluded from
|
|
95
95
|
// both the grep truth and the getCallers set so the exclusion stays symmetric.
|
|
96
|
-
const FIXTURE_FILES = new Set([
|
|
96
|
+
const FIXTURE_FILES = new Set([
|
|
97
|
+
SELF,
|
|
98
|
+
"tests/graph-edges.type-position.test.ts",
|
|
99
|
+
]);
|
|
97
100
|
const rel = (p) => p.replace(`${GMAX_ROOT}/`, "");
|
|
98
101
|
const INBOUND_SYMBOLS = [
|
|
99
102
|
// ── Baselines: called/constructed, so the graph captures them. ──────────────
|
|
@@ -60,8 +60,8 @@ const path = __importStar(require("node:path"));
|
|
|
60
60
|
const config_1 = require("./config");
|
|
61
61
|
const vector_db_1 = require("./lib/store/vector-db");
|
|
62
62
|
const exit_1 = require("./lib/utils/exit");
|
|
63
|
-
const pool_1 = require("./lib/workers/pool");
|
|
64
63
|
const filter_builder_1 = require("./lib/utils/filter-builder");
|
|
64
|
+
const pool_1 = require("./lib/workers/pool");
|
|
65
65
|
const PLATFORM_ROOT = path.join((_b = process.env.HOME) !== null && _b !== void 0 ? _b : "", "Development/beyond/platform");
|
|
66
66
|
const PRE_K = 500;
|
|
67
67
|
const STAGE1_K = 200;
|
|
@@ -89,7 +89,9 @@ function toStrArr(val) {
|
|
|
89
89
|
if (typeof m.toArray === "function") {
|
|
90
90
|
try {
|
|
91
91
|
const a = m.toArray();
|
|
92
|
-
return Array.isArray(a)
|
|
92
|
+
return Array.isArray(a)
|
|
93
|
+
? a.filter((v) => typeof v === "string")
|
|
94
|
+
: [];
|
|
93
95
|
}
|
|
94
96
|
catch (_a) {
|
|
95
97
|
return [];
|
|
@@ -101,22 +103,50 @@ function probe(table, sym, expectedFile) {
|
|
|
101
103
|
return __awaiter(this, void 0, void 0, function* () {
|
|
102
104
|
const pool = (0, pool_1.getWorkerPool)();
|
|
103
105
|
const { dense } = yield pool.encodeQuery(sym);
|
|
104
|
-
const prefix = PLATFORM_ROOT.endsWith("/")
|
|
106
|
+
const prefix = PLATFORM_ROOT.endsWith("/")
|
|
107
|
+
? PLATFORM_ROOT
|
|
108
|
+
: `${PLATFORM_ROOT}/`;
|
|
105
109
|
const where = `path LIKE '${(0, filter_builder_1.escapeSqlString)(prefix)}%'`;
|
|
106
|
-
const columns = [
|
|
107
|
-
|
|
110
|
+
const columns = [
|
|
111
|
+
"id",
|
|
112
|
+
"path",
|
|
113
|
+
"chunk_index",
|
|
114
|
+
"defined_symbols",
|
|
115
|
+
"referenced_symbols",
|
|
116
|
+
];
|
|
117
|
+
const vectorRows = (yield table
|
|
118
|
+
.vectorSearch(dense)
|
|
119
|
+
.select([...columns, "_distance"])
|
|
120
|
+
.where(where)
|
|
121
|
+
.limit(PRE_K)
|
|
122
|
+
.toArray());
|
|
108
123
|
let ftsRows = [];
|
|
109
124
|
try {
|
|
110
|
-
ftsRows = (yield table
|
|
125
|
+
ftsRows = (yield table
|
|
126
|
+
.search(sym)
|
|
127
|
+
.select([...columns, "_score"])
|
|
128
|
+
.where(where)
|
|
129
|
+
.limit(PRE_K)
|
|
130
|
+
.toArray());
|
|
111
131
|
}
|
|
112
132
|
catch (_a) { }
|
|
113
133
|
const scores = new Map();
|
|
114
134
|
const docMap = new Map();
|
|
115
135
|
const keyOf = (d) => d.id || `${d.path}:${d.chunk_index}`;
|
|
116
|
-
vectorRows.forEach((d, r) => {
|
|
117
|
-
|
|
118
|
-
docMap.set(k, d);
|
|
119
|
-
|
|
136
|
+
vectorRows.forEach((d, r) => {
|
|
137
|
+
const k = keyOf(d);
|
|
138
|
+
docMap.set(k, d);
|
|
139
|
+
scores.set(k, (scores.get(k) || 0) + 1 / (RRF_K + r + 1));
|
|
140
|
+
});
|
|
141
|
+
ftsRows.forEach((d, r) => {
|
|
142
|
+
const k = keyOf(d);
|
|
143
|
+
if (!docMap.has(k))
|
|
144
|
+
docMap.set(k, d);
|
|
145
|
+
scores.set(k, (scores.get(k) || 0) + 1 / (RRF_K + r + 1));
|
|
146
|
+
});
|
|
147
|
+
const fusedKeys = Array.from(scores.entries())
|
|
148
|
+
.sort((a, b) => b[1] - a[1])
|
|
149
|
+
.map(([k]) => k);
|
|
120
150
|
const fused = fusedKeys.map((k) => docMap.get(k));
|
|
121
151
|
// Locate the expected definition chunk among retrieved rows.
|
|
122
152
|
const isExpected = (d) => String(d.path).toLowerCase().endsWith(`/${expectedFile.toLowerCase()}`) &&
|
|
@@ -134,7 +164,12 @@ function probe(table, sym, expectedFile) {
|
|
|
134
164
|
// If not in the union, query directly to confirm it exists in the index.
|
|
135
165
|
let defExistsInIndex = defInUnion;
|
|
136
166
|
if (!defInUnion) {
|
|
137
|
-
const direct = (yield table
|
|
167
|
+
const direct = (yield table
|
|
168
|
+
.query()
|
|
169
|
+
.select(columns)
|
|
170
|
+
.where(`${where} AND array_contains(defined_symbols, '${(0, filter_builder_1.escapeSqlString)(sym)}')`)
|
|
171
|
+
.limit(50)
|
|
172
|
+
.toArray());
|
|
138
173
|
defExistsInIndex = direct.some((d) => String(d.path).toLowerCase().endsWith(`/${expectedFile.toLowerCase()}`));
|
|
139
174
|
}
|
|
140
175
|
// ref->def reachability: among top-SEED_K fusion seeds, how many reference `sym`?
|
|
@@ -149,8 +184,12 @@ function probe(table, sym, expectedFile) {
|
|
|
149
184
|
}
|
|
150
185
|
});
|
|
151
186
|
const loc = defRetrievalRank > 0
|
|
152
|
-
?
|
|
153
|
-
|
|
187
|
+
? defInPool
|
|
188
|
+
? `pool#${defRetrievalRank}`
|
|
189
|
+
: `union#${defRetrievalRank}(>200)`
|
|
190
|
+
: defExistsInIndex
|
|
191
|
+
? "OUTSIDE-500"
|
|
192
|
+
: "NOT-IN-INDEX?";
|
|
154
193
|
return { sym, expectedFile, loc, seedsRefSym, firstRefSeedRank };
|
|
155
194
|
});
|
|
156
195
|
}
|
|
@@ -167,4 +206,7 @@ function main() {
|
|
|
167
206
|
yield (0, exit_1.gracefulExit)(0);
|
|
168
207
|
});
|
|
169
208
|
}
|
|
170
|
-
main().catch((e) => {
|
|
209
|
+
main().catch((e) => {
|
|
210
|
+
console.error(e);
|
|
211
|
+
process.exit(1);
|
|
212
|
+
});
|
|
@@ -37,7 +37,9 @@ function toStrArr(v) {
|
|
|
37
37
|
if (typeof m.toArray === "function") {
|
|
38
38
|
try {
|
|
39
39
|
const a = m.toArray();
|
|
40
|
-
return Array.isArray(a)
|
|
40
|
+
return Array.isArray(a)
|
|
41
|
+
? a.filter((x) => typeof x === "string")
|
|
42
|
+
: [];
|
|
41
43
|
}
|
|
42
44
|
catch (_a) {
|
|
43
45
|
return [];
|
|
@@ -53,7 +55,13 @@ function main() {
|
|
|
53
55
|
console.log(`\n── ${file}`);
|
|
54
56
|
const rows = (yield table
|
|
55
57
|
.query()
|
|
56
|
-
.select([
|
|
58
|
+
.select([
|
|
59
|
+
"start_line",
|
|
60
|
+
"end_line",
|
|
61
|
+
"chunk_type",
|
|
62
|
+
"defined_symbols",
|
|
63
|
+
"referenced_symbols",
|
|
64
|
+
])
|
|
57
65
|
.where(`path = '${(0, filter_builder_1.escapeSqlString)(file)}'`)
|
|
58
66
|
.limit(20)
|
|
59
67
|
.toArray());
|
|
@@ -69,7 +69,9 @@ function main() {
|
|
|
69
69
|
return __awaiter(this, void 0, void 0, function* () {
|
|
70
70
|
const db = new vector_db_1.VectorDB(config_1.PATHS.lancedbDir);
|
|
71
71
|
const table = yield db.ensureTable();
|
|
72
|
-
const pathPrefix = PLATFORM_ROOT.endsWith("/")
|
|
72
|
+
const pathPrefix = PLATFORM_ROOT.endsWith("/")
|
|
73
|
+
? PLATFORM_ROOT
|
|
74
|
+
: `${PLATFORM_ROOT}/`;
|
|
73
75
|
const scope = `path LIKE '${(0, filter_builder_1.escapeSqlString)(pathPrefix)}%'`;
|
|
74
76
|
console.log(`Platform graph density check — pathPrefix=${PLATFORM_ROOT}\n`);
|
|
75
77
|
for (const sym of TARGETS) {
|
|
@@ -103,7 +105,8 @@ function main() {
|
|
|
103
105
|
let arr = [];
|
|
104
106
|
if (Array.isArray(raw))
|
|
105
107
|
arr = raw.filter((v) => typeof v === "string");
|
|
106
|
-
else if (raw &&
|
|
108
|
+
else if (raw &&
|
|
109
|
+
typeof raw.toArray === "function") {
|
|
107
110
|
try {
|
|
108
111
|
const a = raw.toArray();
|
|
109
112
|
if (Array.isArray(a))
|