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.
@@ -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
- let vectorDb = null;
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 paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
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
- const scopeWhere = (cond) => buildScopeWhere(scope, cond);
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 tableForCheck = yield vectorDb.ensureTable();
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 graphBuilder = new graph_builder_1.GraphBuilder(vectorDb, scope.pathPrefix, scope.excludePrefixes);
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
- // Get chunk metadata for is_exported and end_line
202
- const table = yield vectorDb.ensureTable();
203
- const metaRows = yield table
204
- .query()
205
- .select(["is_exported", "start_line", "end_line"])
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(multiHop.callerTree);
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 { fetchTestsForFooter, renderTestsFooterAgent } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/tests-footer")));
331
- const tests = yield fetchTestsForFooter(symbol, vectorDb, scope.pathPrefix, scope.excludePrefixes);
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 { fetchTestsForFooter, renderTestsFooterHuman } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/tests-footer")));
400
- const tests = yield fetchTestsForFooter(symbol, vectorDb, scope.pathPrefix, scope.excludePrefixes);
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
- const message = error instanceof Error ? error.message : "Unknown error";
411
- console.error("Peek failed:", message);
412
- process.exitCode = 1;
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 (vectorDb) {
417
+ if (local.db) {
416
418
  try {
417
- yield vectorDb.close();
419
+ yield local.db.close();
418
420
  }
419
421
  catch (_b) { }
420
422
  }
@@ -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 callsites_1 = require("../lib/graph/callsites");
49
- const vector_db_1 = require("../lib/store/vector-db");
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
- vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
71
- const table = yield vectorDb.ensureTable();
72
- const rows = yield table
73
- .query()
74
- .select([
75
- "path",
76
- "role",
77
- "is_exported",
78
- "complexity",
79
- "defined_symbols",
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 = Array.from(extCounts.entries())
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${rows.length}`);
155
- console.log(`files\t${files.size}`);
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${Array.from(dirCounts.entries())
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"} • ${rows.length} chunks • ${files.size} files\n`);
176
- console.log(`Languages: ${extEntries.map(([ext, count]) => `${ext} (${Math.round((count / rows.length) * 100)}%)`).join(", ")}\n`);
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 Array.from(dirCounts.entries())
179
- .sort((a, b) => b[1].chunks - a[1].chunks)
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
- const roleEntries = Array.from(roleCounts.entries()).sort((a, b) => b[1] - a[1]);
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.slice(0, 10)) {
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
- const msg = error instanceof Error ? error.message : "Unknown error";
201
- console.error("Project summary failed:", msg);
202
- process.exitCode = 1;
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
  }));
@@ -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 vector_db_1 = require("../lib/store/vector-db");
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 table = yield vectorDb.ensureTable();
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 pathScope = buildScopeWhere(scope);
88
- const fileChunks = yield table
89
- .query()
90
- .select(["defined_symbols", "referenced_symbols"])
91
- .where(`path = '${(0, filter_builder_1.escapeSqlString)(absPath)}'`)
92
- .toArray();
93
- if (fileChunks.length === 0) {
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 (0, arrow_1.toArr)(chunk.defined_symbols))
103
+ for (const s of (_c = chunk.defined_symbols) !== null && _c !== void 0 ? _c : [])
102
104
  definedHere.add(s);
103
- for (const s of (0, arrow_1.toArr)(chunk.referenced_symbols))
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 sym of referencedHere) {
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 sym of definedHere) {
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
- // No .limit() here: LIKE + limit deadlocks in @lancedb 0.27.x when
174
- // more rows match than the limit (verified). The loop below caps.
175
- const rows = yield (0, query_timeout_1.withQueryTimeout)(table
176
- .query()
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
- const msg = error instanceof Error ? error.message : "Unknown error";
263
- console.error("Related files failed:", msg);
264
- process.exitCode = 1;
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 = 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 DAEMON_FALLBACK_ERRORS = new Set(["ENOENT", "ECONNREFUSED"]);
59
- function shouldFallbackFromDaemonError(error) {
60
- return typeof error === "string" && DAEMON_FALLBACK_ERRORS.has(error);
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 (!shouldFallbackFromDaemonError(resp.error)) {
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
- throw e;
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
  }
@@ -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
- console.error("Search failed:", message);
335
- process.exitCode = 1;
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