@ff-labs/fff-bun 0.4.3-nightly.eb577ea → 0.4.3-nightly.eecb795

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ff-labs/fff-bun",
3
- "version": "0.4.3-nightly.eb577ea",
3
+ "version": "0.4.3-nightly.eecb795",
4
4
  "private": false,
5
5
  "description": "High-performance fuzzy file finder for Bun - perfect for LLM agent tools",
6
6
  "type": "module",
@@ -62,14 +62,14 @@
62
62
  },
63
63
  "homepage": "https://github.com/dmtrKovalenko/fff.nvim#readme",
64
64
  "optionalDependencies": {
65
- "@ff-labs/fff-bin-darwin-arm64": "0.4.3-nightly.eb577ea",
66
- "@ff-labs/fff-bin-darwin-x64": "0.4.3-nightly.eb577ea",
67
- "@ff-labs/fff-bin-linux-x64-gnu": "0.4.3-nightly.eb577ea",
68
- "@ff-labs/fff-bin-linux-arm64-gnu": "0.4.3-nightly.eb577ea",
69
- "@ff-labs/fff-bin-linux-x64-musl": "0.4.3-nightly.eb577ea",
70
- "@ff-labs/fff-bin-linux-arm64-musl": "0.4.3-nightly.eb577ea",
71
- "@ff-labs/fff-bin-win32-x64": "0.4.3-nightly.eb577ea",
72
- "@ff-labs/fff-bin-win32-arm64": "0.4.3-nightly.eb577ea"
65
+ "@ff-labs/fff-bin-darwin-arm64": "0.4.3-nightly.eecb795",
66
+ "@ff-labs/fff-bin-darwin-x64": "0.4.3-nightly.eecb795",
67
+ "@ff-labs/fff-bin-linux-x64-gnu": "0.4.3-nightly.eecb795",
68
+ "@ff-labs/fff-bin-linux-arm64-gnu": "0.4.3-nightly.eecb795",
69
+ "@ff-labs/fff-bin-linux-x64-musl": "0.4.3-nightly.eecb795",
70
+ "@ff-labs/fff-bin-linux-arm64-musl": "0.4.3-nightly.eecb795",
71
+ "@ff-labs/fff-bin-win32-x64": "0.4.3-nightly.eecb795",
72
+ "@ff-labs/fff-bin-win32-arm64": "0.4.3-nightly.eecb795"
73
73
  },
74
74
  "devDependencies": {
75
75
  "@types/bun": "^1.3.8",
package/src/ffi.ts CHANGED
@@ -16,6 +16,7 @@ import type {
16
16
  GrepResult,
17
17
  Location,
18
18
  Result,
19
+ ScanProgress,
19
20
  Score,
20
21
  SearchResult,
21
22
  } from "./types";
@@ -125,6 +126,10 @@ const ffiDefinition = {
125
126
  args: [FFIType.ptr, FFIType.u64],
126
127
  returns: FFIType.ptr,
127
128
  },
129
+ fff_wait_for_watcher: {
130
+ args: [FFIType.ptr, FFIType.u64],
131
+ returns: FFIType.ptr,
132
+ },
128
133
  fff_restart_index: {
129
134
  args: [FFIType.ptr, FFIType.cstring],
130
135
  returns: FFIType.ptr,
@@ -817,16 +822,16 @@ export function ffiIsScanning(handle: NativeHandle): boolean {
817
822
  return library.symbols.fff_is_scanning(handle) as boolean;
818
823
  }
819
824
 
820
- // FffScanProgress { scanned_files_count: u64(8), is_scanning: bool(1+7pad) }
825
+ // FffScanProgress { scanned_files_count: u64(8), is_scanning: bool(1), is_watcher_ready: bool(1), is_warmup_complete: bool(1) + pad }
821
826
  const SP_COUNT = 0; // u64 (8)
822
- const SP_SCANNING = 8; // bool (1 + 7 pad)
827
+ const SP_SCANNING = 8; // bool (1)
828
+ const SP_WATCHER_READY = 9; // bool (1)
829
+ const SP_WARMUP_COMPLETE = 10; // bool (1)
823
830
 
824
831
  /**
825
832
  * Get scan progress.
826
833
  */
827
- export function ffiGetScanProgress(
828
- handle: NativeHandle,
829
- ): Result<{ scannedFilesCount: number; isScanning: boolean }> {
834
+ export function ffiGetScanProgress(handle: NativeHandle): Result<ScanProgress> {
830
835
  const library = loadLibrary();
831
836
  const resultPtr = library.symbols.fff_get_scan_progress(handle);
832
837
  const envelope = readResultEnvelope(resultPtr);
@@ -837,9 +842,11 @@ export function ffiGetScanProgress(
837
842
  }
838
843
 
839
844
  const hp = asPtr(envelope.handlePtr);
840
- const result = {
845
+ const result: ScanProgress = {
841
846
  scannedFilesCount: Number(read.u64(hp, SP_COUNT)),
842
847
  isScanning: read.u8(hp, SP_SCANNING) !== 0,
848
+ isWatcherReady: read.u8(hp, SP_WATCHER_READY) !== 0,
849
+ isWarmupComplete: read.u8(hp, SP_WARMUP_COMPLETE) !== 0,
843
850
  };
844
851
  library.symbols.fff_free_scan_progress(hp);
845
852
  return { ok: true, value: result };
@@ -854,6 +861,18 @@ export function ffiWaitForScan(handle: NativeHandle, timeoutMs: number): Result<
854
861
  return parseBoolResult(resultPtr);
855
862
  }
856
863
 
864
+ /**
865
+ * Wait for the background file watcher to be ready.
866
+ */
867
+ export function ffiWaitForWatcher(
868
+ handle: NativeHandle,
869
+ timeoutMs: number,
870
+ ): Result<boolean> {
871
+ const library = loadLibrary();
872
+ const resultPtr = library.symbols.fff_wait_for_watcher(handle, BigInt(timeoutMs));
873
+ return parseBoolResult(resultPtr);
874
+ }
875
+
857
876
  /**
858
877
  * Restart index in new path.
859
878
  */
package/src/finder.ts CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  ffiSearch,
25
25
  ffiTrackQuery,
26
26
  ffiWaitForScan,
27
+ ffiWaitForWatcher,
27
28
  isAvailable,
28
29
  type NativeHandle,
29
30
  } from "./ffi";
@@ -345,6 +346,22 @@ export class FileFinder {
345
346
  return ffiWaitForScan(guard.value, timeoutMs);
346
347
  }
347
348
 
349
+ /**
350
+ * Wait for the background file watcher to be ready.
351
+ *
352
+ * The watcher is created after the initial scan, git status, and optional
353
+ * warmup phases complete. Useful for tests that need to ensure filesystem
354
+ * events will be detected.
355
+ *
356
+ * @param timeoutMs - Maximum time to wait in milliseconds (default: 10000)
357
+ * @returns true if watcher is ready, false if timed out
358
+ */
359
+ waitForWatcher(timeoutMs: number = 10000): Result<boolean> {
360
+ const guard = this.ensureAlive();
361
+ if (!guard.ok) return guard;
362
+ return ffiWaitForWatcher(guard.value, timeoutMs);
363
+ }
364
+
348
365
  /**
349
366
  * Change the indexed directory to a new path.
350
367
  *
@@ -127,7 +127,7 @@ describe.skipIf(process.platform === "win32")("Git lifecycle integration", () =>
127
127
  let tmpDir: string;
128
128
  let finder: FileFinder;
129
129
 
130
- beforeAll(() => {
130
+ beforeAll(async () => {
131
131
  // Create temp directory and initialise a git repo with two committed files.
132
132
  // Use realpathSync to resolve symlinks (macOS /var -> /private/var) so
133
133
  // that git2's resolved workdir paths match the file picker's base_path.
@@ -151,6 +151,20 @@ describe.skipIf(process.platform === "win32")("Git lifecycle integration", () =>
151
151
  // Wait for the initial scan to finish
152
152
  const scanResult = finder.waitForScan(10_000);
153
153
  expect(scanResult.ok).toBe(true);
154
+
155
+ // Poll getScanProgress until the watcher is ready so that
156
+ // filesystem events (file creates, deletes) are detected.
157
+ const start = Date.now();
158
+ while (Date.now() - start < WATCHER_TIMEOUT_MS) {
159
+ const progress = finder.getScanProgress();
160
+ if (progress.ok && progress.value.isWatcherReady) break;
161
+ await sleep(POLL_INTERVAL_MS);
162
+ }
163
+ const progress = finder.getScanProgress();
164
+ expect(progress.ok).toBe(true);
165
+ if (progress.ok) {
166
+ expect(progress.value.isWatcherReady).toBe(true);
167
+ }
154
168
  });
155
169
 
156
170
  afterAll(() => {
package/src/types.ts CHANGED
@@ -144,6 +144,10 @@ export interface ScanProgress {
144
144
  scannedFilesCount: number;
145
145
  /** Whether a scan is currently in progress */
146
146
  isScanning: boolean;
147
+ /** Whether the background file watcher is ready */
148
+ isWatcherReady: boolean;
149
+ /** Whether the warmup/bigram phase has completed */
150
+ isWarmupComplete: boolean;
147
151
  }
148
152
 
149
153
  /**