dsh-locator 0.7.1 → 0.7.4

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README-es.md +35 -5
  3. package/README-hi.md +33 -5
  4. package/README-pt.md +31 -5
  5. package/README.en.md +32 -4
  6. package/README.md +25 -5
  7. package/client.js +117 -17
  8. package/cordis.patch.yml +13 -0
  9. package/lib/config.d.ts +20 -0
  10. package/lib/config.d.ts.map +1 -1
  11. package/lib/config.js +38 -4
  12. package/lib/config.js.map +1 -1
  13. package/lib/content-search-worker.d.ts +8 -0
  14. package/lib/content-search-worker.d.ts.map +1 -0
  15. package/lib/content-search-worker.js +54 -0
  16. package/lib/content-search-worker.js.map +1 -0
  17. package/lib/content-search.d.ts +15 -0
  18. package/lib/content-search.d.ts.map +1 -0
  19. package/lib/content-search.js +38 -0
  20. package/lib/content-search.js.map +1 -0
  21. package/lib/content.d.ts +70 -4
  22. package/lib/content.d.ts.map +1 -1
  23. package/lib/content.js +420 -77
  24. package/lib/content.js.map +1 -1
  25. package/lib/find.d.ts +1 -1
  26. package/lib/find.d.ts.map +1 -1
  27. package/lib/find.js +8 -3
  28. package/lib/find.js.map +1 -1
  29. package/lib/http.d.ts +1 -1
  30. package/lib/http.d.ts.map +1 -1
  31. package/lib/http.js +4 -2
  32. package/lib/http.js.map +1 -1
  33. package/lib/index.d.ts +5 -1
  34. package/lib/index.d.ts.map +1 -1
  35. package/lib/index.js +102 -27
  36. package/lib/index.js.map +1 -1
  37. package/lib/reindex.d.ts +1 -1
  38. package/lib/reindex.d.ts.map +1 -1
  39. package/lib/reindex.js +2 -1
  40. package/lib/reindex.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/config.ts +58 -4
  43. package/src/content-search-worker.ts +52 -0
  44. package/src/content-search.ts +39 -0
  45. package/src/content.ts +387 -71
  46. package/src/find.ts +8 -3
  47. package/src/http.ts +4 -2
  48. package/src/index.ts +102 -25
  49. package/src/reindex.ts +2 -1
package/client.js CHANGED
@@ -277,23 +277,98 @@ window.__ModuleLoader__.load({
277
277
  // ── panel ───────────────────────────────────────────────────────────────
278
278
  let workspaceService = null
279
279
 
280
- function jumpHighlight(snippet) {
281
- const phrase = String(snippet || '').replace(/\u0001|\u0002/g, '').replace(/…/g, ' ').trim().split(/\s+/).slice(0, 8).join(' ')
282
- if (phrase.length < 2) return false
283
- const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT)
280
+ // ── chat anchors ────────────────────────────────────────────────────────
281
+ // The Chat flow renders one `[data-chat-node-key]` row per node and the key
282
+ // of a human input embeds the message id the content index stored
283
+ // (`"<n>:input-message<messageId>"`). Anchor on that id first: it lands on
284
+ // the exact message instead of whichever copy of the words comes first in
285
+ // the document (the sidebar title, for example).
286
+
287
+ function chatScope() {
288
+ return document.querySelector('[data-conversation-scroll]')
289
+ || document.querySelector('[data-slot="conversation.chat.flow"]')
290
+ || null
291
+ }
292
+
293
+ function findMessageNode(messageId) {
294
+ if (!messageId) return null
295
+ const id = String(messageId)
296
+ if (id === '') return null
297
+ const rows = document.querySelectorAll('[data-chat-node-key]')
298
+ for (const row of rows) {
299
+ const key = row.getAttribute('data-chat-node-key') || ''
300
+ if (key === id || key.endsWith(id)) return row
301
+ }
302
+ return null
303
+ }
304
+
305
+ function markElement(element) {
306
+ if (!element || typeof element.scrollIntoView !== 'function') return false
307
+ element.scrollIntoView({ block: 'center' })
308
+ const previous = element.style.outline
309
+ const previousOffset = element.style.outlineOffset
310
+ const previousRadius = element.style.borderRadius
311
+ element.style.outline = '2px solid #4f7cff'
312
+ element.style.outlineOffset = '3px'
313
+ element.style.borderRadius = '8px'
314
+ clearTimeout(element.__dshLocatorMark)
315
+ element.__dshLocatorMark = setTimeout(() => {
316
+ element.style.outline = previous
317
+ element.style.outlineOffset = previousOffset
318
+ element.style.borderRadius = previousRadius
319
+ }, 2400)
320
+ return true
321
+ }
322
+
323
+ // Progressively shorter fallbacks: a FTS snippet may be cut mid-word or
324
+ // separated by ellipses, so try the whole phrase before the leading words.
325
+ function phraseCandidates(snippet) {
326
+ const clean = String(snippet || '')
327
+ .replace(/[\u0001\u0002]/g, ' ')
328
+ .replace(/…/g, ' ')
329
+ .replace(/\s+/g, ' ')
330
+ .trim()
331
+ const out = []
332
+ const push = value => {
333
+ const text = String(value || '').trim()
334
+ if (text.length >= 2 && !out.includes(text)) out.push(text)
335
+ }
336
+ if (clean === '') return out
337
+ push(clean)
338
+ const words = clean.split(' ')
339
+ if (words.length > 1) {
340
+ push(words.slice(0, 8).join(' '))
341
+ push(words.slice(0, 4).join(' '))
342
+ push(words.slice(0, 2).join(' '))
343
+ }
344
+ push(clean.slice(0, 24))
345
+ push(clean.slice(0, 12))
346
+ return out
347
+ }
348
+
349
+ function findPhraseNode(scope, phrase) {
350
+ if (!scope || phrase.length < 2) return null
351
+ const needle = phrase.toLowerCase()
352
+ const walker = document.createTreeWalker(scope, NodeFilter.SHOW_TEXT)
284
353
  let node
285
354
  while ((node = walker.nextNode())) {
286
355
  const text = node.nodeValue || ''
287
- const index = text.toLowerCase().indexOf(phrase.toLowerCase())
288
- if (index < 0) continue
289
- const element = node.parentElement
290
- if (!element) continue
291
- element.scrollIntoView({ block: 'center' })
292
- const previous = element.style.outline
293
- element.style.outline = '2px solid #4f7cff'
294
- element.style.outlineOffset = '4px'
295
- setTimeout(() => { element.style.outline = previous; element.style.outlineOffset = '' }, 2400)
296
- return true
356
+ if (text.toLowerCase().indexOf(needle) < 0) continue
357
+ // The scope is the conversation transcript, so the first match already
358
+ // belongs to the bubble that contains the phrase.
359
+ const parent = node.parentElement
360
+ if (parent) return parent
361
+ }
362
+ return null
363
+ }
364
+
365
+ function jumpHighlight(snippet, messageId) {
366
+ const anchor = findMessageNode(messageId)
367
+ if (anchor !== null) return markElement(anchor)
368
+ const scope = chatScope()
369
+ for (const phrase of phraseCandidates(snippet)) {
370
+ const element = findPhraseNode(scope, phrase)
371
+ if (element !== null) return markElement(element)
297
372
  }
298
373
  return false
299
374
  }
@@ -312,6 +387,8 @@ window.__ModuleLoader__.load({
312
387
  const [total, setTotal] = useState(0)
313
388
  const [took, setTook] = useState(0)
314
389
  const [truncated, setTruncated] = useState(false)
390
+ const [contentBuilding, setContentBuilding] = useState(false)
391
+ const [refreshTick, setRefreshTick] = useState(0)
315
392
  const [status, setStatus] = useState(null)
316
393
  const [error, setError] = useState('')
317
394
  const [loading, setLoading] = useState(false)
@@ -373,6 +450,7 @@ window.__ModuleLoader__.load({
373
450
  setTotal(typeof data.total === 'number' ? data.total : nextHits.length)
374
451
  setTook(typeof data.tookMs === 'number' ? data.tookMs : 0)
375
452
  setTruncated(data.truncated === true)
453
+ setContentBuilding(contentMode && data.state != null && data.state.building === true)
376
454
  setSelected(0)
377
455
  setLoading(false)
378
456
  }).catch(cause => {
@@ -384,7 +462,15 @@ window.__ModuleLoader__.load({
384
462
  })
385
463
  }, 110)
386
464
  return () => clearTimeout(timer)
387
- }, [open, query, sort, desc, filesOnly, dirsOnly, contentMode])
465
+ }, [open, query, sort, desc, filesOnly, dirsOnly, contentMode, refreshTick])
466
+
467
+ // The content index is built lazily on first use; poll until it settles so
468
+ // the first query fills in without the user retyping it.
469
+ useEffect(() => {
470
+ if (!open || !contentMode || !contentBuilding) return undefined
471
+ const timer = setTimeout(() => setRefreshTick(value => value + 1), 2500)
472
+ return () => clearTimeout(timer)
473
+ }, [open, contentMode, contentBuilding, refreshTick])
388
474
 
389
475
  const toggleSort = useCallback(key => {
390
476
  if (sort === key) {
@@ -425,10 +511,23 @@ window.__ModuleLoader__.load({
425
511
  return
426
512
  }
427
513
  const snippet = hit.snippet
514
+ const messageId = hit.messageId
428
515
  let tries = 0
516
+ let pulledEarlier = false
429
517
  const timer = setInterval(() => {
430
518
  tries++
431
- if (jumpHighlight(snippet) || tries > 40) clearInterval(timer)
519
+ if (jumpHighlight(snippet, messageId)) {
520
+ clearInterval(timer)
521
+ return
522
+ }
523
+ // A long session renders its tail first: nudge the transcript to the
524
+ // top once so paging can load the message the hit points at.
525
+ if (!pulledEarlier && tries === 15) {
526
+ pulledEarlier = true
527
+ const scroller = document.querySelector('[data-conversation-scroll]')
528
+ if (scroller !== null && scroller.scrollTop > 0) scroller.scrollTop = 0
529
+ }
530
+ if (tries > 100) clearInterval(timer)
432
531
  }, 150)
433
532
  }, [close, copy, notify])
434
533
 
@@ -593,7 +692,8 @@ window.__ModuleLoader__.load({
593
692
  loading
594
693
  ? t('loading')
595
694
  : t('results', { total: total.toLocaleString() }) + (truncated ? ' (' + t('showing', { n: hits.length }) + ')' : '') + ' · ' + took.toFixed(1) + ' ms'
596
- + (status && status.scanning ? ' · ' + t('indexing') : '')),
695
+ + (status && status.scanning ? ' · ' + t('indexing') : '')
696
+ + (contentBuilding ? ' · ' + t('indexing') : '')),
597
697
  h('span', { className: 'grow' }),
598
698
  toast === '' ? null : h('span', { className: 'dsh-locator-toast' }, toast),
599
699
  h('span', null, t('footer')),
package/cordis.patch.yml CHANGED
@@ -38,6 +38,19 @@
38
38
  # directory walk. Requires DSH to run as administrator; on any failure
39
39
  # the engine falls back to the walk automatically.
40
40
  windowsUsn: false
41
+ # Content search reads text bodies and DSH session messages into a
42
+ # local SQLite FTS5 database. The defaults are documented in the README;
43
+ # override them here (or in the profile patch) when needed.
44
+ # contentIndex: true
45
+ # contentMaxFileBytes: 1000000
46
+ # contentMaxTotalBytes: 1000000000
47
+ # contentMaxFiles: 200000
48
+ # contentMaxSessions: 100
49
+ # contentRefreshMs: 300000
50
+ # contentIncludeArchived: false
51
+ # contentActiveSessionDelayMs: 120000
52
+ # contentSessionDirs: []
53
+ # contentExcludes: [node_modules, .cargo, .bun, .pnpm, site-packages, toolchain]
41
54
  # Snapshot directory. Empty means the platform cache directory
42
55
  # (%LOCALAPPDATA%\dsh-locator, ~/Library/Application Support/dsh-locator,
43
56
  # or $XDG_CACHE_HOME/dsh-locator).
package/lib/config.d.ts CHANGED
@@ -25,6 +25,12 @@ export interface Config {
25
25
  memoryLimitMB: number;
26
26
  /** Index text-file bodies and DSH session messages into the content database. */
27
27
  contentIndex: boolean;
28
+ /**
29
+ * Build the content index on the first content search instead of at plugin
30
+ * start. Lazy keeps DSH startup free of content indexing; set false to build
31
+ * eagerly in the background right after startup.
32
+ */
33
+ contentLazy: boolean;
28
34
  /** Maximum bytes read from one text file. */
29
35
  contentMaxFileBytes: number;
30
36
  /** Stop adding content after this many body bytes; 0 means unlimited. */
@@ -35,8 +41,22 @@ export interface Config {
35
41
  contentMaxFiles: number;
36
42
  /** Most recent session logs indexed; 0 means all. */
37
43
  contentMaxSessions: number;
44
+ /** Index archived sessions too; the default leaves them out. */
45
+ contentIncludeArchived: boolean;
46
+ /**
47
+ * Session logs modified more recently than this are skipped until they have
48
+ * been quiet that long, so the session being written now is not re-read on
49
+ * every background refresh.
50
+ */
51
+ contentActiveSessionDelayMs: number;
38
52
  /** Extra session directories; empty means $DSH_HOME/sessions. */
39
53
  contentSessionDirs: string[];
54
+ /**
55
+ * Path segments or substrings skipped by the content index only: dependency
56
+ * trees and toolchains would otherwise eat the body-bytes budget before a
57
+ * user's own documents. The name index still covers them.
58
+ */
59
+ contentExcludes: string[];
40
60
  /**
41
61
  * Try the NTFS USN/MFT enumeration before the portable walk (Windows only,
42
62
  * requires running DSH as administrator). Falls back automatically.
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAE7C,oCAAoC;AACpC,MAAM,WAAW,MAAM;IACrB,iEAAiE;IACjE,OAAO,EAAE,OAAO,CAAA;IAChB,2EAA2E;IAC3E,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,2EAA2E;IAC3E,KAAK,EAAE,OAAO,CAAA;IACd;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAA;IACzB,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAA;IACnB,gFAAgF;IAChF,aAAa,EAAE,MAAM,CAAA;IACrB,iFAAiF;IACjF,YAAY,EAAE,OAAO,CAAA;IACrB,6CAA6C;IAC7C,mBAAmB,EAAE,MAAM,CAAA;IAC3B,yEAAyE;IACzE,oBAAoB,EAAE,MAAM,CAAA;IAC5B,0DAA0D;IAC1D,gBAAgB,EAAE,MAAM,CAAA;IACxB,4DAA4D;IAC5D,eAAe,EAAE,MAAM,CAAA;IACvB,qDAAqD;IACrD,kBAAkB,EAAE,MAAM,CAAA;IAC1B,iEAAiE;IACjE,kBAAkB,EAAE,MAAM,EAAE,CAAA;IAC5B;;;OAGG;IACH,UAAU,EAAE,OAAO,CAAA;IACnB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAA;IAClB,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,CAAA;IACxB,2CAA2C;IAC3C,gBAAgB,EAAE,MAAM,CAAA;CACzB;AAED,yEAAyE;AACzE,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,CA+BhC,CAAA"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAE7C,oCAAoC;AACpC,MAAM,WAAW,MAAM;IACrB,iEAAiE;IACjE,OAAO,EAAE,OAAO,CAAA;IAChB,2EAA2E;IAC3E,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,2EAA2E;IAC3E,KAAK,EAAE,OAAO,CAAA;IACd;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAA;IACzB,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAA;IACnB,gFAAgF;IAChF,aAAa,EAAE,MAAM,CAAA;IACrB,iFAAiF;IACjF,YAAY,EAAE,OAAO,CAAA;IACrB;;;;OAIG;IACH,WAAW,EAAE,OAAO,CAAA;IACpB,6CAA6C;IAC7C,mBAAmB,EAAE,MAAM,CAAA;IAC3B,yEAAyE;IACzE,oBAAoB,EAAE,MAAM,CAAA;IAC5B,0DAA0D;IAC1D,gBAAgB,EAAE,MAAM,CAAA;IACxB,4DAA4D;IAC5D,eAAe,EAAE,MAAM,CAAA;IACvB,qDAAqD;IACrD,kBAAkB,EAAE,MAAM,CAAA;IAC1B,gEAAgE;IAChE,sBAAsB,EAAE,OAAO,CAAA;IAC/B;;;;OAIG;IACH,2BAA2B,EAAE,MAAM,CAAA;IACnC,iEAAiE;IACjE,kBAAkB,EAAE,MAAM,EAAE,CAAA;IAC5B;;;;OAIG;IACH,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB;;;OAGG;IACH,UAAU,EAAE,OAAO,CAAA;IACnB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,UAAU,EAAE,MAAM,CAAA;IAClB,uCAAuC;IACvC,UAAU,EAAE,MAAM,CAAA;IAClB,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,CAAA;IACxB,2CAA2C;IAC3C,gBAAgB,EAAE,MAAM,CAAA;CACzB;AAED,yEAAyE;AACzE,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,CAiEhC,CAAA"}
package/lib/config.js CHANGED
@@ -23,12 +23,46 @@ export const Config = Schema.object({
23
23
  scanWorkers: Schema.number().default(0),
24
24
  memoryLimitMB: Schema.number().default(0),
25
25
  contentIndex: Schema.boolean().default(true),
26
- contentMaxFileBytes: Schema.number().default(4_000_000),
27
- contentMaxTotalBytes: Schema.number().default(2_000_000_000),
28
- contentRefreshMs: Schema.number().default(120_000),
26
+ contentLazy: Schema.boolean().default(true),
27
+ contentMaxFileBytes: Schema.number().default(1_000_000),
28
+ contentMaxTotalBytes: Schema.number().default(1_000_000_000),
29
+ contentRefreshMs: Schema.number().default(300_000),
29
30
  contentMaxFiles: Schema.number().default(200_000),
30
- contentMaxSessions: Schema.number().default(200),
31
+ contentMaxSessions: Schema.number().default(100),
32
+ contentIncludeArchived: Schema.boolean().default(false),
33
+ contentActiveSessionDelayMs: Schema.number().default(120_000),
31
34
  contentSessionDirs: Schema.array(Schema.string()).default([]),
35
+ contentExcludes: Schema.array(Schema.string()).default([
36
+ 'node_modules',
37
+ '.git',
38
+ '.hg',
39
+ '.svn',
40
+ '.cache',
41
+ '__pycache__',
42
+ '.venv',
43
+ 'venv',
44
+ '.next',
45
+ '.turbo',
46
+ '.yarn',
47
+ '.pnpm',
48
+ '.npm',
49
+ '.cargo',
50
+ '.rustup',
51
+ '.bun',
52
+ '.gradle',
53
+ '.m2',
54
+ '.nuget',
55
+ '.nvm',
56
+ '.pyenv',
57
+ '.conda',
58
+ '.asdf',
59
+ 'toolchain',
60
+ 'site-packages',
61
+ 'dist-packages',
62
+ '/.local/lib/',
63
+ '/.local/share/pnpm/',
64
+ '/go/pkg/mod/',
65
+ ]),
32
66
  windowsUsn: Schema.boolean().default(false),
33
67
  stateDir: Schema.string().default(''),
34
68
  binaryPath: Schema.string().default(''),
package/lib/config.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAqD7C,yEAAyE;AACzE,MAAM,CAAC,MAAM,MAAM,GAAmB,MAAM,CAAC,MAAM,CAAC;IAClD,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACvC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAChD,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC;QAC9C,cAAc;QACd,MAAM;QACN,KAAK;QACL,MAAM;QACN,QAAQ;QACR,aAAa;QACb,OAAO;QACP,MAAM;QACN,OAAO;KACR,CAAC;IACF,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACrC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;IACrD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACvC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACzC,YAAY,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAC5C,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;IACvD,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;IAC5D,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAClD,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IACjD,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;IAChD,kBAAkB,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC7D,UAAU,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;IACxC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAClD,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;CAClD,CAAC,CAAA"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Search worker: the FTS5 query runs here so a slow content query can never
3
+ * stall the DSH host's event loop. A read-only connection makes the build's
4
+ * writes in the main thread safe to observe concurrently (WAL).
5
+ * @module dsh-locator/content-search-worker
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=content-search-worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-search-worker.d.ts","sourceRoot":"","sources":["../src/content-search-worker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Search worker: the FTS5 query runs here so a slow content query can never
3
+ * stall the DSH host's event loop. A read-only connection makes the build's
4
+ * writes in the main thread safe to observe concurrently (WAL).
5
+ * @module dsh-locator/content-search-worker
6
+ */
7
+ import { parentPort, workerData } from 'node:worker_threads';
8
+ import { DatabaseSync } from 'node:sqlite';
9
+ import { searchContent } from "./content-search.js";
10
+ let db = null;
11
+ function open(path) {
12
+ try {
13
+ db?.close();
14
+ }
15
+ catch { /* ignore */ }
16
+ db = null;
17
+ try {
18
+ db = new DatabaseSync(path, { readOnly: true });
19
+ }
20
+ catch {
21
+ db = null;
22
+ }
23
+ }
24
+ const initial = workerData?.dbPath;
25
+ if (initial !== undefined)
26
+ open(initial);
27
+ parentPort?.on('message', (request) => {
28
+ if (request.open !== undefined) {
29
+ open(request.open);
30
+ parentPort?.postMessage({ id: request.id, ok: true });
31
+ return;
32
+ }
33
+ if (request.close === true) {
34
+ try {
35
+ db?.close();
36
+ }
37
+ catch { /* ignore */ }
38
+ db = null;
39
+ parentPort?.postMessage({ id: request.id, ok: true });
40
+ return;
41
+ }
42
+ let hits = [];
43
+ let error = '';
44
+ if (db !== null) {
45
+ try {
46
+ hits = searchContent(db, request.query ?? '', request.limit ?? 30);
47
+ }
48
+ catch (cause) {
49
+ error = cause instanceof Error ? cause.message : String(cause);
50
+ }
51
+ }
52
+ parentPort?.postMessage({ id: request.id, hits, error });
53
+ });
54
+ //# sourceMappingURL=content-search-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-search-worker.js","sourceRoot":"","sources":["../src/content-search-worker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAWnD,IAAI,EAAE,GAAwB,IAAI,CAAA;AAElC,SAAS,IAAI,CAAC,IAAY;IACxB,IAAI,CAAC;QAAC,EAAE,EAAE,KAAK,EAAE,CAAA;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAC1C,EAAE,GAAG,IAAI,CAAA;IACT,IAAI,CAAC;QAAC,EAAE,GAAG,IAAI,YAAY,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,EAAE,GAAG,IAAI,CAAA;IAAC,CAAC;AAC7E,CAAC;AAED,MAAM,OAAO,GAAI,UAA8C,EAAE,MAAM,CAAA;AACvE,IAAI,OAAO,KAAK,SAAS;IAAE,IAAI,CAAC,OAAO,CAAC,CAAA;AAExC,UAAU,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,OAAgB,EAAE,EAAE;IAC7C,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAClB,UAAU,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;QACrD,OAAM;IACR,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC;YAAC,EAAE,EAAE,KAAK,EAAE,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QAC1C,EAAE,GAAG,IAAI,CAAA;QACT,UAAU,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;QACrD,OAAM;IACR,CAAC;IACD,IAAI,IAAI,GAAiB,EAAE,CAAA;IAC3B,IAAI,KAAK,GAAG,EAAE,CAAA;IACd,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;QAChB,IAAI,CAAC;YAAC,IAAI,GAAG,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,KAAK,IAAI,EAAE,EAAE,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;QAAC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACxF,KAAK,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAChE,CAAC;IACH,CAAC;IACD,UAAU,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;AAC1D,CAAC,CAAC,CAAA"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Content FTS5 query shared by the host thread and the search worker.
3
+ * @module dsh-locator/content-search
4
+ */
5
+ import type { DatabaseSync } from 'node:sqlite';
6
+ import type { ContentHit } from './content.ts';
7
+ /**
8
+ * Run one content query against an open SQLite handle.
9
+ * @param db - open database (read-only in the worker).
10
+ * @param query - user query; shorter than three characters falls back to LIKE.
11
+ * @param limit - maximum hits.
12
+ * @returns hits, ordered by relevance.
13
+ */
14
+ export declare function searchContent(db: DatabaseSync, query: string, limit: number): ContentHit[];
15
+ //# sourceMappingURL=content-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-search.d.ts","sourceRoot":"","sources":["../src/content-search.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAE9C;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,CAuB1F"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Content FTS5 query shared by the host thread and the search worker.
3
+ * @module dsh-locator/content-search
4
+ */
5
+ /**
6
+ * Run one content query against an open SQLite handle.
7
+ * @param db - open database (read-only in the worker).
8
+ * @param query - user query; shorter than three characters falls back to LIKE.
9
+ * @param limit - maximum hits.
10
+ * @returns hits, ordered by relevance.
11
+ */
12
+ export function searchContent(db, query, limit) {
13
+ const text = query.trim();
14
+ if (text === '')
15
+ return [];
16
+ const capped = Math.max(1, Math.min(100, limit));
17
+ let rows;
18
+ if ([...text].length < 3) {
19
+ rows = db.prepare(`SELECT kind, path, title, session_id, message_id, body, 0 AS score
20
+ FROM docs WHERE body LIKE '%' || ? || '%' LIMIT ?`).all(text, capped);
21
+ }
22
+ else {
23
+ const match = text.split(/\s+/).filter(Boolean).map(term => '"' + term.replace(/"/g, '') + '"').join(' AND ');
24
+ rows = db.prepare(`SELECT kind, path, title, session_id, message_id,
25
+ snippet(docs, 0, char(1), char(2), '…', 16) AS snippet, bm25(docs) AS score
26
+ FROM docs WHERE docs MATCH ? ORDER BY score LIMIT ?`).all(match, capped);
27
+ }
28
+ return rows.map(row => ({
29
+ kind: row.kind === 'session' ? 'session' : 'file',
30
+ path: String(row.path ?? ''),
31
+ title: String(row.title ?? ''),
32
+ snippet: String(row.snippet ?? row.body ?? '').replace(/[\u0001\u0002]/g, ''),
33
+ ...(row.session_id ? { sessionId: String(row.session_id) } : {}),
34
+ ...(row.message_id ? { messageId: String(row.message_id) } : {}),
35
+ score: Number(row.score ?? 0),
36
+ }));
37
+ }
38
+ //# sourceMappingURL=content-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-search.js","sourceRoot":"","sources":["../src/content-search.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,EAAgB,EAAE,KAAa,EAAE,KAAa;IAC1E,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IACzB,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,EAAE,CAAA;IAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAA;IAChD,IAAI,IAAoC,CAAA;IACxC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;wDACkC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAmC,CAAA;IAC3G,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC7G,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;;0DAEoC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAmC,CAAA;IAC9G,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtB,IAAI,EAAE,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;QACjD,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;QAC5B,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9B,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC7E,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC;KAC9B,CAAC,CAAC,CAAA;AACL,CAAC"}
package/lib/content.d.ts CHANGED
@@ -6,6 +6,13 @@
6
6
  * `session.v4.jsonl.zstd`, and SQLite's trigram tokenizer gives substring and
7
7
  * CJK search. A meta table stores each source's mtime so refresh() only
8
8
  * re-reads what changed; rebuild() drops and rebuilds everything.
9
+ *
10
+ * Everything here runs inside the DSH host process, so the build must never
11
+ * monopolise its event loop: file reads and zstd decoding are asynchronous and
12
+ * the loops yield to the scheduler every ~8 ms of work. Session logs are read
13
+ * only once they have settled (an actively written session is skipped until it
14
+ * has been quiet for `activeSessionDelayMs`), and archived sessions are left
15
+ * alone unless `includeArchived` is set.
9
16
  * @module dsh-locator/content
10
17
  */
11
18
  import type { LocatorRuntime } from './runtime.ts';
@@ -30,10 +37,25 @@ export interface ContentState {
30
37
  export interface ContentOptions {
31
38
  stateDir: string;
32
39
  sessionDirs?: string[] | undefined;
40
+ /** Path segments or substrings never read into the content index. */
41
+ excludes?: string[];
42
+ /** Index archived sessions too; false (the default) leaves them out. */
43
+ includeArchived?: boolean;
44
+ /**
45
+ * Skip session logs modified more recently than this many milliseconds, so
46
+ * the session being written right now is not re-read on every refresh.
47
+ */
48
+ activeSessionDelayMs?: number;
33
49
  maxFileBytes: number;
34
50
  maxTotalBytes?: number;
35
51
  maxFiles: number;
36
52
  maxSessions: number;
53
+ /**
54
+ * Run content queries in a worker thread so a slow search never blocks the
55
+ * DSH host event loop. Off by default so direct embedders and tests stay
56
+ * single-threaded.
57
+ */
58
+ searchWorker?: boolean;
37
59
  }
38
60
  export declare class ContentIndex {
39
61
  private readonly rt;
@@ -42,11 +64,14 @@ export declare class ContentIndex {
42
64
  private readonly state;
43
65
  private generation;
44
66
  private totalBytes;
45
- private timer;
67
+ private sliceDeadline;
68
+ private worker;
69
+ private lockHeld;
70
+ private readonly lockToken;
71
+ private workerSeq;
72
+ private readonly pending;
46
73
  constructor(rt: LocatorRuntime, options: ContentOptions);
47
74
  status(): ContentState;
48
- /** Start periodic incremental refreshes; 0 disables. */
49
- startAutoRefresh(ms: number): void;
50
75
  /** Queue a full rebuild; false when one is already running. */
51
76
  rebuild(): boolean;
52
77
  /** Queue an incremental refresh; false when one is already running. */
@@ -54,23 +79,64 @@ export declare class ContentIndex {
54
79
  close(): void;
55
80
  /** Build everything from scratch. */
56
81
  start(): void;
82
+ /**
83
+ * Start at plugin boot: reuse an existing database and refresh it
84
+ * incrementally, so a restart does not re-read and re-index gigabytes of
85
+ * text. A missing or incompatible database falls back to a full build.
86
+ */
87
+ boot(): void;
57
88
  /** Re-read changed files/sessions; open the DB when this is the first run. */
58
89
  refresh(): void;
90
+ /**
91
+ * Serialize content builds across plugin instances and DSH processes that
92
+ * share a state directory: a stale lock (dead pid or older than 30 minutes)
93
+ * is taken over, a live one keeps this instance from writing concurrently.
94
+ * @returns whether this instance owns the build lock.
95
+ */
96
+ private acquireLock;
97
+ private releaseLock;
59
98
  private begin;
60
99
  private full;
61
100
  private incremental;
62
101
  private open;
102
+ private reopenWorker;
103
+ private stopWorker;
104
+ private ensureWorker;
105
+ /**
106
+ * Body bytes already stored. Reading a persisted counter avoids a full scan
107
+ * of every FTS body (measured ~0.6 s for 1 GB) at the start of each refresh.
108
+ * A database written before the counter existed falls back to one scan.
109
+ */
110
+ private readTotalBytes;
111
+ private writeTotalBytes;
112
+ /** Yield to the host event loop once the current ~8 ms work slice is spent. */
113
+ private breathe;
114
+ /** True when a session log has been quiet long enough to be read safely. */
115
+ private settled;
63
116
  private finish;
64
117
  private addDoc;
65
118
  private deleteDoc;
66
119
  private deletePath;
67
120
  private indexFiles;
68
121
  private refreshFiles;
122
+ /** Would storing a file of this size overflow the configured body budget? */
123
+ private wouldExceed;
69
124
  private readFileDoc;
70
125
  private indexSessions;
71
126
  private refreshSessions;
72
127
  private indexSessionFile;
128
+ /** Session logs to consider, newest first, minus archived ones by default. */
129
+ private sessionCandidates;
73
130
  sessionRoots(): string[];
74
- search(query: string, limit: number): ContentHit[];
131
+ /**
132
+ * Search file bodies and session messages. With `searchWorker` enabled the
133
+ * query itself runs off the host thread; a failed or wedged worker falls back
134
+ * to the in-process query so a result is still produced.
135
+ * @param query - words or a phrase to find.
136
+ * @param limit - maximum hits.
137
+ * @returns matching documents ordered by relevance.
138
+ */
139
+ search(query: string, limit: number): Promise<ContentHit[]>;
140
+ private searchSync;
75
141
  }
76
142
  //# sourceMappingURL=content.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAWlD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;IAClC,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB;AAaD,qBAAa,YAAY;IAOX,OAAO,CAAC,QAAQ,CAAC,EAAE;IAAkB,OAAO,CAAC,QAAQ,CAAC,OAAO;IANzE,OAAO,CAAC,EAAE,CAA4B;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmH;IACzI,OAAO,CAAC,UAAU,CAAI;IACtB,OAAO,CAAC,UAAU,CAAI;IACtB,OAAO,CAAC,KAAK,CAA4B;gBAEZ,EAAE,EAAE,cAAc,EAAmB,OAAO,EAAE,cAAc;IAEzF,MAAM,IAAI,YAAY;IAEtB,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAKlC,+DAA+D;IAC/D,OAAO,IAAI,OAAO;IAMlB,uEAAuE;IACvE,UAAU,IAAI,OAAO;IAMrB,KAAK,IAAI,IAAI;IAQb,qCAAqC;IACrC,KAAK,IAAI,IAAI;IAEb,8EAA8E;IAC9E,OAAO,IAAI,IAAI;IAEf,OAAO,CAAC,KAAK;YAcC,IAAI;YAUJ,WAAW;IAUzB,OAAO,CAAC,IAAI;IAmBZ,OAAO,CAAC,MAAM;IASd,OAAO,CAAC,MAAM;IAcd,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,UAAU;YAOJ,UAAU;YAoBV,YAAY;IA2B1B,OAAO,CAAC,WAAW;YAOL,aAAa;YAUb,eAAe;IAoB7B,OAAO,CAAC,gBAAgB;IAmBxB,YAAY,IAAI,MAAM,EAAE;IAKxB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE;CA8BnD"}
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"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"}