gitnexus 1.6.6-rc.18 → 1.6.6-rc.19

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.
@@ -15,6 +15,25 @@
15
15
  * from the same Database is the officially supported concurrency pattern.
16
16
  */
17
17
  import lbug from '@ladybugdb/core';
18
+ /**
19
+ * Probe whether a Windows FTS extension binary is locally installed under
20
+ * ~/.lbdb/extension/<any-version>/win_amd64/fts/. Returns true on the first
21
+ * version dir whose libfts.lbug_extension exists on disk; false if the
22
+ * extension root is missing or contains no FTS binary.
23
+ *
24
+ * Gates the Windows skip-FTS-load guard below so we only skip the load
25
+ * when no extension binary is present. When at least one binary exists,
26
+ * loadFTSExtension is called with policy: 'load-only' — LadybugDB resolves
27
+ * LOAD EXTENSION fts to its version-specific path internally, and the
28
+ * ExtensionManager's tryLoad try/catch handles version-mismatch errors
29
+ * cleanly without ever attempting dlopen of a stale binary. The install
30
+ * path that the #1199/#1217 SIGSEGV documented is never exercised at
31
+ * query time.
32
+ *
33
+ * Exported so unit tests can exercise the probe directly against a
34
+ * temp-dir plus spied `os.homedir()` — see lbug-pool-win-fts-probe.test.ts.
35
+ */
36
+ export declare function hasLocalWinFtsExtension(): Promise<boolean>;
18
37
  /**
19
38
  * Listeners notified when a pool entry is torn down (LRU eviction, idle
20
39
  * timeout, explicit close). Used by upper layers (e.g. the BM25 search
@@ -15,9 +15,48 @@
15
15
  * from the same Database is the officially supported concurrency pattern.
16
16
  */
17
17
  import fs from 'fs/promises';
18
+ import os from 'os';
19
+ import path from 'path';
18
20
  import lbug from '@ladybugdb/core';
19
21
  import { isReadOnlyDbError, loadFTSExtension } from './lbug-adapter.js';
20
22
  import { createLbugDatabase, isWalCorruptionError, WAL_RECOVERY_SUGGESTION, } from './lbug-config.js';
23
+ /**
24
+ * Probe whether a Windows FTS extension binary is locally installed under
25
+ * ~/.lbdb/extension/<any-version>/win_amd64/fts/. Returns true on the first
26
+ * version dir whose libfts.lbug_extension exists on disk; false if the
27
+ * extension root is missing or contains no FTS binary.
28
+ *
29
+ * Gates the Windows skip-FTS-load guard below so we only skip the load
30
+ * when no extension binary is present. When at least one binary exists,
31
+ * loadFTSExtension is called with policy: 'load-only' — LadybugDB resolves
32
+ * LOAD EXTENSION fts to its version-specific path internally, and the
33
+ * ExtensionManager's tryLoad try/catch handles version-mismatch errors
34
+ * cleanly without ever attempting dlopen of a stale binary. The install
35
+ * path that the #1199/#1217 SIGSEGV documented is never exercised at
36
+ * query time.
37
+ *
38
+ * Exported so unit tests can exercise the probe directly against a
39
+ * temp-dir plus spied `os.homedir()` — see lbug-pool-win-fts-probe.test.ts.
40
+ */
41
+ export async function hasLocalWinFtsExtension() {
42
+ try {
43
+ const extRoot = path.join(os.homedir(), '.lbdb', 'extension');
44
+ const versions = await fs.readdir(extRoot);
45
+ for (const v of versions) {
46
+ try {
47
+ await fs.stat(path.join(extRoot, v, 'win_amd64', 'fts', 'libfts.lbug_extension'));
48
+ return true;
49
+ }
50
+ catch {
51
+ /* missing for this version, keep looking */
52
+ }
53
+ }
54
+ }
55
+ catch {
56
+ /* no .lbdb/extension dir */
57
+ }
58
+ return false;
59
+ }
21
60
  const pool = new Map();
22
61
  const poolCloseListeners = new Set();
23
62
  /**
@@ -347,14 +386,24 @@ async function doInitLbug(repoId, dbPath) {
347
386
  // install; analyze owns extension installation. If LOAD fails, search
348
387
  // features degrade gracefully and the user-facing query path proceeds.
349
388
  if (!shared.ftsLoaded) {
350
- // Windows guard: LOAD EXTENSION fts crashes with SIGSEGV on Windows when
351
- // the FTS extension binary is not installed locally (@ladybugdb/core native
352
- // bug — the extension loader hits an unhandled error path that signals SIGSEGV
353
- // rather than throwing a JS exception, so try/catch cannot protect here).
354
- // Skip the load on Windows; bm25-index.js catches the resulting Kuzu catalog
355
- // errors and returns empty BM25 results gracefully. Graph queries are unaffected.
389
+ // Windows guard: LOAD EXTENSION fts crashes with SIGSEGV on Windows during
390
+ // *install* — the @ladybugdb/core out-of-process installer hits an unhandled
391
+ // error path that signals SIGSEGV instead of throwing (see #1199, #1217).
392
+ // The previous unconditional skip was over-broad: it also disabled FTS on
393
+ // hosts where the binary was already on disk and only needed LOAD, leaving
394
+ // BM25 silently degraded with no error path (see #1690).
395
+ //
396
+ // Probe ~/.lbdb/extension/*/win_amd64/fts/ first. If any binary is on disk
397
+ // we run loadFTSExtension(..., 'load-only'); the install path is never
398
+ // exercised, and LadybugDB's version-specific resolution + ExtensionManager
399
+ // try/catch handle stale/zero-byte siblings cleanly (verified empirically
400
+ // on Win10 + Node 22.19 + gitnexus 1.6.5 + @ladybugdb/core 0.16.1). With
401
+ // no binary at all, we fall back to the upstream skip so install-time
402
+ // SIGSEGV continues to be avoided.
356
403
  if (process.platform === 'win32') {
357
- shared.ftsLoaded = true;
404
+ shared.ftsLoaded = (await hasLocalWinFtsExtension())
405
+ ? await loadFTSExtension(available[0], { policy: 'load-only' })
406
+ : true;
358
407
  }
359
408
  else {
360
409
  shared.ftsLoaded = await loadFTSExtension(available[0], { policy: 'load-only' });
@@ -414,10 +463,12 @@ export async function initLbugWithDb(repoId, existingDb, dbPath) {
414
463
  // Load FTS extension if not already loaded on this Database.
415
464
  // policy: 'load-only' — same contract as initLbug above; the read pool
416
465
  // must not block on a network install during query execution.
417
- // Windows guard: same SIGSEGV risk as doInitLbug above — skip on Windows.
466
+ // Windows guard: same probe-then-load policy as doInitLbug above.
418
467
  if (!shared.ftsLoaded) {
419
468
  if (process.platform === 'win32') {
420
- shared.ftsLoaded = true;
469
+ shared.ftsLoaded = (await hasLocalWinFtsExtension())
470
+ ? await loadFTSExtension(available[0], { policy: 'load-only' })
471
+ : true;
421
472
  }
422
473
  else {
423
474
  shared.ftsLoaded = await loadFTSExtension(available[0], { policy: 'load-only' });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.6-rc.18",
3
+ "version": "1.6.6-rc.19",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",