@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 +1 -1
- package/search/queries.ts +30 -9
- package/telescope.tsx +7 -4
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.
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
356
|
+
if (searchKey(q, role, db, dir) === lastFiredSearchKey) return
|
|
354
357
|
searchTimer = setTimeout(() => {
|
|
355
358
|
searchTimer = undefined
|
|
356
359
|
executeSearch(q, role, db, dir)
|