grepmax 0.26.27 → 0.26.28
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/.claude-plugin/marketplace.json +1 -1
- package/README.md +40 -0
- package/dist/commands/audit.js +28 -260
- package/dist/commands/context.js +42 -26
- package/dist/commands/dead.js +37 -35
- package/dist/commands/doctor.js +280 -10
- package/dist/commands/extract.js +79 -49
- package/dist/commands/impact.js +74 -20
- package/dist/commands/log.js +25 -25
- package/dist/commands/mcp.js +622 -474
- package/dist/commands/peek.js +49 -47
- package/dist/commands/project.js +29 -107
- package/dist/commands/related.js +43 -52
- package/dist/commands/search-run.js +23 -8
- package/dist/commands/search.js +7 -2
- package/dist/commands/similar.js +50 -76
- package/dist/commands/skeleton.js +137 -83
- package/dist/commands/status.js +90 -25
- package/dist/commands/surprises.js +73 -16
- package/dist/commands/symbols.js +58 -77
- package/dist/commands/test-find.js +51 -17
- package/dist/commands/trace.js +26 -11
- package/dist/lib/daemon/daemon.js +26 -0
- package/dist/lib/daemon/graph-handler.js +853 -0
- package/dist/lib/daemon/ipc-handler.js +19 -2
- package/dist/lib/daemon/read-verbs.js +105 -0
- package/dist/lib/daemon/rows-handler.js +665 -0
- package/dist/lib/daemon/vector-handler.js +199 -0
- package/dist/lib/utils/daemon-client.js +11 -0
- package/dist/lib/utils/store-access.js +381 -0
- package/dist/lib/utils/tests-footer.js +19 -2
- package/dist/lib/utils/watcher-launcher.js +10 -0
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
package/dist/commands/peek.js
CHANGED
|
@@ -45,17 +45,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
exports.peek = void 0;
|
|
46
46
|
const fs = __importStar(require("node:fs"));
|
|
47
47
|
const commander_1 = require("commander");
|
|
48
|
+
const graph_handler_1 = require("../lib/daemon/graph-handler");
|
|
48
49
|
const callsites_1 = require("../lib/graph/callsites");
|
|
49
|
-
const graph_builder_1 = require("../lib/graph/graph-builder");
|
|
50
50
|
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
|
-
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
54
53
|
const language_1 = require("../lib/utils/language");
|
|
55
54
|
const path_containment_1 = require("../lib/utils/path-containment");
|
|
56
55
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
57
56
|
const project_root_1 = require("../lib/utils/project-root");
|
|
58
57
|
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
58
|
+
const store_access_1 = require("../lib/utils/store-access");
|
|
59
59
|
const useColors = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
60
60
|
const style = {
|
|
61
61
|
bold: (s) => (useColors ? `\x1b[1m${s}\x1b[22m` : s),
|
|
@@ -124,7 +124,7 @@ exports.peek = new commander_1.Command("peek")
|
|
|
124
124
|
.option("--no-tests", "Suppress the tests footer")
|
|
125
125
|
.action((symbol, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
126
126
|
var _a;
|
|
127
|
-
|
|
127
|
+
const local = { db: null };
|
|
128
128
|
const root = (0, project_registry_1.resolveRootOrExit)(opts.root);
|
|
129
129
|
if (root === null)
|
|
130
130
|
return;
|
|
@@ -133,15 +133,35 @@ exports.peek = new commander_1.Command("peek")
|
|
|
133
133
|
const projectRoot = (_a = (0, project_root_1.findProjectRoot)(root)) !== null && _a !== void 0 ? _a : root;
|
|
134
134
|
(0, stale_hint_1.maybeWarnStaleChunker)(projectRoot, { agent: opts.agent });
|
|
135
135
|
(0, stale_hint_1.maybeWarnStaleEmbedding)(projectRoot, { agent: opts.agent });
|
|
136
|
-
const
|
|
137
|
-
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
138
|
-
const { resolveScope, buildScopeWhere } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/scope-filter")));
|
|
136
|
+
const { resolveScope } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/scope-filter")));
|
|
139
137
|
const scope = resolveScope({
|
|
140
138
|
projectRoot,
|
|
141
139
|
in: opts.in,
|
|
142
140
|
exclude: opts.exclude,
|
|
143
141
|
});
|
|
144
|
-
|
|
142
|
+
// One round trip for everything peek needs out of the store: the
|
|
143
|
+
// defining chunks, the graph, the chunk metadata, and the tests footer.
|
|
144
|
+
// The signature below is read from the working tree by this process.
|
|
145
|
+
const store = yield (0, graph_handler_1.callGraphVerb)("graph.peek", {
|
|
146
|
+
projectRoot,
|
|
147
|
+
scope,
|
|
148
|
+
payload: {
|
|
149
|
+
target: symbol,
|
|
150
|
+
depth,
|
|
151
|
+
includeTests: opts.tests !== false,
|
|
152
|
+
},
|
|
153
|
+
render: (resp) => resp.peek,
|
|
154
|
+
inProcess: () => {
|
|
155
|
+
var _a;
|
|
156
|
+
(_a = local.db) !== null && _a !== void 0 ? _a : (local.db = new vector_db_1.VectorDB((0, project_root_1.ensureProjectPaths)(projectRoot).lancedbDir));
|
|
157
|
+
return (0, graph_handler_1.runGraphPeek)(local.db, {
|
|
158
|
+
symbol,
|
|
159
|
+
depth,
|
|
160
|
+
scope,
|
|
161
|
+
includeTests: opts.tests !== false,
|
|
162
|
+
});
|
|
163
|
+
},
|
|
164
|
+
});
|
|
145
165
|
// Cross-language disambiguation: when the symbol is defined in 2+
|
|
146
166
|
// languages, refuse to silently pick one. The graph builder otherwise
|
|
147
167
|
// picks one chunk arbitrarily and lists callers from a different
|
|
@@ -150,17 +170,7 @@ exports.peek = new commander_1.Command("peek")
|
|
|
150
170
|
// the first definition still wins, but the agent learns it guessed.
|
|
151
171
|
let otherDefs = [];
|
|
152
172
|
{
|
|
153
|
-
const
|
|
154
|
-
const allDefs = yield tableForCheck
|
|
155
|
-
.query()
|
|
156
|
-
.select(["path", "start_line"])
|
|
157
|
-
.where(scopeWhere(`array_contains(defined_symbols, '${(0, filter_builder_1.escapeSqlString)(symbol)}')`))
|
|
158
|
-
.limit(20)
|
|
159
|
-
.toArray();
|
|
160
|
-
const chunks = allDefs.map((row) => ({
|
|
161
|
-
path: String(row.path || ""),
|
|
162
|
-
startLine: Number(row.start_line || 0),
|
|
163
|
-
}));
|
|
173
|
+
const chunks = store.defChunks;
|
|
164
174
|
// Dedupe by file: split sub-chunks of one definition share a path,
|
|
165
175
|
// while genuine ambiguity (same name defined elsewhere) crosses files.
|
|
166
176
|
const distinct = new Map();
|
|
@@ -185,8 +195,7 @@ exports.peek = new commander_1.Command("peek")
|
|
|
185
195
|
return;
|
|
186
196
|
}
|
|
187
197
|
}
|
|
188
|
-
const
|
|
189
|
-
const graph = yield graphBuilder.buildGraph(symbol);
|
|
198
|
+
const graph = store.graph;
|
|
190
199
|
if (!graph.center) {
|
|
191
200
|
console.log((0, agent_errors_1.symbolNotFoundLines)(symbol, {
|
|
192
201
|
agent: opts.agent,
|
|
@@ -198,24 +207,13 @@ exports.peek = new commander_1.Command("peek")
|
|
|
198
207
|
}
|
|
199
208
|
const center = graph.center;
|
|
200
209
|
const rel = (p) => p.startsWith(projectRoot) ? p.slice(projectRoot.length + 1) : p;
|
|
201
|
-
//
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
.where(scopeWhere(`array_contains(defined_symbols, '${(0, filter_builder_1.escapeSqlString)(symbol)}')`))
|
|
207
|
-
.limit(1)
|
|
208
|
-
.toArray();
|
|
209
|
-
const exported = metaRows.length > 0 && Boolean(metaRows[0].is_exported);
|
|
210
|
-
const startLine = metaRows.length > 0
|
|
211
|
-
? Number(metaRows[0].start_line || 0)
|
|
212
|
-
: center.line;
|
|
213
|
-
const endLine = metaRows.length > 0
|
|
214
|
-
? Number(metaRows[0].end_line || 0)
|
|
215
|
-
: center.line;
|
|
210
|
+
// Chunk metadata for is_exported and end_line
|
|
211
|
+
const meta = store.meta;
|
|
212
|
+
const exported = (meta === null || meta === void 0 ? void 0 : meta.isExported) === true;
|
|
213
|
+
const startLine = meta ? meta.startLine : center.line;
|
|
214
|
+
const endLine = meta ? meta.endLine : center.line;
|
|
216
215
|
let callerList;
|
|
217
|
-
if (depth > 1) {
|
|
218
|
-
const multiHop = yield graphBuilder.buildGraphMultiHop(symbol, depth);
|
|
216
|
+
if (depth > 1 && store.callerTree) {
|
|
219
217
|
// Flatten caller tree
|
|
220
218
|
const flat = [];
|
|
221
219
|
function walkCallers(tree) {
|
|
@@ -229,7 +227,7 @@ exports.peek = new commander_1.Command("peek")
|
|
|
229
227
|
walkCallers(t.callers);
|
|
230
228
|
}
|
|
231
229
|
}
|
|
232
|
-
walkCallers(
|
|
230
|
+
walkCallers(store.callerTree);
|
|
233
231
|
callerList = flat;
|
|
234
232
|
}
|
|
235
233
|
else {
|
|
@@ -327,8 +325,8 @@ exports.peek = new commander_1.Command("peek")
|
|
|
327
325
|
console.log(`-> ... ${calleeList.length - MAX_CALLEES} more`);
|
|
328
326
|
}
|
|
329
327
|
if (opts.tests !== false) {
|
|
330
|
-
const {
|
|
331
|
-
const tests =
|
|
328
|
+
const { renderTestsFooterAgent } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/tests-footer")));
|
|
329
|
+
const tests = store.footerTests;
|
|
332
330
|
if (tests && tests.length > 0) {
|
|
333
331
|
for (const line of renderTestsFooterAgent(tests, projectRoot)) {
|
|
334
332
|
console.log(line);
|
|
@@ -396,8 +394,8 @@ exports.peek = new commander_1.Command("peek")
|
|
|
396
394
|
console.log(style.dim("No known callees."));
|
|
397
395
|
}
|
|
398
396
|
if (opts.tests !== false) {
|
|
399
|
-
const {
|
|
400
|
-
const tests =
|
|
397
|
+
const { renderTestsFooterHuman } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/tests-footer")));
|
|
398
|
+
const tests = store.footerTests;
|
|
401
399
|
if (tests && tests.length > 0) {
|
|
402
400
|
for (const line of renderTestsFooterHuman(tests, projectRoot)) {
|
|
403
401
|
console.log(line);
|
|
@@ -407,14 +405,18 @@ exports.peek = new commander_1.Command("peek")
|
|
|
407
405
|
}
|
|
408
406
|
}
|
|
409
407
|
catch (error) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
408
|
+
// A sandbox refusal is already one actionable line; a "Peek failed:"
|
|
409
|
+
// prefix would bury the settings key that fixes it.
|
|
410
|
+
if (!(0, store_access_1.reportStoreAccessRefusal)(error)) {
|
|
411
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
412
|
+
console.error("Peek failed:", message);
|
|
413
|
+
process.exitCode = 1;
|
|
414
|
+
}
|
|
413
415
|
}
|
|
414
416
|
finally {
|
|
415
|
-
if (
|
|
417
|
+
if (local.db) {
|
|
416
418
|
try {
|
|
417
|
-
yield
|
|
419
|
+
yield local.db.close();
|
|
418
420
|
}
|
|
419
421
|
catch (_b) { }
|
|
420
422
|
}
|
package/dist/commands/project.js
CHANGED
|
@@ -45,118 +45,50 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
exports.project = void 0;
|
|
46
46
|
const path = __importStar(require("node:path"));
|
|
47
47
|
const commander_1 = require("commander");
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const arrow_1 = require("../lib/utils/arrow");
|
|
48
|
+
const rows_handler_1 = require("../lib/daemon/rows-handler");
|
|
49
|
+
const daemon_client_1 = require("../lib/utils/daemon-client");
|
|
51
50
|
const exit_1 = require("../lib/utils/exit");
|
|
52
|
-
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
53
51
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
54
52
|
const project_root_1 = require("../lib/utils/project-root");
|
|
53
|
+
const store_access_1 = require("../lib/utils/store-access");
|
|
55
54
|
exports.project = new commander_1.Command("project")
|
|
56
55
|
.description("Show project overview — languages, structure, key symbols")
|
|
57
56
|
.option("--root <dir>", "Project root (defaults to current directory)")
|
|
58
57
|
.option("--agent", "Compact output for AI agents", false)
|
|
59
58
|
.action((opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
60
59
|
var _a, _b, _c;
|
|
61
|
-
let vectorDb = null;
|
|
62
60
|
try {
|
|
63
61
|
const resolvedRoot = (0, project_registry_1.resolveRootOrExit)(opts.root);
|
|
64
62
|
if (resolvedRoot === null)
|
|
65
63
|
return;
|
|
66
64
|
const root = (_a = (0, project_root_1.findProjectRoot)(resolvedRoot)) !== null && _a !== void 0 ? _a : resolvedRoot;
|
|
67
|
-
const prefix = root.endsWith("/") ? root : `${root}/`;
|
|
68
65
|
const projectName = path.basename(root);
|
|
69
66
|
const paths = (0, project_root_1.ensureProjectPaths)(root);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
"referenced_symbols",
|
|
81
|
-
])
|
|
82
|
-
.where((0, filter_builder_1.pathStartsWith)(prefix))
|
|
83
|
-
.limit(200000)
|
|
84
|
-
.toArray();
|
|
85
|
-
if (rows.length === 0) {
|
|
67
|
+
// The scan behind this overview reaches 200 000 rows with two symbol
|
|
68
|
+
// array columns; the daemon aggregates and ships the summary, never the
|
|
69
|
+
// rows (the platform project alone holds 266 753 chunks).
|
|
70
|
+
const overview = yield (0, store_access_1.withStoreRead)("project", {
|
|
71
|
+
daemon: () => (0, daemon_client_1.sendDaemonCommand)({ cmd: "rows.project", projectRoot: root }, { timeoutMs: 120000 }),
|
|
72
|
+
render: (resp) => resp.overview,
|
|
73
|
+
inProcess: () => (0, rows_handler_1.withLocalStore)(paths.lancedbDir, (deps) => (0, rows_handler_1.runProject)(deps, root)),
|
|
74
|
+
fallbackOnUnknownVerb: true,
|
|
75
|
+
});
|
|
76
|
+
if (overview.chunks === 0) {
|
|
86
77
|
console.log(`No indexed data found for ${root}. Run: gmax index --path ${root}`);
|
|
87
78
|
process.exitCode = 1;
|
|
88
79
|
return;
|
|
89
80
|
}
|
|
90
|
-
const files = new Set();
|
|
91
|
-
const extCounts = new Map();
|
|
92
|
-
const dirCounts = new Map();
|
|
93
|
-
const roleCounts = new Map();
|
|
94
|
-
const symbolRefs = new Map();
|
|
95
|
-
const definedInProject = new Set();
|
|
96
|
-
const entryPoints = [];
|
|
97
|
-
const seenEntryPoints = new Set();
|
|
98
|
-
for (const row of rows) {
|
|
99
|
-
const p = String(row.path || "");
|
|
100
|
-
const role = String(row.role || "IMPLEMENTATION");
|
|
101
|
-
const exported = Boolean(row.is_exported);
|
|
102
|
-
const complexity = Number(row.complexity || 0);
|
|
103
|
-
const defs = (0, arrow_1.toArr)(row.defined_symbols);
|
|
104
|
-
const refs = (0, arrow_1.toArr)(row.referenced_symbols);
|
|
105
|
-
files.add(p);
|
|
106
|
-
const ext = path.extname(p).toLowerCase() || path.basename(p);
|
|
107
|
-
extCounts.set(ext, (extCounts.get(ext) || 0) + 1);
|
|
108
|
-
const rel = p.startsWith(prefix) ? p.slice(prefix.length) : p;
|
|
109
|
-
const parts = rel.split("/");
|
|
110
|
-
const dir = parts.length > 2
|
|
111
|
-
? `${parts.slice(0, 2).join("/")}/`
|
|
112
|
-
: parts.length > 1
|
|
113
|
-
? `${parts[0]}/`
|
|
114
|
-
: "(root)";
|
|
115
|
-
if (!dirCounts.has(dir))
|
|
116
|
-
dirCounts.set(dir, { files: new Set(), chunks: 0 });
|
|
117
|
-
const dc = dirCounts.get(dir);
|
|
118
|
-
dc.files.add(p);
|
|
119
|
-
dc.chunks++;
|
|
120
|
-
roleCounts.set(role, (roleCounts.get(role) || 0) + 1);
|
|
121
|
-
for (const d of defs)
|
|
122
|
-
definedInProject.add(d);
|
|
123
|
-
for (const ref of refs)
|
|
124
|
-
symbolRefs.set(ref, (symbolRefs.get(ref) || 0) + 1);
|
|
125
|
-
if (exported &&
|
|
126
|
-
role === "ORCHESTRATION" &&
|
|
127
|
-
complexity >= 5 &&
|
|
128
|
-
defs.length > 0) {
|
|
129
|
-
const epKey = `${defs[0]}:${p}`;
|
|
130
|
-
if (!seenEntryPoints.has(epKey)) {
|
|
131
|
-
seenEntryPoints.add(epKey);
|
|
132
|
-
entryPoints.push({
|
|
133
|
-
symbol: defs[0],
|
|
134
|
-
path: p.startsWith(prefix) ? p.slice(prefix.length) : p,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
81
|
const projects = (0, project_registry_1.listProjects)();
|
|
140
82
|
const proj = projects.find((p) => p.root === root);
|
|
141
|
-
const extEntries =
|
|
142
|
-
.sort((a, b) => b[1] - a[1])
|
|
143
|
-
.slice(0, 8);
|
|
144
|
-
// Key symbols must be the project's own: raw referenced_symbols counts
|
|
145
|
-
// are dominated by JS builtins (push, slice, map, …) which say nothing
|
|
146
|
-
// about the codebase.
|
|
147
|
-
const topSymbols = Array.from(symbolRefs.entries())
|
|
148
|
-
.filter(([s]) => definedInProject.has(s) && !(0, callsites_1.isBuiltinCallee)(s))
|
|
149
|
-
.sort((a, b) => b[1] - a[1])
|
|
150
|
-
.slice(0, 8);
|
|
83
|
+
const { chunks, files, extEntries, dirEntries, roleEntries, topSymbols, entryPoints, } = overview;
|
|
151
84
|
if (opts.agent) {
|
|
152
85
|
console.log(`name\t${projectName}`);
|
|
153
86
|
console.log(`root\t${root}`);
|
|
154
|
-
console.log(`chunks\t${
|
|
155
|
-
console.log(`files\t${files
|
|
87
|
+
console.log(`chunks\t${chunks}`);
|
|
88
|
+
console.log(`files\t${files}`);
|
|
156
89
|
console.log(`last_indexed\t${(_b = proj === null || proj === void 0 ? void 0 : proj.lastIndexed) !== null && _b !== void 0 ? _b : "unknown"}`);
|
|
157
90
|
console.log(`languages\t${extEntries.map(([ext]) => ext).join(",")}`);
|
|
158
|
-
console.log(`top_dirs\t${
|
|
159
|
-
.sort((a, b) => b[1].chunks - a[1].chunks)
|
|
91
|
+
console.log(`top_dirs\t${dirEntries
|
|
160
92
|
.slice(0, 8)
|
|
161
93
|
.map(([d]) => d)
|
|
162
94
|
.join(",")}`);
|
|
@@ -164,24 +96,18 @@ exports.project = new commander_1.Command("project")
|
|
|
164
96
|
console.log(`key_symbols\t${topSymbols.map(([s]) => s).join(",")}`);
|
|
165
97
|
}
|
|
166
98
|
if (entryPoints.length > 0) {
|
|
167
|
-
console.log(`entry_points\t${entryPoints
|
|
168
|
-
.slice(0, 10)
|
|
169
|
-
.map((e) => e.symbol)
|
|
170
|
-
.join(",")}`);
|
|
99
|
+
console.log(`entry_points\t${entryPoints.map((e) => e.symbol).join(",")}`);
|
|
171
100
|
}
|
|
172
101
|
}
|
|
173
102
|
else {
|
|
174
103
|
console.log(`Project: ${projectName} (${root})`);
|
|
175
|
-
console.log(`Last indexed: ${(_c = proj === null || proj === void 0 ? void 0 : proj.lastIndexed) !== null && _c !== void 0 ? _c : "unknown"} • ${
|
|
176
|
-
console.log(`Languages: ${extEntries.map(([ext, count]) => `${ext} (${Math.round((count /
|
|
104
|
+
console.log(`Last indexed: ${(_c = proj === null || proj === void 0 ? void 0 : proj.lastIndexed) !== null && _c !== void 0 ? _c : "unknown"} • ${chunks} chunks • ${files} files\n`);
|
|
105
|
+
console.log(`Languages: ${extEntries.map(([ext, count]) => `${ext} (${Math.round((count / chunks) * 100)}%)`).join(", ")}\n`);
|
|
177
106
|
console.log("Directory structure:");
|
|
178
|
-
for (const [dir, data] of
|
|
179
|
-
.
|
|
180
|
-
.slice(0, 12)) {
|
|
181
|
-
console.log(` ${dir.padEnd(25)} (${data.files.size} files, ${data.chunks} chunks)`);
|
|
107
|
+
for (const [dir, data] of dirEntries) {
|
|
108
|
+
console.log(` ${dir.padEnd(25)} (${data.files} files, ${data.chunks} chunks)`);
|
|
182
109
|
}
|
|
183
|
-
|
|
184
|
-
console.log(`\nRoles: ${roleEntries.map(([r, c]) => `${Math.round((c / rows.length) * 100)}% ${r}`).join(", ")}\n`);
|
|
110
|
+
console.log(`\nRoles: ${roleEntries.map(([r, c]) => `${Math.round((c / chunks) * 100)}% ${r}`).join(", ")}\n`);
|
|
185
111
|
if (topSymbols.length > 0) {
|
|
186
112
|
console.log("Key symbols (by reference count):");
|
|
187
113
|
for (const [sym, count] of topSymbols) {
|
|
@@ -190,24 +116,20 @@ exports.project = new commander_1.Command("project")
|
|
|
190
116
|
}
|
|
191
117
|
if (entryPoints.length > 0) {
|
|
192
118
|
console.log("\nEntry points (exported orchestration):");
|
|
193
|
-
for (const ep of entryPoints
|
|
119
|
+
for (const ep of entryPoints) {
|
|
194
120
|
console.log(` ${ep.symbol.padEnd(25)} ${ep.path}`);
|
|
195
121
|
}
|
|
196
122
|
}
|
|
197
123
|
}
|
|
198
124
|
}
|
|
199
125
|
catch (error) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
126
|
+
if (!(0, store_access_1.reportStoreAccessRefusal)(error)) {
|
|
127
|
+
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
128
|
+
console.error("Project summary failed:", msg);
|
|
129
|
+
process.exitCode = 1;
|
|
130
|
+
}
|
|
203
131
|
}
|
|
204
132
|
finally {
|
|
205
|
-
if (vectorDb) {
|
|
206
|
-
try {
|
|
207
|
-
yield vectorDb.close();
|
|
208
|
-
}
|
|
209
|
-
catch (_d) { }
|
|
210
|
-
}
|
|
211
133
|
yield (0, exit_1.gracefulExit)();
|
|
212
134
|
}
|
|
213
135
|
}));
|
package/dist/commands/related.js
CHANGED
|
@@ -45,16 +45,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
exports.related = void 0;
|
|
46
46
|
const path = __importStar(require("node:path"));
|
|
47
47
|
const commander_1 = require("commander");
|
|
48
|
-
const
|
|
48
|
+
const rows_handler_1 = require("../lib/daemon/rows-handler");
|
|
49
49
|
const agent_errors_1 = require("../lib/utils/agent-errors");
|
|
50
|
-
const arrow_1 = require("../lib/utils/arrow");
|
|
51
50
|
const exit_1 = require("../lib/utils/exit");
|
|
52
|
-
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
53
51
|
const path_containment_1 = require("../lib/utils/path-containment");
|
|
54
52
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
55
53
|
const project_root_1 = require("../lib/utils/project-root");
|
|
56
|
-
const query_timeout_1 = require("../lib/utils/query-timeout");
|
|
57
54
|
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
55
|
+
const store_access_1 = require("../lib/utils/store-access");
|
|
58
56
|
exports.related = new commander_1.Command("related")
|
|
59
57
|
.description("Find files related by shared symbol references")
|
|
60
58
|
.argument("<file>", "File path relative to project root")
|
|
@@ -64,9 +62,8 @@ exports.related = new commander_1.Command("related")
|
|
|
64
62
|
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
65
63
|
.option("--agent", "Compact output for AI agents", false)
|
|
66
64
|
.action((file, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
67
|
-
var _a, _b;
|
|
65
|
+
var _a, _b, _c, _d;
|
|
68
66
|
const limit = Math.min(Math.max(Number.parseInt(opts.limit || "10", 10), 1), 25);
|
|
69
|
-
let vectorDb = null;
|
|
70
67
|
try {
|
|
71
68
|
const root = (0, project_registry_1.resolveRootOrExit)(opts.root);
|
|
72
69
|
if (root === null)
|
|
@@ -75,22 +72,27 @@ exports.related = new commander_1.Command("related")
|
|
|
75
72
|
(0, stale_hint_1.maybeWarnStaleChunker)(projectRoot, { agent: opts.agent });
|
|
76
73
|
(0, stale_hint_1.maybeWarnStaleEmbedding)(projectRoot, { agent: opts.agent });
|
|
77
74
|
const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
|
|
78
|
-
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
79
75
|
const absPath = (_b = (0, path_containment_1.resolveContainedExistingPath)(projectRoot, file)) !== null && _b !== void 0 ? _b : path.resolve(projectRoot, file);
|
|
80
|
-
const
|
|
81
|
-
const { resolveScope, buildScopeWhere } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/scope-filter")));
|
|
76
|
+
const { resolveScope } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/scope-filter")));
|
|
82
77
|
const scope = resolveScope({
|
|
83
78
|
projectRoot,
|
|
84
79
|
in: opts.in,
|
|
85
80
|
exclude: opts.exclude,
|
|
86
81
|
});
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
82
|
+
const locate = (matches, select, rowLimit, scoped = true) => (0, rows_handler_1.readRows)({
|
|
83
|
+
name: "related",
|
|
84
|
+
projectRoot,
|
|
85
|
+
lancedbDir: paths.lancedbDir,
|
|
86
|
+
scope,
|
|
87
|
+
select,
|
|
88
|
+
matches,
|
|
89
|
+
limit: rowLimit,
|
|
90
|
+
scoped,
|
|
91
|
+
});
|
|
92
|
+
// The file's own chunks. Unscoped, exactly as before: the file was named
|
|
93
|
+
// explicitly, so an --in that excludes it must not hide it from itself.
|
|
94
|
+
const [fileChunks] = yield locate([{ kind: "path", path: absPath }], ["defined_symbols", "referenced_symbols"], undefined, false);
|
|
95
|
+
if (!fileChunks || fileChunks.length === 0) {
|
|
94
96
|
console.log((0, agent_errors_1.fileNotFoundLines)(file, { agent: opts.agent }).join("\n"));
|
|
95
97
|
process.exitCode = 1;
|
|
96
98
|
return;
|
|
@@ -98,22 +100,20 @@ exports.related = new commander_1.Command("related")
|
|
|
98
100
|
const definedHere = new Set();
|
|
99
101
|
const referencedHere = new Set();
|
|
100
102
|
for (const chunk of fileChunks) {
|
|
101
|
-
for (const s of (
|
|
103
|
+
for (const s of (_c = chunk.defined_symbols) !== null && _c !== void 0 ? _c : [])
|
|
102
104
|
definedHere.add(s);
|
|
103
|
-
for (const s of (
|
|
105
|
+
for (const s of (_d = chunk.referenced_symbols) !== null && _d !== void 0 ? _d : [])
|
|
104
106
|
referencedHere.add(s);
|
|
105
107
|
}
|
|
106
|
-
// Dependencies
|
|
108
|
+
// Dependencies. One batched round trip instead of one per symbol — the
|
|
109
|
+
// daemon runs the same N selects, the socket carries one request.
|
|
110
|
+
const depSymbols = [...referencedHere].filter((s) => !definedHere.has(s));
|
|
111
|
+
const depResults = yield locate(depSymbols.map((symbol) => ({
|
|
112
|
+
kind: "definedSymbol",
|
|
113
|
+
symbol,
|
|
114
|
+
})), ["path"], 3);
|
|
107
115
|
const depCounts = new Map();
|
|
108
|
-
for (const
|
|
109
|
-
if (definedHere.has(sym))
|
|
110
|
-
continue;
|
|
111
|
-
const rows = yield table
|
|
112
|
-
.query()
|
|
113
|
-
.select(["path"])
|
|
114
|
-
.where(`array_contains(defined_symbols, '${(0, filter_builder_1.escapeSqlString)(sym)}') AND ${pathScope}`)
|
|
115
|
-
.limit(3)
|
|
116
|
-
.toArray();
|
|
116
|
+
for (const rows of depResults) {
|
|
117
117
|
for (const row of rows) {
|
|
118
118
|
const p = String(row.path || "");
|
|
119
119
|
if (p === absPath)
|
|
@@ -122,14 +122,12 @@ exports.related = new commander_1.Command("related")
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
// Dependents
|
|
125
|
+
const revResults = yield locate([...definedHere].map((symbol) => ({
|
|
126
|
+
kind: "referencedSymbol",
|
|
127
|
+
symbol,
|
|
128
|
+
})), ["path"], 20);
|
|
125
129
|
const revCounts = new Map();
|
|
126
|
-
for (const
|
|
127
|
-
const rows = yield table
|
|
128
|
-
.query()
|
|
129
|
-
.select(["path"])
|
|
130
|
-
.where(`array_contains(referenced_symbols, '${(0, filter_builder_1.escapeSqlString)(sym)}') AND ${pathScope}`)
|
|
131
|
-
.limit(20)
|
|
132
|
-
.toArray();
|
|
130
|
+
for (const rows of revResults) {
|
|
133
131
|
for (const row of rows) {
|
|
134
132
|
const p = String(row.path || "");
|
|
135
133
|
if (p === absPath)
|
|
@@ -170,15 +168,12 @@ exports.related = new commander_1.Command("related")
|
|
|
170
168
|
basenameRejected = true;
|
|
171
169
|
}
|
|
172
170
|
else {
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
.select(["path"])
|
|
178
|
-
.where(`content LIKE '%${(0, filter_builder_1.escapeSqlString)(basename)}%' AND ${pathScope}`)
|
|
179
|
-
.toArray(), `content LIKE %${basename}% (related mentions)`);
|
|
171
|
+
// Still no .limit(): LIKE + limit deadlocks in @lancedb when more
|
|
172
|
+
// rows match than the limit (verified). The verb caps the wire
|
|
173
|
+
// response at MAX_LOCATE_ROWS; the loop below caps the output.
|
|
174
|
+
const [rows] = yield locate([{ kind: "contentLike", value: basename }], ["path"], undefined);
|
|
180
175
|
const seen = new Set();
|
|
181
|
-
for (const row of rows) {
|
|
176
|
+
for (const row of rows !== null && rows !== void 0 ? rows : []) {
|
|
182
177
|
const p = String(row.path || "");
|
|
183
178
|
if (!p || p === absPath)
|
|
184
179
|
continue;
|
|
@@ -259,17 +254,13 @@ exports.related = new commander_1.Command("related")
|
|
|
259
254
|
}
|
|
260
255
|
}
|
|
261
256
|
catch (error) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
257
|
+
if (!(0, store_access_1.reportStoreAccessRefusal)(error)) {
|
|
258
|
+
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
259
|
+
console.error("Related files failed:", msg);
|
|
260
|
+
process.exitCode = 1;
|
|
261
|
+
}
|
|
265
262
|
}
|
|
266
263
|
finally {
|
|
267
|
-
if (vectorDb) {
|
|
268
|
-
try {
|
|
269
|
-
yield vectorDb.close();
|
|
270
|
-
}
|
|
271
|
-
catch (_c) { }
|
|
272
|
-
}
|
|
273
264
|
yield (0, exit_1.gracefulExit)();
|
|
274
265
|
}
|
|
275
266
|
}));
|
|
@@ -42,7 +42,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
42
42
|
});
|
|
43
43
|
};
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
-
exports.shouldFallbackFromDaemonError =
|
|
45
|
+
exports.shouldFallbackFromDaemonError = void 0;
|
|
46
46
|
exports.runSearch = runSearch;
|
|
47
47
|
const path = __importStar(require("node:path"));
|
|
48
48
|
const config_1 = require("../config");
|
|
@@ -55,10 +55,13 @@ const searcher_1 = require("../lib/search/searcher");
|
|
|
55
55
|
const vector_db_1 = require("../lib/store/vector-db");
|
|
56
56
|
const lock_1 = require("../lib/utils/lock");
|
|
57
57
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
const store_access_1 = require("../lib/utils/store-access");
|
|
59
|
+
/**
|
|
60
|
+
* Re-exported from store-access.ts, where the errno policy now lives so every
|
|
61
|
+
* read command shares one table. Kept here because it has been this module's
|
|
62
|
+
* public predicate since v0.16.
|
|
63
|
+
*/
|
|
64
|
+
exports.shouldFallbackFromDaemonError = store_access_1.shouldFallbackFromDaemonError;
|
|
62
65
|
/**
|
|
63
66
|
* Acquire search results, picking the path: daemon-mediated first (ships the
|
|
64
67
|
* query over IPC to the already-warm daemon), in-process fallback otherwise
|
|
@@ -116,7 +119,12 @@ function runSearch(params) {
|
|
|
116
119
|
precomputedGraph = resp.graph;
|
|
117
120
|
indexState = resp.indexState;
|
|
118
121
|
}
|
|
119
|
-
else if (
|
|
122
|
+
else if ((0, store_access_1.classifyDaemonError)(resp.error) === "sandboxed") {
|
|
123
|
+
// The sandbox blocked the socket. Naming the settings key beats
|
|
124
|
+
// "Daemon search failed: EPERM", and the store must stay unopened.
|
|
125
|
+
throw (0, store_access_1.refuseStoreAccess)("socket");
|
|
126
|
+
}
|
|
127
|
+
else if (!(0, exports.shouldFallbackFromDaemonError)(resp.error)) {
|
|
120
128
|
const detail = typeof resp.hint === "string"
|
|
121
129
|
? `: ${resp.hint}`
|
|
122
130
|
: typeof resp.error === "string"
|
|
@@ -129,10 +137,15 @@ function runSearch(params) {
|
|
|
129
137
|
}
|
|
130
138
|
}
|
|
131
139
|
catch (err) {
|
|
140
|
+
if ((0, store_access_1.isStoreAccessRefused)(err))
|
|
141
|
+
throw err;
|
|
132
142
|
const code = err === null || err === void 0 ? void 0 : err.code;
|
|
143
|
+
if ((0, store_access_1.classifyDaemonError)(code) === "sandboxed") {
|
|
144
|
+
throw (0, store_access_1.refuseStoreAccess)("socket");
|
|
145
|
+
}
|
|
133
146
|
if ((err instanceof Error &&
|
|
134
147
|
err.message.startsWith("Daemon search failed")) ||
|
|
135
|
-
!shouldFallbackFromDaemonError(code)) {
|
|
148
|
+
!(0, exports.shouldFallbackFromDaemonError)(code)) {
|
|
136
149
|
throw err;
|
|
137
150
|
}
|
|
138
151
|
if (process.env.GMAX_DEBUG === "1") {
|
|
@@ -263,7 +276,9 @@ function runSearch(params) {
|
|
|
263
276
|
}
|
|
264
277
|
catch (_d) { }
|
|
265
278
|
}
|
|
266
|
-
|
|
279
|
+
// A lease/LMDB denial from the in-process path becomes the same one-line
|
|
280
|
+
// refusal as a blocked socket, naming the filesystem settings key instead.
|
|
281
|
+
throw (0, store_access_1.asStoreAccessError)(e);
|
|
267
282
|
}
|
|
268
283
|
});
|
|
269
284
|
}
|
package/dist/commands/search.js
CHANGED
|
@@ -54,6 +54,7 @@ const project_root_1 = require("../lib/utils/project-root");
|
|
|
54
54
|
const scope_filter_1 = require("../lib/utils/scope-filter");
|
|
55
55
|
const server_registry_1 = require("../lib/utils/server-registry");
|
|
56
56
|
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
57
|
+
const store_access_1 = require("../lib/utils/store-access");
|
|
57
58
|
const search_output_1 = require("./search-output");
|
|
58
59
|
const search_run_1 = require("./search-run");
|
|
59
60
|
exports.search = new commander_1.Command("search")
|
|
@@ -331,8 +332,12 @@ Examples:
|
|
|
331
332
|
catch (error) {
|
|
332
333
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
333
334
|
_searchError = message;
|
|
334
|
-
|
|
335
|
-
|
|
335
|
+
// A sandbox refusal is already one actionable line; printing it under a
|
|
336
|
+
// "Search failed:" prefix (and with exit 1) buries the fix.
|
|
337
|
+
if (!(0, store_access_1.reportStoreAccessRefusal)(error)) {
|
|
338
|
+
console.error("Search failed:", message);
|
|
339
|
+
process.exitCode = 1;
|
|
340
|
+
}
|
|
336
341
|
}
|
|
337
342
|
finally {
|
|
338
343
|
// Best-effort query logging
|