sensemaking 0.27.0 → 0.27.1

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 (285) hide show
  1. package/dist/cjs/chunk/extract.js.map +1 -1
  2. package/dist/cjs/chunk/group.js.map +1 -1
  3. package/dist/cjs/chunk/index.js.map +1 -1
  4. package/dist/cjs/chunk/parse.js.map +1 -1
  5. package/dist/cjs/chunk/parser.js.map +1 -1
  6. package/dist/cjs/chunk/tokens.js.map +1 -1
  7. package/dist/cjs/chunk/version.js.map +1 -1
  8. package/dist/cjs/cli/build.js.map +1 -1
  9. package/dist/cjs/cli/download.js.map +1 -1
  10. package/dist/cjs/cli/index.js.map +1 -1
  11. package/dist/cjs/cli/init.js.map +1 -1
  12. package/dist/cjs/cli/map.js.map +1 -1
  13. package/dist/cjs/cli/named.js.map +1 -1
  14. package/dist/cjs/cli/path.js.map +1 -1
  15. package/dist/cjs/cli/peek.js.map +1 -1
  16. package/dist/cjs/cli/related.js.map +1 -1
  17. package/dist/cjs/cli/search.js.map +1 -1
  18. package/dist/cjs/cli/shared.js.map +1 -1
  19. package/dist/cjs/cli/sql.js.map +1 -1
  20. package/dist/cjs/cli/status.js.map +1 -1
  21. package/dist/cjs/cli/watch.js.map +1 -1
  22. package/dist/cjs/cli.js.map +1 -1
  23. package/dist/cjs/commands/index.js.map +1 -1
  24. package/dist/cjs/commands/map.js.map +1 -1
  25. package/dist/cjs/commands/path.js.map +1 -1
  26. package/dist/cjs/commands/peek.js.map +1 -1
  27. package/dist/cjs/commands/related.js.map +1 -1
  28. package/dist/cjs/commands/scope.js.map +1 -1
  29. package/dist/cjs/commands/search.js.map +1 -1
  30. package/dist/cjs/commands/signals.js.map +1 -1
  31. package/dist/cjs/commands/snapshot.js.map +1 -1
  32. package/dist/cjs/commands/status.js.map +1 -1
  33. package/dist/cjs/config/access.js.map +1 -1
  34. package/dist/cjs/config/index.js.map +1 -1
  35. package/dist/cjs/config/load.js.map +1 -1
  36. package/dist/cjs/config/resolve.js.map +1 -1
  37. package/dist/cjs/config/signals.js.map +1 -1
  38. package/dist/cjs/config/types.js.map +1 -1
  39. package/dist/cjs/config/validate.js.map +1 -1
  40. package/dist/cjs/embed/cohere.js.map +1 -1
  41. package/dist/cjs/embed/distribution.js.map +1 -1
  42. package/dist/cjs/embed/endpoint.js.map +1 -1
  43. package/dist/cjs/embed/handoff.js.map +1 -1
  44. package/dist/cjs/embed/http.js.map +1 -1
  45. package/dist/cjs/embed/identity.js.map +1 -1
  46. package/dist/cjs/embed/langfit.js.map +1 -1
  47. package/dist/cjs/embed/languages.js.map +1 -1
  48. package/dist/cjs/embed/openai.js.map +1 -1
  49. package/dist/cjs/embed/query.js.map +1 -1
  50. package/dist/cjs/embed/registry.js.map +1 -1
  51. package/dist/cjs/embed/static.js.map +1 -1
  52. package/dist/cjs/embed/store.js.map +1 -1
  53. package/dist/cjs/embed/types.js.map +1 -1
  54. package/dist/cjs/errors.js.map +1 -1
  55. package/dist/cjs/features/embed.js.map +1 -1
  56. package/dist/cjs/features/fences.js.map +1 -1
  57. package/dist/cjs/features/index.js.map +1 -1
  58. package/dist/cjs/features/links.js.map +1 -1
  59. package/dist/cjs/features/rank.js.map +1 -1
  60. package/dist/cjs/features/sections.js.map +1 -1
  61. package/dist/cjs/features/tags.js.map +1 -1
  62. package/dist/cjs/graph/graph.js.map +1 -1
  63. package/dist/cjs/graph/traverse.js.map +1 -1
  64. package/dist/cjs/index.js.map +1 -1
  65. package/dist/cjs/lib/atomic-write.js.map +1 -1
  66. package/dist/cjs/lib/guarded-tick.js.map +1 -1
  67. package/dist/cjs/lib/serial-query.js.map +1 -1
  68. package/dist/cjs/lib/watch-notification.js.map +1 -1
  69. package/dist/cjs/lib/worker-file.js.map +1 -1
  70. package/dist/cjs/output/column-hint.js.map +1 -1
  71. package/dist/cjs/output/output.js.map +1 -1
  72. package/dist/cjs/output/progress.js.map +1 -1
  73. package/dist/cjs/output/search-error.js.map +1 -1
  74. package/dist/cjs/scan/frontmatter.js.map +1 -1
  75. package/dist/cjs/scan/index.js.map +1 -1
  76. package/dist/cjs/scan/list.js.map +1 -1
  77. package/dist/cjs/scan/pool.js.map +1 -1
  78. package/dist/cjs/scan/reparse.js.map +1 -1
  79. package/dist/cjs/scan/worker-error.js.map +1 -1
  80. package/dist/cjs/store/batch.js.map +1 -1
  81. package/dist/cjs/store/builder.js.map +1 -1
  82. package/dist/cjs/store/cache.js.map +1 -1
  83. package/dist/cjs/store/duckdb/batch.js.map +1 -1
  84. package/dist/cjs/store/duckdb/connection.js.map +1 -1
  85. package/dist/cjs/store/duckdb/fieldStats.js.map +1 -1
  86. package/dist/cjs/store/duckdb/lexical.d.cts +1 -6
  87. package/dist/cjs/store/duckdb/lexical.d.ts +1 -6
  88. package/dist/cjs/store/duckdb/lexical.js +28 -39
  89. package/dist/cjs/store/duckdb/lexical.js.map +1 -1
  90. package/dist/cjs/store/duckdb/native.d.cts +1 -2
  91. package/dist/cjs/store/duckdb/native.d.ts +1 -2
  92. package/dist/cjs/store/duckdb/native.js +1 -6
  93. package/dist/cjs/store/duckdb/native.js.map +1 -1
  94. package/dist/cjs/store/duckdb/open.js.map +1 -1
  95. package/dist/cjs/store/duckdb/ordered-bm25.d.cts +3 -16
  96. package/dist/cjs/store/duckdb/ordered-bm25.d.ts +3 -16
  97. package/dist/cjs/store/duckdb/ordered-bm25.js +27 -79
  98. package/dist/cjs/store/duckdb/ordered-bm25.js.map +1 -1
  99. package/dist/cjs/store/duckdb/reconcile.js.map +1 -1
  100. package/dist/cjs/store/duckdb/sql-functions.js.map +1 -1
  101. package/dist/cjs/store/duckdb/store.js.map +1 -1
  102. package/dist/cjs/store/duckdb/vectors.js.map +1 -1
  103. package/dist/cjs/store/embed-scope.js.map +1 -1
  104. package/dist/cjs/store/feature-scope.js.map +1 -1
  105. package/dist/cjs/store/index.js.map +1 -1
  106. package/dist/cjs/store/lock-wait.js.map +1 -1
  107. package/dist/cjs/store/native.js.map +1 -1
  108. package/dist/cjs/store/open.js.map +1 -1
  109. package/dist/cjs/store/preset-scope.js.map +1 -1
  110. package/dist/cjs/store/readiness.js.map +1 -1
  111. package/dist/cjs/store/reconcile.js.map +1 -1
  112. package/dist/cjs/store/shared.js.map +1 -1
  113. package/dist/cjs/store/signature.js.map +1 -1
  114. package/dist/cjs/store/sql-functions.js.map +1 -1
  115. package/dist/cjs/store/sqlite/connection.js.map +1 -1
  116. package/dist/cjs/store/sqlite/fieldStats.js.map +1 -1
  117. package/dist/cjs/store/sqlite/lexical.js.map +1 -1
  118. package/dist/cjs/store/sqlite/open.js.map +1 -1
  119. package/dist/cjs/store/sqlite/reconcile.js.map +1 -1
  120. package/dist/cjs/store/sqlite/sql-functions.js.map +1 -1
  121. package/dist/cjs/store/sqlite/store.js.map +1 -1
  122. package/dist/cjs/store/sqlite/vectors.js.map +1 -1
  123. package/dist/cjs/store/stages.js.map +1 -1
  124. package/dist/cjs/store/transaction.js.map +1 -1
  125. package/dist/cjs/store/turso/connection.js.map +1 -1
  126. package/dist/cjs/store/turso/fieldStats.js.map +1 -1
  127. package/dist/cjs/store/turso/lexical-text.js.map +1 -1
  128. package/dist/cjs/store/turso/lexical.js.map +1 -1
  129. package/dist/cjs/store/turso/native.js.map +1 -1
  130. package/dist/cjs/store/turso/open.js.map +1 -1
  131. package/dist/cjs/store/turso/reconcile.js.map +1 -1
  132. package/dist/cjs/store/turso/sql-functions.js.map +1 -1
  133. package/dist/cjs/store/turso/store.js.map +1 -1
  134. package/dist/cjs/store/turso/vectors.js.map +1 -1
  135. package/dist/cjs/store/types.js.map +1 -1
  136. package/dist/cjs/store/vectors.js.map +1 -1
  137. package/dist/cjs/text/segment.js.map +1 -1
  138. package/dist/cjs/text/strip.js.map +1 -1
  139. package/dist/cjs/watch-claim.js.map +1 -1
  140. package/dist/cjs/watch.js.map +1 -1
  141. package/dist/cjs/workers/parse.js.map +1 -1
  142. package/dist/cjs/workers/watch-heartbeat.js.map +1 -1
  143. package/dist/esm/chunk/extract.js.map +1 -1
  144. package/dist/esm/chunk/group.js.map +1 -1
  145. package/dist/esm/chunk/index.js.map +1 -1
  146. package/dist/esm/chunk/parse.js.map +1 -1
  147. package/dist/esm/chunk/parser.js.map +1 -1
  148. package/dist/esm/chunk/tokens.js.map +1 -1
  149. package/dist/esm/chunk/types.js.map +1 -1
  150. package/dist/esm/chunk/version.js.map +1 -1
  151. package/dist/esm/cli/build.js.map +1 -1
  152. package/dist/esm/cli/download.js.map +1 -1
  153. package/dist/esm/cli/index.js.map +1 -1
  154. package/dist/esm/cli/init.js.map +1 -1
  155. package/dist/esm/cli/map.js.map +1 -1
  156. package/dist/esm/cli/named.js.map +1 -1
  157. package/dist/esm/cli/path.js.map +1 -1
  158. package/dist/esm/cli/peek.js.map +1 -1
  159. package/dist/esm/cli/related.js.map +1 -1
  160. package/dist/esm/cli/search.js.map +1 -1
  161. package/dist/esm/cli/shared.js.map +1 -1
  162. package/dist/esm/cli/sql.js.map +1 -1
  163. package/dist/esm/cli/status.js.map +1 -1
  164. package/dist/esm/cli/types.js.map +1 -1
  165. package/dist/esm/cli/watch.js.map +1 -1
  166. package/dist/esm/cli.js.map +1 -1
  167. package/dist/esm/commands/index.js.map +1 -1
  168. package/dist/esm/commands/map.js.map +1 -1
  169. package/dist/esm/commands/path.js.map +1 -1
  170. package/dist/esm/commands/peek.js.map +1 -1
  171. package/dist/esm/commands/related.js.map +1 -1
  172. package/dist/esm/commands/scope.js.map +1 -1
  173. package/dist/esm/commands/search.js.map +1 -1
  174. package/dist/esm/commands/signals.js.map +1 -1
  175. package/dist/esm/commands/snapshot.js.map +1 -1
  176. package/dist/esm/commands/status.js.map +1 -1
  177. package/dist/esm/config/access.js.map +1 -1
  178. package/dist/esm/config/index.js.map +1 -1
  179. package/dist/esm/config/load.js.map +1 -1
  180. package/dist/esm/config/resolve.js.map +1 -1
  181. package/dist/esm/config/signals.js.map +1 -1
  182. package/dist/esm/config/types.js.map +1 -1
  183. package/dist/esm/config/validate.js.map +1 -1
  184. package/dist/esm/embed/cohere.js.map +1 -1
  185. package/dist/esm/embed/distribution.js.map +1 -1
  186. package/dist/esm/embed/endpoint.js.map +1 -1
  187. package/dist/esm/embed/handoff.js.map +1 -1
  188. package/dist/esm/embed/http.js.map +1 -1
  189. package/dist/esm/embed/identity.js.map +1 -1
  190. package/dist/esm/embed/langfit.js.map +1 -1
  191. package/dist/esm/embed/languages.js.map +1 -1
  192. package/dist/esm/embed/openai.js.map +1 -1
  193. package/dist/esm/embed/query.js.map +1 -1
  194. package/dist/esm/embed/registry.js.map +1 -1
  195. package/dist/esm/embed/static.js.map +1 -1
  196. package/dist/esm/embed/store.js.map +1 -1
  197. package/dist/esm/embed/types.js.map +1 -1
  198. package/dist/esm/errors.js.map +1 -1
  199. package/dist/esm/features/embed.js.map +1 -1
  200. package/dist/esm/features/fences.js.map +1 -1
  201. package/dist/esm/features/index.js.map +1 -1
  202. package/dist/esm/features/links.js.map +1 -1
  203. package/dist/esm/features/rank.js.map +1 -1
  204. package/dist/esm/features/sections.js.map +1 -1
  205. package/dist/esm/features/tags.js.map +1 -1
  206. package/dist/esm/features/types.js.map +1 -1
  207. package/dist/esm/graph/graph.js.map +1 -1
  208. package/dist/esm/graph/traverse.js.map +1 -1
  209. package/dist/esm/index.js.map +1 -1
  210. package/dist/esm/lib/atomic-write.js.map +1 -1
  211. package/dist/esm/lib/guarded-tick.js.map +1 -1
  212. package/dist/esm/lib/serial-query.js.map +1 -1
  213. package/dist/esm/lib/watch-notification.js.map +1 -1
  214. package/dist/esm/lib/worker-file.js.map +1 -1
  215. package/dist/esm/output/column-hint.js.map +1 -1
  216. package/dist/esm/output/output.js.map +1 -1
  217. package/dist/esm/output/progress.js.map +1 -1
  218. package/dist/esm/output/search-error.js.map +1 -1
  219. package/dist/esm/scan/frontmatter.js.map +1 -1
  220. package/dist/esm/scan/index.js.map +1 -1
  221. package/dist/esm/scan/list.js.map +1 -1
  222. package/dist/esm/scan/pool.js.map +1 -1
  223. package/dist/esm/scan/reparse.js.map +1 -1
  224. package/dist/esm/scan/worker-error.js.map +1 -1
  225. package/dist/esm/store/batch.js.map +1 -1
  226. package/dist/esm/store/builder.js.map +1 -1
  227. package/dist/esm/store/cache.js.map +1 -1
  228. package/dist/esm/store/duckdb/batch.js.map +1 -1
  229. package/dist/esm/store/duckdb/connection.js.map +1 -1
  230. package/dist/esm/store/duckdb/fieldStats.js.map +1 -1
  231. package/dist/esm/store/duckdb/lexical.d.ts +1 -6
  232. package/dist/esm/store/duckdb/lexical.js +13 -17
  233. package/dist/esm/store/duckdb/lexical.js.map +1 -1
  234. package/dist/esm/store/duckdb/native.d.ts +1 -2
  235. package/dist/esm/store/duckdb/native.js +1 -3
  236. package/dist/esm/store/duckdb/native.js.map +1 -1
  237. package/dist/esm/store/duckdb/open.js.map +1 -1
  238. package/dist/esm/store/duckdb/ordered-bm25.d.ts +3 -16
  239. package/dist/esm/store/duckdb/ordered-bm25.js +18 -54
  240. package/dist/esm/store/duckdb/ordered-bm25.js.map +1 -1
  241. package/dist/esm/store/duckdb/reconcile.js.map +1 -1
  242. package/dist/esm/store/duckdb/sql-functions.js.map +1 -1
  243. package/dist/esm/store/duckdb/store.js.map +1 -1
  244. package/dist/esm/store/duckdb/vectors.js.map +1 -1
  245. package/dist/esm/store/embed-scope.js.map +1 -1
  246. package/dist/esm/store/feature-scope.js.map +1 -1
  247. package/dist/esm/store/index.js.map +1 -1
  248. package/dist/esm/store/lock-wait.js.map +1 -1
  249. package/dist/esm/store/native.js.map +1 -1
  250. package/dist/esm/store/open.js.map +1 -1
  251. package/dist/esm/store/preset-scope.js.map +1 -1
  252. package/dist/esm/store/readiness.js.map +1 -1
  253. package/dist/esm/store/reconcile.js.map +1 -1
  254. package/dist/esm/store/shared.js.map +1 -1
  255. package/dist/esm/store/signature.js.map +1 -1
  256. package/dist/esm/store/sql-functions.js.map +1 -1
  257. package/dist/esm/store/sqlite/connection.js.map +1 -1
  258. package/dist/esm/store/sqlite/fieldStats.js.map +1 -1
  259. package/dist/esm/store/sqlite/lexical.js.map +1 -1
  260. package/dist/esm/store/sqlite/open.js.map +1 -1
  261. package/dist/esm/store/sqlite/reconcile.js.map +1 -1
  262. package/dist/esm/store/sqlite/sql-functions.js.map +1 -1
  263. package/dist/esm/store/sqlite/store.js.map +1 -1
  264. package/dist/esm/store/sqlite/vectors.js.map +1 -1
  265. package/dist/esm/store/stages.js.map +1 -1
  266. package/dist/esm/store/transaction.js.map +1 -1
  267. package/dist/esm/store/turso/connection.js.map +1 -1
  268. package/dist/esm/store/turso/fieldStats.js.map +1 -1
  269. package/dist/esm/store/turso/lexical-text.js.map +1 -1
  270. package/dist/esm/store/turso/lexical.js.map +1 -1
  271. package/dist/esm/store/turso/native.js.map +1 -1
  272. package/dist/esm/store/turso/open.js.map +1 -1
  273. package/dist/esm/store/turso/reconcile.js.map +1 -1
  274. package/dist/esm/store/turso/sql-functions.js.map +1 -1
  275. package/dist/esm/store/turso/store.js.map +1 -1
  276. package/dist/esm/store/turso/vectors.js.map +1 -1
  277. package/dist/esm/store/types.js.map +1 -1
  278. package/dist/esm/store/vectors.js.map +1 -1
  279. package/dist/esm/text/segment.js.map +1 -1
  280. package/dist/esm/text/strip.js.map +1 -1
  281. package/dist/esm/watch-claim.js.map +1 -1
  282. package/dist/esm/watch.js.map +1 -1
  283. package/dist/esm/workers/parse.js.map +1 -1
  284. package/dist/esm/workers/watch-heartbeat.js.map +1 -1
  285. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/duckdb/lexical.ts"],"sourcesContent":["// D1: fts BM25 for ranking, contains() scans for exact substring / phrase verification /\n// unspaced scripts, JS snippets for every doc (no snippet()).\nimport { SenseError } from '../../errors.ts';\nimport { foldForSearch, matchesSearchPhrase, type SearchToken, searchTokens } from '../../text/segment.ts';\nimport { getMeta, setMeta } from '../shared.ts';\nimport { withTransaction } from '../transaction.ts';\nimport type { Connection, LexicalHit, LexicalQueryOptions } from '../types.ts';\nimport { ensureOrderedBm25, ORDERED_BM25_MACRO } from './ordered-bm25.ts';\n\nconst FIELDS = ['title', 'summary', 'text'] as const;\ntype Field = (typeof FIELDS)[number];\n// Mirrors sqlite's bm25(content, 10.0, 5.0, 1.0, ...) column-weight intent; DuckDB's match_bm25 has no\n// field_weights argument (verified 1.5.5), so each field is scored separately and combined here.\nconst FIELD_WEIGHT: Record<Field, number> = { title: 10, summary: 5, text: 1 };\n\n// FTS5 operator syntax (sqlite.org/fts5.html sec. 3) that words/substrings below would otherwise silently\n// treat as literal terms (PRINCIPLES: no-silent-modes). Quoted contents stay ignored while their boundary remains detectable.\nconst FTS5_OPERATORS: Array<{ label: string; re: RegExp }> = [\n { label: 'prefix query', re: /[\\p{L}\\p{N}_]+\\*(?=\\s|$)/u },\n { label: 'boolean operator', re: /(?:^|\\s)(?:AND|OR|NOT)(?=\\s|$)/ },\n { label: 'NEAR operator', re: /(?:^|\\s)NEAR\\b/ },\n { label: 'initial-token operator', re: /(?:^|\\s)\\^\\S+/ },\n { label: 'column filter', re: /(?:^|\\s)[\\p{L}_]\\w*\\s*:/u },\n { label: 'grouping operator', re: /[()]/ },\n];\n\nfunction unsupportedOperator(terms: string): { label: string; token: string } | null {\n const withoutPhrases = terms.replace(/\"[^\"]*\"/g, 'phrase');\n for (const { label, re } of FTS5_OPERATORS) {\n const m = withoutPhrases.match(re);\n if (m) return { label, token: m[0].trim() };\n }\n return null;\n}\n\ninterface FtsIndexState {\n stale: boolean;\n orderedMacroReady: boolean;\n}\n\n// Durable across connections/processes (meta table, shared.ts); `stale` is the in-memory cache of\n// it for this connection's lifetime, so a watcher's repeat queries don't re-read meta every time.\nconst FTS_STALE_META_KEY = 'fts_stale';\n\n// One state per connection, not per store instance: reconcileContent (reconcile.ts) marks it\n// stale from outside createLexicalIndex's closure, whether a one-shot open or a watcher's builder ran it.\nconst ftsState = new WeakMap<Connection, FtsIndexState>();\nasync function stateFor(conn: Connection): Promise<FtsIndexState> {\n let state = ftsState.get(conn);\n if (!state) {\n // Anything but a persisted '0' (missing key, or '1') means a rebuild is owed: a cache that\n // never built an index, or one a prior process marked stale and never got to clear.\n state = { stale: (await getMeta(conn, FTS_STALE_META_KEY)) !== '0', orderedMacroReady: false };\n ftsState.set(conn, state);\n }\n return state;\n}\n\nasync function hasFtsArtifact(conn: Connection): Promise<boolean> {\n const stmt = await conn.prepare(`\n SELECT 1 AS ready\n FROM duckdb_functions()\n WHERE schema_name = 'fts_main_content'\n AND function_name = 'match_bm25'\n AND function_type = 'macro'\n LIMIT 1\n `);\n return (await stmt.get()) !== undefined;\n}\n\n// Called whenever this store's reconcileContent changes `content`; must run inside that same\n// transaction (reconcile.ts) so a crash never lands the content write without the stale mark.\nexport async function markContentStale(conn: Connection): Promise<void> {\n ftsState.set(conn, { stale: true, orderedMacroReady: false });\n await setMeta(conn, FTS_STALE_META_KEY, '1');\n}\n\n// A run whose script marks no word boundaries makes match_bm25's whitespace tokenizer index the whole run as one token,\n// so unspaced terms use contains() and quoted phrases use the shared authored-field verifier.\nfunction splitTerms(terms: string): { words: string[]; bareWords: string[]; phraseWords: string[]; substrings: string[]; phrases: SearchToken[][]; emptyPhrase: boolean } {\n const words: string[] = [];\n const bareWords: string[] = [];\n const phraseWords: string[] = [];\n const substrings: string[] = [];\n const phrases: SearchToken[][] = [];\n let emptyPhrase = false;\n const withoutPhrases = terms.replace(/\"([^\"]*)\"/g, (_m, inner: string) => {\n const phrase = inner.trim();\n const phraseTokens = searchTokens(phrase);\n if (phraseTokens.length === 0) {\n emptyPhrase = true;\n return ' ';\n }\n phrases.push(phraseTokens);\n for (const token of phraseTokens) {\n if (token.unspaced) substrings.push(token.text);\n else {\n words.push(token.text);\n phraseWords.push(token.text);\n }\n }\n return ' ';\n });\n for (const tok of withoutPhrases.split(/\\s+/)) {\n if (tok.length === 0) continue;\n for (const token of searchTokens(tok)) {\n if (token.unspaced) substrings.push(token.text);\n else {\n words.push(token.text);\n bareWords.push(token.text);\n }\n }\n }\n return { words, bareWords, phraseWords, substrings, phrases, emptyPhrase };\n}\n\n// No incremental update (verified 1.5.5: PRAGMA create_fts_index is rebuild-only), so this pays\n// the full rebuild whenever `state.stale`, which meta.fts_stale keeps true across processes until cleared below.\nasync function rebuildFts(conn: Connection, state: FtsIndexState): Promise<void> {\n await conn.exec('INSTALL fts; LOAD fts;');\n if (!state.stale && (await hasFtsArtifact(conn))) return;\n state.stale = true;\n state.orderedMacroReady = false;\n await withTransaction(conn, async () => {\n // stopwords='none': sqlite's porter/unicode61 tokenizer never removes stopwords either (verified 1.5.5); the fts extension's\n // default 571-word list would otherwise drop common words (e.g. \"and\") from the index but not match_bm25's conjunctive gate, breaking multi-word matches.\n await conn.exec(`PRAGMA create_fts_index('content', 'path', 'title', 'summary', 'text', stopwords='none', overwrite=1)`);\n // Same transaction as the rebuild: a crash before commit leaves the mark set (a redundant\n // rebuild next time), never a cleared mark serving a half-built index as fresh.\n await setMeta(conn, FTS_STALE_META_KEY, '0');\n });\n state.stale = false;\n}\n\nexport async function prepareFts(conn: Connection): Promise<void> {\n await rebuildFts(conn, await stateFor(conn));\n}\n\nexport async function assertFtsReady(conn: Connection): Promise<void> {\n const state = await stateFor(conn);\n if (state.stale) throw new SenseError('INDEX_NOT_READY', 'the DuckDB lexical index is missing or stale; run `sense build` (or library build(config)) before lexical querying with build disabled');\n try {\n await conn.exec('LOAD fts;');\n if (!(await hasFtsArtifact(conn))) {\n throw new SenseError('INDEX_NOT_READY', 'the DuckDB lexical index artifact is missing; run `sense build` (or library build(config)) before lexical querying with build disabled');\n }\n } catch (err) {\n if (err instanceof SenseError) throw err;\n throw new SenseError('INDEX_NOT_READY', `the DuckDB lexical extension is not prepared (${(err as Error).message}); run \\`sense build\\` (or library build(config))`);\n }\n}\n\n// Field-weighted fragments (title 10 / summary 5 / text 1), with params emitted in the exact left-to-right order the assembled SQL needs for positional `?` binding.\n// score/gate params stay in separate arrays until joined at the end, since the SQL puts every score part before every gate part; sharing one array would shift binds once a query has both words and substrings (PRINCIPLES: no-silent-modes).\nfunction buildScoreAndGate(words: string[], bareWords: string[], phraseWords: string[], substrings: string[]): { scoreSql: string; gateSql: string; params: unknown[] } {\n const scoreParts: string[] = [];\n const gateParts: string[] = [];\n const scoreParams: unknown[] = [];\n const gateParams: unknown[] = [];\n\n if (words.length > 0) {\n const wordQuery = words.map(foldForSearch).join(' ');\n for (const field of FIELDS) {\n scoreParts.push(`${FIELD_WEIGHT[field]}.0 * COALESCE(${ORDERED_BM25_MACRO}(content.\"path\", ?, fields := '${field}', conjunctive := false), 0)`);\n scoreParams.push(wordQuery);\n }\n if (bareWords.length > 0) {\n const nativeGate = `${ORDERED_BM25_MACRO}(content.\"path\", ?, conjunctive := true) IS NOT NULL`;\n gateParts.push(nativeGate);\n gateParams.push(bareWords.map(foldForSearch).join(' '));\n }\n if (phraseWords.length > 0) {\n const nativeGate = `${ORDERED_BM25_MACRO}(content.\"path\", ?, conjunctive := true) IS NOT NULL`;\n const fallback = phraseWords.map((_word) => `(${FIELDS.map((field) => `contains(strip_accents(lower(content.${field})), ?)`).join(' OR ')})`).join(' AND ');\n gateParts.push(`(${nativeGate} OR (${fallback}))`);\n gateParams.push(phraseWords.map(foldForSearch).join(' '));\n gateParams.push(...phraseWords.flatMap((word) => FIELDS.map(() => foldForSearch(word))));\n }\n }\n\n for (const raw of substrings) {\n const needle = raw.toLowerCase();\n for (const field of FIELDS) {\n scoreParts.push(`${FIELD_WEIGHT[field]}.0 * CAST(contains(strip_accents(lower(content.${field})), ?) AS INTEGER)`);\n scoreParams.push(foldForSearch(needle));\n }\n gateParts.push(`(${FIELDS.map((field) => `contains(strip_accents(lower(content.${field})), ?)`).join(' OR ')})`);\n gateParams.push(...FIELDS.map(() => foldForSearch(needle)));\n }\n\n return { scoreSql: scoreParts.join(' + '), gateSql: gateParts.join(' AND ') || 'TRUE', params: [...scoreParams, ...gateParams] };\n}\n\n// Ranked query, scoped by the caller-built SQL fragments (same fragments sqlite's queryLexical takes).\n// Phrase rows carry authored fields through the post-filter; the public result still contains paths only.\nexport async function queryLexical(conn: Connection, terms: string, opts: LexicalQueryOptions, state: FtsIndexState): Promise<LexicalHit[]> {\n const unsupported = unsupportedOperator(terms);\n if (unsupported !== null) {\n throw new SenseError('STORE_CAPABILITY_MISSING', `store \"duckdb\" does not implement FTS5's ${unsupported.label} (\"${unsupported.token}\") in this build; rephrase \"${terms.trim()}\" without it, or set \"store\" to \"sqlite\" in this tree's config to search it as written`);\n }\n const { whereJoin, whereCond, scopeCond, limit } = opts;\n const { words, bareWords, phraseWords, substrings, phrases, emptyPhrase } = splitTerms(terms);\n if (emptyPhrase || (words.length === 0 && substrings.length === 0)) return [];\n\n if (words.length > 0) await assertFtsReady(conn);\n if (words.length > 0) await ensureOrderedBm25(conn, state);\n\n const { scoreSql, gateSql, params } = buildScoreAndGate(words, bareWords, phraseWords, substrings);\n const selectFields = phrases.length > 0 ? ', content.title, content.summary, content.text' : '';\n const sqlLimit = phrases.length > 0 ? '' : ' LIMIT ?';\n const sql = `SELECT path, score${phrases.length > 0 ? ', title, summary, text' : ''} FROM (\n SELECT content.\"path\" AS path, (${scoreSql}) AS score${selectFields}\n FROM content\n ${whereJoin}\n WHERE ${gateSql}\n ${whereCond} ${scopeCond}\n ) sq ORDER BY score DESC, path${sqlLimit}`;\n const stmt = await conn.prepare(sql);\n const rows = (await stmt.all(...params, ...(phrases.length > 0 ? [] : [limit]))) as Array<LexicalHit & Partial<Record<Field, string>>>;\n const matches = phrases.length === 0 ? rows : rows.filter((row) => phrases.every((phrase) => FIELDS.some((field) => matchesSearchPhrase(row[field] ?? '', phrase))));\n return matches.slice(0, limit).map(({ path }) => ({ path }));\n}\n\n// `stale`'s first read for a connection comes from meta.fts_stale (a fresh connection can't know\n// otherwise), and reconcileContent (reconcile.ts) marks it stale again on every content change.\nexport function createLexicalIndex(conn: Connection): { query: (terms: string, opts: LexicalQueryOptions) => Promise<LexicalHit[]>; markStale: () => Promise<void> } {\n return {\n query: async (terms, opts) => queryLexical(conn, terms, opts, await stateFor(conn)),\n markStale: () => markContentStale(conn),\n };\n}\n"],"names":["assertFtsReady","createLexicalIndex","markContentStale","prepareFts","queryLexical","FIELDS","FIELD_WEIGHT","title","summary","text","FTS5_OPERATORS","label","re","unsupportedOperator","terms","withoutPhrases","replace","m","match","token","trim","FTS_STALE_META_KEY","ftsState","WeakMap","stateFor","conn","state","get","getMeta","stale","orderedMacroReady","set","hasFtsArtifact","stmt","prepare","undefined","setMeta","splitTerms","words","bareWords","phraseWords","substrings","phrases","emptyPhrase","_m","inner","phrase","phraseTokens","searchTokens","length","push","unspaced","split","tok","rebuildFts","exec","withTransaction","err","SenseError","message","buildScoreAndGate","scoreParts","gateParts","scoreParams","gateParams","wordQuery","map","foldForSearch","join","field","ORDERED_BM25_MACRO","nativeGate","fallback","_word","flatMap","word","raw","needle","toLowerCase","scoreSql","gateSql","params","opts","unsupported","whereJoin","whereCond","scopeCond","limit","selectFields","sqlLimit","sql","rows","matches","ensureOrderedBm25","all","filter","row","every","some","matchesSearchPhrase","slice","path","query","markStale"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/lexical.ts"],"sourcesContent":["// D1: fts BM25 for ranking, contains() scans for exact substring / phrase verification /\n// unspaced scripts, JS snippets for every doc (no snippet()).\nimport { SenseError } from '../../errors.ts';\nimport { foldForSearch, matchesSearchPhrase, type SearchToken, searchTokens } from '../../text/segment.ts';\nimport { getMeta, setMeta } from '../shared.ts';\nimport { withTransaction } from '../transaction.ts';\nimport type { Connection, LexicalHit, LexicalQueryOptions } from '../types.ts';\nimport { FTS_STEMMER, nativeQueryTerms, orderedBm25Sql } from './ordered-bm25.ts';\n\nconst FIELDS = ['title', 'summary', 'text'] as const;\ntype Field = (typeof FIELDS)[number];\n// Mirrors sqlite's bm25(content, 10.0, 5.0, 1.0, ...) column-weight intent; DuckDB's match_bm25 has no\n// field_weights argument (verified 1.5.5), so each field is scored separately and combined here.\nconst FIELD_WEIGHT: Record<Field, number> = { title: 10, summary: 5, text: 1 };\n\n// FTS5 operator syntax (sqlite.org/fts5.html sec. 3) that words/substrings below would otherwise silently\n// treat as literal terms (PRINCIPLES: no-silent-modes). Quoted contents stay ignored while their boundary remains detectable.\nconst FTS5_OPERATORS: Array<{ label: string; re: RegExp }> = [\n { label: 'prefix query', re: /[\\p{L}\\p{N}_]+\\*(?=\\s|$)/u },\n { label: 'boolean operator', re: /(?:^|\\s)(?:AND|OR|NOT)(?=\\s|$)/ },\n { label: 'NEAR operator', re: /(?:^|\\s)NEAR\\b/ },\n { label: 'initial-token operator', re: /(?:^|\\s)\\^\\S+/ },\n { label: 'column filter', re: /(?:^|\\s)[\\p{L}_]\\w*\\s*:/u },\n { label: 'grouping operator', re: /[()]/ },\n];\n\nfunction unsupportedOperator(terms: string): { label: string; token: string } | null {\n const withoutPhrases = terms.replace(/\"[^\"]*\"/g, 'phrase');\n for (const { label, re } of FTS5_OPERATORS) {\n const m = withoutPhrases.match(re);\n if (m) return { label, token: m[0].trim() };\n }\n return null;\n}\n\ninterface FtsIndexState {\n stale: boolean;\n}\n\n// Durable across connections/processes (meta table, shared.ts); `stale` is the in-memory cache of\n// it for this connection's lifetime, so a watcher's repeat queries don't re-read meta every time.\nconst FTS_STALE_META_KEY = 'fts_stale';\n\n// One state per connection, not per store instance: reconcileContent (reconcile.ts) marks it\n// stale from outside createLexicalIndex's closure, whether a one-shot open or a watcher's builder ran it.\nconst ftsState = new WeakMap<Connection, FtsIndexState>();\nasync function stateFor(conn: Connection): Promise<FtsIndexState> {\n let state = ftsState.get(conn);\n if (!state) {\n // Anything but a persisted '0' (missing key, or '1') means a rebuild is owed: a cache that\n // never built an index, or one a prior process marked stale and never got to clear.\n state = { stale: (await getMeta(conn, FTS_STALE_META_KEY)) !== '0' };\n ftsState.set(conn, state);\n }\n return state;\n}\n\nasync function hasFtsArtifact(conn: Connection): Promise<boolean> {\n const stmt = await conn.prepare(`\n SELECT 1 AS ready\n FROM duckdb_functions()\n WHERE schema_name = 'fts_main_content'\n AND function_name = 'match_bm25'\n AND function_type = 'macro'\n LIMIT 1\n `);\n return (await stmt.get()) !== undefined;\n}\n\n// Called whenever this store's reconcileContent changes `content`; must run inside that same\n// transaction (reconcile.ts) so a crash never lands the content write without the stale mark.\nexport async function markContentStale(conn: Connection): Promise<void> {\n ftsState.set(conn, { stale: true });\n await setMeta(conn, FTS_STALE_META_KEY, '1');\n}\n\n// A run whose script marks no word boundaries makes match_bm25's whitespace tokenizer index the whole run as one token,\n// so unspaced terms use contains() and quoted phrases use the shared authored-field verifier.\nfunction splitTerms(terms: string): { words: string[]; bareWords: string[]; phraseWords: string[]; substrings: string[]; phrases: SearchToken[][]; emptyPhrase: boolean } {\n const words: string[] = [];\n const bareWords: string[] = [];\n const phraseWords: string[] = [];\n const substrings: string[] = [];\n const phrases: SearchToken[][] = [];\n let emptyPhrase = false;\n const withoutPhrases = terms.replace(/\"([^\"]*)\"/g, (_m, inner: string) => {\n const phrase = inner.trim();\n const phraseTokens = searchTokens(phrase);\n if (phraseTokens.length === 0) {\n emptyPhrase = true;\n return ' ';\n }\n phrases.push(phraseTokens);\n for (const token of phraseTokens) {\n if (token.unspaced) substrings.push(token.text);\n else {\n words.push(token.text);\n phraseWords.push(token.text);\n }\n }\n return ' ';\n });\n for (const tok of withoutPhrases.split(/\\s+/)) {\n if (tok.length === 0) continue;\n for (const token of searchTokens(tok)) {\n if (token.unspaced) substrings.push(token.text);\n else {\n words.push(token.text);\n bareWords.push(token.text);\n }\n }\n }\n return { words, bareWords, phraseWords, substrings, phrases, emptyPhrase };\n}\n\n// No incremental update (verified 1.5.5: PRAGMA create_fts_index is rebuild-only), so this pays\n// the full rebuild whenever `state.stale`, which meta.fts_stale keeps true across processes until cleared below.\nasync function rebuildFts(conn: Connection, state: FtsIndexState): Promise<void> {\n await conn.exec('INSTALL fts; LOAD fts;');\n if (!state.stale && (await hasFtsArtifact(conn))) return;\n state.stale = true;\n await withTransaction(conn, async () => {\n // stopwords='none': sqlite's porter/unicode61 tokenizer never removes stopwords either (verified 1.5.5); the fts extension's\n // default 571-word list would otherwise drop common words (e.g. \"and\") from the index but not match_bm25's conjunctive gate, breaking multi-word matches.\n await conn.exec(`PRAGMA create_fts_index('content', 'path', 'title', 'summary', 'text', stemmer='${FTS_STEMMER}', stopwords='none', overwrite=1)`);\n // Same transaction as the rebuild: a crash before commit leaves the mark set (a redundant\n // rebuild next time), never a cleared mark serving a half-built index as fresh.\n await setMeta(conn, FTS_STALE_META_KEY, '0');\n });\n state.stale = false;\n}\n\nexport async function prepareFts(conn: Connection): Promise<void> {\n await rebuildFts(conn, await stateFor(conn));\n}\n\nexport async function assertFtsReady(conn: Connection): Promise<void> {\n const state = await stateFor(conn);\n if (state.stale) throw new SenseError('INDEX_NOT_READY', 'the DuckDB lexical index is missing or stale; run `sense build` (or library build(config)) before lexical querying with build disabled');\n try {\n await conn.exec('LOAD fts;');\n if (!(await hasFtsArtifact(conn))) {\n throw new SenseError('INDEX_NOT_READY', 'the DuckDB lexical index artifact is missing; run `sense build` (or library build(config)) before lexical querying with build disabled');\n }\n } catch (err) {\n if (err instanceof SenseError) throw err;\n throw new SenseError('INDEX_NOT_READY', `the DuckDB lexical extension is not prepared (${(err as Error).message}); run \\`sense build\\` (or library build(config))`);\n }\n}\n\n// Field-weighted fragments (title 10 / summary 5 / text 1), with params emitted in the exact left-to-right order the assembled SQL needs for positional `?` binding.\n// score/gate params stay in separate arrays until joined at the end, since the SQL puts every score part before every gate part; sharing one array would shift binds once a query has both words and substrings (PRINCIPLES: no-silent-modes).\nfunction buildScoreAndGate(words: string[], nativeTerms: string[], bareWords: string[], phraseWords: string[], substrings: string[]): { scoreSql: string; gateSql: string; params: unknown[] } {\n const scoreParts: string[] = [];\n const gateParts: string[] = [];\n const scoreParams: unknown[] = [];\n const gateParams: unknown[] = [];\n\n if (words.length > 0) {\n for (const field of FIELDS) {\n scoreParts.push(`${FIELD_WEIGHT[field]}.0 * COALESCE(${orderedBm25Sql(field, nativeTerms.length)}, 0)`);\n scoreParams.push(...nativeTerms);\n }\n if (bareWords.length > 0) {\n const nativeGate = `fts_main_content.match_bm25(content.\"path\", ?, conjunctive := true) IS NOT NULL`;\n gateParts.push(nativeGate);\n gateParams.push(bareWords.map(foldForSearch).join(' '));\n }\n if (phraseWords.length > 0) {\n const nativeGate = `fts_main_content.match_bm25(content.\"path\", ?, conjunctive := true) IS NOT NULL`;\n const fallback = phraseWords.map((_word) => `(${FIELDS.map((field) => `contains(strip_accents(lower(content.${field})), ?)`).join(' OR ')})`).join(' AND ');\n gateParts.push(`(${nativeGate} OR (${fallback}))`);\n gateParams.push(phraseWords.map(foldForSearch).join(' '));\n gateParams.push(...phraseWords.flatMap((word) => FIELDS.map(() => foldForSearch(word))));\n }\n }\n\n for (const raw of substrings) {\n const needle = raw.toLowerCase();\n for (const field of FIELDS) {\n scoreParts.push(`${FIELD_WEIGHT[field]}.0 * CAST(contains(strip_accents(lower(content.${field})), ?) AS INTEGER)`);\n scoreParams.push(foldForSearch(needle));\n }\n gateParts.push(`(${FIELDS.map((field) => `contains(strip_accents(lower(content.${field})), ?)`).join(' OR ')})`);\n gateParams.push(...FIELDS.map(() => foldForSearch(needle)));\n }\n\n return { scoreSql: scoreParts.join(' + '), gateSql: gateParts.join(' AND ') || 'TRUE', params: [...scoreParams, ...gateParams] };\n}\n\n// Ranked query, scoped by the caller-built SQL fragments (same fragments sqlite's queryLexical takes).\n// Phrase rows carry authored fields through the post-filter; the public result still contains paths only.\nexport async function queryLexical(conn: Connection, terms: string, opts: LexicalQueryOptions): Promise<LexicalHit[]> {\n const unsupported = unsupportedOperator(terms);\n if (unsupported !== null) {\n throw new SenseError('STORE_CAPABILITY_MISSING', `store \"duckdb\" does not implement FTS5's ${unsupported.label} (\"${unsupported.token}\") in this build; rephrase \"${terms.trim()}\" without it, or set \"store\" to \"sqlite\" in this tree's config to search it as written`);\n }\n const { whereJoin, whereCond, scopeCond, limit } = opts;\n const { words, bareWords, phraseWords, substrings, phrases, emptyPhrase } = splitTerms(terms);\n if (emptyPhrase || (words.length === 0 && substrings.length === 0)) return [];\n\n if (words.length > 0) await assertFtsReady(conn);\n const nativeTerms = words.length > 0 ? await nativeQueryTerms(conn, words.map(foldForSearch).join(' ')) : [];\n\n const { scoreSql, gateSql, params } = buildScoreAndGate(words, nativeTerms, bareWords, phraseWords, substrings);\n const selectFields = phrases.length > 0 ? ', content.title, content.summary, content.text' : '';\n const sqlLimit = phrases.length > 0 ? '' : ' LIMIT ?';\n const sql = `SELECT path, score${phrases.length > 0 ? ', title, summary, text' : ''} FROM (\n SELECT content.\"path\" AS path, (${scoreSql}) AS score${selectFields}\n FROM content\n ${whereJoin}\n WHERE ${gateSql}\n ${whereCond} ${scopeCond}\n ) sq ORDER BY score DESC, path${sqlLimit}`;\n const stmt = await conn.prepare(sql);\n const rows = (await stmt.all(...params, ...(phrases.length > 0 ? [] : [limit]))) as Array<LexicalHit & Partial<Record<Field, string>>>;\n const matches = phrases.length === 0 ? rows : rows.filter((row) => phrases.every((phrase) => FIELDS.some((field) => matchesSearchPhrase(row[field] ?? '', phrase))));\n return matches.slice(0, limit).map(({ path }) => ({ path }));\n}\n\n// `stale`'s first read for a connection comes from meta.fts_stale (a fresh connection can't know\n// otherwise), and reconcileContent (reconcile.ts) marks it stale again on every content change.\nexport function createLexicalIndex(conn: Connection): { query: (terms: string, opts: LexicalQueryOptions) => Promise<LexicalHit[]>; markStale: () => Promise<void> } {\n return {\n query: async (terms, opts) => queryLexical(conn, terms, opts),\n markStale: () => markContentStale(conn),\n };\n}\n"],"names":["assertFtsReady","createLexicalIndex","markContentStale","prepareFts","queryLexical","FIELDS","FIELD_WEIGHT","title","summary","text","FTS5_OPERATORS","label","re","unsupportedOperator","terms","withoutPhrases","replace","m","match","token","trim","FTS_STALE_META_KEY","ftsState","WeakMap","stateFor","conn","state","get","getMeta","stale","set","hasFtsArtifact","stmt","prepare","undefined","setMeta","splitTerms","words","bareWords","phraseWords","substrings","phrases","emptyPhrase","_m","inner","phrase","phraseTokens","searchTokens","length","push","unspaced","split","tok","rebuildFts","exec","withTransaction","FTS_STEMMER","err","SenseError","message","buildScoreAndGate","nativeTerms","scoreParts","gateParts","scoreParams","gateParams","field","orderedBm25Sql","nativeGate","map","foldForSearch","join","fallback","_word","flatMap","word","raw","needle","toLowerCase","scoreSql","gateSql","params","opts","unsupported","whereJoin","whereCond","scopeCond","limit","selectFields","sqlLimit","sql","rows","matches","nativeQueryTerms","all","filter","row","every","some","matchesSearchPhrase","slice","path","query","markStale"],"mappings":"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"}
@@ -1,4 +1,3 @@
1
1
  export declare const DUCKDB_PACKAGE = "@duckdb/node-api";
2
- export declare const DUCKDB_VERSION = "1.5.5-r.5";
3
- export declare const DUCKDB_INSTALL_SPEC = "@duckdb/node-api@1.5.5-r.5";
2
+ export declare const DUCKDB_INSTALL_SPEC = "@duckdb/node-api@1.5.6-r.1";
4
3
  export declare function duckdbApi(): Promise<typeof import('@duckdb/node-api')>;
@@ -1,4 +1,3 @@
1
1
  export declare const DUCKDB_PACKAGE = "@duckdb/node-api";
2
- export declare const DUCKDB_VERSION = "1.5.5-r.5";
3
- export declare const DUCKDB_INSTALL_SPEC = "@duckdb/node-api@1.5.5-r.5";
2
+ export declare const DUCKDB_INSTALL_SPEC = "@duckdb/node-api@1.5.6-r.1";
4
3
  export declare function duckdbApi(): Promise<typeof import('@duckdb/node-api')>;
@@ -15,22 +15,17 @@ _export(exports, {
15
15
  get DUCKDB_PACKAGE () {
16
16
  return DUCKDB_PACKAGE;
17
17
  },
18
- get DUCKDB_VERSION () {
19
- return DUCKDB_VERSION;
20
- },
21
18
  get duckdbApi () {
22
19
  return duckdbApi;
23
20
  }
24
21
  });
25
22
  var _nativets = require("../native.js");
26
23
  var DUCKDB_PACKAGE = '@duckdb/node-api';
27
- var DUCKDB_VERSION = '1.5.5-r.5';
28
- var DUCKDB_INSTALL_SPEC = "".concat(DUCKDB_PACKAGE, "@").concat(DUCKDB_VERSION);
24
+ var DUCKDB_INSTALL_SPEC = "".concat(DUCKDB_PACKAGE, "@1.5.6-r.1");
29
25
  var DUCKDB = {
30
26
  store: 'duckdb',
31
27
  pkg: DUCKDB_PACKAGE,
32
28
  sizeHint: '~110MB',
33
- version: DUCKDB_VERSION,
34
29
  installSpec: DUCKDB_INSTALL_SPEC
35
30
  };
36
31
  var duckdbApiPromise;
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/duckdb/native.ts"],"sourcesContent":["import { loadOrInstall, type NativeDescriptor, packageNodeModules } from '../native.ts';\n\nexport const DUCKDB_PACKAGE = '@duckdb/node-api';\nexport const DUCKDB_VERSION = '1.5.5-r.5';\nexport const DUCKDB_INSTALL_SPEC = `${DUCKDB_PACKAGE}@${DUCKDB_VERSION}`;\n\nconst DUCKDB: NativeDescriptor = {\n store: 'duckdb',\n pkg: DUCKDB_PACKAGE,\n sizeHint: '~110MB',\n version: DUCKDB_VERSION,\n installSpec: DUCKDB_INSTALL_SPEC,\n};\n\nlet duckdbApiPromise: Promise<typeof import('@duckdb/node-api')> | undefined;\n\n// The one accessor every consumer of @duckdb/node-api must go through: after a fresh install in this process, Node keeps returning\n// the pre-install \"not found\" miss to any new bare-specifier lookup of the same path, so caching the resolved module here means only the first caller ever resolves it.\nexport function duckdbApi(): Promise<typeof import('@duckdb/node-api')> {\n if (!duckdbApiPromise) duckdbApiPromise = loadOrInstall<typeof import('@duckdb/node-api')>(DUCKDB, packageNodeModules());\n return duckdbApiPromise;\n}\n"],"names":["DUCKDB_INSTALL_SPEC","DUCKDB_PACKAGE","DUCKDB_VERSION","duckdbApi","DUCKDB","store","pkg","sizeHint","version","installSpec","duckdbApiPromise","loadOrInstall","packageNodeModules"],"mappings":";;;;;;;;;;;QAIaA;eAAAA;;QAFAC;eAAAA;;QACAC;eAAAA;;QAeGC;eAAAA;;;wBAlByD;AAElE,IAAMF,iBAAiB;AACvB,IAAMC,iBAAiB;AACvB,IAAMF,sBAAsB,AAAC,GAAoBE,OAAlBD,gBAAe,KAAkB,OAAfC;AAExD,IAAME,SAA2B;IAC/BC,OAAO;IACPC,KAAKL;IACLM,UAAU;IACVC,SAASN;IACTO,aAAaT;AACf;AAEA,IAAIU;AAIG,SAASP;IACd,IAAI,CAACO,kBAAkBA,mBAAmBC,IAAAA,uBAAa,EAAoCP,QAAQQ,IAAAA,4BAAkB;IACrH,OAAOF;AACT"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/native.ts"],"sourcesContent":["import { loadOrInstall, type NativeDescriptor, packageNodeModules } from '../native.ts';\n\nexport const DUCKDB_PACKAGE = '@duckdb/node-api';\nexport const DUCKDB_INSTALL_SPEC = `${DUCKDB_PACKAGE}@1.5.6-r.1`;\n\nconst DUCKDB: NativeDescriptor = {\n store: 'duckdb',\n pkg: DUCKDB_PACKAGE,\n sizeHint: '~110MB',\n installSpec: DUCKDB_INSTALL_SPEC,\n};\n\nlet duckdbApiPromise: Promise<typeof import('@duckdb/node-api')> | undefined;\n\n// The one accessor every consumer of @duckdb/node-api must go through: after a fresh install in this process, Node keeps returning\n// the pre-install \"not found\" miss to any new bare-specifier lookup of the same path, so caching the resolved module here means only the first caller ever resolves it.\nexport function duckdbApi(): Promise<typeof import('@duckdb/node-api')> {\n if (!duckdbApiPromise) duckdbApiPromise = loadOrInstall<typeof import('@duckdb/node-api')>(DUCKDB, packageNodeModules());\n return duckdbApiPromise;\n}\n"],"names":["DUCKDB_INSTALL_SPEC","DUCKDB_PACKAGE","duckdbApi","DUCKDB","store","pkg","sizeHint","installSpec","duckdbApiPromise","loadOrInstall","packageNodeModules"],"mappings":";;;;;;;;;;;QAGaA;eAAAA;;QADAC;eAAAA;;QAcGC;eAAAA;;;wBAhByD;AAElE,IAAMD,iBAAiB;AACvB,IAAMD,sBAAsB,AAAC,GAAiB,OAAfC,gBAAe;AAErD,IAAME,SAA2B;IAC/BC,OAAO;IACPC,KAAKJ;IACLK,UAAU;IACVC,aAAaP;AACf;AAEA,IAAIQ;AAIG,SAASN;IACd,IAAI,CAACM,kBAAkBA,mBAAmBC,IAAAA,uBAAa,EAAoCN,QAAQO,IAAAA,4BAAkB;IACrH,OAAOF;AACT"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/duckdb/open.ts"],"sourcesContent":["import type { DuckDBConnection, DuckDBInstance } from '@duckdb/node-api';\nimport type { Config, ResolvedConfig } from '../../config/index.ts';\nimport { STORE_DIMS } from '../../embed/types.ts';\nimport { SenseError } from '../../errors.ts';\nimport { activeFeatures } from '../../features/index.ts';\nimport type { InternalOpenOptions, OpenResult } from '../open.ts';\nimport { openWithDialect } from '../open.ts';\nimport { getMeta, setMeta } from '../shared.ts';\nimport type { Connection, OpenDialect } from '../types.ts';\nimport { createConnection } from './connection.ts';\nimport { assertFtsReady, prepareFts } from './lexical.ts';\nimport { DUCKDB_PACKAGE, duckdbApi } from './native.ts';\nimport { duckdbDialect } from './reconcile.ts';\nimport { registerFunctions } from './sql-functions.ts';\nimport { createStore } from './store.ts';\nimport { createVectorWriteStage } from './vectors.ts';\n\nexport const DB_FILENAME = 'cache.duckdb';\n// Independent of sqlite's SCHEMA_VERSION -- the two stores' cache shapes evolve separately (VARIANT frontmatter columns vs untyped).\n// The store name already joins the feature signature, so switching a config's `store` key rebuilds rather than reusing the other engine's cache.\nexport const SCHEMA_VERSION = '6';\n\nexport type { OpenResult };\n\n// The connection plus this store's own native handles (types.ts's OpenDialect<Handle>): the\n// instance owns the WAL and must outlive the connection borrowed from it.\ninterface DuckdbHandle {\n instance: DuckDBInstance;\n duckdb: DuckDBConnection;\n}\n\n// `content` is a plain table (not FTS-virtual): build prepares the persistent FTS index over it,\n// while contains() verification reads the table directly.\n// No tokenizer resolution: this store always uses the fts extension's default (porter) stemmer.\nasync function ensureCoreSchema(_handle: DuckdbHandle, conn: Connection): Promise<void> {\n await conn.exec(`CREATE TABLE IF NOT EXISTS frontmatter (\"path\" TEXT PRIMARY KEY, \"_mtime\" DOUBLE, \"_ctime\" DOUBLE, \"_size\" INTEGER, \"_parse_error\" TEXT)`);\n await conn.exec(`CREATE TABLE IF NOT EXISTS content (\"path\" TEXT PRIMARY KEY, title TEXT, summary TEXT, text TEXT)`);\n await conn.exec(`CREATE TABLE IF NOT EXISTS indexed_sources (\"path\" TEXT PRIMARY KEY, text TEXT NOT NULL)`);\n await conn.exec(`CREATE TABLE IF NOT EXISTS preset_files (\"path\" TEXT, preset TEXT, PRIMARY KEY (\"path\", preset))`);\n await conn.exec('CREATE INDEX IF NOT EXISTS preset_files_preset ON preset_files(preset)');\n if ((await getMeta(conn, 'schema_version')) === null) await setMeta(conn, 'schema_version', SCHEMA_VERSION);\n}\n\nasync function ensureFeatureSchema(_handle: DuckdbHandle, conn: Connection, cfg: Config): Promise<void> {\n for (const feature of activeFeatures(cfg)) {\n // Native FLOAT[STORE_DIMS] instead of the embed feature's engine-neutral BLOB+scale DDL (vectors.ts). `scale` is kept, unused,\n // so the feature's shared reconcile-time INSERT/DELETE (features/embed.ts) names a column that exists on both stores.\n if (feature.name === 'embed') {\n await conn.exec(`CREATE TABLE IF NOT EXISTS embeddings (\"path\" TEXT, chunk INTEGER, start_line INTEGER, end_line INTEGER, content_identity TEXT NOT NULL, scale REAL, vector FLOAT[${STORE_DIMS}], PRIMARY KEY (\"path\", chunk))`);\n continue;\n }\n await feature.schema(conn);\n }\n}\n\nasync function prepareConnection(handle: DuckdbHandle, _conn: Connection, _cfg: Config): Promise<void> {\n await createVectorWriteStage(handle.duckdb, STORE_DIMS);\n}\n\n// Order matters: the connection must be gone before the instance closes the WAL.\nasync function close(handle: DuckdbHandle): Promise<void> {\n handle.duckdb.disconnectSync();\n handle.instance.closeSync();\n}\n\nasync function connect(dbPath: string, _cfg: ResolvedConfig, options: { existingOnly: boolean; observational: boolean }): Promise<{ handle: DuckdbHandle; conn: Connection }> {\n // Dynamic, not a top-level import: sqlite trees must never attempt to resolve this optional peer dependency, so nothing imports\n // it as a value until a duckdb tree opens (types-only imports are erased). Installed on first use if missing, shared with sql-functions.ts and vectors.ts via native.ts's duckdbApi.\n let DuckDBInstance: typeof import('@duckdb/node-api').DuckDBInstance;\n try {\n ({ DuckDBInstance } = await duckdbApi());\n } catch (err) {\n if (err instanceof SenseError) throw err;\n throw new SenseError('STORE_DEPENDENCY_MISSING', `store \"duckdb\" needs the ${DUCKDB_PACKAGE} package (${(err as Error).message})`);\n }\n\n let duckdb: DuckDBConnection;\n let instance: DuckDBInstance | undefined;\n try {\n // On-disk files default to an older storage format for cross-version compatibility, which rejects VARIANT columns (\"VARIANT\n // columns are not supported in storage versions prior to v1.5.0\"); this store's dynamic frontmatter columns need VARIANT (reconcile.ts), so the floor is pinned explicitly.\n instance = await DuckDBInstance.create(dbPath, options.observational ? { access_mode: 'READ_ONLY' } : { storage_compatibility_version: 'v1.5.0' });\n duckdb = await instance.connect();\n } catch (err) {\n // create() may have succeeded before connect() failed: close it, or its WAL stays open.\n instance?.closeSync();\n throw new SenseError('STORE_DEPENDENCY_MISSING', `store \"duckdb\" failed to open ${dbPath}: ${(err as Error).message}`);\n }\n // A throw below would leak the open instance, whose WAL then locks the .duckdb file undeletable on Windows.\n try {\n await registerFunctions(duckdb);\n const conn = createConnection(duckdb);\n return { handle: { instance, duckdb }, conn };\n } catch (err) {\n await close({ instance, duckdb });\n throw err;\n }\n}\n\n// This store's dialect (types.ts's OpenDialect) for the shared orchestration in store/open.ts.\nexport const duckdbOpenDialect: OpenDialect<DuckdbHandle> = {\n filename: DB_FILENAME,\n schemaVersion: SCHEMA_VERSION,\n reconcileDialect: duckdbDialect,\n connect,\n close,\n // duckdb's file lock spans the connection's life, and each platform words the refusal its own\n // way: posix \"Could not set lock on file ... Conflicting lock is held in <exe> (PID n)\", Windows\n // \"Cannot open file ... being used by another process\". Both are the same condition.\n isLocked: (err) => /Could not set lock on file|being used by another process/.test(err.message),\n ensureCoreSchema,\n ensureFeatureSchema,\n prepareConnection,\n prepareLexical: prepareFts,\n assertLexicalReady: assertFtsReady,\n createStore: (handle, conn) => createStore(handle.instance, handle.duckdb, conn),\n};\n\nexport async function openDuckdb(cfg: ResolvedConfig, options?: InternalOpenOptions): Promise<OpenResult> {\n return openWithDialect(cfg, duckdbOpenDialect, options);\n}\n"],"names":["DB_FILENAME","SCHEMA_VERSION","duckdbOpenDialect","openDuckdb","ensureCoreSchema","_handle","conn","exec","getMeta","setMeta","ensureFeatureSchema","cfg","feature","activeFeatures","name","STORE_DIMS","schema","prepareConnection","handle","_conn","_cfg","createVectorWriteStage","duckdb","close","disconnectSync","instance","closeSync","connect","dbPath","options","DuckDBInstance","err","duckdbApi","SenseError","DUCKDB_PACKAGE","message","create","observational","access_mode","storage_compatibility_version","registerFunctions","createConnection","filename","schemaVersion","reconcileDialect","duckdbDialect","isLocked","test","prepareLexical","prepareFts","assertLexicalReady","assertFtsReady","createStore","openWithDialect"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/open.ts"],"sourcesContent":["import type { DuckDBConnection, DuckDBInstance } from '@duckdb/node-api';\nimport type { Config, ResolvedConfig } from '../../config/index.ts';\nimport { STORE_DIMS } from '../../embed/types.ts';\nimport { SenseError } from '../../errors.ts';\nimport { activeFeatures } from '../../features/index.ts';\nimport type { InternalOpenOptions, OpenResult } from '../open.ts';\nimport { openWithDialect } from '../open.ts';\nimport { getMeta, setMeta } from '../shared.ts';\nimport type { Connection, OpenDialect } from '../types.ts';\nimport { createConnection } from './connection.ts';\nimport { assertFtsReady, prepareFts } from './lexical.ts';\nimport { DUCKDB_PACKAGE, duckdbApi } from './native.ts';\nimport { duckdbDialect } from './reconcile.ts';\nimport { registerFunctions } from './sql-functions.ts';\nimport { createStore } from './store.ts';\nimport { createVectorWriteStage } from './vectors.ts';\n\nexport const DB_FILENAME = 'cache.duckdb';\n// Independent of sqlite's SCHEMA_VERSION -- the two stores' cache shapes evolve separately (VARIANT frontmatter columns vs untyped).\n// The store name already joins the feature signature, so switching a config's `store` key rebuilds rather than reusing the other engine's cache.\nexport const SCHEMA_VERSION = '6';\n\nexport type { OpenResult };\n\n// The connection plus this store's own native handles (types.ts's OpenDialect<Handle>): the\n// instance owns the WAL and must outlive the connection borrowed from it.\ninterface DuckdbHandle {\n instance: DuckDBInstance;\n duckdb: DuckDBConnection;\n}\n\n// `content` is a plain table (not FTS-virtual): build prepares the persistent FTS index over it,\n// while contains() verification reads the table directly.\n// No tokenizer resolution: this store always uses the fts extension's default (porter) stemmer.\nasync function ensureCoreSchema(_handle: DuckdbHandle, conn: Connection): Promise<void> {\n await conn.exec(`CREATE TABLE IF NOT EXISTS frontmatter (\"path\" TEXT PRIMARY KEY, \"_mtime\" DOUBLE, \"_ctime\" DOUBLE, \"_size\" INTEGER, \"_parse_error\" TEXT)`);\n await conn.exec(`CREATE TABLE IF NOT EXISTS content (\"path\" TEXT PRIMARY KEY, title TEXT, summary TEXT, text TEXT)`);\n await conn.exec(`CREATE TABLE IF NOT EXISTS indexed_sources (\"path\" TEXT PRIMARY KEY, text TEXT NOT NULL)`);\n await conn.exec(`CREATE TABLE IF NOT EXISTS preset_files (\"path\" TEXT, preset TEXT, PRIMARY KEY (\"path\", preset))`);\n await conn.exec('CREATE INDEX IF NOT EXISTS preset_files_preset ON preset_files(preset)');\n if ((await getMeta(conn, 'schema_version')) === null) await setMeta(conn, 'schema_version', SCHEMA_VERSION);\n}\n\nasync function ensureFeatureSchema(_handle: DuckdbHandle, conn: Connection, cfg: Config): Promise<void> {\n for (const feature of activeFeatures(cfg)) {\n // Native FLOAT[STORE_DIMS] instead of the embed feature's engine-neutral BLOB+scale DDL (vectors.ts). `scale` is kept, unused,\n // so the feature's shared reconcile-time INSERT/DELETE (features/embed.ts) names a column that exists on both stores.\n if (feature.name === 'embed') {\n await conn.exec(`CREATE TABLE IF NOT EXISTS embeddings (\"path\" TEXT, chunk INTEGER, start_line INTEGER, end_line INTEGER, content_identity TEXT NOT NULL, scale REAL, vector FLOAT[${STORE_DIMS}], PRIMARY KEY (\"path\", chunk))`);\n continue;\n }\n await feature.schema(conn);\n }\n}\n\nasync function prepareConnection(handle: DuckdbHandle, _conn: Connection, _cfg: Config): Promise<void> {\n await createVectorWriteStage(handle.duckdb, STORE_DIMS);\n}\n\n// Order matters: the connection must be gone before the instance closes the WAL.\nasync function close(handle: DuckdbHandle): Promise<void> {\n handle.duckdb.disconnectSync();\n handle.instance.closeSync();\n}\n\nasync function connect(dbPath: string, _cfg: ResolvedConfig, options: { existingOnly: boolean; observational: boolean }): Promise<{ handle: DuckdbHandle; conn: Connection }> {\n // Dynamic, not a top-level import: sqlite trees must never attempt to resolve this optional peer dependency, so nothing imports\n // it as a value until a duckdb tree opens (types-only imports are erased). Installed on first use if missing, shared with sql-functions.ts and vectors.ts via native.ts's duckdbApi.\n let DuckDBInstance: typeof import('@duckdb/node-api').DuckDBInstance;\n try {\n ({ DuckDBInstance } = await duckdbApi());\n } catch (err) {\n if (err instanceof SenseError) throw err;\n throw new SenseError('STORE_DEPENDENCY_MISSING', `store \"duckdb\" needs the ${DUCKDB_PACKAGE} package (${(err as Error).message})`);\n }\n\n let duckdb: DuckDBConnection;\n let instance: DuckDBInstance | undefined;\n try {\n // On-disk files default to an older storage format for cross-version compatibility, which rejects VARIANT columns (\"VARIANT\n // columns are not supported in storage versions prior to v1.5.0\"); this store's dynamic frontmatter columns need VARIANT (reconcile.ts), so the floor is pinned explicitly.\n instance = await DuckDBInstance.create(dbPath, options.observational ? { access_mode: 'READ_ONLY' } : { storage_compatibility_version: 'v1.5.0' });\n duckdb = await instance.connect();\n } catch (err) {\n // create() may have succeeded before connect() failed: close it, or its WAL stays open.\n instance?.closeSync();\n throw new SenseError('STORE_DEPENDENCY_MISSING', `store \"duckdb\" failed to open ${dbPath}: ${(err as Error).message}`);\n }\n // A throw below would leak the open instance, whose WAL then locks the .duckdb file undeletable on Windows.\n try {\n await registerFunctions(duckdb);\n const conn = createConnection(duckdb);\n return { handle: { instance, duckdb }, conn };\n } catch (err) {\n await close({ instance, duckdb });\n throw err;\n }\n}\n\n// This store's dialect (types.ts's OpenDialect) for the shared orchestration in store/open.ts.\nexport const duckdbOpenDialect: OpenDialect<DuckdbHandle> = {\n filename: DB_FILENAME,\n schemaVersion: SCHEMA_VERSION,\n reconcileDialect: duckdbDialect,\n connect,\n close,\n // duckdb's file lock spans the connection's life, and each platform words the refusal its own\n // way: posix \"Could not set lock on file ... Conflicting lock is held in <exe> (PID n)\", Windows\n // \"Cannot open file ... being used by another process\". Both are the same condition.\n isLocked: (err) => /Could not set lock on file|being used by another process/.test(err.message),\n ensureCoreSchema,\n ensureFeatureSchema,\n prepareConnection,\n prepareLexical: prepareFts,\n assertLexicalReady: assertFtsReady,\n createStore: (handle, conn) => createStore(handle.instance, handle.duckdb, conn),\n};\n\nexport async function openDuckdb(cfg: ResolvedConfig, options?: InternalOpenOptions): Promise<OpenResult> {\n return openWithDialect(cfg, duckdbOpenDialect, options);\n}\n"],"names":["DB_FILENAME","SCHEMA_VERSION","duckdbOpenDialect","openDuckdb","ensureCoreSchema","_handle","conn","exec","getMeta","setMeta","ensureFeatureSchema","cfg","feature","activeFeatures","name","STORE_DIMS","schema","prepareConnection","handle","_conn","_cfg","createVectorWriteStage","duckdb","close","disconnectSync","instance","closeSync","connect","dbPath","options","DuckDBInstance","err","duckdbApi","SenseError","DUCKDB_PACKAGE","message","create","observational","access_mode","storage_compatibility_version","registerFunctions","createConnection","filename","schemaVersion","reconcileDialect","duckdbDialect","isLocked","test","prepareLexical","prepareFts","assertLexicalReady","assertFtsReady","createStore","openWithDialect"],"mappings":"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"}
@@ -1,17 +1,4 @@
1
1
  import type { Connection } from '../types.js';
2
- export declare const ORDERED_BM25_MACRO = "sense_ordered_match_bm25";
3
- interface NativeMacroRow {
4
- function_type: string;
5
- parameters: unknown;
6
- parameter_types: unknown;
7
- macro_definition: string;
8
- }
9
- interface NativeMacroContract {
10
- version: string;
11
- macro: NativeMacroRow;
12
- }
13
- export declare function validateNativeMacroContract({ version, macro }: NativeMacroContract): string;
14
- export declare function ensureOrderedBm25(conn: Connection, state: {
15
- orderedMacroReady: boolean;
16
- }): Promise<void>;
17
- export {};
2
+ export declare const FTS_STEMMER = "porter";
3
+ export declare function nativeQueryTerms(conn: Connection, query: string): Promise<string[]>;
4
+ export declare function orderedBm25Sql(field: 'title' | 'summary' | 'text', termCount: number): string;
@@ -1,17 +1,4 @@
1
1
  import type { Connection } from '../types.js';
2
- export declare const ORDERED_BM25_MACRO = "sense_ordered_match_bm25";
3
- interface NativeMacroRow {
4
- function_type: string;
5
- parameters: unknown;
6
- parameter_types: unknown;
7
- macro_definition: string;
8
- }
9
- interface NativeMacroContract {
10
- version: string;
11
- macro: NativeMacroRow;
12
- }
13
- export declare function validateNativeMacroContract({ version, macro }: NativeMacroContract): string;
14
- export declare function ensureOrderedBm25(conn: Connection, state: {
15
- orderedMacroReady: boolean;
16
- }): Promise<void>;
17
- export {};
2
+ export declare const FTS_STEMMER = "porter";
3
+ export declare function nativeQueryTerms(conn: Connection, query: string): Promise<string[]>;
4
+ export declare function orderedBm25Sql(field: 'title' | 'summary' | 'text', termCount: number): string;
@@ -9,18 +9,16 @@ function _export(target, all) {
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
- get ORDERED_BM25_MACRO () {
13
- return ORDERED_BM25_MACRO;
12
+ get FTS_STEMMER () {
13
+ return FTS_STEMMER;
14
14
  },
15
- get ensureOrderedBm25 () {
16
- return ensureOrderedBm25;
15
+ get nativeQueryTerms () {
16
+ return nativeQueryTerms;
17
17
  },
18
- get validateNativeMacroContract () {
19
- return validateNativeMacroContract;
18
+ get orderedBm25Sql () {
19
+ return orderedBm25Sql;
20
20
  }
21
21
  });
22
- var _nodecrypto = require("node:crypto");
23
- var _errorsts = require("../../errors.js");
24
22
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
25
23
  try {
26
24
  var info = gen[key](arg);
@@ -146,93 +144,43 @@ function _ts_generator(thisArg, body) {
146
144
  };
147
145
  }
148
146
  }
149
- var ORDERED_BM25_MACRO = 'sense_ordered_match_bm25';
150
- var SUPPORTED_DUCKDB_VERSION = 'v1.5.5';
151
- var SUPPORTED_CONTRACT_SHA256 = '4476d543e43e7f8c89751cac0659b64e09d906cd3fefb1bfcaf4d15d3b1d9e00';
152
- var EXPECTED_PARAMETERS = [
153
- 'docname',
154
- 'query_string',
155
- 'fields',
156
- 'k',
157
- 'b',
158
- 'conjunctive'
159
- ];
160
- var EXPECTED_DEFAULTS = {
161
- fields: 'NULL',
162
- k: '1.2',
163
- b: '0.75',
164
- conjunctive: 'false'
165
- };
166
- var EXPECTED_SIGNATURE = "docname, query_string, fields := ".concat(EXPECTED_DEFAULTS.fields, ", k := ").concat(EXPECTED_DEFAULTS.k, ", b := ").concat(EXPECTED_DEFAULTS.b, ", conjunctive := ").concat(EXPECTED_DEFAULTS.conjunctive);
167
- var UNORDERED_SUM = 'sum(subscore)';
168
- function unsupported(message) {
169
- return new _errorsts.SenseError('STORE_CAPABILITY_MISSING', 'store "duckdb" cannot install its deterministic native BM25 adapter: '.concat(message, "; update the DuckDB adapter before using lexical search"));
170
- }
171
- function contractSha256(version, definition) {
172
- return (0, _nodecrypto.createHash)('sha256').update("".concat(version, "\0").concat(EXPECTED_SIGNATURE, "\0").concat(definition)).digest('hex');
173
- }
174
- function validateNativeMacroContract(param) {
175
- var version = param.version, macro = param.macro;
176
- if (version !== SUPPORTED_DUCKDB_VERSION) throw unsupported("DuckDB ".concat(version, " is unsupported (validated version is ").concat(SUPPORTED_DUCKDB_VERSION, ")"));
177
- if (macro.function_type !== 'macro') throw unsupported("match_bm25 is ".concat(macro.function_type, ", not a macro"));
178
- if (JSON.stringify(macro.parameters) !== JSON.stringify(EXPECTED_PARAMETERS)) throw unsupported("match_bm25 parameters changed (".concat(JSON.stringify(macro.parameters), ")"));
179
- if (!Array.isArray(macro.parameter_types) || macro.parameter_types.some(function(type) {
180
- return type !== null;
181
- })) throw unsupported('match_bm25 parameter types changed');
182
- if (contractSha256(version, macro.macro_definition) !== SUPPORTED_CONTRACT_SHA256) throw unsupported('match_bm25 definition or reviewed parameter-default contract changed');
183
- if (macro.macro_definition.split(UNORDERED_SUM).length !== 2) throw unsupported('match_bm25 does not contain exactly one validated unordered subscore sum');
184
- return macro.macro_definition.replace(UNORDERED_SUM, 'sum(subscore ORDER BY subscore)');
185
- }
186
- function ensureOrderedBm25(conn, state) {
147
+ var FTS_STEMMER = 'porter';
148
+ function nativeQueryTerms(conn, query) {
187
149
  return _async_to_generator(function() {
188
- var versionStatement, versionRow, macroStatement, macro, orderedDefinition;
150
+ var stmt, rows;
189
151
  return _ts_generator(this, function(_state) {
190
152
  switch(_state.label){
191
153
  case 0:
192
- if (state.orderedMacroReady) return [
193
- 2
194
- ];
195
154
  return [
196
155
  4,
197
- conn.prepare('SELECT version() AS version')
156
+ conn.prepare("\n WITH tokens AS (SELECT unnest(fts_main_content.tokenize(?)) AS raw_term)\n SELECT min(raw_term) AS term FROM tokens\n WHERE raw_term <> '' GROUP BY stem(raw_term, '".concat(FTS_STEMMER, "') ORDER BY term\n "))
198
157
  ];
199
158
  case 1:
200
- versionStatement = _state.sent();
159
+ stmt = _state.sent();
201
160
  return [
202
161
  4,
203
- versionStatement.get()
162
+ stmt.all(query)
204
163
  ];
205
164
  case 2:
206
- versionRow = _state.sent();
165
+ rows = _state.sent();
207
166
  return [
208
- 4,
209
- conn.prepare("\n SELECT function_type, parameters, parameter_types, macro_definition\n FROM duckdb_functions()\n WHERE schema_name = 'fts_main_content' AND function_name = 'match_bm25'\n ")
210
- ];
211
- case 3:
212
- macroStatement = _state.sent();
213
- return [
214
- 4,
215
- macroStatement.get()
216
- ];
217
- case 4:
218
- macro = _state.sent();
219
- if (!macro) throw unsupported('fts_main_content.match_bm25 is missing');
220
- orderedDefinition = validateNativeMacroContract({
221
- version: versionRow.version,
222
- macro: macro
223
- });
224
- return [
225
- 4,
226
- conn.exec("CREATE OR REPLACE TEMP MACRO ".concat(ORDERED_BM25_MACRO, "(").concat(EXPECTED_SIGNATURE, ") AS ").concat(orderedDefinition))
227
- ];
228
- case 5:
229
- _state.sent();
230
- state.orderedMacroReady = true;
231
- return [
232
- 2
167
+ 2,
168
+ rows.map(function(param) {
169
+ var term = param.term;
170
+ return term;
171
+ })
233
172
  ];
234
173
  }
235
174
  });
236
175
  })();
237
176
  }
177
+ function orderedBm25Sql(field, termCount) {
178
+ if (termCount === 0) return 'NULL';
179
+ var contributions = Array.from({
180
+ length: termCount
181
+ }, function() {
182
+ return 'SELECT fts_main_content.match_bm25(content."path", ?, fields := \''.concat(field, "', conjunctive := false) AS score");
183
+ });
184
+ return "(SELECT sum(score ORDER BY score) FROM (".concat(contributions.join(' UNION ALL '), "))");
185
+ }
238
186
  /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/duckdb/ordered-bm25.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { SenseError } from '../../errors.ts';\nimport type { Connection } from '../types.ts';\n\n// This is a connection-local TEMP macro. The contract hash covers the native fts definition,\n// DuckDB version, and the reviewed parameter defaults captured in the retained diagnostic.\nexport const ORDERED_BM25_MACRO = 'sense_ordered_match_bm25';\nconst SUPPORTED_DUCKDB_VERSION = 'v1.5.5';\nconst SUPPORTED_CONTRACT_SHA256 = '4476d543e43e7f8c89751cac0659b64e09d906cd3fefb1bfcaf4d15d3b1d9e00';\nconst EXPECTED_PARAMETERS = ['docname', 'query_string', 'fields', 'k', 'b', 'conjunctive'];\nconst EXPECTED_DEFAULTS = { fields: 'NULL', k: '1.2', b: '0.75', conjunctive: 'false' } as const;\nconst EXPECTED_SIGNATURE = `docname, query_string, fields := ${EXPECTED_DEFAULTS.fields}, k := ${EXPECTED_DEFAULTS.k}, b := ${EXPECTED_DEFAULTS.b}, conjunctive := ${EXPECTED_DEFAULTS.conjunctive}`;\nconst UNORDERED_SUM = 'sum(subscore)';\n\ninterface NativeMacroRow {\n function_type: string;\n parameters: unknown;\n parameter_types: unknown;\n macro_definition: string;\n}\n\ninterface NativeMacroContract {\n version: string;\n macro: NativeMacroRow;\n}\n\nfunction unsupported(message: string): SenseError {\n return new SenseError('STORE_CAPABILITY_MISSING', `store \"duckdb\" cannot install its deterministic native BM25 adapter: ${message}; update the DuckDB adapter before using lexical search`);\n}\n\nfunction contractSha256(version: string, definition: string): string {\n return createHash('sha256').update(`${version}\\0${EXPECTED_SIGNATURE}\\0${definition}`).digest('hex');\n}\n\nexport function validateNativeMacroContract({ version, macro }: NativeMacroContract): string {\n if (version !== SUPPORTED_DUCKDB_VERSION) throw unsupported(`DuckDB ${version} is unsupported (validated version is ${SUPPORTED_DUCKDB_VERSION})`);\n if (macro.function_type !== 'macro') throw unsupported(`match_bm25 is ${macro.function_type}, not a macro`);\n if (JSON.stringify(macro.parameters) !== JSON.stringify(EXPECTED_PARAMETERS)) throw unsupported(`match_bm25 parameters changed (${JSON.stringify(macro.parameters)})`);\n if (!Array.isArray(macro.parameter_types) || macro.parameter_types.some((type) => type !== null)) throw unsupported('match_bm25 parameter types changed');\n if (contractSha256(version, macro.macro_definition) !== SUPPORTED_CONTRACT_SHA256) throw unsupported('match_bm25 definition or reviewed parameter-default contract changed');\n if (macro.macro_definition.split(UNORDERED_SUM).length !== 2) throw unsupported('match_bm25 does not contain exactly one validated unordered subscore sum');\n return macro.macro_definition.replace(UNORDERED_SUM, 'sum(subscore ORDER BY subscore)');\n}\n\nexport async function ensureOrderedBm25(conn: Connection, state: { orderedMacroReady: boolean }): Promise<void> {\n if (state.orderedMacroReady) return;\n const versionStatement = await conn.prepare('SELECT version() AS version');\n const versionRow = (await versionStatement.get()) as { version: string };\n const macroStatement = await conn.prepare(`\n SELECT function_type, parameters, parameter_types, macro_definition\n FROM duckdb_functions()\n WHERE schema_name = 'fts_main_content' AND function_name = 'match_bm25'\n `);\n const macro = (await macroStatement.get()) as NativeMacroRow | undefined;\n if (!macro) throw unsupported('fts_main_content.match_bm25 is missing');\n const orderedDefinition = validateNativeMacroContract({ version: versionRow.version, macro });\n await conn.exec(`CREATE OR REPLACE TEMP MACRO ${ORDERED_BM25_MACRO}(${EXPECTED_SIGNATURE}) AS ${orderedDefinition}`);\n state.orderedMacroReady = true;\n}\n"],"names":["ORDERED_BM25_MACRO","ensureOrderedBm25","validateNativeMacroContract","SUPPORTED_DUCKDB_VERSION","SUPPORTED_CONTRACT_SHA256","EXPECTED_PARAMETERS","EXPECTED_DEFAULTS","fields","k","b","conjunctive","EXPECTED_SIGNATURE","UNORDERED_SUM","unsupported","message","SenseError","contractSha256","version","definition","createHash","update","digest","macro","function_type","JSON","stringify","parameters","Array","isArray","parameter_types","some","type","macro_definition","split","length","replace","conn","state","versionStatement","versionRow","macroStatement","orderedDefinition","orderedMacroReady","prepare","get","exec"],"mappings":";;;;;;;;;;;QAMaA;eAAAA;;QAsCSC;eAAAA;;QAVNC;eAAAA;;;0BAlCW;wBACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKpB,IAAMF,qBAAqB;AAClC,IAAMG,2BAA2B;AACjC,IAAMC,4BAA4B;AAClC,IAAMC,sBAAsB;IAAC;IAAW;IAAgB;IAAU;IAAK;IAAK;CAAc;AAC1F,IAAMC,oBAAoB;IAAEC,QAAQ;IAAQC,GAAG;IAAOC,GAAG;IAAQC,aAAa;AAAQ;AACtF,IAAMC,qBAAqB,AAAC,oCAAqEL,OAAlCA,kBAAkBC,MAAM,EAAC,WAAsCD,OAA7BA,kBAAkBE,CAAC,EAAC,WAAgDF,OAAvCA,kBAAkBG,CAAC,EAAC,qBAAiD,OAA9BH,kBAAkBI,WAAW;AAClM,IAAME,gBAAgB;AActB,SAASC,YAAYC,OAAe;IAClC,OAAO,IAAIC,oBAAU,CAAC,4BAA4B,AAAC,wEAA+E,OAARD,SAAQ;AACpI;AAEA,SAASE,eAAeC,OAAe,EAAEC,UAAkB;IACzD,OAAOC,IAAAA,sBAAU,EAAC,UAAUC,MAAM,CAAC,AAAC,GAAcT,OAAZM,SAAQ,MAA2BC,OAAvBP,oBAAmB,MAAe,OAAXO,aAAcG,MAAM,CAAC;AAChG;AAEO,SAASnB,4BAA4B,KAAuC;QAArCe,UAAF,MAAEA,SAASK,QAAX,MAAWA;IACrD,IAAIL,YAAYd,0BAA0B,MAAMU,YAAY,AAAC,UAAyDV,OAAhDc,SAAQ,0CAAiE,OAAzBd,0BAAyB;IAC/I,IAAImB,MAAMC,aAAa,KAAK,SAAS,MAAMV,YAAY,AAAC,iBAAoC,OAApBS,MAAMC,aAAa,EAAC;IAC5F,IAAIC,KAAKC,SAAS,CAACH,MAAMI,UAAU,MAAMF,KAAKC,SAAS,CAACpB,sBAAsB,MAAMQ,YAAY,AAAC,kCAAkE,OAAjCW,KAAKC,SAAS,CAACH,MAAMI,UAAU,GAAE;IACnK,IAAI,CAACC,MAAMC,OAAO,CAACN,MAAMO,eAAe,KAAKP,MAAMO,eAAe,CAACC,IAAI,CAAC,SAACC;eAASA,SAAS;QAAO,MAAMlB,YAAY;IACpH,IAAIG,eAAeC,SAASK,MAAMU,gBAAgB,MAAM5B,2BAA2B,MAAMS,YAAY;IACrG,IAAIS,MAAMU,gBAAgB,CAACC,KAAK,CAACrB,eAAesB,MAAM,KAAK,GAAG,MAAMrB,YAAY;IAChF,OAAOS,MAAMU,gBAAgB,CAACG,OAAO,CAACvB,eAAe;AACvD;AAEO,SAAeX,kBAAkBmC,IAAgB,EAAEC,KAAqC;;YAEvFC,kBACAC,YACAC,gBAKAlB,OAEAmB;;;;oBAVN,IAAIJ,MAAMK,iBAAiB,EAAE;;;oBACJ;;wBAAMN,KAAKO,OAAO,CAAC;;;oBAAtCL,mBAAmB;oBACL;;wBAAMA,iBAAiBM,GAAG;;;oBAAxCL,aAAc;oBACG;;wBAAMH,KAAKO,OAAO,CAAC;;;oBAApCH,iBAAiB;oBAKR;;wBAAMA,eAAeI,GAAG;;;oBAAjCtB,QAAS;oBACf,IAAI,CAACA,OAAO,MAAMT,YAAY;oBACxB4B,oBAAoBvC,4BAA4B;wBAAEe,SAASsB,WAAWtB,OAAO;wBAAEK,OAAAA;oBAAM;oBAC3F;;wBAAMc,KAAKS,IAAI,CAAC,AAAC,gCAAqDlC,OAAtBX,oBAAmB,KAA6ByC,OAA1B9B,oBAAmB,SAAyB,OAAlB8B;;;oBAAhG;oBACAJ,MAAMK,iBAAiB,GAAG;;;;;;IAC5B"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/ordered-bm25.ts"],"sourcesContent":["import type { Connection } from '../types.ts';\n\nexport const FTS_STEMMER = 'porter';\n\n// Keep deduplication native, but return original tokens so native scoring stems once.\nexport async function nativeQueryTerms(conn: Connection, query: string): Promise<string[]> {\n const stmt = await conn.prepare(`\n WITH tokens AS (SELECT unnest(fts_main_content.tokenize(?)) AS raw_term)\n SELECT min(raw_term) AS term FROM tokens\n WHERE raw_term <> '' GROUP BY stem(raw_term, '${FTS_STEMMER}') ORDER BY term\n `);\n const rows = (await stmt.all(query)) as Array<{ term: string }>;\n return rows.map(({ term }) => term);\n}\n\n// Fixed parameters avoid a correlated document-by-term intermediate relation in DuckDB.\n// Only the number of terms shapes this authored SQL; query values are always bound.\nexport function orderedBm25Sql(field: 'title' | 'summary' | 'text', termCount: number): string {\n if (termCount === 0) return 'NULL';\n const contributions = Array.from({ length: termCount }, () => `SELECT fts_main_content.match_bm25(content.\"path\", ?, fields := '${field}', conjunctive := false) AS score`);\n return `(SELECT sum(score ORDER BY score) FROM (${contributions.join(' UNION ALL ')}))`;\n}\n"],"names":["FTS_STEMMER","nativeQueryTerms","orderedBm25Sql","conn","query","stmt","rows","prepare","all","map","term","field","termCount","contributions","Array","from","length","join"],"mappings":";;;;;;;;;;;QAEaA;eAAAA;;QAGSC;eAAAA;;QAYNC;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAfT,IAAMF,cAAc;AAGpB,SAAeC,iBAAiBE,IAAgB,EAAEC,KAAa;;YAC9DC,MAKAC;;;;oBALO;;wBAAMH,KAAKI,OAAO,CAAC,AAAC,mLAG6B,OAAZP,aAAY;;;oBAHxDK,OAAO;oBAKC;;wBAAMA,KAAKG,GAAG,CAACJ;;;oBAAvBE,OAAQ;oBACd;;wBAAOA,KAAKG,GAAG,CAAC;gCAAGC,aAAAA;mCAAWA;;;;;IAChC;;AAIO,SAASR,eAAeS,KAAmC,EAAEC,SAAiB;IACnF,IAAIA,cAAc,GAAG,OAAO;IAC5B,IAAMC,gBAAgBC,MAAMC,IAAI,CAAC;QAAEC,QAAQJ;IAAU,GAAG;eAAM,AAAC,qEAAyE,OAAND,OAAM;;IACxI,OAAO,AAAC,2CAA4E,OAAlCE,cAAcI,IAAI,CAAC,gBAAe;AACtF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/duckdb/reconcile.ts"],"sourcesContent":["import type { DuckDBConnection, DuckDBPreparedStatement, DuckDBValue } from '@duckdb/node-api';\nimport { SenseError } from '../../errors.ts';\nimport type { ReconcileDelta } from '../../features/types.ts';\nimport type { ParsedDoc } from '../../scan/index.ts';\nimport { appendRows, quoteIdent } from '../shared.ts';\nimport type { Connection, ReconcileDialect } from '../types.ts';\nimport type { DuckdbConnection } from './connection.ts';\nimport { markContentStale } from './lexical.ts';\nimport { duckdbApi } from './native.ts';\n\n// This store's dialect (types.ts's ReconcileDialect) for the shared orchestration in\n// store/reconcile.ts. `content` is a plain table, not FTS-virtual, so changed rows are maintained\n// here; DuckDB's ALTER TABLE needs a declared type, so every dynamic frontmatter\n// column is VARIANT (holds mapValue()'s mixed JS types for one key across files).\n\n// No rowid coupling needed (unlike sqlite's content, which links to frontmatter's rowid):\n// `path` is content's own primary key, so this is a plain per-doc row.\nconst CONTENT_COLUMNS = ['path', 'title', 'summary', 'text'];\nconst INSERT_CONTENT_SQL = `INSERT INTO content (${CONTENT_COLUMNS.map(quoteIdent).join(', ')}) VALUES (?, ?, ?, ?)`;\n// Bound the extra persisted text held for exact comparison, even during a full reparse.\nconst CONTENT_LOOKUP_CHUNK = 128;\n\ninterface ContentRow {\n path: string;\n title: string | null;\n summary: string | null;\n text: string | null;\n}\n\nfunction contentRow(doc: ParsedDoc): unknown[] {\n return [doc.relPath, doc.search.title, doc.search.summary, doc.search.text];\n}\n\n// No compile-time column cap in DuckDB (unlike SQLite's SQLITE_MAX_COLUMN); kept as a sanity fence anyway\n// so a runaway frontmatter generator fails with a clear message instead of an unbounded ALTER TABLE loop.\nconst MAX_FRONTMATTER_COLUMNS = 10_000;\nconst FRONTMATTER_UPDATE_CHUNK = 128;\n\nasync function withNativeStatement<T>(native: DuckDBConnection, sql: string, fn: (stmt: DuckDBPreparedStatement) => Promise<T>): Promise<T> {\n const stmt = await native.prepare(sql);\n const errors: unknown[] = [];\n let result!: T;\n try {\n result = await fn(stmt);\n } catch (err) {\n errors.push(err);\n }\n try {\n stmt.destroySync();\n } catch (err) {\n errors.push(err);\n }\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) throw new AggregateError(errors, 'frontmatter statement and cleanup failed');\n return result;\n}\n\n// Wide writes amplify native commit allocations even for one changed stamp.\n// Skip only known, exactly equal values; uncertain representations still write.\nasync function updateFrontmatter(conn: Connection, writableColumns: string[], rows: unknown[][]): Promise<void> {\n if (rows.length === 0) return;\n const native = (conn as DuckdbConnection).duckdb;\n const { DuckDBVariantValue, DuckDBTypeId } = await duckdbApi();\n const physical = await withNativeStatement(native, 'PRAGMA table_info(frontmatter)', async (stmt) => {\n const reader = await stmt.runAndReadAll();\n return reader.getRowObjectsJS() as Array<{ name: string; type: string }>;\n });\n const writable = new Map(writableColumns.map((name, i) => [name, i]));\n const pathIndex = writable.get('path');\n if (pathIndex === undefined) throw new Error('frontmatter update requires a writable path column');\n const columnTypes = new Map(physical.map((column) => [column.name, column.type]));\n const insertSql = `INSERT INTO frontmatter (${writableColumns.map(quoteIdent).join(', ')}) VALUES (${writableColumns.map(() => '?').join(', ')})`;\n const sameValue = (old: DuckDBValue, value: unknown, column: string): boolean => {\n if (value === null || value === undefined) return old === null;\n if (columnTypes.get(column) !== 'VARIANT') return Object.is(old, value);\n if (!(old instanceof DuckDBVariantValue)) return false;\n const typeId = typeof value === 'string' ? DuckDBTypeId.VARCHAR : typeof value === 'bigint' ? DuckDBTypeId.HUGEINT : typeof value === 'number' && !Number.isInteger(value) ? DuckDBTypeId.DOUBLE : undefined;\n return typeId !== undefined && old.type?.typeId === typeId && Object.is(old.value, value);\n };\n for (let i = 0; i < rows.length; i += FRONTMATTER_UPDATE_CHUNK) {\n const chunk = rows.slice(i, i + FRONTMATTER_UPDATE_CHUNK);\n const paths = chunk.map((row) => row[pathIndex] as string);\n const placeholders = paths.map(() => '?').join(', ');\n const selected = writableColumns.map(quoteIdent).join(', ');\n const existing = await withNativeStatement(native, `SELECT ${selected} FROM frontmatter WHERE \"path\" IN (${placeholders})`, async (stmt) => {\n stmt.bind(paths);\n const reader = await stmt.runAndReadAll();\n // Native wrappers distinguish numeric tags and SQL NULL from VARIANT null.\n return new Map(reader.getRowObjects().map((row) => [row.path as string, row]));\n });\n const plans = chunk.map((row) => {\n const old = existing.get(row[pathIndex] as string);\n const changed = old ? writableColumns.flatMap((column, index) => (sameValue(old[column], row[index], column) ? [] : [index])) : [];\n return { row, missing: old === undefined, changed, signature: changed.join(',') };\n });\n for (let position = 0; position < plans.length; ) {\n const plan = plans[position];\n if (!plan.missing && plan.changed.length === 0) {\n ++position;\n continue;\n }\n let end = position + 1;\n while (end < plans.length && plans[end].missing === plan.missing && plans[end].signature === plan.signature) ++end;\n if (plan.missing) {\n await appendRows(\n conn,\n 'frontmatter',\n writableColumns,\n insertSql,\n plans.slice(position, end).map((repair) => repair.row)\n );\n } else {\n const assignments = plan.changed.map((index) => `${quoteIdent(writableColumns[index])} = ?`).join(', ');\n await withNativeStatement(native, `UPDATE frontmatter SET ${assignments} WHERE \"path\" = ?`, async (stmt) => {\n for (let rowIndex = position; rowIndex < end; ++rowIndex) {\n const row = plans[rowIndex].row;\n stmt.bind([...plan.changed.map((index) => row[index] ?? null), row[pathIndex]] as DuckDBValue[]);\n await stmt.run();\n }\n });\n }\n position = end;\n }\n }\n}\n\nasync function reconcileContent(conn: Connection, touched: string[], docs: ParsedDoc[], delta: ReconcileDelta): Promise<void> {\n const added = new Set(delta.added);\n const reparsed = docs.filter((doc) => !added.has(doc.relPath));\n const changed = new Set(delta.added);\n const removed: string[] = [];\n for (let i = 0; i < reparsed.length; i += CONTENT_LOOKUP_CHUNK) {\n const chunk = reparsed.slice(i, i + CONTENT_LOOKUP_CHUNK);\n const stmt = await conn.prepare(`SELECT \"path\", title, summary, text FROM content WHERE \"path\" IN (${chunk.map(() => '?').join(', ')})`);\n const rows = (await stmt.all(...chunk.map((doc) => doc.relPath))) as ContentRow[];\n const existing = new Map(rows.map((row) => [row.path, row]));\n for (const doc of chunk) {\n const row = existing.get(doc.relPath);\n if (row && row.title === doc.search.title && row.summary === doc.search.summary && row.text === doc.search.text) continue;\n changed.add(doc.relPath);\n if (row) removed.push(doc.relPath);\n }\n }\n\n const docPaths = new Set(docs.map((doc) => doc.relPath));\n const vanished = touched.filter((path) => !docPaths.has(path));\n for (let i = 0; i < vanished.length; i += CONTENT_LOOKUP_CHUNK) {\n const chunk = vanished.slice(i, i + CONTENT_LOOKUP_CHUNK);\n const stmt = await conn.prepare(`SELECT \"path\" FROM content WHERE \"path\" IN (${chunk.map(() => '?').join(', ')})`);\n const rows = (await stmt.all(...chunk)) as Array<{ path: string }>;\n removed.push(...rows.map((row) => row.path));\n }\n\n if (removed.length > 0)\n await conn.runBatch(\n 'DELETE FROM content WHERE \"path\" = ?',\n removed.map((p) => [p])\n );\n // Keep document order and the existing insert/error semantics for added paths.\n const changedDocs = docs.filter((doc) => changed.has(doc.relPath));\n await appendRows(conn, 'content', CONTENT_COLUMNS, INSERT_CONTENT_SQL, changedDocs.map(contentRow));\n // Commit the stale mark with actual content changes. Identical rows leave prior staleness\n // untouched, and FTS preparation still owns missing-index recovery.\n if (removed.length > 0 || changedDocs.length > 0) await markContentStale(conn);\n}\n\n// DuckDB rejects more than one ALTER command per statement (\"Parser Error: Only one ALTER\n// command per statement is supported\", measured), so every name's clause joins into one string\n// and runs as a single exec() -- one column-add \"leg\" through the driver instead of `names.length`.\n// VARIANT is the only type that can hold the mixed bigint/number/string/null shapes mapValue()\n// produces for one key across files.\nasync function addColumns(conn: Connection, names: string[]): Promise<void> {\n if (names.length === 0) return;\n await conn.exec(names.map((name) => `ALTER TABLE frontmatter ADD COLUMN ${quoteIdent(name)} VARIANT`).join('; '));\n}\n\nexport const duckdbDialect: ReconcileDialect = {\n beginMode: () => 'BEGIN',\n checkColumnLimit(count) {\n if (count > MAX_FRONTMATTER_COLUMNS) {\n throw new SenseError('COLUMN_LIMIT', `frontmatter would need ${count} columns, crossing this store's sanity limit (${MAX_FRONTMATTER_COLUMNS}). Narrow the presets' include globs so fewer/other files are indexed, or fix whatever is generating unbounded frontmatter keys.`);\n }\n },\n addColumns,\n updateFrontmatter,\n reconcileContent,\n};\n"],"names":["duckdbDialect","CONTENT_COLUMNS","INSERT_CONTENT_SQL","map","quoteIdent","join","CONTENT_LOOKUP_CHUNK","contentRow","doc","relPath","search","title","summary","text","MAX_FRONTMATTER_COLUMNS","FRONTMATTER_UPDATE_CHUNK","withNativeStatement","native","sql","fn","stmt","errors","result","err","prepare","push","destroySync","length","AggregateError","updateFrontmatter","conn","writableColumns","rows","DuckDBVariantValue","DuckDBTypeId","physical","writable","pathIndex","columnTypes","insertSql","sameValue","i","chunk","paths","placeholders","selected","existing","plans","position","plan","end","assignments","missing","changed","signature","appendRows","slice","repair","row","index","rowIndex","bind","run","reader","runAndReadAll","Map","getRowObjects","path","old","get","flatMap","column","undefined","duckdb","duckdbApi","getRowObjectsJS","name","Error","type","value","Object","is","typeId","VARCHAR","HUGEINT","Number","isInteger","DOUBLE","reconcileContent","touched","docs","delta","added","reparsed","removed","docPaths","vanished","changedDocs","Set","filter","has","all","add","runBatch","p","markContentStale","addColumns","names","exec","beginMode","checkColumnLimit","count","SenseError"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/reconcile.ts"],"sourcesContent":["import type { DuckDBConnection, DuckDBPreparedStatement, DuckDBValue } from '@duckdb/node-api';\nimport { SenseError } from '../../errors.ts';\nimport type { ReconcileDelta } from '../../features/types.ts';\nimport type { ParsedDoc } from '../../scan/index.ts';\nimport { appendRows, quoteIdent } from '../shared.ts';\nimport type { Connection, ReconcileDialect } from '../types.ts';\nimport type { DuckdbConnection } from './connection.ts';\nimport { markContentStale } from './lexical.ts';\nimport { duckdbApi } from './native.ts';\n\n// This store's dialect (types.ts's ReconcileDialect) for the shared orchestration in\n// store/reconcile.ts. `content` is a plain table, not FTS-virtual, so changed rows are maintained\n// here; DuckDB's ALTER TABLE needs a declared type, so every dynamic frontmatter\n// column is VARIANT (holds mapValue()'s mixed JS types for one key across files).\n\n// No rowid coupling needed (unlike sqlite's content, which links to frontmatter's rowid):\n// `path` is content's own primary key, so this is a plain per-doc row.\nconst CONTENT_COLUMNS = ['path', 'title', 'summary', 'text'];\nconst INSERT_CONTENT_SQL = `INSERT INTO content (${CONTENT_COLUMNS.map(quoteIdent).join(', ')}) VALUES (?, ?, ?, ?)`;\n// Bound the extra persisted text held for exact comparison, even during a full reparse.\nconst CONTENT_LOOKUP_CHUNK = 128;\n\ninterface ContentRow {\n path: string;\n title: string | null;\n summary: string | null;\n text: string | null;\n}\n\nfunction contentRow(doc: ParsedDoc): unknown[] {\n return [doc.relPath, doc.search.title, doc.search.summary, doc.search.text];\n}\n\n// No compile-time column cap in DuckDB (unlike SQLite's SQLITE_MAX_COLUMN); kept as a sanity fence anyway\n// so a runaway frontmatter generator fails with a clear message instead of an unbounded ALTER TABLE loop.\nconst MAX_FRONTMATTER_COLUMNS = 10_000;\nconst FRONTMATTER_UPDATE_CHUNK = 128;\n\nasync function withNativeStatement<T>(native: DuckDBConnection, sql: string, fn: (stmt: DuckDBPreparedStatement) => Promise<T>): Promise<T> {\n const stmt = await native.prepare(sql);\n const errors: unknown[] = [];\n let result!: T;\n try {\n result = await fn(stmt);\n } catch (err) {\n errors.push(err);\n }\n try {\n stmt.destroySync();\n } catch (err) {\n errors.push(err);\n }\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) throw new AggregateError(errors, 'frontmatter statement and cleanup failed');\n return result;\n}\n\n// Wide writes amplify native commit allocations even for one changed stamp.\n// Skip only known, exactly equal values; uncertain representations still write.\nasync function updateFrontmatter(conn: Connection, writableColumns: string[], rows: unknown[][]): Promise<void> {\n if (rows.length === 0) return;\n const native = (conn as DuckdbConnection).duckdb;\n const { DuckDBVariantValue, DuckDBTypeId } = await duckdbApi();\n const physical = await withNativeStatement(native, 'PRAGMA table_info(frontmatter)', async (stmt) => {\n const reader = await stmt.runAndReadAll();\n return reader.getRowObjectsJS() as Array<{ name: string; type: string }>;\n });\n const writable = new Map(writableColumns.map((name, i) => [name, i]));\n const pathIndex = writable.get('path');\n if (pathIndex === undefined) throw new Error('frontmatter update requires a writable path column');\n const columnTypes = new Map(physical.map((column) => [column.name, column.type]));\n const insertSql = `INSERT INTO frontmatter (${writableColumns.map(quoteIdent).join(', ')}) VALUES (${writableColumns.map(() => '?').join(', ')})`;\n const sameValue = (old: DuckDBValue, value: unknown, column: string): boolean => {\n if (value === null || value === undefined) return old === null;\n if (columnTypes.get(column) !== 'VARIANT') return Object.is(old, value);\n if (!(old instanceof DuckDBVariantValue)) return false;\n const typeId = typeof value === 'string' ? DuckDBTypeId.VARCHAR : typeof value === 'bigint' ? DuckDBTypeId.HUGEINT : typeof value === 'number' && !Number.isInteger(value) ? DuckDBTypeId.DOUBLE : undefined;\n return typeId !== undefined && old.type?.typeId === typeId && Object.is(old.value, value);\n };\n for (let i = 0; i < rows.length; i += FRONTMATTER_UPDATE_CHUNK) {\n const chunk = rows.slice(i, i + FRONTMATTER_UPDATE_CHUNK);\n const paths = chunk.map((row) => row[pathIndex] as string);\n const placeholders = paths.map(() => '?').join(', ');\n const selected = writableColumns.map(quoteIdent).join(', ');\n const existing = await withNativeStatement(native, `SELECT ${selected} FROM frontmatter WHERE \"path\" IN (${placeholders})`, async (stmt) => {\n stmt.bind(paths);\n const reader = await stmt.runAndReadAll();\n // Native wrappers distinguish numeric tags and SQL NULL from VARIANT null.\n return new Map(reader.getRowObjects().map((row) => [row.path as string, row]));\n });\n const plans = chunk.map((row) => {\n const old = existing.get(row[pathIndex] as string);\n const changed = old ? writableColumns.flatMap((column, index) => (sameValue(old[column], row[index], column) ? [] : [index])) : [];\n return { row, missing: old === undefined, changed, signature: changed.join(',') };\n });\n for (let position = 0; position < plans.length; ) {\n const plan = plans[position];\n if (!plan.missing && plan.changed.length === 0) {\n ++position;\n continue;\n }\n let end = position + 1;\n while (end < plans.length && plans[end].missing === plan.missing && plans[end].signature === plan.signature) ++end;\n if (plan.missing) {\n await appendRows(\n conn,\n 'frontmatter',\n writableColumns,\n insertSql,\n plans.slice(position, end).map((repair) => repair.row)\n );\n } else {\n const assignments = plan.changed.map((index) => `${quoteIdent(writableColumns[index])} = ?`).join(', ');\n await withNativeStatement(native, `UPDATE frontmatter SET ${assignments} WHERE \"path\" = ?`, async (stmt) => {\n for (let rowIndex = position; rowIndex < end; ++rowIndex) {\n const row = plans[rowIndex].row;\n stmt.bind([...plan.changed.map((index) => row[index] ?? null), row[pathIndex]] as DuckDBValue[]);\n await stmt.run();\n }\n });\n }\n position = end;\n }\n }\n}\n\nasync function reconcileContent(conn: Connection, touched: string[], docs: ParsedDoc[], delta: ReconcileDelta): Promise<void> {\n const added = new Set(delta.added);\n const reparsed = docs.filter((doc) => !added.has(doc.relPath));\n const changed = new Set(delta.added);\n const removed: string[] = [];\n for (let i = 0; i < reparsed.length; i += CONTENT_LOOKUP_CHUNK) {\n const chunk = reparsed.slice(i, i + CONTENT_LOOKUP_CHUNK);\n const stmt = await conn.prepare(`SELECT \"path\", title, summary, text FROM content WHERE \"path\" IN (${chunk.map(() => '?').join(', ')})`);\n const rows = (await stmt.all(...chunk.map((doc) => doc.relPath))) as ContentRow[];\n const existing = new Map(rows.map((row) => [row.path, row]));\n for (const doc of chunk) {\n const row = existing.get(doc.relPath);\n if (row && row.title === doc.search.title && row.summary === doc.search.summary && row.text === doc.search.text) continue;\n changed.add(doc.relPath);\n if (row) removed.push(doc.relPath);\n }\n }\n\n const docPaths = new Set(docs.map((doc) => doc.relPath));\n const vanished = touched.filter((path) => !docPaths.has(path));\n for (let i = 0; i < vanished.length; i += CONTENT_LOOKUP_CHUNK) {\n const chunk = vanished.slice(i, i + CONTENT_LOOKUP_CHUNK);\n const stmt = await conn.prepare(`SELECT \"path\" FROM content WHERE \"path\" IN (${chunk.map(() => '?').join(', ')})`);\n const rows = (await stmt.all(...chunk)) as Array<{ path: string }>;\n removed.push(...rows.map((row) => row.path));\n }\n\n if (removed.length > 0)\n await conn.runBatch(\n 'DELETE FROM content WHERE \"path\" = ?',\n removed.map((p) => [p])\n );\n // Keep document order and the existing insert/error semantics for added paths.\n const changedDocs = docs.filter((doc) => changed.has(doc.relPath));\n await appendRows(conn, 'content', CONTENT_COLUMNS, INSERT_CONTENT_SQL, changedDocs.map(contentRow));\n // Commit the stale mark with actual content changes. Identical rows leave prior staleness\n // untouched, and FTS preparation still owns missing-index recovery.\n if (removed.length > 0 || changedDocs.length > 0) await markContentStale(conn);\n}\n\n// DuckDB rejects more than one ALTER command per statement (\"Parser Error: Only one ALTER\n// command per statement is supported\", measured), so every name's clause joins into one string\n// and runs as a single exec() -- one column-add \"leg\" through the driver instead of `names.length`.\n// VARIANT is the only type that can hold the mixed bigint/number/string/null shapes mapValue()\n// produces for one key across files.\nasync function addColumns(conn: Connection, names: string[]): Promise<void> {\n if (names.length === 0) return;\n await conn.exec(names.map((name) => `ALTER TABLE frontmatter ADD COLUMN ${quoteIdent(name)} VARIANT`).join('; '));\n}\n\nexport const duckdbDialect: ReconcileDialect = {\n beginMode: () => 'BEGIN',\n checkColumnLimit(count) {\n if (count > MAX_FRONTMATTER_COLUMNS) {\n throw new SenseError('COLUMN_LIMIT', `frontmatter would need ${count} columns, crossing this store's sanity limit (${MAX_FRONTMATTER_COLUMNS}). Narrow the presets' include globs so fewer/other files are indexed, or fix whatever is generating unbounded frontmatter keys.`);\n }\n },\n addColumns,\n updateFrontmatter,\n reconcileContent,\n};\n"],"names":["duckdbDialect","CONTENT_COLUMNS","INSERT_CONTENT_SQL","map","quoteIdent","join","CONTENT_LOOKUP_CHUNK","contentRow","doc","relPath","search","title","summary","text","MAX_FRONTMATTER_COLUMNS","FRONTMATTER_UPDATE_CHUNK","withNativeStatement","native","sql","fn","stmt","errors","result","err","prepare","push","destroySync","length","AggregateError","updateFrontmatter","conn","writableColumns","rows","DuckDBVariantValue","DuckDBTypeId","physical","writable","pathIndex","columnTypes","insertSql","sameValue","i","chunk","paths","placeholders","selected","existing","plans","position","plan","end","assignments","missing","changed","signature","appendRows","slice","repair","row","index","rowIndex","bind","run","reader","runAndReadAll","Map","getRowObjects","path","old","get","flatMap","column","undefined","duckdb","duckdbApi","getRowObjectsJS","name","Error","type","value","Object","is","typeId","VARCHAR","HUGEINT","Number","isInteger","DOUBLE","reconcileContent","touched","docs","delta","added","reparsed","removed","docPaths","vanished","changedDocs","Set","filter","has","all","add","runBatch","p","markContentStale","addColumns","names","exec","beginMode","checkColumnLimit","count","SenseError"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/duckdb/sql-functions.ts"],"sourcesContent":["import type { DuckDBConnection } from '@duckdb/node-api';\nimport { segmentMatch } from '../../text/segment.ts';\nimport { basenameImpl, hasImpl } from '../sql-functions.ts';\nimport { duckdbApi } from './native.ts';\n\n// Dynamic, not a top-level import: sqlite trees must never attempt to resolve this optional peer dependency (open.ts's connect()).\n// Goes through native.ts's shared duckdbApi(), not its own bare import, since a second independent lookup would hit Node's stale pre-install resolution miss.\nexport async function registerFunctions(conn: DuckDBConnection): Promise<void> {\n const { DuckDBIntegerType, DuckDBScalarFunction, DuckDBVarCharType } = await duckdbApi();\n conn.registerScalarFunction(\n DuckDBScalarFunction.create({\n name: 'has',\n parameterTypes: [DuckDBVarCharType.instance, DuckDBVarCharType.instance],\n returnType: DuckDBIntegerType.instance,\n mainFunction(_info, inputChunk, outputVector) {\n const fieldVec = inputChunk.getColumnVector(0);\n const valueVec = inputChunk.getColumnVector(1);\n for (let i = 0; i < inputChunk.rowCount; i++) outputVector.setItem(i, hasImpl(fieldVec.getItem(i), valueVec.getItem(i)));\n outputVector.flush();\n },\n })\n );\n conn.registerScalarFunction(\n DuckDBScalarFunction.create({\n name: 'basename',\n parameterTypes: [DuckDBVarCharType.instance],\n varArgsType: DuckDBVarCharType.instance,\n returnType: DuckDBVarCharType.instance,\n mainFunction(_info, inputChunk, outputVector) {\n const pathVec = inputChunk.getColumnVector(0);\n const suffixVec = inputChunk.columnCount > 1 ? inputChunk.getColumnVector(1) : null;\n for (let i = 0; i < inputChunk.rowCount; i++) outputVector.setItem(i, basenameImpl(pathVec.getItem(i), suffixVec ? suffixVec.getItem(i) : undefined));\n outputVector.flush();\n },\n })\n );\n // segment() rewrites unspaced-script runs into the grapheme phrase FTS5's `_seg` sidecars need (text/segment.ts); this store's own\n // lexical index uses contains() instead and never calls this, but hand-written raw SQL naming it gets the real implementation, not a silent passthrough (PRINCIPLES: no-silent-modes).\n conn.registerScalarFunction(\n DuckDBScalarFunction.create({\n name: 'segment',\n parameterTypes: [DuckDBVarCharType.instance],\n returnType: DuckDBVarCharType.instance,\n mainFunction(_info, inputChunk, outputVector) {\n const textVec = inputChunk.getColumnVector(0);\n for (let i = 0; i < inputChunk.rowCount; i++) outputVector.setItem(i, segmentMatch(String(textVec.getItem(i) ?? '')));\n outputVector.flush();\n },\n })\n );\n}\n"],"names":["registerFunctions","conn","DuckDBIntegerType","DuckDBScalarFunction","DuckDBVarCharType","duckdbApi","registerScalarFunction","create","name","parameterTypes","instance","returnType","mainFunction","_info","inputChunk","outputVector","fieldVec","getColumnVector","valueVec","i","rowCount","setItem","hasImpl","getItem","flush","varArgsType","pathVec","suffixVec","columnCount","basenameImpl","undefined","textVec","segmentMatch","String"],"mappings":";;;;+BAOsBA;;;eAAAA;;;yBANO;8BACS;wBACZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAInB,SAAeA,kBAAkBC,IAAsB;;YACW,MAA/DC,mBAAmBC,sBAAsBC;;;;oBAAsB;;wBAAMC,IAAAA,mBAAS;;;oBAAf,OAAA,eAA/DH,oBAA+D,KAA/DA,mBAAmBC,uBAA4C,KAA5CA,sBAAsBC,oBAAsB,KAAtBA;oBACjDH,KAAKK,sBAAsB,CACzBH,qBAAqBI,MAAM,CAAC;wBAC1BC,MAAM;wBACNC,cAAc;4BAAGL,kBAAkBM,QAAQ;4BAAEN,kBAAkBM,QAAQ;;wBACvEC,YAAYT,kBAAkBQ,QAAQ;wBACtCE,cAAAA,SAAAA,aAAaC,KAAK,EAAEC,UAAU,EAAEC,YAAY;4BAC1C,IAAMC,WAAWF,WAAWG,eAAe,CAAC;4BAC5C,IAAMC,WAAWJ,WAAWG,eAAe,CAAC;4BAC5C,IAAK,IAAIE,IAAI,GAAGA,IAAIL,WAAWM,QAAQ,EAAED,IAAKJ,aAAaM,OAAO,CAACF,GAAGG,IAAAA,uBAAO,EAACN,SAASO,OAAO,CAACJ,IAAID,SAASK,OAAO,CAACJ;4BACpHJ,aAAaS,KAAK;wBACpB;oBACF;oBAEFvB,KAAKK,sBAAsB,CACzBH,qBAAqBI,MAAM,CAAC;wBAC1BC,MAAM;wBACNC,cAAc;4BAAGL,kBAAkBM,QAAQ;;wBAC3Ce,aAAarB,kBAAkBM,QAAQ;wBACvCC,YAAYP,kBAAkBM,QAAQ;wBACtCE,cAAAA,SAAAA,aAAaC,KAAK,EAAEC,UAAU,EAAEC,YAAY;4BAC1C,IAAMW,UAAUZ,WAAWG,eAAe,CAAC;4BAC3C,IAAMU,YAAYb,WAAWc,WAAW,GAAG,IAAId,WAAWG,eAAe,CAAC,KAAK;4BAC/E,IAAK,IAAIE,IAAI,GAAGA,IAAIL,WAAWM,QAAQ,EAAED,IAAKJ,aAAaM,OAAO,CAACF,GAAGU,IAAAA,4BAAY,EAACH,QAAQH,OAAO,CAACJ,IAAIQ,YAAYA,UAAUJ,OAAO,CAACJ,KAAKW;4BAC1If,aAAaS,KAAK;wBACpB;oBACF;oBAEF,mIAAmI;oBACnI,uLAAuL;oBACvLvB,KAAKK,sBAAsB,CACzBH,qBAAqBI,MAAM,CAAC;wBAC1BC,MAAM;wBACNC,cAAc;4BAAGL,kBAAkBM,QAAQ;;wBAC3CC,YAAYP,kBAAkBM,QAAQ;wBACtCE,cAAAA,SAAAA,aAAaC,KAAK,EAAEC,UAAU,EAAEC,YAAY;gCAEgDgB;4BAD1F,IAAMA,UAAUjB,WAAWG,eAAe,CAAC;4BAC3C,IAAK,IAAIE,IAAI,GAAGA,IAAIL,WAAWM,QAAQ,EAAED,IAAKJ,aAAaM,OAAO,CAACF,GAAGa,IAAAA,uBAAY,EAACC,QAAOF,mBAAAA,QAAQR,OAAO,CAACJ,gBAAhBY,8BAAAA,mBAAsB;4BAChHhB,aAAaS,KAAK;wBACpB;oBACF;;;;;;IAEJ"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/sql-functions.ts"],"sourcesContent":["import type { DuckDBConnection } from '@duckdb/node-api';\nimport { segmentMatch } from '../../text/segment.ts';\nimport { basenameImpl, hasImpl } from '../sql-functions.ts';\nimport { duckdbApi } from './native.ts';\n\n// Dynamic, not a top-level import: sqlite trees must never attempt to resolve this optional peer dependency (open.ts's connect()).\n// Goes through native.ts's shared duckdbApi(), not its own bare import, since a second independent lookup would hit Node's stale pre-install resolution miss.\nexport async function registerFunctions(conn: DuckDBConnection): Promise<void> {\n const { DuckDBIntegerType, DuckDBScalarFunction, DuckDBVarCharType } = await duckdbApi();\n conn.registerScalarFunction(\n DuckDBScalarFunction.create({\n name: 'has',\n parameterTypes: [DuckDBVarCharType.instance, DuckDBVarCharType.instance],\n returnType: DuckDBIntegerType.instance,\n mainFunction(_info, inputChunk, outputVector) {\n const fieldVec = inputChunk.getColumnVector(0);\n const valueVec = inputChunk.getColumnVector(1);\n for (let i = 0; i < inputChunk.rowCount; i++) outputVector.setItem(i, hasImpl(fieldVec.getItem(i), valueVec.getItem(i)));\n outputVector.flush();\n },\n })\n );\n conn.registerScalarFunction(\n DuckDBScalarFunction.create({\n name: 'basename',\n parameterTypes: [DuckDBVarCharType.instance],\n varArgsType: DuckDBVarCharType.instance,\n returnType: DuckDBVarCharType.instance,\n mainFunction(_info, inputChunk, outputVector) {\n const pathVec = inputChunk.getColumnVector(0);\n const suffixVec = inputChunk.columnCount > 1 ? inputChunk.getColumnVector(1) : null;\n for (let i = 0; i < inputChunk.rowCount; i++) outputVector.setItem(i, basenameImpl(pathVec.getItem(i), suffixVec ? suffixVec.getItem(i) : undefined));\n outputVector.flush();\n },\n })\n );\n // segment() rewrites unspaced-script runs into the grapheme phrase FTS5's `_seg` sidecars need (text/segment.ts); this store's own\n // lexical index uses contains() instead and never calls this, but hand-written raw SQL naming it gets the real implementation, not a silent passthrough (PRINCIPLES: no-silent-modes).\n conn.registerScalarFunction(\n DuckDBScalarFunction.create({\n name: 'segment',\n parameterTypes: [DuckDBVarCharType.instance],\n returnType: DuckDBVarCharType.instance,\n mainFunction(_info, inputChunk, outputVector) {\n const textVec = inputChunk.getColumnVector(0);\n for (let i = 0; i < inputChunk.rowCount; i++) outputVector.setItem(i, segmentMatch(String(textVec.getItem(i) ?? '')));\n outputVector.flush();\n },\n })\n );\n}\n"],"names":["registerFunctions","conn","DuckDBIntegerType","DuckDBScalarFunction","DuckDBVarCharType","duckdbApi","registerScalarFunction","create","name","parameterTypes","instance","returnType","mainFunction","_info","inputChunk","outputVector","fieldVec","getColumnVector","valueVec","i","rowCount","setItem","hasImpl","getItem","flush","varArgsType","pathVec","suffixVec","columnCount","basenameImpl","undefined","textVec","segmentMatch","String"],"mappings":";;;;+BAOsBA;;;eAAAA;;;yBANO;8BACS;wBACZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAInB,SAAeA,kBAAkBC,IAAsB;;YACW,MAA/DC,mBAAmBC,sBAAsBC;;;;oBAAsB;;wBAAMC,IAAAA,mBAAS;;;oBAAf,OAAA,eAA/DH,oBAA+D,KAA/DA,mBAAmBC,uBAA4C,KAA5CA,sBAAsBC,oBAAsB,KAAtBA;oBACjDH,KAAKK,sBAAsB,CACzBH,qBAAqBI,MAAM,CAAC;wBAC1BC,MAAM;wBACNC,cAAc;4BAAGL,kBAAkBM,QAAQ;4BAAEN,kBAAkBM,QAAQ;;wBACvEC,YAAYT,kBAAkBQ,QAAQ;wBACtCE,cAAAA,SAAAA,aAAaC,KAAK,EAAEC,UAAU,EAAEC,YAAY;4BAC1C,IAAMC,WAAWF,WAAWG,eAAe,CAAC;4BAC5C,IAAMC,WAAWJ,WAAWG,eAAe,CAAC;4BAC5C,IAAK,IAAIE,IAAI,GAAGA,IAAIL,WAAWM,QAAQ,EAAED,IAAKJ,aAAaM,OAAO,CAACF,GAAGG,IAAAA,uBAAO,EAACN,SAASO,OAAO,CAACJ,IAAID,SAASK,OAAO,CAACJ;4BACpHJ,aAAaS,KAAK;wBACpB;oBACF;oBAEFvB,KAAKK,sBAAsB,CACzBH,qBAAqBI,MAAM,CAAC;wBAC1BC,MAAM;wBACNC,cAAc;4BAAGL,kBAAkBM,QAAQ;;wBAC3Ce,aAAarB,kBAAkBM,QAAQ;wBACvCC,YAAYP,kBAAkBM,QAAQ;wBACtCE,cAAAA,SAAAA,aAAaC,KAAK,EAAEC,UAAU,EAAEC,YAAY;4BAC1C,IAAMW,UAAUZ,WAAWG,eAAe,CAAC;4BAC3C,IAAMU,YAAYb,WAAWc,WAAW,GAAG,IAAId,WAAWG,eAAe,CAAC,KAAK;4BAC/E,IAAK,IAAIE,IAAI,GAAGA,IAAIL,WAAWM,QAAQ,EAAED,IAAKJ,aAAaM,OAAO,CAACF,GAAGU,IAAAA,4BAAY,EAACH,QAAQH,OAAO,CAACJ,IAAIQ,YAAYA,UAAUJ,OAAO,CAACJ,KAAKW;4BAC1If,aAAaS,KAAK;wBACpB;oBACF;oBAEF,mIAAmI;oBACnI,uLAAuL;oBACvLvB,KAAKK,sBAAsB,CACzBH,qBAAqBI,MAAM,CAAC;wBAC1BC,MAAM;wBACNC,cAAc;4BAAGL,kBAAkBM,QAAQ;;wBAC3CC,YAAYP,kBAAkBM,QAAQ;wBACtCE,cAAAA,SAAAA,aAAaC,KAAK,EAAEC,UAAU,EAAEC,YAAY;gCAEgDgB;4BAD1F,IAAMA,UAAUjB,WAAWG,eAAe,CAAC;4BAC3C,IAAK,IAAIE,IAAI,GAAGA,IAAIL,WAAWM,QAAQ,EAAED,IAAKJ,aAAaM,OAAO,CAACF,GAAGa,IAAAA,uBAAY,EAACC,QAAOF,mBAAAA,QAAQR,OAAO,CAACJ,gBAAhBY,8BAAAA,mBAAsB;4BAChHhB,aAAaS,KAAK;wBACpB;oBACF;;;;;;IAEJ"}