@bojackduy/opencode-telescope 0.1.23 → 0.1.24
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/telescope.tsx +69 -40
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.24",
|
|
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/telescope.tsx
CHANGED
|
@@ -98,6 +98,8 @@ 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 lastFiredQuery = ""
|
|
101
|
+
let searchRequestId = 0
|
|
102
|
+
let searchWorker: Worker | undefined
|
|
101
103
|
const SEARCH_DEBOUNCE_MS = 200
|
|
102
104
|
type PreviewBeforeIntent = "passive-prefetch" | "explicit-scroll"
|
|
103
105
|
type PendingPreviewBefore = {
|
|
@@ -131,10 +133,60 @@ export const Telescope = (props: { api: TuiPluginApi; config: TelescopeConfig; o
|
|
|
131
133
|
setPrefetchingPreviewAfter(false)
|
|
132
134
|
setLoadingPreviewMore(false)
|
|
133
135
|
}
|
|
136
|
+
const ensureSearchWorker = () => {
|
|
137
|
+
if (searchWorker) return true
|
|
138
|
+
try {
|
|
139
|
+
searchWorker = new Worker(new URL("./search-worker.ts", import.meta.url))
|
|
140
|
+
searchWorker.onmessage = (event: MessageEvent) => {
|
|
141
|
+
const msg = event.data
|
|
142
|
+
if (msg.type === "search-result") {
|
|
143
|
+
if (msg.id !== searchRequestId) return
|
|
144
|
+
const batch = msg.result
|
|
145
|
+
const limit = msg.limit
|
|
146
|
+
debug.log("bootstrap:search:done", { rows: batch.length, limit, mode: searchMode() })
|
|
147
|
+
solidBatch(() => {
|
|
148
|
+
setResults(batch)
|
|
149
|
+
setResultBaseOffset(0)
|
|
150
|
+
setNextResultOffset(batch.length)
|
|
151
|
+
setHasMore(batch.length >= limit)
|
|
152
|
+
setResultPageInfo({ loadedUntil: batch.length, hasMore: batch.length >= limit, pageSize: limit, lastOffset: 0, lastAdded: batch.length })
|
|
153
|
+
setSelected(0)
|
|
154
|
+
})
|
|
155
|
+
setBusy(false)
|
|
156
|
+
setLoading(false)
|
|
157
|
+
debug.timeEnd("query:search")
|
|
158
|
+
}
|
|
159
|
+
if (msg.type === "error") {
|
|
160
|
+
if (msg.id !== searchRequestId) return
|
|
161
|
+
debug.log("bootstrap:search:error", msg.error)
|
|
162
|
+
solidBatch(() => {
|
|
163
|
+
setResults([])
|
|
164
|
+
setResultBaseOffset(0)
|
|
165
|
+
setNextResultOffset(0)
|
|
166
|
+
setResultPageInfo({ loadedUntil: 0, hasMore: false, pageSize: 0, lastOffset: 0, lastAdded: 0 })
|
|
167
|
+
})
|
|
168
|
+
setError(msg.error)
|
|
169
|
+
setBusy(false)
|
|
170
|
+
setLoading(false)
|
|
171
|
+
debug.timeEnd("query:search")
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
searchWorker.onerror = (err) => {
|
|
175
|
+
debug.log("worker:error", err.message)
|
|
176
|
+
}
|
|
177
|
+
return true
|
|
178
|
+
} catch (err) {
|
|
179
|
+
debug.log("worker:create-error", err instanceof Error ? err.message : String(err))
|
|
180
|
+
return false
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
134
184
|
onCleanup(() => {
|
|
135
185
|
if (resultPrefetchTimer) clearTimeout(resultPrefetchTimer)
|
|
136
186
|
if (resultPreviousTimer) clearTimeout(resultPreviousTimer)
|
|
137
187
|
cancelPreviewPrefetch()
|
|
188
|
+
searchWorker?.terminate()
|
|
189
|
+
searchWorker = undefined
|
|
138
190
|
})
|
|
139
191
|
|
|
140
192
|
const resultRowHeight = createMemo(() => leftWidth() >= 48 ? 3 : 4)
|
|
@@ -205,41 +257,31 @@ export const Telescope = (props: { api: TuiPluginApi; config: TelescopeConfig; o
|
|
|
205
257
|
return config.disableVector ? "keyword" as const : "hybrid" as const
|
|
206
258
|
}
|
|
207
259
|
|
|
208
|
-
const executeSearch =
|
|
260
|
+
const executeSearch = (q: string, role: SearchRole | undefined, db: string, dir: string) => {
|
|
209
261
|
lastFiredQuery = q
|
|
210
262
|
const limit = q ? Math.min(searchBatchSize(), 80) : recentBatchSize()
|
|
263
|
+
setError("")
|
|
264
|
+
setHasMore(true)
|
|
265
|
+
advanceSelectionAfterLoad = false
|
|
266
|
+
advanceSelectionBeforeLoad = false
|
|
267
|
+
resultNavigationStarted = false
|
|
268
|
+
setLoadingMore(false)
|
|
269
|
+
setLoadingPreviousResults(false)
|
|
270
|
+
setPrefetchingResults(false)
|
|
211
271
|
setLoading(true)
|
|
212
272
|
if (q) setBusy(true)
|
|
213
273
|
setSearchMode(detectSearchMode())
|
|
214
274
|
debug.time("query:search")
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const batch = q
|
|
218
|
-
? await performSearch(q, { limit, offset: 0, dbPath: db, directory: dir, role })
|
|
219
|
-
: recentSessionMessages({ limit, offset: 0, dbPath: db, directory: dir, role })
|
|
220
|
-
debug.log("bootstrap:search:done", { rows: batch.length, limit, mode: searchMode() })
|
|
221
|
-
solidBatch(() => {
|
|
222
|
-
setResults(batch)
|
|
223
|
-
setResultBaseOffset(0)
|
|
224
|
-
setNextResultOffset(batch.length)
|
|
225
|
-
setHasMore(batch.length >= limit)
|
|
226
|
-
setResultPageInfo({ loadedUntil: batch.length, hasMore: batch.length >= limit, pageSize: limit, lastOffset: 0, lastAdded: batch.length })
|
|
227
|
-
setSelected(0)
|
|
228
|
-
})
|
|
229
|
-
} catch (err) {
|
|
230
|
-
debug.log("bootstrap:search:error", err instanceof Error ? err.message : String(err))
|
|
231
|
-
solidBatch(() => {
|
|
232
|
-
setResults([])
|
|
233
|
-
setResultBaseOffset(0)
|
|
234
|
-
setNextResultOffset(0)
|
|
235
|
-
setResultPageInfo({ loadedUntil: 0, hasMore: false, pageSize: limit, lastOffset: 0, lastAdded: 0 })
|
|
236
|
-
})
|
|
237
|
-
setError(err instanceof Error ? err.message : String(err))
|
|
238
|
-
} finally {
|
|
275
|
+
const id = ++searchRequestId
|
|
276
|
+
if (!ensureSearchWorker()) {
|
|
239
277
|
debug.timeEnd("query:search")
|
|
240
|
-
|
|
241
|
-
setLoading(false)
|
|
278
|
+
return
|
|
242
279
|
}
|
|
280
|
+
const msg = q
|
|
281
|
+
? { type: "search" as const, id, query: q, limit, offset: 0, directory: dir, role, dbPath: db }
|
|
282
|
+
: { type: "recent" as const, id, limit, offset: 0, directory: dir, role, dbPath: db }
|
|
283
|
+
debug.log("bootstrap:search:start", { limit, directory: dir, role, query: q || "(all recent)", worker: true })
|
|
284
|
+
searchWorker!.postMessage(msg)
|
|
243
285
|
}
|
|
244
286
|
|
|
245
287
|
const scheduleSearch = (q: string, role: SearchRole | undefined, db: string, dir: string) => {
|
|
@@ -254,21 +296,8 @@ export const Telescope = (props: { api: TuiPluginApi; config: TelescopeConfig; o
|
|
|
254
296
|
createEffect(() => {
|
|
255
297
|
const q = query().trim()
|
|
256
298
|
const role = ownerRole()
|
|
257
|
-
setError("")
|
|
258
|
-
setHasMore(true)
|
|
259
|
-
if (resultPrefetchTimer) clearTimeout(resultPrefetchTimer)
|
|
260
|
-
if (resultPreviousTimer) clearTimeout(resultPreviousTimer)
|
|
261
|
-
resultPrefetchTimer = undefined
|
|
262
|
-
resultPreviousTimer = undefined
|
|
263
|
-
advanceSelectionAfterLoad = false
|
|
264
|
-
advanceSelectionBeforeLoad = false
|
|
265
|
-
resultNavigationStarted = false
|
|
266
|
-
setLoadingMore(false)
|
|
267
|
-
setLoadingPreviousResults(false)
|
|
268
|
-
setPrefetchingResults(false)
|
|
269
299
|
const db = dbPath()
|
|
270
300
|
const dir = directory
|
|
271
|
-
|
|
272
301
|
scheduleSearch(q, role, db, dir)
|
|
273
302
|
onCleanup(() => {
|
|
274
303
|
if (searchTimer) clearTimeout(searchTimer)
|