grepmax 0.26.43 → 0.26.44

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.
Files changed (92) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/NOTICE +6 -0
  3. package/README.md +3 -1
  4. package/dist/bin.js +4 -0
  5. package/dist/commands/doctor.js +2 -1
  6. package/dist/commands/mcp.js +142 -67
  7. package/dist/commands/project.js +0 -1
  8. package/dist/commands/similar.js +0 -1
  9. package/dist/commands/skeleton.js +0 -1
  10. package/dist/commands/status.js +32 -18
  11. package/dist/commands/surprises.js +0 -1
  12. package/dist/commands/symbols.js +0 -1
  13. package/dist/commands/watch.js +2 -1
  14. package/dist/eval-like-limit-probe.js +60 -41
  15. package/dist/lib/analysis/surprising-connections.js +4 -3
  16. package/dist/lib/daemon/daemon.js +14 -2
  17. package/dist/lib/daemon/graph-handler.js +33 -33
  18. package/dist/lib/daemon/rows-handler.js +13 -51
  19. package/dist/lib/daemon/vector-handler.js +18 -17
  20. package/dist/lib/graph/graph-builder.js +33 -16
  21. package/dist/lib/graph/impact.js +9 -8
  22. package/dist/lib/index/index-config.js +2 -2
  23. package/dist/lib/llm/config.js +9 -3
  24. package/dist/lib/llm/tools.js +5 -4
  25. package/dist/lib/search/pagerank.js +2 -1
  26. package/dist/lib/search/searcher.js +5 -4
  27. package/dist/lib/skeleton/retriever.js +2 -1
  28. package/dist/lib/store/lance-sdk.js +46 -0
  29. package/dist/lib/store/vector-db.js +57 -16
  30. package/dist/lib/utils/cross-project.js +2 -2
  31. package/dist/lib/utils/project-registry.js +8 -8
  32. package/dist/lib/utils/query-timeout.js +53 -13
  33. package/dist/lib/utils/store-access.js +6 -5
  34. package/dist/lib/utils/store-context.js +102 -0
  35. package/dist/lib/utils/stores.js +1 -1
  36. package/dist/vendor/lancedb/LICENSE +202 -0
  37. package/dist/vendor/lancedb/NODEJS_THIRD_PARTY_LICENSES.md +668 -0
  38. package/dist/vendor/lancedb/RUST_THIRD_PARTY_LICENSES.html +14607 -0
  39. package/dist/vendor/lancedb/arrow.d.ts +296 -0
  40. package/dist/vendor/lancedb/arrow.js +1145 -0
  41. package/dist/vendor/lancedb/arrow_type.d.ts +9 -0
  42. package/dist/vendor/lancedb/arrow_type.js +29 -0
  43. package/dist/vendor/lancedb/connection.d.ts +508 -0
  44. package/dist/vendor/lancedb/connection.js +298 -0
  45. package/dist/vendor/lancedb/embedding/embedding_function.d.ts +103 -0
  46. package/dist/vendor/lancedb/embedding/embedding_function.js +192 -0
  47. package/dist/vendor/lancedb/embedding/index.d.ts +37 -0
  48. package/dist/vendor/lancedb/embedding/index.js +108 -0
  49. package/dist/vendor/lancedb/embedding/openai.d.ts +16 -0
  50. package/dist/vendor/lancedb/embedding/openai.js +81 -0
  51. package/dist/vendor/lancedb/embedding/registry.d.ts +94 -0
  52. package/dist/vendor/lancedb/embedding/registry.js +221 -0
  53. package/dist/vendor/lancedb/embedding/transformers.d.ts +36 -0
  54. package/dist/vendor/lancedb/embedding/transformers.js +110 -0
  55. package/dist/vendor/lancedb/header.d.ts +162 -0
  56. package/dist/vendor/lancedb/header.js +217 -0
  57. package/dist/vendor/lancedb/index.d.ts +246 -0
  58. package/dist/vendor/lancedb/index.js +176 -0
  59. package/dist/vendor/lancedb/indices.d.ts +721 -0
  60. package/dist/vendor/lancedb/indices.js +166 -0
  61. package/dist/vendor/lancedb/license_header.txt +2 -0
  62. package/dist/vendor/lancedb/materialized_view.d.ts +69 -0
  63. package/dist/vendor/lancedb/materialized_view.js +112 -0
  64. package/dist/vendor/lancedb/merge.d.ts +104 -0
  65. package/dist/vendor/lancedb/merge.js +120 -0
  66. package/dist/vendor/lancedb/native.d.ts +1193 -0
  67. package/dist/vendor/lancedb/native.js +688 -0
  68. package/dist/vendor/lancedb/oauth.d.ts +66 -0
  69. package/dist/vendor/lancedb/oauth.js +15 -0
  70. package/dist/vendor/lancedb/otel.d.ts +26 -0
  71. package/dist/vendor/lancedb/otel.js +114 -0
  72. package/dist/vendor/lancedb/permutation.d.ts +143 -0
  73. package/dist/vendor/lancedb/permutation.js +184 -0
  74. package/dist/vendor/lancedb/provenance.json +6 -0
  75. package/dist/vendor/lancedb/query.d.ts +663 -0
  76. package/dist/vendor/lancedb/query.js +966 -0
  77. package/dist/vendor/lancedb/rerankers/index.d.ts +5 -0
  78. package/dist/vendor/lancedb/rerankers/index.js +19 -0
  79. package/dist/vendor/lancedb/rerankers/rrf.d.ts +14 -0
  80. package/dist/vendor/lancedb/rerankers/rrf.js +28 -0
  81. package/dist/vendor/lancedb/sanitize.d.ts +32 -0
  82. package/dist/vendor/lancedb/sanitize.js +544 -0
  83. package/dist/vendor/lancedb/scannable.d.ts +92 -0
  84. package/dist/vendor/lancedb/scannable.js +200 -0
  85. package/dist/vendor/lancedb/schema.d.ts +16 -0
  86. package/dist/vendor/lancedb/schema.js +387 -0
  87. package/dist/vendor/lancedb/table.d.ts +1069 -0
  88. package/dist/vendor/lancedb/table.js +498 -0
  89. package/dist/vendor/lancedb/util.d.ts +14 -0
  90. package/dist/vendor/lancedb/util.js +77 -0
  91. package/package.json +19 -7
  92. package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
@@ -57,7 +57,9 @@ const filter_builder_1 = require("../lib/utils/filter-builder");
57
57
  const lock_1 = require("../lib/utils/lock");
58
58
  const project_registry_1 = require("../lib/utils/project-registry");
59
59
  const project_root_1 = require("../lib/utils/project-root");
60
+ const query_timeout_1 = require("../lib/utils/query-timeout");
60
61
  const store_access_1 = require("../lib/utils/store-access");
62
+ const store_context_1 = require("../lib/utils/store-context");
61
63
  const watcher_store_1 = require("../lib/utils/watcher-store");
62
64
  /**
63
65
  * Ask the daemon first. Both verbs already exist, so this works against an
@@ -117,9 +119,10 @@ function loadStatusView(projects) {
117
119
  watchers.set(project.root, { status: watcher.status });
118
120
  }
119
121
  const chunkCounts = new Map();
122
+ let db;
120
123
  try {
121
124
  const { VectorDB } = yield Promise.resolve().then(() => __importStar(require("../lib/store/vector-db")));
122
- const db = new VectorDB(config_1.PATHS.lancedbDir);
125
+ db = new VectorDB(config_1.PATHS.lancedbDir);
123
126
  const table = yield db.ensureTable();
124
127
  for (const project of projects) {
125
128
  const prefix = project.root.endsWith("/")
@@ -129,10 +132,9 @@ function loadStatusView(projects) {
129
132
  .query()
130
133
  .select(["id"])
131
134
  .where((0, filter_builder_1.pathStartsWith)(prefix))
132
- .toArray();
135
+ .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS);
133
136
  chunkCounts.set(project.root, rows.length);
134
137
  }
135
- yield db.close();
136
138
  }
137
139
  catch (err) {
138
140
  // A sandbox denial is not "the query failed" — let it surface as the
@@ -141,6 +143,9 @@ function loadStatusView(projects) {
141
143
  throw err;
142
144
  console.warn(`[status] Failed to query LanceDB for live chunk counts, using cached counts`);
143
145
  }
146
+ finally {
147
+ yield db === null || db === void 0 ? void 0 : db.close();
148
+ }
144
149
  return { watchers, chunkCounts };
145
150
  }),
146
151
  });
@@ -201,22 +206,15 @@ function buildStatusJson(input) {
201
206
  ? ((_c = input.countWorkers) !== null && _c !== void 0 ? _c : countWorkerProcesses)(d.pid)
202
207
  : null);
203
208
  }
204
- return {
205
- daemon: Object.assign(Object.assign({ running: d !== undefined, pid: (_d = d === null || d === void 0 ? void 0 : d.pid) !== null && _d !== void 0 ? _d : null, since: (d === null || d === void 0 ? void 0 : d.uptimeSec) != null ? now - d.uptimeSec * 1000 : null, workerThreads: (_e = d === null || d === void 0 ? void 0 : d.workerThreads) !== null && _e !== void 0 ? _e : null }, ((d === null || d === void 0 ? void 0 : d.resources) !== undefined ? { resources: d.resources } : {})), ((d === null || d === void 0 ? void 0 : d.compaction) !== undefined ? { compaction: d.compaction } : {})),
206
- settings: {
209
+ return Object.assign(Object.assign({}, (input.stores ? { stores: input.stores } : {})), { daemon: Object.assign(Object.assign({ running: d !== undefined, pid: (_d = d === null || d === void 0 ? void 0 : d.pid) !== null && _d !== void 0 ? _d : null, since: (d === null || d === void 0 ? void 0 : d.uptimeSec) != null ? now - d.uptimeSec * 1000 : null, workerThreads: (_e = d === null || d === void 0 ? void 0 : d.workerThreads) !== null && _e !== void 0 ? _e : null }, ((d === null || d === void 0 ? void 0 : d.resources) !== undefined ? { resources: d.resources } : {})), ((d === null || d === void 0 ? void 0 : d.compaction) !== undefined ? { compaction: d.compaction } : {})), settings: {
207
210
  embedMode: globalConfig.embedMode,
208
211
  modelTier: globalConfig.modelTier,
209
212
  vectorDim: globalConfig.vectorDim,
210
213
  queryLog: globalConfig.queryLog === true,
211
214
  workerThreads: input.workerThreads,
212
- },
213
- workersRunning,
214
- indexing: input.indexing,
215
- projects: input.projects.map((project) => { var _a; var _b, _c; return (Object.assign({ name: project.name, root: project.root, chunks: (_c = (_b = view.chunkCounts.get(project.root)) !== null && _b !== void 0 ? _b : project.chunkCount) !== null && _c !== void 0 ? _c : 0, indexedAt: toMs(project.lastIndexed), state: projectState(project, view.watchers.get(project.root)), embedding: (0, embedding_status_1.projectEmbeddingStatus)(project, globalConfig).state }, (((_a = view.health) === null || _a === void 0 ? void 0 : _a.has(project.root))
215
+ }, workersRunning, indexing: input.indexing, projects: input.projects.map((project) => { var _a; var _b, _c; return (Object.assign({ name: project.name, root: project.root, chunks: (_c = (_b = view.chunkCounts.get(project.root)) !== null && _b !== void 0 ? _b : project.chunkCount) !== null && _c !== void 0 ? _c : 0, indexedAt: toMs(project.lastIndexed), state: projectState(project, view.watchers.get(project.root)), embedding: (0, embedding_status_1.projectEmbeddingStatus)(project, globalConfig).state }, (((_a = view.health) === null || _a === void 0 ? void 0 : _a.has(project.root))
216
216
  ? { health: view.health.get(project.root) }
217
- : {}))); }),
218
- at: now,
219
- };
217
+ : {}))); }), at: now });
220
218
  }
221
219
  const style = {
222
220
  bold: (s) => `\x1b[1m${s}\x1b[22m`,
@@ -266,11 +264,12 @@ Examples:
266
264
  `)
267
265
  .action((opts) => __awaiter(void 0, void 0, void 0, function* () {
268
266
  var _a, _b;
269
- var _c, _d, _e, _f;
267
+ var _c, _d, _e, _f, _g, _h, _j;
270
268
  const globalConfig = (0, index_config_1.readGlobalConfig)();
271
269
  const projects = (0, project_registry_1.listProjects)();
272
270
  const indexing = (0, lock_1.isLocked)(config_1.PATHS.globalRoot);
273
271
  const currentRoot = (0, project_root_1.findProjectRoot)(process.cwd());
272
+ const stores = (0, store_context_1.storeInventory)();
274
273
  // Resolved before the header so a sandbox refusal prints one clean line.
275
274
  let view;
276
275
  try {
@@ -286,6 +285,7 @@ Examples:
286
285
  const { watchers, chunkCounts } = view;
287
286
  if (opts.json) {
288
287
  const json = buildStatusJson({
288
+ stores,
289
289
  view,
290
290
  projects,
291
291
  globalConfig,
@@ -303,6 +303,20 @@ Examples:
303
303
  // Header
304
304
  console.log(`\n${style.bold("gmax")} · ${globalConfig.modelTier} (${globalConfig.vectorDim}d, ${globalConfig.embedMode})${indexing ? style.yellow(" · indexing...") : ""}`);
305
305
  }
306
+ for (const store of stores) {
307
+ if (opts.agent) {
308
+ console.log(`store\t${store.home}\t${store.state}\tprefixes=${store.prefixes.join(",")}${store.error ? `\terror=${store.error}` : ""}`);
309
+ for (const project of store.projects)
310
+ console.log(`store_project\t${store.home}\t${project.name}\t${(_c = project.chunkCount) !== null && _c !== void 0 ? _c : 0}\t${(_d = project.status) !== null && _d !== void 0 ? _d : "indexed"}\tcounts=cached`);
311
+ }
312
+ else {
313
+ console.log(`\nStore: ${shortenPath(store.home)} — ${store.state}${store.error ? ` (${store.error})` : ""}`);
314
+ if (store.state === "offline")
315
+ console.log(" Connect the drive to list its projects.");
316
+ for (const project of store.projects)
317
+ console.log(` ${project.name} ${formatChunks(project.chunkCount)} chunks (cached) ${(_e = project.status) !== null && _e !== void 0 ? _e : "indexed"}`);
318
+ }
319
+ }
306
320
  if (projects.length === 0) {
307
321
  if (opts.agent) {
308
322
  console.log("(none)");
@@ -317,9 +331,9 @@ Examples:
317
331
  for (const project of projects) {
318
332
  const st = projectState(project, watchers.get(project.root));
319
333
  const isCurrent = project.root === currentRoot;
320
- const count = (_c = chunkCounts.get(project.root)) !== null && _c !== void 0 ? _c : project.chunkCount;
334
+ const count = (_f = chunkCounts.get(project.root)) !== null && _f !== void 0 ? _f : project.chunkCount;
321
335
  const identity = (0, embedding_status_1.projectEmbeddingStatus)(project, globalConfig);
322
- console.log(`${project.name}\t${formatChunks(count)}\t${formatAge(project.lastIndexed)}\t${st}\tembedding=${identity.state}${isCurrent ? "\tcurrent" : ""}${((_a = view.health) === null || _a === void 0 ? void 0 : _a.get(project.root)) ? `\t${(_d = (0, index_state_footer_1.formatIndexStateFooter)(view.health.get(project.root), { agent: true })) !== null && _d !== void 0 ? _d : ""}` : ""}`);
336
+ console.log(`${project.name}\t${formatChunks(count)}\t${formatAge(project.lastIndexed)}\t${st}\tembedding=${identity.state}${isCurrent ? "\tcurrent" : ""}${((_a = view.health) === null || _a === void 0 ? void 0 : _a.get(project.root)) ? `\t${(_g = (0, index_state_footer_1.formatIndexStateFooter)(view.health.get(project.root), { agent: true })) !== null && _g !== void 0 ? _g : ""}` : ""}`);
323
337
  }
324
338
  const legacyNotice = (0, embedding_status_1.formatLegacyEmbeddingNotice)((0, embedding_status_1.countLegacyEmbeddingProjects)(projects, globalConfig), { agent: true });
325
339
  if (legacyNotice)
@@ -335,7 +349,7 @@ Examples:
335
349
  const watcher = watchers.get(project.root);
336
350
  // Status column
337
351
  let statusStr;
338
- const projectStatus = (_e = project.status) !== null && _e !== void 0 ? _e : "indexed";
352
+ const projectStatus = (_h = project.status) !== null && _h !== void 0 ? _h : "indexed";
339
353
  if (projectStatus === "pending") {
340
354
  statusStr = style.yellow("pending");
341
355
  }
@@ -355,7 +369,7 @@ Examples:
355
369
  statusStr = style.dim("idle");
356
370
  }
357
371
  // Chunks column
358
- const count = (_f = chunkCounts.get(project.root)) !== null && _f !== void 0 ? _f : project.chunkCount;
372
+ const count = (_j = chunkCounts.get(project.root)) !== null && _j !== void 0 ? _j : project.chunkCount;
359
373
  const chunks = `${formatChunks(count)} chunks`;
360
374
  // Age column
361
375
  const age = formatAge(project.lastIndexed);
@@ -190,7 +190,6 @@ exports.surprises = new commander_1.Command("surprises")
190
190
  daemon: () => (0, daemon_client_1.sendDaemonCommand)({ cmd: "vector.surprises", projectRoot, options, top }, { timeoutMs: 300000 }),
191
191
  render: (resp) => resp,
192
192
  inProcess: () => (0, rows_handler_1.withLocalStore)(paths.lancedbDir, (deps) => (0, vector_handler_1.runSurprises)(deps, { projectRoot, options, top })),
193
- fallbackOnUnknownVerb: true,
194
193
  });
195
194
  console.log(opts.agent ? formatAgent(result, top) : formatHuman(result, top));
196
195
  }
@@ -86,7 +86,6 @@ function collectSymbols(options) {
86
86
  pattern: options.pattern,
87
87
  limit: options.limit,
88
88
  })),
89
- fallbackOnUnknownVerb: true,
90
89
  });
91
90
  });
92
91
  }
@@ -60,6 +60,7 @@ const log_rotate_1 = require("../lib/utils/log-rotate");
60
60
  const process_1 = require("../lib/utils/process");
61
61
  const project_registry_1 = require("../lib/utils/project-registry");
62
62
  const project_root_1 = require("../lib/utils/project-root");
63
+ const query_timeout_1 = require("../lib/utils/query-timeout");
63
64
  const watcher_store_1 = require("../lib/utils/watcher-store");
64
65
  // Hard ceiling on signal-driven shutdown; comfortably above the daemon's own
65
66
  // 30s operation-drain grace so the orderly path normally wins.
@@ -278,7 +279,7 @@ exports.watch = new commander_1.Command("watch")
278
279
  .select(["id"])
279
280
  .where((0, filter_builder_1.pathStartsWith)(prefix))
280
281
  .limit(1)
281
- .toArray();
282
+ .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS);
282
283
  let degraded = false;
283
284
  let degradedErrors = 0;
284
285
  let initialScanErrors = 0;
@@ -1,19 +1,37 @@
1
1
  "use strict";
2
- /**
3
- * Regression probe for the @lancedb 0.27.x LIKE + limit deadlock.
4
- *
5
- * A `content LIKE '%X%'` scan with `.limit(N)` never resolves when more than
6
- * N rows match — the limit-pushdown cancellation loses the completion (same
7
- * family as lancedb/lancedb#2189). gmax works around it by scanning without a
8
- * limit and capping in JS; this probe tells us when an upstream lancedb
9
- * upgrade makes the limited shape safe again (so the workaround can go).
10
- *
11
- * Exit 0 = limited LIKE scan resolved (upstream fixed, or matches < limit).
12
- * Exit 1 = timed out — the deadlock is still present, keep the workarounds.
13
- *
14
- * Run: `npx tsx src/eval-like-limit-probe.ts [needle]` (default: "Daemon",
15
- * which matches >100 chunks in this repo's index).
16
- */
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
17
35
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
36
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
37
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -24,39 +42,40 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
24
42
  });
25
43
  };
26
44
  Object.defineProperty(exports, "__esModule", { value: true });
27
- const config_1 = require("./config");
28
- const vector_db_1 = require("./lib/store/vector-db");
45
+ /** Native LIKE+limit regression probe. Always uses synthetic temporary data. */
46
+ const fs = __importStar(require("node:fs"));
47
+ const os = __importStar(require("node:os"));
48
+ const path = __importStar(require("node:path"));
49
+ const lance_sdk_1 = require("./lib/store/lance-sdk");
29
50
  const filter_builder_1 = require("./lib/utils/filter-builder");
30
51
  const query_timeout_1 = require("./lib/utils/query-timeout");
31
- const needle = process.argv[2] || "Daemon";
32
- const TIMEOUT_MS = 10000;
33
52
  function main() {
34
53
  return __awaiter(this, void 0, void 0, function* () {
35
- const db = new vector_db_1.VectorDB(config_1.PATHS.lancedbDir);
36
- const table = yield db.ensureTable();
37
- const where = `content LIKE '%${(0, filter_builder_1.escapeSqlString)(needle)}%'`;
38
- const all = yield (0, query_timeout_1.withQueryTimeout)(table.query().select(["path"]).where(where).toArray(), "unlimited LIKE scan", TIMEOUT_MS);
39
- console.log(`unlimited scan: ${all.length} matches for '%${needle}%'`);
40
- if (all.length < 2) {
41
- console.log("needle too rare to exercise the bug — pick a common one");
42
- process.exit(0);
43
- }
44
- const limit = Math.max(1, Math.floor(all.length / 2));
45
- const t0 = Date.now();
54
+ const needle = process.argv[2] || "Fixture";
55
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "gmax-like-probe-"));
56
+ const db = yield (0, lance_sdk_1.connect)(dir, {
57
+ session: new lance_sdk_1.Session(BigInt(8 * Math.pow(1024, 2)), BigInt(8 * Math.pow(1024, 2))),
58
+ });
46
59
  try {
47
- const rows = yield (0, query_timeout_1.withQueryTimeout)(table.query().select(["path"]).where(where).limit(limit).toArray(), `LIKE scan with limit ${limit} < ${all.length} matches`, TIMEOUT_MS);
48
- console.log(`limited scan OK: ${rows.length} rows in ${Date.now() - t0}ms — ` +
49
- `upstream deadlock not reproduced; LIKE+limit workarounds may be removable`);
50
- process.exit(0);
60
+ const table = yield db.createTable("probe", Array.from({ length: 200 }, (_, i) => ({
61
+ path: `/fixture/${i}.ts`,
62
+ content: `import ${needle}`,
63
+ })));
64
+ const where = `content LIKE '%${(0, filter_builder_1.escapeSqlString)(needle)}%'`;
65
+ const options = { timeoutMs: 5000 };
66
+ const rows = yield (0, query_timeout_1.withQueryTimeout)(table.query().select(["path"]).where(where).limit(7).toArray(options), "temporary LIKE+limit probe", 6000);
67
+ if (rows.length !== 7)
68
+ throw new Error(`Expected 7 rows, got ${rows.length}`);
69
+ console.log("Temporary LIKE+limit probe: 7 of 200 matching rows returned");
70
+ table.close();
51
71
  }
52
- catch (err) {
53
- console.error(String(err));
54
- console.error("LIKE+limit deadlock still present — keep the unlimited-scan workarounds");
55
- process.exit(1);
72
+ finally {
73
+ db.close();
74
+ fs.rmSync(dir, { recursive: true, force: true });
56
75
  }
57
76
  });
58
77
  }
59
- main().catch((err) => {
60
- console.error(err);
61
- process.exit(1);
78
+ main().catch((error) => {
79
+ console.error(error);
80
+ process.exitCode = 1;
62
81
  });
@@ -63,6 +63,7 @@ const callsites_1 = require("../graph/callsites");
63
63
  const ann_config_1 = require("../store/ann-config");
64
64
  const arrow_1 = require("../utils/arrow");
65
65
  const filter_builder_1 = require("../utils/filter-builder");
66
+ const query_timeout_1 = require("../utils/query-timeout");
66
67
  const scope_filter_1 = require("../utils/scope-filter");
67
68
  exports.DEFAULT_SURPRISE_OPTIONS = {
68
69
  sample: 160,
@@ -512,7 +513,7 @@ function hydrateRows(table, where, ids, columns) {
512
513
  .select(["id", ...columns])
513
514
  .where(`(${where}) AND id IN (${list})`)
514
515
  .limit(batch.length)
515
- .toArray());
516
+ .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS));
516
517
  for (const row of rows)
517
518
  out.set(String(row.id || ""), row);
518
519
  }
@@ -580,7 +581,7 @@ function analyzeSurprisingConnections(table_1, projectRoot_1) {
580
581
  .select(SCAN_SELECT)
581
582
  .where(where)
582
583
  .limit(opts.maxRows)
583
- .toArray());
584
+ .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS));
584
585
  const rows = rawRows.map((row) => toChunkRow(row, prefix));
585
586
  const fileEdges = buildFileEdges(rows);
586
587
  // Weak-code test: decided from the scan's bounds where possible, otherwise
@@ -643,7 +644,7 @@ function analyzeSurprisingConnections(table_1, projectRoot_1) {
643
644
  .select([...exports.SURPRISE_COLUMNS, "_distance"])
644
645
  .where(where)
645
646
  .limit(opts.neighbors + 8)
646
- .toArray());
647
+ .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS));
647
648
  for (const rawTarget of neighbors) {
648
649
  filters.rawNeighbors++;
649
650
  const target = withoutVector(toChunkRow(rawTarget, prefix));
@@ -252,7 +252,10 @@ class Daemon {
252
252
  yield this.processManager.killStaleProcesses();
253
253
  this.assertStartupActive();
254
254
  // 1. Acquire exclusive lock — kernel-enforced, atomic, auto-released on death
255
- fs.mkdirSync(path.dirname(config_1.PATHS.daemonLockFile), { recursive: true });
255
+ const ipcHome = path.dirname(config_1.PATHS.daemonLockFile);
256
+ fs.mkdirSync(ipcHome, { recursive: true, mode: 0o700 });
257
+ // IPC is local and private to this account, including an existing home.
258
+ fs.chmodSync(ipcHome, 0o700);
256
259
  fs.writeFileSync(config_1.PATHS.daemonLockFile, "", { flag: "a" }); // ensure file exists
257
260
  (0, logger_1.debug)("daemon", "acquiring lock...");
258
261
  try {
@@ -338,7 +341,16 @@ class Daemon {
338
341
  reject(err);
339
342
  }
340
343
  });
341
- this.server.listen(config_1.PATHS.daemonSocket, () => resolve());
344
+ this.server.listen(config_1.PATHS.daemonSocket, () => {
345
+ try {
346
+ fs.chmodSync(config_1.PATHS.daemonSocket, 0o600);
347
+ resolve();
348
+ }
349
+ catch (error) {
350
+ this.server.close();
351
+ reject(error);
352
+ }
353
+ });
342
354
  });
343
355
  this.assertStartupActive();
344
356
  // 3. Write PID file AFTER socket is listening — ensures any process that
@@ -1,29 +1,4 @@
1
1
  "use strict";
2
- /**
3
- * Daemon-side handlers for the `graph.*` read verbs.
4
- *
5
- * The commands that used to open LanceDB themselves (`test`, `impact`, `trace`,
6
- * `peek`, `dead`, `audit`) now send one IPC line and render the answer. The work
7
- * they used to do between `ensureTable()` and the first `console.log` lives
8
- * here, so both paths run the *same* code:
9
- *
10
- * - the daemon runs `runGraph*` against its warm `VectorDB`
11
- * - a CLI with no daemon runs the identical `runGraph*` against a local one
12
- *
13
- * That is what makes the two paths byte-identical: the commands hold only
14
- * argument parsing and rendering, and every clamp lives inside the `runGraph*`
15
- * function rather than in one of the two callers.
16
- *
17
- * Results are finished answers, never raw rows. `graph.audit` reads up to 500k
18
- * chunks and returns a few dozen ranked lines; `graph.dead` reads the whole
19
- * caller set and returns a count plus three locations. Nothing here streams.
20
- *
21
- * Scope on the wire: the CLI resolves `--in`/`--exclude` locally (that needs its
22
- * cwd and the filesystem) and sends absolute prefixes. The daemon re-validates
23
- * every one with `resolveContainedPath` — exactly as the `search` case does —
24
- * and rebuilds the same `ResolvedScope` with `scopeFromPrefixes`, including the
25
- * single-`--in`-collapses-into-pathPrefix rule, so the WHERE clauses match.
26
- */
27
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
28
3
  if (k2 === undefined) k2 = k;
29
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -88,6 +63,32 @@ exports.computeAudit = computeAudit;
88
63
  exports.runGraphAudit = runGraphAudit;
89
64
  exports.createGraphVerbs = createGraphVerbs;
90
65
  exports.callGraphVerb = callGraphVerb;
66
+ const query_timeout_1 = require("../utils/query-timeout");
67
+ /**
68
+ * Daemon-side handlers for the `graph.*` read verbs.
69
+ *
70
+ * The commands that used to open LanceDB themselves (`test`, `impact`, `trace`,
71
+ * `peek`, `dead`, `audit`) now send one IPC line and render the answer. The work
72
+ * they used to do between `ensureTable()` and the first `console.log` lives
73
+ * here, so both paths run the *same* code:
74
+ *
75
+ * - the daemon runs `runGraph*` against its warm `VectorDB`
76
+ * - a CLI with no daemon runs the identical `runGraph*` against a local one
77
+ *
78
+ * That is what makes the two paths byte-identical: the commands hold only
79
+ * argument parsing and rendering, and every clamp lives inside the `runGraph*`
80
+ * function rather than in one of the two callers.
81
+ *
82
+ * Results are finished answers, never raw rows. `graph.audit` reads up to 500k
83
+ * chunks and returns a few dozen ranked lines; `graph.dead` reads the whole
84
+ * caller set and returns a count plus three locations. Nothing here streams.
85
+ *
86
+ * Scope on the wire: the CLI resolves `--in`/`--exclude` locally (that needs its
87
+ * cwd and the filesystem) and sends absolute prefixes. The daemon re-validates
88
+ * every one with `resolveContainedPath` — exactly as the `search` case does —
89
+ * and rebuilds the same `ResolvedScope` with `scopeFromPrefixes`, including the
90
+ * single-`--in`-collapses-into-pathPrefix rule, so the WHERE clauses match.
91
+ */
91
92
  const path = __importStar(require("node:path"));
92
93
  const languages_1 = require("../core/languages");
93
94
  const callsites_1 = require("../graph/callsites");
@@ -328,7 +329,7 @@ function runGraphPeek(db, args) {
328
329
  .select(["path", "start_line"])
329
330
  .where(definedWhere)
330
331
  .limit(20)
331
- .toArray();
332
+ .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS);
332
333
  const defChunks = defRows.map((row) => ({
333
334
  path: String(row.path || ""),
334
335
  startLine: Number(row.start_line || 0),
@@ -340,7 +341,7 @@ function runGraphPeek(db, args) {
340
341
  .select(["is_exported", "start_line", "end_line"])
341
342
  .where(definedWhere)
342
343
  .limit(1)
343
- .toArray();
344
+ .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS);
344
345
  const metaRow = metaRows[0];
345
346
  const meta = metaRow
346
347
  ? {
@@ -366,7 +367,7 @@ function runGraphDead(db, args) {
366
367
  .select(["path", "start_line", "is_exported"])
367
368
  .where((0, scope_filter_1.buildScopeWhere)(args.scope, `array_contains(defined_symbols, '${(0, filter_builder_1.escapeSqlString)(args.symbol)}')`))
368
369
  .limit(1)
369
- .toArray();
370
+ .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS);
370
371
  if (defRows.length === 0) {
371
372
  return {
372
373
  found: false,
@@ -696,7 +697,7 @@ function runGraphAudit(db, args) {
696
697
  ])
697
698
  .where((0, scope_filter_1.buildScopeWhere)(args.scope))
698
699
  .limit(AUDIT_ROW_LIMIT)
699
- .toArray();
700
+ .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS);
700
701
  if (rows.length === 0)
701
702
  return null;
702
703
  return computeAudit(rows.map((r) => {
@@ -851,10 +852,9 @@ exports.GRAPH_VERB_TIMEOUT_MS = 60000;
851
852
  /**
852
853
  * Send one graph verb through the store-access policy.
853
854
  *
854
- * `fallbackOnUnknownVerb` is the one-release skew allowance: a daemon older
855
- * than this CLI answers `unknown command`, and the command still works. An
856
- * unregistered project skips the daemon outright — see isDaemonReadableProject.
855
+ * An unsupported verb requires restarting the live daemon. An unregistered
856
+ * project skips the daemon outright — see isDaemonReadableProject.
857
857
  */
858
858
  function callGraphVerb(verb, call) {
859
- return (0, store_access_1.withStoreRead)(verb, Object.assign({ skipDaemon: !isDaemonReadableProject(call.projectRoot), fallbackOnUnknownVerb: true, daemon: () => (0, daemon_client_1.sendDaemonCommand)(Object.assign(Object.assign({ cmd: verb }, encodeScope(call.projectRoot, call.scope)), call.payload), { timeoutMs: exports.GRAPH_VERB_TIMEOUT_MS }), render: call.render, inProcess: call.inProcess }, call.fallback));
859
+ return (0, store_access_1.withStoreRead)(verb, Object.assign({ skipDaemon: !isDaemonReadableProject(call.projectRoot), daemon: () => (0, daemon_client_1.sendDaemonCommand)(Object.assign(Object.assign({ cmd: verb }, encodeScope(call.projectRoot, call.scope)), call.payload), { timeoutMs: exports.GRAPH_VERB_TIMEOUT_MS }), render: call.render, inProcess: call.inProcess }, call.fallback));
860
860
  }
@@ -1,36 +1,4 @@
1
1
  "use strict";
2
- /**
3
- * Daemon-side handlers for the `rows.*` read verbs.
4
- *
5
- * These serve the commands whose store work is a plain row select: `symbols`,
6
- * `project`, `extract`, `related`, `log`, `skeleton`. The daemon runs the query
7
- * against its already-warm VectorDB and returns the finished answer; the client
8
- * renders it and does anything tied to its own cwd, git, or filesystem.
9
- *
10
- * Every exported `run*` function is the *shared* implementation: the verb
11
- * handler calls it with the daemon's VectorDB, and the command's in-process
12
- * fallback calls the same function with a VectorDB it opened itself. That is
13
- * what makes the two paths byte-identical — there is only one implementation of
14
- * each query and each aggregation, and neither path can drift from the other.
15
- *
16
- * Two things are deliberately *not* raw row proxies:
17
- *
18
- * - `rows.symbols` returns the aggregated symbol table, not the 2000–10000 rows
19
- * the select produces. The aggregation is pure, so moving it daemon-side
20
- * cannot change the answer, and it turns a multi-megabyte JSON line into a
21
- * list bounded by `--limit`.
22
- * - `rows.project` likewise returns the overview, not the rows. `project.ts`
23
- * selects up to 200 000 rows including two symbol-array columns; on the
24
- * platform project (266 753 chunks) proxying those rows would push hundreds
25
- * of megabytes through the daemon's event loop for a summary that fits in a
26
- * few kilobytes. The plan's own reasoning — "verbs at the library-function
27
- * boundary, not a row proxy" — applies here more than anywhere.
28
- *
29
- * `rows.locate` *is* a row select, because its callers need the rows: extract
30
- * reads the file body at the returned line range, log feeds the paths to git,
31
- * related counts them. It is batched (an array of matchers, one response) so
32
- * `related`'s per-symbol loop costs one round trip instead of hundreds.
33
- */
34
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
35
3
  if (k2 === undefined) k2 = k;
36
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -92,13 +60,14 @@ exports.findFileBySymbol = findFileBySymbol;
92
60
  exports.readRows = readRows;
93
61
  exports.handleRowsSkeleton = handleRowsSkeleton;
94
62
  exports.registerRowsVerbs = registerRowsVerbs;
63
+ const query_timeout_1 = require("../utils/query-timeout");
95
64
  const callsites_1 = require("../graph/callsites");
96
65
  const retriever_1 = require("../skeleton/retriever");
97
66
  const arrow_1 = require("../utils/arrow");
98
67
  const filter_builder_1 = require("../utils/filter-builder");
99
68
  const path_containment_1 = require("../utils/path-containment");
100
69
  const project_registry_1 = require("../utils/project-registry");
101
- const query_timeout_1 = require("../utils/query-timeout");
70
+ const query_timeout_2 = require("../utils/query-timeout");
102
71
  const scope_filter_1 = require("../utils/scope-filter");
103
72
  const read_verbs_1 = require("./read-verbs");
104
73
  /**
@@ -109,10 +78,10 @@ const read_verbs_1 = require("./read-verbs");
109
78
  * only from a `withStoreRead` `inProcess` callback — i.e. only when nothing is
110
79
  * listening on the daemon socket.
111
80
  */
112
- function withLocalStore(lancedbDir, fn) {
81
+ function withLocalStore(lancedbDir, fn, vectorDim) {
113
82
  return __awaiter(this, void 0, void 0, function* () {
114
83
  const { VectorDB } = yield Promise.resolve().then(() => __importStar(require("../store/vector-db")));
115
- const db = new VectorDB(lancedbDir);
84
+ const db = new VectorDB(lancedbDir, vectorDim);
116
85
  try {
117
86
  return yield fn({ vectorDb: db });
118
87
  }
@@ -244,7 +213,7 @@ function runSymbols(deps, req) {
244
213
  if (req.pathPrefix) {
245
214
  query = query.where((0, filter_builder_1.pathStartsWith)((0, filter_builder_1.normalizePath)(req.pathPrefix)));
246
215
  }
247
- const rows = yield query.toArray();
216
+ const rows = yield query.toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS);
248
217
  const map = new Map();
249
218
  for (const row of rows) {
250
219
  const defs = toStringArray(row.defined_symbols);
@@ -321,7 +290,7 @@ function runProject(deps, projectRoot) {
321
290
  ])
322
291
  .where((0, filter_builder_1.pathStartsWith)(prefix))
323
292
  .limit(200000)
324
- .toArray();
293
+ .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS);
325
294
  const nodePath = yield Promise.resolve().then(() => __importStar(require("node:path")));
326
295
  const files = new Set();
327
296
  const extCounts = new Map();
@@ -420,13 +389,7 @@ const LOCATE_COLUMNS = new Set([
420
389
  "id",
421
390
  ]);
422
391
  const ARRAY_COLUMNS = new Set(["defined_symbols", "referenced_symbols"]);
423
- /**
424
- * Upper bound on rows one matcher may return when the caller sets no limit.
425
- * `related`'s `content LIKE` scan deliberately has no `.limit()` — the limit
426
- * pushdown deadlocks on that shape (see query-timeout.ts) — and its JS loop
427
- * caps at `--limit` distinct paths, so a wire cap only bites on a query that
428
- * would already have been unreasonable to render.
429
- */
392
+ /** Upper bound applied by the native query before materialization/wire output. */
430
393
  exports.MAX_LOCATE_ROWS = 5000;
431
394
  function matchCondition(match) {
432
395
  switch (match.kind) {
@@ -477,7 +440,7 @@ function normalizeRow(row, select) {
477
440
  /** Run a batch of row selects, one result array per matcher, order preserved. */
478
441
  function runLocate(deps, req) {
479
442
  return __awaiter(this, void 0, void 0, function* () {
480
- var _a;
443
+ var _a, _b;
481
444
  const table = yield tableOf(deps);
482
445
  const scoped = req.scoped !== false;
483
446
  const pathScope = (0, scope_filter_1.buildScopeWhere)(req.scope);
@@ -488,11 +451,10 @@ function runLocate(deps, req) {
488
451
  .query()
489
452
  .select(req.select)
490
453
  .where(scoped ? `${where} AND ${pathScope}` : where);
491
- if (req.limit !== undefined)
492
- query = query.limit(req.limit);
493
- const rows = yield (0, query_timeout_1.withQueryTimeout)(query.toArray(), label);
454
+ query = query.limit((_a = req.limit) !== null && _a !== void 0 ? _a : exports.MAX_LOCATE_ROWS);
455
+ const rows = yield (0, query_timeout_2.withQueryTimeout)(query.toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS), label);
494
456
  results.push(rows
495
- .slice(0, (_a = req.limit) !== null && _a !== void 0 ? _a : exports.MAX_LOCATE_ROWS)
457
+ .slice(0, (_b = req.limit) !== null && _b !== void 0 ? _b : exports.MAX_LOCATE_ROWS)
496
458
  .map((row) => normalizeRow(row, req.select)));
497
459
  }
498
460
  return results;
@@ -579,7 +541,7 @@ function findFileBySymbol(db, symbol, projectRoot) {
579
541
  .search(symbol)
580
542
  .where((0, filter_builder_1.pathStartsWith)(`${projectRoot}/`))
581
543
  .limit(10)
582
- .toArray();
544
+ .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS);
583
545
  for (const result of results) {
584
546
  const defined = result.defined_symbols;
585
547
  if ((0, arrow_1.toArr)(defined).includes(symbol)) {
@@ -623,7 +585,7 @@ function readRows(opts) {
623
585
  matches: opts.matches,
624
586
  limit: opts.limit,
625
587
  scoped: opts.scoped,
626
- })), fallbackOnUnknownVerb: true }, opts.fallback));
588
+ }), opts.vectorDim) }, opts.fallback));
627
589
  });
628
590
  }
629
591
  function handleRowsSkeleton(deps, payload) {