grepmax 0.26.42 → 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 (95) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/NOTICE +6 -0
  3. package/README.md +7 -1
  4. package/dist/bin.js +4 -0
  5. package/dist/commands/doctor.js +23 -33
  6. package/dist/commands/mcp.js +144 -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 +35 -19
  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 +36 -9
  17. package/dist/lib/daemon/graph-handler.js +33 -33
  18. package/dist/lib/daemon/ipc-handler.js +11 -10
  19. package/dist/lib/daemon/rows-handler.js +13 -51
  20. package/dist/lib/daemon/vector-handler.js +18 -17
  21. package/dist/lib/graph/graph-builder.js +33 -16
  22. package/dist/lib/graph/impact.js +9 -8
  23. package/dist/lib/index/index-config.js +2 -2
  24. package/dist/lib/llm/config.js +9 -3
  25. package/dist/lib/llm/tools.js +5 -4
  26. package/dist/lib/search/pagerank.js +2 -1
  27. package/dist/lib/search/searcher.js +5 -4
  28. package/dist/lib/skeleton/retriever.js +2 -1
  29. package/dist/lib/store/compaction-result.js +35 -0
  30. package/dist/lib/store/lance-sdk.js +46 -0
  31. package/dist/lib/store/vector-db.js +118 -31
  32. package/dist/lib/utils/cross-project.js +2 -2
  33. package/dist/lib/utils/doctor-optimize.js +81 -0
  34. package/dist/lib/utils/project-registry.js +8 -8
  35. package/dist/lib/utils/query-timeout.js +53 -13
  36. package/dist/lib/utils/store-access.js +6 -5
  37. package/dist/lib/utils/store-context.js +102 -0
  38. package/dist/lib/utils/stores.js +1 -1
  39. package/dist/vendor/lancedb/LICENSE +202 -0
  40. package/dist/vendor/lancedb/NODEJS_THIRD_PARTY_LICENSES.md +668 -0
  41. package/dist/vendor/lancedb/RUST_THIRD_PARTY_LICENSES.html +14607 -0
  42. package/dist/vendor/lancedb/arrow.d.ts +296 -0
  43. package/dist/vendor/lancedb/arrow.js +1145 -0
  44. package/dist/vendor/lancedb/arrow_type.d.ts +9 -0
  45. package/dist/vendor/lancedb/arrow_type.js +29 -0
  46. package/dist/vendor/lancedb/connection.d.ts +508 -0
  47. package/dist/vendor/lancedb/connection.js +298 -0
  48. package/dist/vendor/lancedb/embedding/embedding_function.d.ts +103 -0
  49. package/dist/vendor/lancedb/embedding/embedding_function.js +192 -0
  50. package/dist/vendor/lancedb/embedding/index.d.ts +37 -0
  51. package/dist/vendor/lancedb/embedding/index.js +108 -0
  52. package/dist/vendor/lancedb/embedding/openai.d.ts +16 -0
  53. package/dist/vendor/lancedb/embedding/openai.js +81 -0
  54. package/dist/vendor/lancedb/embedding/registry.d.ts +94 -0
  55. package/dist/vendor/lancedb/embedding/registry.js +221 -0
  56. package/dist/vendor/lancedb/embedding/transformers.d.ts +36 -0
  57. package/dist/vendor/lancedb/embedding/transformers.js +110 -0
  58. package/dist/vendor/lancedb/header.d.ts +162 -0
  59. package/dist/vendor/lancedb/header.js +217 -0
  60. package/dist/vendor/lancedb/index.d.ts +246 -0
  61. package/dist/vendor/lancedb/index.js +176 -0
  62. package/dist/vendor/lancedb/indices.d.ts +721 -0
  63. package/dist/vendor/lancedb/indices.js +166 -0
  64. package/dist/vendor/lancedb/license_header.txt +2 -0
  65. package/dist/vendor/lancedb/materialized_view.d.ts +69 -0
  66. package/dist/vendor/lancedb/materialized_view.js +112 -0
  67. package/dist/vendor/lancedb/merge.d.ts +104 -0
  68. package/dist/vendor/lancedb/merge.js +120 -0
  69. package/dist/vendor/lancedb/native.d.ts +1193 -0
  70. package/dist/vendor/lancedb/native.js +688 -0
  71. package/dist/vendor/lancedb/oauth.d.ts +66 -0
  72. package/dist/vendor/lancedb/oauth.js +15 -0
  73. package/dist/vendor/lancedb/otel.d.ts +26 -0
  74. package/dist/vendor/lancedb/otel.js +114 -0
  75. package/dist/vendor/lancedb/permutation.d.ts +143 -0
  76. package/dist/vendor/lancedb/permutation.js +184 -0
  77. package/dist/vendor/lancedb/provenance.json +6 -0
  78. package/dist/vendor/lancedb/query.d.ts +663 -0
  79. package/dist/vendor/lancedb/query.js +966 -0
  80. package/dist/vendor/lancedb/rerankers/index.d.ts +5 -0
  81. package/dist/vendor/lancedb/rerankers/index.js +19 -0
  82. package/dist/vendor/lancedb/rerankers/rrf.d.ts +14 -0
  83. package/dist/vendor/lancedb/rerankers/rrf.js +28 -0
  84. package/dist/vendor/lancedb/sanitize.d.ts +32 -0
  85. package/dist/vendor/lancedb/sanitize.js +544 -0
  86. package/dist/vendor/lancedb/scannable.d.ts +92 -0
  87. package/dist/vendor/lancedb/scannable.js +200 -0
  88. package/dist/vendor/lancedb/schema.d.ts +16 -0
  89. package/dist/vendor/lancedb/schema.js +387 -0
  90. package/dist/vendor/lancedb/table.d.ts +1069 -0
  91. package/dist/vendor/lancedb/table.js +498 -0
  92. package/dist/vendor/lancedb/util.d.ts +14 -0
  93. package/dist/vendor/lancedb/util.js +77 -0
  94. package/package.json +19 -7
  95. 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
@@ -96,7 +98,9 @@ function loadStatusView(projects) {
96
98
  chunkCounts.set(project.root, stats.chunks);
97
99
  }
98
100
  }
99
- const daemon = Object.assign(Object.assign({}, (resp.resources !== undefined
101
+ const daemon = Object.assign(Object.assign(Object.assign({}, (resp.compaction !== undefined
102
+ ? { compaction: resp.compaction }
103
+ : {})), (resp.resources !== undefined
100
104
  ? { resources: resp.resources }
101
105
  : {})), { pid: typeof resp.pid === "number" ? resp.pid : null, uptimeSec: typeof resp.uptime === "number" ? resp.uptime : null,
102
106
  // Older daemons do not report these.
@@ -115,9 +119,10 @@ function loadStatusView(projects) {
115
119
  watchers.set(project.root, { status: watcher.status });
116
120
  }
117
121
  const chunkCounts = new Map();
122
+ let db;
118
123
  try {
119
124
  const { VectorDB } = yield Promise.resolve().then(() => __importStar(require("../lib/store/vector-db")));
120
- const db = new VectorDB(config_1.PATHS.lancedbDir);
125
+ db = new VectorDB(config_1.PATHS.lancedbDir);
121
126
  const table = yield db.ensureTable();
122
127
  for (const project of projects) {
123
128
  const prefix = project.root.endsWith("/")
@@ -127,10 +132,9 @@ function loadStatusView(projects) {
127
132
  .query()
128
133
  .select(["id"])
129
134
  .where((0, filter_builder_1.pathStartsWith)(prefix))
130
- .toArray();
135
+ .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS);
131
136
  chunkCounts.set(project.root, rows.length);
132
137
  }
133
- yield db.close();
134
138
  }
135
139
  catch (err) {
136
140
  // A sandbox denial is not "the query failed" — let it surface as the
@@ -139,6 +143,9 @@ function loadStatusView(projects) {
139
143
  throw err;
140
144
  console.warn(`[status] Failed to query LanceDB for live chunk counts, using cached counts`);
141
145
  }
146
+ finally {
147
+ yield db === null || db === void 0 ? void 0 : db.close();
148
+ }
142
149
  return { watchers, chunkCounts };
143
150
  }),
144
151
  });
@@ -199,22 +206,15 @@ function buildStatusJson(input) {
199
206
  ? ((_c = input.countWorkers) !== null && _c !== void 0 ? _c : countWorkerProcesses)(d.pid)
200
207
  : null);
201
208
  }
202
- return {
203
- daemon: 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 } : {})),
204
- 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: {
205
210
  embedMode: globalConfig.embedMode,
206
211
  modelTier: globalConfig.modelTier,
207
212
  vectorDim: globalConfig.vectorDim,
208
213
  queryLog: globalConfig.queryLog === true,
209
214
  workerThreads: input.workerThreads,
210
- },
211
- workersRunning,
212
- indexing: input.indexing,
213
- 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))
214
216
  ? { health: view.health.get(project.root) }
215
- : {}))); }),
216
- at: now,
217
- };
217
+ : {}))); }), at: now });
218
218
  }
219
219
  const style = {
220
220
  bold: (s) => `\x1b[1m${s}\x1b[22m`,
@@ -264,11 +264,12 @@ Examples:
264
264
  `)
265
265
  .action((opts) => __awaiter(void 0, void 0, void 0, function* () {
266
266
  var _a, _b;
267
- var _c, _d, _e, _f;
267
+ var _c, _d, _e, _f, _g, _h, _j;
268
268
  const globalConfig = (0, index_config_1.readGlobalConfig)();
269
269
  const projects = (0, project_registry_1.listProjects)();
270
270
  const indexing = (0, lock_1.isLocked)(config_1.PATHS.globalRoot);
271
271
  const currentRoot = (0, project_root_1.findProjectRoot)(process.cwd());
272
+ const stores = (0, store_context_1.storeInventory)();
272
273
  // Resolved before the header so a sandbox refusal prints one clean line.
273
274
  let view;
274
275
  try {
@@ -284,6 +285,7 @@ Examples:
284
285
  const { watchers, chunkCounts } = view;
285
286
  if (opts.json) {
286
287
  const json = buildStatusJson({
288
+ stores,
287
289
  view,
288
290
  projects,
289
291
  globalConfig,
@@ -301,6 +303,20 @@ Examples:
301
303
  // Header
302
304
  console.log(`\n${style.bold("gmax")} · ${globalConfig.modelTier} (${globalConfig.vectorDim}d, ${globalConfig.embedMode})${indexing ? style.yellow(" · indexing...") : ""}`);
303
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
+ }
304
320
  if (projects.length === 0) {
305
321
  if (opts.agent) {
306
322
  console.log("(none)");
@@ -315,9 +331,9 @@ Examples:
315
331
  for (const project of projects) {
316
332
  const st = projectState(project, watchers.get(project.root));
317
333
  const isCurrent = project.root === currentRoot;
318
- 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;
319
335
  const identity = (0, embedding_status_1.projectEmbeddingStatus)(project, globalConfig);
320
- 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 : ""}` : ""}`);
321
337
  }
322
338
  const legacyNotice = (0, embedding_status_1.formatLegacyEmbeddingNotice)((0, embedding_status_1.countLegacyEmbeddingProjects)(projects, globalConfig), { agent: true });
323
339
  if (legacyNotice)
@@ -333,7 +349,7 @@ Examples:
333
349
  const watcher = watchers.get(project.root);
334
350
  // Status column
335
351
  let statusStr;
336
- const projectStatus = (_e = project.status) !== null && _e !== void 0 ? _e : "indexed";
352
+ const projectStatus = (_h = project.status) !== null && _h !== void 0 ? _h : "indexed";
337
353
  if (projectStatus === "pending") {
338
354
  statusStr = style.yellow("pending");
339
355
  }
@@ -353,7 +369,7 @@ Examples:
353
369
  statusStr = style.dim("idle");
354
370
  }
355
371
  // Chunks column
356
- 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;
357
373
  const chunks = `${formatChunks(count)} chunks`;
358
374
  // Age column
359
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
@@ -609,13 +621,23 @@ class Daemon {
609
621
  * fall back to in-process only when no daemon answers, and are then the sole
610
622
  * writer themselves.
611
623
  */
624
+ compactionStatus() {
625
+ var _a;
626
+ var _b;
627
+ return (_b = (_a = this.vectorDb) === null || _a === void 0 ? void 0 : _a.compactionStatus()) !== null && _b !== void 0 ? _b : null;
628
+ }
612
629
  runOptimize() {
613
630
  return __awaiter(this, void 0, void 0, function* () {
631
+ var _a;
614
632
  const db = this.vectorDb;
615
633
  if (!db)
616
634
  throw new Error("daemon resources not ready");
617
- yield this.runSharedOperation("store-maintenance", undefined, () => db.runMaintenance({ force: true }));
618
- return { ok: true };
635
+ const compaction = yield this.runSharedOperation("store-maintenance", undefined, () => db.runMaintenance({ force: true }));
636
+ if (!compaction)
637
+ return { ok: false, error: "maintenance produced no compaction outcome" };
638
+ return Object.assign({ ok: compaction.status === "completed", compaction }, (compaction.status === "completed"
639
+ ? {}
640
+ : { error: (_a = compaction.reason) !== null && _a !== void 0 ? _a : compaction.status }));
619
641
  });
620
642
  }
621
643
  operationStatus() {
@@ -1867,13 +1889,18 @@ class Daemon {
1867
1889
  if (this.recycleDueSinceMs === null &&
1868
1890
  !ageExceeded &&
1869
1891
  sampleFootprint &&
1870
- RSS_WATERMARK_MB > 0 &&
1871
- // A fresh daemon above the watermark would recycle in a loop; give the
1872
- // caches a chance to settle before judging the footprint.
1873
- ageMs > FOOTPRINT_RECYCLE_MIN_AGE_MS) {
1892
+ RSS_WATERMARK_MB > 0) {
1874
1893
  footprintMb = (0, process_footprint_1.readFootprintMb)();
1875
1894
  }
1876
- const footprintExceeded = footprintMb !== null && footprintMb > RSS_WATERMARK_MB;
1895
+ // The existing five-minute probe also records a baseline for memory soaks;
1896
+ // the intervening heartbeat ticks add no footprint probe or snapshot.
1897
+ if (sampleFootprint)
1898
+ this.logResourceSnapshot("periodic", footprintMb);
1899
+ const footprintExceeded = footprintMb !== null &&
1900
+ footprintMb > RSS_WATERMARK_MB &&
1901
+ // Sampling young daemons is useful; recycling them would loop before
1902
+ // their caches have had a chance to settle.
1903
+ ageMs > FOOTPRINT_RECYCLE_MIN_AGE_MS;
1877
1904
  if (this.recycleDueSinceMs === null) {
1878
1905
  if (!ageExceeded && !footprintExceeded)
1879
1906
  return;
@@ -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
  }
@@ -122,8 +122,8 @@ function startHeartbeat(conn, intervalMs = HEARTBEAT_INTERVAL_MS) {
122
122
  */
123
123
  function handleCommand(daemon, cmd, conn) {
124
124
  return __awaiter(this, void 0, void 0, function* () {
125
- var _a;
126
- var _b, _c, _d, _e, _f, _g, _h, _j;
125
+ var _a, _b;
126
+ var _c, _d, _e, _f, _g, _h, _j, _k, _l;
127
127
  try {
128
128
  (0, logger_1.debug)("daemon", `ipc cmd=${cmd.cmd}${cmd.root ? ` root=${cmd.root}` : ""}`);
129
129
  if (cmd.cmd !== "ping" &&
@@ -186,7 +186,8 @@ function handleCommand(daemon, cmd, conn) {
186
186
  diskPressure: daemon.getDiskPressure(),
187
187
  mlx: daemon.getMlxStatus(),
188
188
  workers: daemon.workerCount(),
189
- resources: (_b = (_a = daemon.resourceSnapshot) === null || _a === void 0 ? void 0 : _a.call(daemon)) !== null && _b !== void 0 ? _b : null,
189
+ resources: (_c = (_a = daemon.resourceSnapshot) === null || _a === void 0 ? void 0 : _a.call(daemon)) !== null && _c !== void 0 ? _c : null,
190
+ compaction: (_d = (_b = daemon.compactionStatus) === null || _b === void 0 ? void 0 : _b.call(daemon)) !== null && _d !== void 0 ? _d : null,
190
191
  workerThreads: config_1.WORKER_THREADS_SETTING,
191
192
  };
192
193
  case "optimize":
@@ -202,14 +203,14 @@ function handleCommand(daemon, cmd, conn) {
202
203
  return Object.assign({ ok: true }, (yield daemon.projectStats(root)));
203
204
  }
204
205
  case "shutdown": {
205
- const reason = String((_c = cmd.reason) !== null && _c !== void 0 ? _c : "unknown");
206
- const fromPid = (_d = cmd.from_pid) !== null && _d !== void 0 ? _d : "?";
207
- const fromPpid = (_e = cmd.from_ppid) !== null && _e !== void 0 ? _e : "?";
208
- const fromVer = (_f = cmd.from_version) !== null && _f !== void 0 ? _f : "?";
206
+ const reason = String((_e = cmd.reason) !== null && _e !== void 0 ? _e : "unknown");
207
+ const fromPid = (_f = cmd.from_pid) !== null && _f !== void 0 ? _f : "?";
208
+ const fromPpid = (_g = cmd.from_ppid) !== null && _g !== void 0 ? _g : "?";
209
+ const fromVer = (_h = cmd.from_version) !== null && _h !== void 0 ? _h : "?";
209
210
  const fromArgv = Array.isArray(cmd.from_argv)
210
211
  ? cmd.from_argv.join(" ")
211
212
  : "?";
212
- const fromParentCmd = (_g = cmd.from_parent_cmd) !== null && _g !== void 0 ? _g : "?";
213
+ const fromParentCmd = (_j = cmd.from_parent_cmd) !== null && _j !== void 0 ? _j : "?";
213
214
  console.log(`[daemon] shutdown command received via IPC: reason=${reason} from_pid=${fromPid} from_ppid=${fromPpid} from_version=${fromVer} from_argv=[${fromArgv}] from_parent_cmd=[${fromParentCmd}]`);
214
215
  setImmediate(() => daemon.shutdown());
215
216
  return { ok: true };
@@ -274,8 +275,8 @@ function handleCommand(daemon, cmd, conn) {
274
275
  return { ok: false, error: "invalid project_roots" };
275
276
  }
276
277
  for (const prefix of [
277
- ...((_h = filters === null || filters === void 0 ? void 0 : filters.inPrefixes) !== null && _h !== void 0 ? _h : []),
278
- ...((_j = filters === null || filters === void 0 ? void 0 : filters.excludePrefixes) !== null && _j !== void 0 ? _j : []),
278
+ ...((_k = filters === null || filters === void 0 ? void 0 : filters.inPrefixes) !== null && _k !== void 0 ? _k : []),
279
+ ...((_l = filters === null || filters === void 0 ? void 0 : filters.excludePrefixes) !== null && _l !== void 0 ? _l : []),
279
280
  ]) {
280
281
  (0, path_containment_1.resolveContainedPath)(projectRoot, prefix);
281
282
  }