@bojackduy/opencode-telescope 0.1.28 → 0.1.32

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,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@bojackduy/opencode-telescope",
4
- "version": "0.1.28",
4
+ "version": "0.1.32",
5
5
  "description": "OpenCode TUI plugin for fuzzy and semantic search across local conversation history, session transcripts, and AI coding chats",
6
6
  "type": "module",
7
7
  "license": "MIT",
package/search/queries.ts CHANGED
@@ -58,11 +58,14 @@ export function recentSessionMessages(options?: { limit?: number; offset?: numbe
58
58
  const db = getDb(dbPath)
59
59
  const limit = options?.limit ?? 40
60
60
  const indexed = dbPath === ":memory:" ? undefined : indexedRecentRows(db, dbPath, limit, options?.directory, options?.offset, options?.role)
61
- if (indexed) return indexed.flatMap((row) => rowToSearchResult(row, "") ?? [])
62
- debug.log("query:recent:source-fallback", { limit, offset: options?.offset ?? 0, directory: options?.directory, role: options?.role })
63
- return visibleTextRows(db, limit, undefined, options?.directory, options?.offset, options?.role).flatMap(
64
- (row) => rowToSearchResult(row, "") ?? [],
65
- )
61
+ if (indexed && !indexed.stale && indexed.rows.length > 0) return indexed.rows.flatMap((row) => rowToSearchResult(row, "") ?? [])
62
+
63
+ if (dbPath !== ":memory:") scheduleBackgroundIndexRebuild(dbPath)
64
+ if (!indexed) debug.log("query:recent:index-pending", { limit, offset: options?.offset ?? 0, directory: options?.directory, role: options?.role })
65
+
66
+ const sourceRows = sourceRecentRows(db, limit, options?.directory, options?.offset, options?.role)
67
+ if (sourceRows) return sourceRows.flatMap((row) => rowToSearchResult(row, "") ?? [])
68
+ return indexed?.rows.flatMap((row) => rowToSearchResult(row, "") ?? []) ?? []
66
69
  }
67
70
 
68
71
  export function loadConversationAround(result: SearchResult, options?: { before?: number; after?: number; dbPath?: string }): ConversationPreviewPage {
@@ -379,7 +382,12 @@ function indexedTextRows(db: Database, dbPath: string, limit: number, query: str
379
382
  }
380
383
  }
381
384
 
382
- function indexedRecentRows(db: Database, dbPath: string, limit: number, directory?: string, offset?: number, role?: SearchRole) {
385
+ type IndexedRecentRows = {
386
+ rows: Row[]
387
+ stale: boolean
388
+ }
389
+
390
+ function indexedRecentRows(db: Database, dbPath: string, limit: number, directory?: string, offset?: number, role?: SearchRole): IndexedRecentRows | undefined {
383
391
  try {
384
392
  const index = ensureSearchIndex(db, dbPath, { rebuild: false, useStale: true })
385
393
  if (!index) {
@@ -390,7 +398,7 @@ function indexedRecentRows(db: Database, dbPath: string, limit: number, director
390
398
  const rowCount = index.query<{ count: number }, []>("SELECT COUNT(*) as count FROM document_index").get()?.count ?? 0
391
399
  if (rowCount === 0) {
392
400
  debug.log("query:recent:index:empty", { dbPath })
393
- return
401
+ return { rows: [], stale: true }
394
402
  }
395
403
 
396
404
  const state = sourceState(db, dbPath)
@@ -398,12 +406,14 @@ function indexedRecentRows(db: Database, dbPath: string, limit: number, director
398
406
  const currentMtimeMs = getMeta(index, "source_mtime_ms")
399
407
  const currentPath = getMeta(index, "source_path")
400
408
  const currentIndexVersion = getMeta(index, "index_version")
401
- if (currentPath !== dbPath || currentDataVersion !== String(state.dataVersion) || currentMtimeMs !== String(state.mtimeMs) || currentIndexVersion !== SEARCH_INDEX_VERSION) {
409
+ const stale = currentPath !== dbPath || currentDataVersion !== String(state.dataVersion) || currentMtimeMs !== String(state.mtimeMs) || currentIndexVersion !== SEARCH_INDEX_VERSION
410
+ if (stale) {
402
411
  debug.log("query:recent:index:stale", {
403
412
  dbPath,
404
413
  expectedDataVersion: state.dataVersion,
405
414
  actualDataVersion: currentDataVersion,
406
415
  })
416
+ scheduleBackgroundIndexRebuild(dbPath)
407
417
  }
408
418
 
409
419
  const conditions: string[] = ["part_type = 'text'"]
@@ -431,13 +441,24 @@ function indexedRecentRows(db: Database, dbPath: string, limit: number, director
431
441
  LIMIT ? ${offsetClause}
432
442
  `).all(...params as any[])
433
443
  debug.timeEnd("query:recent:index:exec")
434
- return rows
444
+ return { rows, stale }
435
445
  } catch (err) {
436
446
  debug.log("recent:index:fallback", err instanceof Error ? err.message : String(err))
437
447
  return
438
448
  }
439
449
  }
440
450
 
451
+ function sourceRecentRows(db: Database, limit: number, directory?: string, offset?: number, role?: SearchRole) {
452
+ try {
453
+ if (!tableExists(db, "part") || !tableExists(db, "message") || !tableExists(db, "session")) return []
454
+ debug.log("query:recent:source-fallback", { limit, offset: offset ?? 0, directory, role })
455
+ return visibleTextRows(db, limit, undefined, directory, offset, role)
456
+ } catch (err) {
457
+ debug.log("query:recent:source-fallback:error", err instanceof Error ? err.message : String(err))
458
+ return
459
+ }
460
+ }
461
+
441
462
  function visibleTextRows(db: Database, limit: number, query?: string, directory?: string, offset?: number, role?: SearchRole) {
442
463
  const offsetClause = offset ? "OFFSET ?" : ""
443
464
  const conditions: string[] = [
package/telescope.tsx CHANGED
@@ -98,7 +98,7 @@ export const Telescope = (props: { api: TuiPluginApi; config: TelescopeConfig; o
98
98
  let resultPreviousTimer: ReturnType<typeof setTimeout> | undefined
99
99
  let searchTimer: ReturnType<typeof setTimeout> | undefined
100
100
  let searchWatchdogTimer: ReturnType<typeof setTimeout> | undefined
101
- let lastFiredQuery = ""
101
+ let lastFiredSearchKey = ""
102
102
  let searchRequestId = 0
103
103
  let fallbackSearchRequestId: number | undefined
104
104
  let searchWorker: Worker | undefined
@@ -309,8 +309,11 @@ export const Telescope = (props: { api: TuiPluginApi; config: TelescopeConfig; o
309
309
  return config.disableVector ? "keyword" as const : "hybrid" as const
310
310
  }
311
311
 
312
+ const searchKey = (q: string, role: SearchRole | undefined, db: string, dir: string) =>
313
+ JSON.stringify([q, role ?? null, db, dir])
314
+
312
315
  const executeSearch = (q: string, role: SearchRole | undefined, db: string, dir: string) => {
313
- lastFiredQuery = q
316
+ lastFiredSearchKey = searchKey(q, role, db, dir)
314
317
  const limit = q ? Math.min(searchBatchSize(), 80) : recentBatchSize()
315
318
  setError("")
316
319
  setHasMore(true)
@@ -342,7 +345,7 @@ export const Telescope = (props: { api: TuiPluginApi; config: TelescopeConfig; o
342
345
  debug.log("worker:timeout", { id: request.id, ms: SEARCH_WORKER_TIMEOUT_MS })
343
346
  searchWorker?.terminate()
344
347
  searchWorker = undefined
345
- runSearchFallback(request, "worker-timeout")
348
+ failSearch(request, "Search worker timed out. The conversation index may still be building; try again shortly.")
346
349
  }, SEARCH_WORKER_TIMEOUT_MS)
347
350
  ;(searchWatchdogTimer as { unref?: () => void }).unref?.()
348
351
  searchWorker!.postMessage(msg)
@@ -350,7 +353,7 @@ export const Telescope = (props: { api: TuiPluginApi; config: TelescopeConfig; o
350
353
 
351
354
  const scheduleSearch = (q: string, role: SearchRole | undefined, db: string, dir: string) => {
352
355
  if (searchTimer) clearTimeout(searchTimer)
353
- if (q === lastFiredQuery && results().length > 0) return
356
+ if (searchKey(q, role, db, dir) === lastFiredSearchKey) return
354
357
  searchTimer = setTimeout(() => {
355
358
  searchTimer = undefined
356
359
  executeSearch(q, role, db, dir)