sensemaking 0.26.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 (324) hide show
  1. package/README.md +36 -4
  2. package/dist/cjs/chunk/extract.js.map +1 -1
  3. package/dist/cjs/chunk/group.js.map +1 -1
  4. package/dist/cjs/chunk/index.js.map +1 -1
  5. package/dist/cjs/chunk/parse.js.map +1 -1
  6. package/dist/cjs/chunk/parser.js.map +1 -1
  7. package/dist/cjs/chunk/tokens.js.map +1 -1
  8. package/dist/cjs/chunk/version.js.map +1 -1
  9. package/dist/cjs/cli/build.js.map +1 -1
  10. package/dist/cjs/cli/download.js.map +1 -1
  11. package/dist/cjs/cli/index.d.cts +2 -2
  12. package/dist/cjs/cli/index.d.ts +2 -2
  13. package/dist/cjs/cli/index.js +2 -2
  14. package/dist/cjs/cli/index.js.map +1 -1
  15. package/dist/cjs/cli/init.js.map +1 -1
  16. package/dist/cjs/cli/map.js.map +1 -1
  17. package/dist/cjs/cli/named.js.map +1 -1
  18. package/dist/cjs/cli/path.js.map +1 -1
  19. package/dist/cjs/cli/peek.js +43 -2
  20. package/dist/cjs/cli/peek.js.map +1 -1
  21. package/dist/cjs/cli/related.js.map +1 -1
  22. package/dist/cjs/cli/search.js +38 -6
  23. package/dist/cjs/cli/search.js.map +1 -1
  24. package/dist/cjs/cli/shared.js.map +1 -1
  25. package/dist/cjs/cli/sql.js.map +1 -1
  26. package/dist/cjs/cli/status.js.map +1 -1
  27. package/dist/cjs/cli/watch.js.map +1 -1
  28. package/dist/cjs/cli.js.map +1 -1
  29. package/dist/cjs/commands/index.d.cts +2 -2
  30. package/dist/cjs/commands/index.d.ts +2 -2
  31. package/dist/cjs/commands/index.js.map +1 -1
  32. package/dist/cjs/commands/map.js.map +1 -1
  33. package/dist/cjs/commands/path.js.map +1 -1
  34. package/dist/cjs/commands/peek.d.cts +9 -1
  35. package/dist/cjs/commands/peek.d.ts +9 -1
  36. package/dist/cjs/commands/peek.js +72 -29
  37. package/dist/cjs/commands/peek.js.map +1 -1
  38. package/dist/cjs/commands/related.js.map +1 -1
  39. package/dist/cjs/commands/scope.js.map +1 -1
  40. package/dist/cjs/commands/search.d.cts +6 -2
  41. package/dist/cjs/commands/search.d.ts +6 -2
  42. package/dist/cjs/commands/search.js +31 -4
  43. package/dist/cjs/commands/search.js.map +1 -1
  44. package/dist/cjs/commands/signals.d.cts +19 -5
  45. package/dist/cjs/commands/signals.d.ts +19 -5
  46. package/dist/cjs/commands/signals.js +64 -11
  47. package/dist/cjs/commands/signals.js.map +1 -1
  48. package/dist/cjs/commands/snapshot.js.map +1 -1
  49. package/dist/cjs/commands/status.js.map +1 -1
  50. package/dist/cjs/config/access.js.map +1 -1
  51. package/dist/cjs/config/index.js.map +1 -1
  52. package/dist/cjs/config/load.js +6 -0
  53. package/dist/cjs/config/load.js.map +1 -1
  54. package/dist/cjs/config/resolve.js.map +1 -1
  55. package/dist/cjs/config/signals.js.map +1 -1
  56. package/dist/cjs/config/types.js.map +1 -1
  57. package/dist/cjs/config/validate.js.map +1 -1
  58. package/dist/cjs/embed/cohere.js.map +1 -1
  59. package/dist/cjs/embed/distribution.js.map +1 -1
  60. package/dist/cjs/embed/endpoint.js.map +1 -1
  61. package/dist/cjs/embed/handoff.js.map +1 -1
  62. package/dist/cjs/embed/http.js.map +1 -1
  63. package/dist/cjs/embed/identity.js.map +1 -1
  64. package/dist/cjs/embed/langfit.js.map +1 -1
  65. package/dist/cjs/embed/languages.js.map +1 -1
  66. package/dist/cjs/embed/openai.js.map +1 -1
  67. package/dist/cjs/embed/query.js.map +1 -1
  68. package/dist/cjs/embed/registry.js.map +1 -1
  69. package/dist/cjs/embed/static.js.map +1 -1
  70. package/dist/cjs/embed/store.js.map +1 -1
  71. package/dist/cjs/embed/types.js.map +1 -1
  72. package/dist/cjs/errors.js.map +1 -1
  73. package/dist/cjs/features/embed.js.map +1 -1
  74. package/dist/cjs/features/fences.js.map +1 -1
  75. package/dist/cjs/features/index.js.map +1 -1
  76. package/dist/cjs/features/links.js.map +1 -1
  77. package/dist/cjs/features/rank.js.map +1 -1
  78. package/dist/cjs/features/sections.js.map +1 -1
  79. package/dist/cjs/features/tags.js.map +1 -1
  80. package/dist/cjs/graph/graph.js.map +1 -1
  81. package/dist/cjs/graph/traverse.js.map +1 -1
  82. package/dist/cjs/index.d.cts +1 -1
  83. package/dist/cjs/index.d.ts +1 -1
  84. package/dist/cjs/index.js.map +1 -1
  85. package/dist/cjs/lib/atomic-write.js.map +1 -1
  86. package/dist/cjs/lib/guarded-tick.js.map +1 -1
  87. package/dist/cjs/lib/serial-query.js.map +1 -1
  88. package/dist/cjs/lib/watch-notification.js.map +1 -1
  89. package/dist/cjs/lib/worker-file.js.map +1 -1
  90. package/dist/cjs/output/column-hint.js.map +1 -1
  91. package/dist/cjs/output/output.js.map +1 -1
  92. package/dist/cjs/output/progress.js.map +1 -1
  93. package/dist/cjs/output/search-error.js.map +1 -1
  94. package/dist/cjs/scan/frontmatter.js.map +1 -1
  95. package/dist/cjs/scan/index.js.map +1 -1
  96. package/dist/cjs/scan/list.js.map +1 -1
  97. package/dist/cjs/scan/pool.js.map +1 -1
  98. package/dist/cjs/scan/reparse.js.map +1 -1
  99. package/dist/cjs/scan/worker-error.js.map +1 -1
  100. package/dist/cjs/store/batch.js.map +1 -1
  101. package/dist/cjs/store/builder.js.map +1 -1
  102. package/dist/cjs/store/cache.js.map +1 -1
  103. package/dist/cjs/store/duckdb/batch.js.map +1 -1
  104. package/dist/cjs/store/duckdb/connection.js.map +1 -1
  105. package/dist/cjs/store/duckdb/fieldStats.js.map +1 -1
  106. package/dist/cjs/store/duckdb/lexical.d.cts +1 -6
  107. package/dist/cjs/store/duckdb/lexical.d.ts +1 -6
  108. package/dist/cjs/store/duckdb/lexical.js +28 -39
  109. package/dist/cjs/store/duckdb/lexical.js.map +1 -1
  110. package/dist/cjs/store/duckdb/native.d.cts +1 -2
  111. package/dist/cjs/store/duckdb/native.d.ts +1 -2
  112. package/dist/cjs/store/duckdb/native.js +1 -6
  113. package/dist/cjs/store/duckdb/native.js.map +1 -1
  114. package/dist/cjs/store/duckdb/open.js.map +1 -1
  115. package/dist/cjs/store/duckdb/ordered-bm25.d.cts +3 -16
  116. package/dist/cjs/store/duckdb/ordered-bm25.d.ts +3 -16
  117. package/dist/cjs/store/duckdb/ordered-bm25.js +27 -79
  118. package/dist/cjs/store/duckdb/ordered-bm25.js.map +1 -1
  119. package/dist/cjs/store/duckdb/reconcile.js.map +1 -1
  120. package/dist/cjs/store/duckdb/sql-functions.js.map +1 -1
  121. package/dist/cjs/store/duckdb/store.js.map +1 -1
  122. package/dist/cjs/store/duckdb/vectors.js.map +1 -1
  123. package/dist/cjs/store/embed-scope.js.map +1 -1
  124. package/dist/cjs/store/feature-scope.js.map +1 -1
  125. package/dist/cjs/store/index.js.map +1 -1
  126. package/dist/cjs/store/lock-wait.js.map +1 -1
  127. package/dist/cjs/store/native.js.map +1 -1
  128. package/dist/cjs/store/open.js.map +1 -1
  129. package/dist/cjs/store/preset-scope.js.map +1 -1
  130. package/dist/cjs/store/readiness.js.map +1 -1
  131. package/dist/cjs/store/reconcile.js.map +1 -1
  132. package/dist/cjs/store/shared.js.map +1 -1
  133. package/dist/cjs/store/signature.js.map +1 -1
  134. package/dist/cjs/store/sql-functions.js.map +1 -1
  135. package/dist/cjs/store/sqlite/connection.js.map +1 -1
  136. package/dist/cjs/store/sqlite/fieldStats.js.map +1 -1
  137. package/dist/cjs/store/sqlite/lexical.js.map +1 -1
  138. package/dist/cjs/store/sqlite/open.js.map +1 -1
  139. package/dist/cjs/store/sqlite/reconcile.js.map +1 -1
  140. package/dist/cjs/store/sqlite/sql-functions.js.map +1 -1
  141. package/dist/cjs/store/sqlite/store.js.map +1 -1
  142. package/dist/cjs/store/sqlite/vectors.js.map +1 -1
  143. package/dist/cjs/store/stages.js.map +1 -1
  144. package/dist/cjs/store/transaction.js.map +1 -1
  145. package/dist/cjs/store/turso/connection.js.map +1 -1
  146. package/dist/cjs/store/turso/fieldStats.js.map +1 -1
  147. package/dist/cjs/store/turso/lexical-text.js.map +1 -1
  148. package/dist/cjs/store/turso/lexical.js.map +1 -1
  149. package/dist/cjs/store/turso/native.js.map +1 -1
  150. package/dist/cjs/store/turso/open.js.map +1 -1
  151. package/dist/cjs/store/turso/reconcile.js.map +1 -1
  152. package/dist/cjs/store/turso/sql-functions.js.map +1 -1
  153. package/dist/cjs/store/turso/store.js.map +1 -1
  154. package/dist/cjs/store/turso/vectors.js.map +1 -1
  155. package/dist/cjs/store/types.js.map +1 -1
  156. package/dist/cjs/store/vectors.js.map +1 -1
  157. package/dist/cjs/text/segment.js.map +1 -1
  158. package/dist/cjs/text/strip.js.map +1 -1
  159. package/dist/cjs/watch-claim.js.map +1 -1
  160. package/dist/cjs/watch.js.map +1 -1
  161. package/dist/cjs/workers/parse.js.map +1 -1
  162. package/dist/cjs/workers/watch-heartbeat.js.map +1 -1
  163. package/dist/esm/chunk/extract.js.map +1 -1
  164. package/dist/esm/chunk/group.js.map +1 -1
  165. package/dist/esm/chunk/index.js.map +1 -1
  166. package/dist/esm/chunk/parse.js.map +1 -1
  167. package/dist/esm/chunk/parser.js.map +1 -1
  168. package/dist/esm/chunk/tokens.js.map +1 -1
  169. package/dist/esm/chunk/types.js.map +1 -1
  170. package/dist/esm/chunk/version.js.map +1 -1
  171. package/dist/esm/cli/build.js.map +1 -1
  172. package/dist/esm/cli/download.js.map +1 -1
  173. package/dist/esm/cli/index.d.ts +2 -2
  174. package/dist/esm/cli/index.js +2 -2
  175. package/dist/esm/cli/index.js.map +1 -1
  176. package/dist/esm/cli/init.js.map +1 -1
  177. package/dist/esm/cli/map.js.map +1 -1
  178. package/dist/esm/cli/named.js.map +1 -1
  179. package/dist/esm/cli/path.js.map +1 -1
  180. package/dist/esm/cli/peek.js +20 -2
  181. package/dist/esm/cli/peek.js.map +1 -1
  182. package/dist/esm/cli/related.js.map +1 -1
  183. package/dist/esm/cli/search.js +12 -2
  184. package/dist/esm/cli/search.js.map +1 -1
  185. package/dist/esm/cli/shared.js.map +1 -1
  186. package/dist/esm/cli/sql.js.map +1 -1
  187. package/dist/esm/cli/status.js.map +1 -1
  188. package/dist/esm/cli/types.js.map +1 -1
  189. package/dist/esm/cli/watch.js.map +1 -1
  190. package/dist/esm/cli.js.map +1 -1
  191. package/dist/esm/commands/index.d.ts +2 -2
  192. package/dist/esm/commands/index.js.map +1 -1
  193. package/dist/esm/commands/map.js.map +1 -1
  194. package/dist/esm/commands/path.js.map +1 -1
  195. package/dist/esm/commands/peek.d.ts +9 -1
  196. package/dist/esm/commands/peek.js +26 -12
  197. package/dist/esm/commands/peek.js.map +1 -1
  198. package/dist/esm/commands/related.js.map +1 -1
  199. package/dist/esm/commands/scope.js.map +1 -1
  200. package/dist/esm/commands/search.d.ts +6 -2
  201. package/dist/esm/commands/search.js +11 -3
  202. package/dist/esm/commands/search.js.map +1 -1
  203. package/dist/esm/commands/signals.d.ts +19 -5
  204. package/dist/esm/commands/signals.js +64 -14
  205. package/dist/esm/commands/signals.js.map +1 -1
  206. package/dist/esm/commands/snapshot.js.map +1 -1
  207. package/dist/esm/commands/status.js.map +1 -1
  208. package/dist/esm/config/access.js.map +1 -1
  209. package/dist/esm/config/index.js.map +1 -1
  210. package/dist/esm/config/load.js +6 -0
  211. package/dist/esm/config/load.js.map +1 -1
  212. package/dist/esm/config/resolve.js.map +1 -1
  213. package/dist/esm/config/signals.js.map +1 -1
  214. package/dist/esm/config/types.js.map +1 -1
  215. package/dist/esm/config/validate.js.map +1 -1
  216. package/dist/esm/embed/cohere.js.map +1 -1
  217. package/dist/esm/embed/distribution.js.map +1 -1
  218. package/dist/esm/embed/endpoint.js.map +1 -1
  219. package/dist/esm/embed/handoff.js.map +1 -1
  220. package/dist/esm/embed/http.js.map +1 -1
  221. package/dist/esm/embed/identity.js.map +1 -1
  222. package/dist/esm/embed/langfit.js.map +1 -1
  223. package/dist/esm/embed/languages.js.map +1 -1
  224. package/dist/esm/embed/openai.js.map +1 -1
  225. package/dist/esm/embed/query.js.map +1 -1
  226. package/dist/esm/embed/registry.js.map +1 -1
  227. package/dist/esm/embed/static.js.map +1 -1
  228. package/dist/esm/embed/store.js.map +1 -1
  229. package/dist/esm/embed/types.js.map +1 -1
  230. package/dist/esm/errors.js.map +1 -1
  231. package/dist/esm/features/embed.js.map +1 -1
  232. package/dist/esm/features/fences.js.map +1 -1
  233. package/dist/esm/features/index.js.map +1 -1
  234. package/dist/esm/features/links.js.map +1 -1
  235. package/dist/esm/features/rank.js.map +1 -1
  236. package/dist/esm/features/sections.js.map +1 -1
  237. package/dist/esm/features/tags.js.map +1 -1
  238. package/dist/esm/features/types.js.map +1 -1
  239. package/dist/esm/graph/graph.js.map +1 -1
  240. package/dist/esm/graph/traverse.js.map +1 -1
  241. package/dist/esm/index.d.ts +1 -1
  242. package/dist/esm/index.js.map +1 -1
  243. package/dist/esm/lib/atomic-write.js.map +1 -1
  244. package/dist/esm/lib/guarded-tick.js.map +1 -1
  245. package/dist/esm/lib/serial-query.js.map +1 -1
  246. package/dist/esm/lib/watch-notification.js.map +1 -1
  247. package/dist/esm/lib/worker-file.js.map +1 -1
  248. package/dist/esm/output/column-hint.js.map +1 -1
  249. package/dist/esm/output/output.js.map +1 -1
  250. package/dist/esm/output/progress.js.map +1 -1
  251. package/dist/esm/output/search-error.js.map +1 -1
  252. package/dist/esm/scan/frontmatter.js.map +1 -1
  253. package/dist/esm/scan/index.js.map +1 -1
  254. package/dist/esm/scan/list.js.map +1 -1
  255. package/dist/esm/scan/pool.js.map +1 -1
  256. package/dist/esm/scan/reparse.js.map +1 -1
  257. package/dist/esm/scan/worker-error.js.map +1 -1
  258. package/dist/esm/store/batch.js.map +1 -1
  259. package/dist/esm/store/builder.js.map +1 -1
  260. package/dist/esm/store/cache.js.map +1 -1
  261. package/dist/esm/store/duckdb/batch.js.map +1 -1
  262. package/dist/esm/store/duckdb/connection.js.map +1 -1
  263. package/dist/esm/store/duckdb/fieldStats.js.map +1 -1
  264. package/dist/esm/store/duckdb/lexical.d.ts +1 -6
  265. package/dist/esm/store/duckdb/lexical.js +13 -17
  266. package/dist/esm/store/duckdb/lexical.js.map +1 -1
  267. package/dist/esm/store/duckdb/native.d.ts +1 -2
  268. package/dist/esm/store/duckdb/native.js +1 -3
  269. package/dist/esm/store/duckdb/native.js.map +1 -1
  270. package/dist/esm/store/duckdb/open.js.map +1 -1
  271. package/dist/esm/store/duckdb/ordered-bm25.d.ts +3 -16
  272. package/dist/esm/store/duckdb/ordered-bm25.js +18 -54
  273. package/dist/esm/store/duckdb/ordered-bm25.js.map +1 -1
  274. package/dist/esm/store/duckdb/reconcile.js.map +1 -1
  275. package/dist/esm/store/duckdb/sql-functions.js.map +1 -1
  276. package/dist/esm/store/duckdb/store.js.map +1 -1
  277. package/dist/esm/store/duckdb/vectors.js.map +1 -1
  278. package/dist/esm/store/embed-scope.js.map +1 -1
  279. package/dist/esm/store/feature-scope.js.map +1 -1
  280. package/dist/esm/store/index.js.map +1 -1
  281. package/dist/esm/store/lock-wait.js.map +1 -1
  282. package/dist/esm/store/native.js.map +1 -1
  283. package/dist/esm/store/open.js.map +1 -1
  284. package/dist/esm/store/preset-scope.js.map +1 -1
  285. package/dist/esm/store/readiness.js.map +1 -1
  286. package/dist/esm/store/reconcile.js.map +1 -1
  287. package/dist/esm/store/shared.js.map +1 -1
  288. package/dist/esm/store/signature.js.map +1 -1
  289. package/dist/esm/store/sql-functions.js.map +1 -1
  290. package/dist/esm/store/sqlite/connection.js.map +1 -1
  291. package/dist/esm/store/sqlite/fieldStats.js.map +1 -1
  292. package/dist/esm/store/sqlite/lexical.js.map +1 -1
  293. package/dist/esm/store/sqlite/open.js.map +1 -1
  294. package/dist/esm/store/sqlite/reconcile.js.map +1 -1
  295. package/dist/esm/store/sqlite/sql-functions.js.map +1 -1
  296. package/dist/esm/store/sqlite/store.js.map +1 -1
  297. package/dist/esm/store/sqlite/vectors.js.map +1 -1
  298. package/dist/esm/store/stages.js.map +1 -1
  299. package/dist/esm/store/transaction.js.map +1 -1
  300. package/dist/esm/store/turso/connection.js.map +1 -1
  301. package/dist/esm/store/turso/fieldStats.js.map +1 -1
  302. package/dist/esm/store/turso/lexical-text.js.map +1 -1
  303. package/dist/esm/store/turso/lexical.js.map +1 -1
  304. package/dist/esm/store/turso/native.js.map +1 -1
  305. package/dist/esm/store/turso/open.js.map +1 -1
  306. package/dist/esm/store/turso/reconcile.js.map +1 -1
  307. package/dist/esm/store/turso/sql-functions.js.map +1 -1
  308. package/dist/esm/store/turso/store.js.map +1 -1
  309. package/dist/esm/store/turso/vectors.js.map +1 -1
  310. package/dist/esm/store/types.js.map +1 -1
  311. package/dist/esm/store/vectors.js.map +1 -1
  312. package/dist/esm/text/segment.js.map +1 -1
  313. package/dist/esm/text/strip.js.map +1 -1
  314. package/dist/esm/watch-claim.js.map +1 -1
  315. package/dist/esm/watch.js.map +1 -1
  316. package/dist/esm/workers/parse.js.map +1 -1
  317. package/dist/esm/workers/watch-heartbeat.js.map +1 -1
  318. package/package.json +2 -2
  319. package/skills/sense/EXAMPLES.md +3 -3
  320. package/skills/sense/SKILL.md +7 -1
  321. package/skills/sense/references/search.md +17 -1
  322. package/skills/sense/references/sql.md +1 -1
  323. package/skills/sense/references/terminology.md +32 -0
  324. package/skills/sense-setup/references/store-benchmarks.md +5 -5
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/duckdb/connection.ts"],"sourcesContent":["import type { DuckDBConnection, DuckDBPreparedStatement, DuckDBValue } from '@duckdb/node-api';\nimport { quoteIdent } from '../shared.ts';\nimport { withTransaction } from '../transaction.ts';\nimport type { Connection, RunResult, Statement } from '../types.ts';\nimport { rewriteBatch } from './batch.ts';\nimport { duckdbApi } from './native.ts';\n\n// getRowObjectsJS returns INT64 columns as BigInt regardless of magnitude, while sqlite's small\n// ints are numbers and consumers assume number; in-range values convert here, out-of-range stays BigInt.\nconst MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);\nexport function storeValueToJs(value: unknown): unknown {\n return typeof value === 'bigint' && value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value;\n}\nexport function storeRowToJs(row: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(row)) out[key] = storeValueToJs(value);\n return out;\n}\n\n// @duckdb/node-api only destroys a prepared statement when its connection closes, but a connection can stay open for a whole `sense watch` session.\n// Statement has no dispose (callers reuse one instance across several calls), so this FinalizationRegistry reclaims it once nothing references the wrapper.\nconst preparedFinalizer = new FinalizationRegistry<DuckDBPreparedStatement>((prepared) => {\n prepared.destroySync();\n});\n\n// Wraps one already-prepared DuckDB statement: prepare() is the only async step, so run/get/all rebind and\n// re-execute the same native statement, matching how callers like graph/traverse.ts's ring loop reuse one Statement across several calls.\nclass DuckdbStatement implements Statement {\n private prepared: DuckDBPreparedStatement;\n\n constructor(prepared: DuckDBPreparedStatement) {\n this.prepared = prepared;\n preparedFinalizer.register(this, prepared);\n }\n\n async run(...params: unknown[]): Promise<RunResult> {\n if (params.length > 0) this.prepared.bind(params as DuckDBValue[]);\n const result = await this.prepared.run();\n return { changes: result.rowsChanged, lastInsertRowid: 0 };\n }\n\n async get(...params: unknown[]): Promise<unknown> {\n const rows = await this.all(...params);\n return rows[0];\n }\n\n async all(...params: unknown[]): Promise<unknown[]> {\n if (params.length > 0) this.prepared.bind(params as DuckDBValue[]);\n const reader = await this.prepared.runAndReadAll();\n return (reader.getRowObjectsJS() as Array<Record<string, unknown>>).map(storeRowToJs);\n }\n\n async *iterate(...params: unknown[]): AsyncIterable<unknown> {\n // Never called on the portable Connection/Statement surface today (only Store.raw streams);\n // materializing keeps this a correct, if eager, AsyncIterable.\n yield* await this.all(...params);\n }\n\n columns(): Array<{ name: string }> {\n const out: Array<{ name: string }> = [];\n for (let i = 0; i < this.prepared.columnCount; i++) out.push({ name: this.prepared.columnName(i) });\n return out;\n }\n\n setReadBigInts(_enabled: boolean): void {\n // No-op: in-range ints are already numbers here (storeRowToJs converts what getRowObjectsJS\n // hands back as BigInt), so the node:sqlite throw-at-step-time problem does not exist.\n }\n}\n\n// Adds the native DuckDBConnection to the portable Connection, so duckdb's own dialect code\n// (reconcile.ts's insertNew) can reach createAppender(); sqlite/turso have no such member.\nexport interface DuckdbConnection extends Connection {\n readonly duckdb: DuckDBConnection;\n}\n\nexport function createConnection(duckdb: DuckDBConnection): DuckdbConnection {\n const conn: DuckdbConnection = {\n duckdb,\n async exec(sql: string): Promise<void> {\n await duckdb.run(sql);\n },\n async prepare(sql: string): Promise<Statement> {\n return new DuckdbStatement(await duckdb.prepare(sql));\n },\n // The appender writes columnar vectors with no per-parameter binding, which is the cost\n // runBatch pays: measured 7.2x on frontmatter at 6,566 rows. Alignment is against the table's\n // own physical column order, read fresh, so a column the caller does not write (a\n // feature-owned \"_rank\", say) takes appendDefault() rather than shifting every value one slot.\n async appendRows(table: string, columns: string[], rows: unknown[][]): Promise<void> {\n if (rows.length === 0) return;\n const { variantValue } = await duckdbApi();\n const infoStmt = await conn.prepare(`PRAGMA table_info(${quoteIdent(table)})`);\n const physical = (await infoStmt.all()) as Array<{ name: string; type: string }>;\n const rowIndexOf = new Map(columns.map((name, i) => [name, i]));\n\n await withTransaction(conn, async () => {\n const appender = await duckdb.createAppender(table);\n const errors: unknown[] = [];\n try {\n for (const row of rows) {\n for (const column of physical) {\n const idx = rowIndexOf.get(column.name);\n const value = idx === undefined ? undefined : row[idx];\n if (idx === undefined) appender.appendDefault();\n else if (value === null || value === undefined) appender.appendNull();\n // VARIANT is frontmatter's dynamic columns only; every other table is statically\n // typed, and appendValue is what preserves those types.\n else if (column.type === 'VARIANT') appender.appendVariant(variantValue(value as DuckDBValue));\n else appender.appendValue(value as DuckDBValue);\n }\n appender.endRow();\n }\n appender.flushSync();\n } catch (err) {\n errors.push(err);\n }\n try {\n appender.closeSync();\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, errors[0] instanceof Error ? `${errors[0].message}; appender cleanup also failed` : 'DuckDB appender execution and cleanup failed');\n });\n },\n // One crossing regardless of row count: rewriteBatch folds recognized shapes into a multi-row statement (batch.ts),\n // else falls back to a bind-and-run loop, one call either way. Joins the caller's transaction when there is one, else opens its own.\n async runBatch(sql: string, paramRows: unknown[][]): Promise<void> {\n if (paramRows.length === 0) return;\n await withTransaction(conn, async () => {\n const rewritten = rewriteBatch(sql, paramRows.length);\n if (rewritten) {\n const stmt = await duckdb.prepare(rewritten.sql);\n try {\n stmt.bind(paramRows.flat() as DuckDBValue[]);\n await stmt.run();\n } finally {\n stmt.destroySync();\n }\n return;\n }\n const stmt = await duckdb.prepare(sql);\n try {\n for (const row of paramRows) {\n stmt.bind(row as DuckDBValue[]);\n await stmt.run();\n }\n } finally {\n stmt.destroySync();\n }\n });\n },\n };\n return conn;\n}\n"],"names":["createConnection","storeRowToJs","storeValueToJs","MAX_SAFE","BigInt","Number","MAX_SAFE_INTEGER","value","row","out","Object","entries","key","preparedFinalizer","FinalizationRegistry","prepared","destroySync","DuckdbStatement","register","run","params","result","length","bind","changes","rowsChanged","lastInsertRowid","get","rows","all","reader","runAndReadAll","getRowObjectsJS","map","iterate","columns","i","columnCount","push","name","columnName","setReadBigInts","_enabled","duckdb","conn","exec","sql","prepare","appendRows","table","variantValue","infoStmt","physical","rowIndexOf","duckdbApi","quoteIdent","Map","withTransaction","appender","errors","column","idx","createAppender","undefined","appendDefault","appendNull","type","appendVariant","appendValue","endRow","flushSync","err","closeSync","AggregateError","Error","message","runBatch","paramRows","rewritten","stmt","rewriteBatch","flat"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/connection.ts"],"sourcesContent":["import type { DuckDBConnection, DuckDBPreparedStatement, DuckDBValue } from '@duckdb/node-api';\nimport { quoteIdent } from '../shared.ts';\nimport { withTransaction } from '../transaction.ts';\nimport type { Connection, RunResult, Statement } from '../types.ts';\nimport { rewriteBatch } from './batch.ts';\nimport { duckdbApi } from './native.ts';\n\n// getRowObjectsJS returns INT64 columns as BigInt regardless of magnitude, while sqlite's small\n// ints are numbers and consumers assume number; in-range values convert here, out-of-range stays BigInt.\nconst MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);\nexport function storeValueToJs(value: unknown): unknown {\n return typeof value === 'bigint' && value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value;\n}\nexport function storeRowToJs(row: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(row)) out[key] = storeValueToJs(value);\n return out;\n}\n\n// @duckdb/node-api only destroys a prepared statement when its connection closes, but a connection can stay open for a whole `sense watch` session.\n// Statement has no dispose (callers reuse one instance across several calls), so this FinalizationRegistry reclaims it once nothing references the wrapper.\nconst preparedFinalizer = new FinalizationRegistry<DuckDBPreparedStatement>((prepared) => {\n prepared.destroySync();\n});\n\n// Wraps one already-prepared DuckDB statement: prepare() is the only async step, so run/get/all rebind and\n// re-execute the same native statement, matching how callers like graph/traverse.ts's ring loop reuse one Statement across several calls.\nclass DuckdbStatement implements Statement {\n private prepared: DuckDBPreparedStatement;\n\n constructor(prepared: DuckDBPreparedStatement) {\n this.prepared = prepared;\n preparedFinalizer.register(this, prepared);\n }\n\n async run(...params: unknown[]): Promise<RunResult> {\n if (params.length > 0) this.prepared.bind(params as DuckDBValue[]);\n const result = await this.prepared.run();\n return { changes: result.rowsChanged, lastInsertRowid: 0 };\n }\n\n async get(...params: unknown[]): Promise<unknown> {\n const rows = await this.all(...params);\n return rows[0];\n }\n\n async all(...params: unknown[]): Promise<unknown[]> {\n if (params.length > 0) this.prepared.bind(params as DuckDBValue[]);\n const reader = await this.prepared.runAndReadAll();\n return (reader.getRowObjectsJS() as Array<Record<string, unknown>>).map(storeRowToJs);\n }\n\n async *iterate(...params: unknown[]): AsyncIterable<unknown> {\n // Never called on the portable Connection/Statement surface today (only Store.raw streams);\n // materializing keeps this a correct, if eager, AsyncIterable.\n yield* await this.all(...params);\n }\n\n columns(): Array<{ name: string }> {\n const out: Array<{ name: string }> = [];\n for (let i = 0; i < this.prepared.columnCount; i++) out.push({ name: this.prepared.columnName(i) });\n return out;\n }\n\n setReadBigInts(_enabled: boolean): void {\n // No-op: in-range ints are already numbers here (storeRowToJs converts what getRowObjectsJS\n // hands back as BigInt), so the node:sqlite throw-at-step-time problem does not exist.\n }\n}\n\n// Adds the native DuckDBConnection to the portable Connection, so duckdb's own dialect code\n// (reconcile.ts's insertNew) can reach createAppender(); sqlite/turso have no such member.\nexport interface DuckdbConnection extends Connection {\n readonly duckdb: DuckDBConnection;\n}\n\nexport function createConnection(duckdb: DuckDBConnection): DuckdbConnection {\n const conn: DuckdbConnection = {\n duckdb,\n async exec(sql: string): Promise<void> {\n await duckdb.run(sql);\n },\n async prepare(sql: string): Promise<Statement> {\n return new DuckdbStatement(await duckdb.prepare(sql));\n },\n // The appender writes columnar vectors with no per-parameter binding, which is the cost\n // runBatch pays: measured 7.2x on frontmatter at 6,566 rows. Alignment is against the table's\n // own physical column order, read fresh, so a column the caller does not write (a\n // feature-owned \"_rank\", say) takes appendDefault() rather than shifting every value one slot.\n async appendRows(table: string, columns: string[], rows: unknown[][]): Promise<void> {\n if (rows.length === 0) return;\n const { variantValue } = await duckdbApi();\n const infoStmt = await conn.prepare(`PRAGMA table_info(${quoteIdent(table)})`);\n const physical = (await infoStmt.all()) as Array<{ name: string; type: string }>;\n const rowIndexOf = new Map(columns.map((name, i) => [name, i]));\n\n await withTransaction(conn, async () => {\n const appender = await duckdb.createAppender(table);\n const errors: unknown[] = [];\n try {\n for (const row of rows) {\n for (const column of physical) {\n const idx = rowIndexOf.get(column.name);\n const value = idx === undefined ? undefined : row[idx];\n if (idx === undefined) appender.appendDefault();\n else if (value === null || value === undefined) appender.appendNull();\n // VARIANT is frontmatter's dynamic columns only; every other table is statically\n // typed, and appendValue is what preserves those types.\n else if (column.type === 'VARIANT') appender.appendVariant(variantValue(value as DuckDBValue));\n else appender.appendValue(value as DuckDBValue);\n }\n appender.endRow();\n }\n appender.flushSync();\n } catch (err) {\n errors.push(err);\n }\n try {\n appender.closeSync();\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, errors[0] instanceof Error ? `${errors[0].message}; appender cleanup also failed` : 'DuckDB appender execution and cleanup failed');\n });\n },\n // One crossing regardless of row count: rewriteBatch folds recognized shapes into a multi-row statement (batch.ts),\n // else falls back to a bind-and-run loop, one call either way. Joins the caller's transaction when there is one, else opens its own.\n async runBatch(sql: string, paramRows: unknown[][]): Promise<void> {\n if (paramRows.length === 0) return;\n await withTransaction(conn, async () => {\n const rewritten = rewriteBatch(sql, paramRows.length);\n if (rewritten) {\n const stmt = await duckdb.prepare(rewritten.sql);\n try {\n stmt.bind(paramRows.flat() as DuckDBValue[]);\n await stmt.run();\n } finally {\n stmt.destroySync();\n }\n return;\n }\n const stmt = await duckdb.prepare(sql);\n try {\n for (const row of paramRows) {\n stmt.bind(row as DuckDBValue[]);\n await stmt.run();\n }\n } finally {\n stmt.destroySync();\n }\n });\n },\n };\n return conn;\n}\n"],"names":["createConnection","storeRowToJs","storeValueToJs","MAX_SAFE","BigInt","Number","MAX_SAFE_INTEGER","value","row","out","Object","entries","key","preparedFinalizer","FinalizationRegistry","prepared","destroySync","DuckdbStatement","register","run","params","result","length","bind","changes","rowsChanged","lastInsertRowid","get","rows","all","reader","runAndReadAll","getRowObjectsJS","map","iterate","columns","i","columnCount","push","name","columnName","setReadBigInts","_enabled","duckdb","conn","exec","sql","prepare","appendRows","table","variantValue","infoStmt","physical","rowIndexOf","duckdbApi","quoteIdent","Map","withTransaction","appender","errors","column","idx","createAppender","undefined","appendDefault","appendNull","type","appendVariant","appendValue","endRow","flushSync","err","closeSync","AggregateError","Error","message","runBatch","paramRows","rewritten","stmt","rewriteBatch","flat"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/duckdb/fieldStats.ts"],"sourcesContent":["import { quoteIdent } from '../shared.ts';\nimport type { Connection, FieldStat } from '../types.ts';\n\n// DuckDB's frontmatter columns are VARIANT (reconcile.ts), so typeof() always reports VARIANT; variant_typeof() reports the boxed native\n// type instead -- INT128, DOUBLE, VARCHAR, or a literal's narrower type like DECIMAL(p, s) -- mapped onto sqlite/turso's integer/real/text vocabulary; an unrecognized name throws (no-silent-modes).\nfunction classifyVariantType(name: string, field: string): 'integer' | 'real' | 'text' {\n if (/^U?INT\\d+$/.test(name)) return 'integer';\n if (name === 'FLOAT' || name === 'DOUBLE' || name.startsWith('DECIMAL(')) return 'real';\n if (name === 'VARCHAR') return 'text';\n throw new Error(`duckdb: variant_typeof() returned unrecognized type \"${name}\" for column \"${field}\"`);\n}\n\n// duckdb degrades superlinearly in the number of string_agg(DISTINCT variant_typeof()) aggregates\n// per projection, not the column width (301 columns: 1148ms unchunked vs 88ms at chunk size 25);\n// 16 sits inside the measured flat 10-25 range. sqlite/turso need none of this: GROUP_CONCAT over\n// 300 columns runs in 7ms.\nconst AGGREGATES_PER_QUERY = 16;\n\n// COUNT + string_agg(DISTINCT variant_typeof()) per column keeps this O(columns), not O(rows x columns).\n// '|' is the separator, not ',': DECIMAL's display name (\"DECIMAL(4, 2)\") contains a comma.\nexport async function fieldStats(conn: Connection, columns: string[], scopeWhere: string): Promise<FieldStat[]> {\n const stats: FieldStat[] = [];\n for (let start = 0; start < columns.length; start += AGGREGATES_PER_QUERY) {\n const chunk = columns.slice(start, start + AGGREGATES_PER_QUERY);\n const exprs = chunk.map((name, i) => {\n const quoted = quoteIdent(name);\n return `COUNT(${quoted}) AS n${i}, string_agg(DISTINCT variant_typeof(${quoted}), '|') FILTER (WHERE ${quoted} IS NOT NULL) AS t${i}`;\n });\n const stmt = await conn.prepare(`SELECT ${exprs.join(', ')} FROM frontmatter ${scopeWhere}`);\n const row = (await stmt.get()) as Record<string, number | string | null>;\n for (const [i, name] of chunk.entries()) {\n const raw = ((row[`t${i}`] as string) ?? '').split('|').filter(Boolean);\n const types = [...new Set(raw.map((t) => classifyVariantType(t, name)))].sort();\n stats.push({ field: name, coverage: Number(row[`n${i}`] ?? 0), type: types.join(',') });\n }\n }\n return stats;\n}\n"],"names":["fieldStats","classifyVariantType","name","field","test","startsWith","Error","AGGREGATES_PER_QUERY","conn","columns","scopeWhere","stats","start","chunk","exprs","stmt","row","length","slice","map","i","quoted","quoteIdent","prepare","join","get","raw","split","filter","Boolean","types","Set","t","sort","push","coverage","Number","type","entries"],"mappings":";;;;+BAoBsBA;;;eAAAA;;;wBApBK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAG3B,yIAAyI;AACzI,sMAAsM;AACtM,SAASC,oBAAoBC,IAAY,EAAEC,KAAa;IACtD,IAAI,aAAaC,IAAI,CAACF,OAAO,OAAO;IACpC,IAAIA,SAAS,WAAWA,SAAS,YAAYA,KAAKG,UAAU,CAAC,aAAa,OAAO;IACjF,IAAIH,SAAS,WAAW,OAAO;IAC/B,MAAM,IAAII,MAAM,AAAC,wDAA4EH,OAArBD,MAAK,kBAAsB,OAANC,OAAM;AACrG;AAEA,kGAAkG;AAClG,iGAAiG;AACjG,kGAAkG;AAClG,2BAA2B;AAC3B,IAAMI,uBAAuB;AAItB,SAAeP,WAAWQ,IAAgB,EAAEC,OAAiB,EAAEC,UAAkB;;YAChFC,OACGC,OACDC,OACAC,OAIAC,MACAC,KACD,2BAAA,mBAAA,uBAAA,WAAA;;;;oBATDL;oBACGC,QAAQ;;;yBAAGA,CAAAA,QAAQH,QAAQQ,MAAM,AAAD;;;;oBACjCJ,QAAQJ,QAAQS,KAAK,CAACN,OAAOA,QAAQL;oBACrCO,QAAQD,MAAMM,GAAG,CAAC,SAACjB,MAAMkB;wBAC7B,IAAMC,SAASC,IAAAA,oBAAU,EAACpB;wBAC1B,OAAO,AAAC,SAAuBkB,OAAfC,QAAO,UAAiDA,OAAzCD,GAAE,yCAAsEC,OAA/BA,QAAO,0BAAmDD,OAA3BC,QAAO,sBAAsB,OAAFD;oBACpI;oBACa;;wBAAMZ,KAAKe,OAAO,CAAC,AAAC,UAA8Cb,OAArCI,MAAMU,IAAI,CAAC,OAAM,sBAA+B,OAAXd;;;oBAAzEK,OAAO;oBACA;;wBAAMA,KAAKU,GAAG;;;oBAArBT,MAAO;oBACR,kCAAA,2BAAA;;;4BAAA,mCAAA,iBAAOI,oBAAGlB;gCACCc,OAE6BA;4BAF3C,IAAMU,MAAM,EAAEV,QAAAA,GAAG,CAAC,AAAC,IAAK,OAAFI,GAAI,cAAZJ,mBAAAA,QAA2B,IAAIW,KAAK,CAAC,KAAKC,MAAM,CAACC;4BAC/D,IAAMC,QAAQ,AAAC,qBAAG,IAAIC,IAAIL,IAAIP,GAAG,CAAC,SAACa;uCAAM/B,oBAAoB+B,GAAG9B;iCAAS+B,IAAI;4BAC7EtB,MAAMuB,IAAI,CAAC;gCAAE/B,OAAOD;gCAAMiC,UAAUC,QAAOpB,SAAAA,GAAG,CAAC,AAAC,IAAK,OAAFI,GAAI,cAAZJ,oBAAAA,SAAgB;gCAAIqB,MAAMP,MAAMN,IAAI,CAAC;4BAAK;wBACvF;wBAJA,IAAK,YAAmBX,MAAMyB,OAAO,yBAAhC,6BAAA,QAAA,yBAAA;;wBAAA;wBAAA;;;iCAAA,6BAAA;gCAAA;;;gCAAA;sCAAA;;;;;;oBARqC1B,SAASL;;;;;;oBAcrD;;wBAAOI;;;;IACT"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/fieldStats.ts"],"sourcesContent":["import { quoteIdent } from '../shared.ts';\nimport type { Connection, FieldStat } from '../types.ts';\n\n// DuckDB's frontmatter columns are VARIANT (reconcile.ts), so typeof() always reports VARIANT; variant_typeof() reports the boxed native\n// type instead -- INT128, DOUBLE, VARCHAR, or a literal's narrower type like DECIMAL(p, s) -- mapped onto sqlite/turso's integer/real/text vocabulary; an unrecognized name throws (no-silent-modes).\nfunction classifyVariantType(name: string, field: string): 'integer' | 'real' | 'text' {\n if (/^U?INT\\d+$/.test(name)) return 'integer';\n if (name === 'FLOAT' || name === 'DOUBLE' || name.startsWith('DECIMAL(')) return 'real';\n if (name === 'VARCHAR') return 'text';\n throw new Error(`duckdb: variant_typeof() returned unrecognized type \"${name}\" for column \"${field}\"`);\n}\n\n// duckdb degrades superlinearly in the number of string_agg(DISTINCT variant_typeof()) aggregates\n// per projection, not the column width (301 columns: 1148ms unchunked vs 88ms at chunk size 25);\n// 16 sits inside the measured flat 10-25 range. sqlite/turso need none of this: GROUP_CONCAT over\n// 300 columns runs in 7ms.\nconst AGGREGATES_PER_QUERY = 16;\n\n// COUNT + string_agg(DISTINCT variant_typeof()) per column keeps this O(columns), not O(rows x columns).\n// '|' is the separator, not ',': DECIMAL's display name (\"DECIMAL(4, 2)\") contains a comma.\nexport async function fieldStats(conn: Connection, columns: string[], scopeWhere: string): Promise<FieldStat[]> {\n const stats: FieldStat[] = [];\n for (let start = 0; start < columns.length; start += AGGREGATES_PER_QUERY) {\n const chunk = columns.slice(start, start + AGGREGATES_PER_QUERY);\n const exprs = chunk.map((name, i) => {\n const quoted = quoteIdent(name);\n return `COUNT(${quoted}) AS n${i}, string_agg(DISTINCT variant_typeof(${quoted}), '|') FILTER (WHERE ${quoted} IS NOT NULL) AS t${i}`;\n });\n const stmt = await conn.prepare(`SELECT ${exprs.join(', ')} FROM frontmatter ${scopeWhere}`);\n const row = (await stmt.get()) as Record<string, number | string | null>;\n for (const [i, name] of chunk.entries()) {\n const raw = ((row[`t${i}`] as string) ?? '').split('|').filter(Boolean);\n const types = [...new Set(raw.map((t) => classifyVariantType(t, name)))].sort();\n stats.push({ field: name, coverage: Number(row[`n${i}`] ?? 0), type: types.join(',') });\n }\n }\n return stats;\n}\n"],"names":["fieldStats","classifyVariantType","name","field","test","startsWith","Error","AGGREGATES_PER_QUERY","conn","columns","scopeWhere","stats","start","chunk","exprs","stmt","row","length","slice","map","i","quoted","quoteIdent","prepare","join","get","raw","split","filter","Boolean","types","Set","t","sort","push","coverage","Number","type","entries"],"mappings":";;;;+BAoBsBA;;;eAAAA;;;wBApBK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAG3B,yIAAyI;AACzI,sMAAsM;AACtM,SAASC,oBAAoBC,IAAY,EAAEC,KAAa;IACtD,IAAI,aAAaC,IAAI,CAACF,OAAO,OAAO;IACpC,IAAIA,SAAS,WAAWA,SAAS,YAAYA,KAAKG,UAAU,CAAC,aAAa,OAAO;IACjF,IAAIH,SAAS,WAAW,OAAO;IAC/B,MAAM,IAAII,MAAM,AAAC,wDAA4EH,OAArBD,MAAK,kBAAsB,OAANC,OAAM;AACrG;AAEA,kGAAkG;AAClG,iGAAiG;AACjG,kGAAkG;AAClG,2BAA2B;AAC3B,IAAMI,uBAAuB;AAItB,SAAeP,WAAWQ,IAAgB,EAAEC,OAAiB,EAAEC,UAAkB;;YAChFC,OACGC,OACDC,OACAC,OAIAC,MACAC,KACD,2BAAA,mBAAA,uBAAA,WAAA;;;;oBATDL;oBACGC,QAAQ;;;yBAAGA,CAAAA,QAAQH,QAAQQ,MAAM,AAAD;;;;oBACjCJ,QAAQJ,QAAQS,KAAK,CAACN,OAAOA,QAAQL;oBACrCO,QAAQD,MAAMM,GAAG,CAAC,SAACjB,MAAMkB;wBAC7B,IAAMC,SAASC,IAAAA,oBAAU,EAACpB;wBAC1B,OAAO,AAAC,SAAuBkB,OAAfC,QAAO,UAAiDA,OAAzCD,GAAE,yCAAsEC,OAA/BA,QAAO,0BAAmDD,OAA3BC,QAAO,sBAAsB,OAAFD;oBACpI;oBACa;;wBAAMZ,KAAKe,OAAO,CAAC,AAAC,UAA8Cb,OAArCI,MAAMU,IAAI,CAAC,OAAM,sBAA+B,OAAXd;;;oBAAzEK,OAAO;oBACA;;wBAAMA,KAAKU,GAAG;;;oBAArBT,MAAO;oBACR,kCAAA,2BAAA;;;4BAAA,mCAAA,iBAAOI,oBAAGlB;gCACCc,OAE6BA;4BAF3C,IAAMU,MAAM,EAAEV,QAAAA,GAAG,CAAC,AAAC,IAAK,OAAFI,GAAI,cAAZJ,mBAAAA,QAA2B,IAAIW,KAAK,CAAC,KAAKC,MAAM,CAACC;4BAC/D,IAAMC,QAAQ,AAAC,qBAAG,IAAIC,IAAIL,IAAIP,GAAG,CAAC,SAACa;uCAAM/B,oBAAoB+B,GAAG9B;iCAAS+B,IAAI;4BAC7EtB,MAAMuB,IAAI,CAAC;gCAAE/B,OAAOD;gCAAMiC,UAAUC,QAAOpB,SAAAA,GAAG,CAAC,AAAC,IAAK,OAAFI,GAAI,cAAZJ,oBAAAA,SAAgB;gCAAIqB,MAAMP,MAAMN,IAAI,CAAC;4BAAK;wBACvF;wBAJA,IAAK,YAAmBX,MAAMyB,OAAO,yBAAhC,6BAAA,QAAA,yBAAA;;wBAAA;wBAAA;;;iCAAA,6BAAA;gCAAA;;;gCAAA;sCAAA;;;;;;oBARqC1B,SAASL;;;;;;oBAcrD;;wBAAOI;;;;IACT"}
@@ -1,14 +1,9 @@
1
1
  import type { Connection, LexicalHit, LexicalQueryOptions } from '../types.js';
2
- interface FtsIndexState {
3
- stale: boolean;
4
- orderedMacroReady: boolean;
5
- }
6
2
  export declare function markContentStale(conn: Connection): Promise<void>;
7
3
  export declare function prepareFts(conn: Connection): Promise<void>;
8
4
  export declare function assertFtsReady(conn: Connection): Promise<void>;
9
- export declare function queryLexical(conn: Connection, terms: string, opts: LexicalQueryOptions, state: FtsIndexState): Promise<LexicalHit[]>;
5
+ export declare function queryLexical(conn: Connection, terms: string, opts: LexicalQueryOptions): Promise<LexicalHit[]>;
10
6
  export declare function createLexicalIndex(conn: Connection): {
11
7
  query: (terms: string, opts: LexicalQueryOptions) => Promise<LexicalHit[]>;
12
8
  markStale: () => Promise<void>;
13
9
  };
14
- export {};
@@ -1,14 +1,9 @@
1
1
  import type { Connection, LexicalHit, LexicalQueryOptions } from '../types.js';
2
- interface FtsIndexState {
3
- stale: boolean;
4
- orderedMacroReady: boolean;
5
- }
6
2
  export declare function markContentStale(conn: Connection): Promise<void>;
7
3
  export declare function prepareFts(conn: Connection): Promise<void>;
8
4
  export declare function assertFtsReady(conn: Connection): Promise<void>;
9
- export declare function queryLexical(conn: Connection, terms: string, opts: LexicalQueryOptions, state: FtsIndexState): Promise<LexicalHit[]>;
5
+ export declare function queryLexical(conn: Connection, terms: string, opts: LexicalQueryOptions): Promise<LexicalHit[]>;
10
6
  export declare function createLexicalIndex(conn: Connection): {
11
7
  query: (terms: string, opts: LexicalQueryOptions) => Promise<LexicalHit[]>;
12
8
  markStale: () => Promise<void>;
13
9
  };
14
- export {};
@@ -283,7 +283,7 @@ function stateFor(conn) {
283
283
  case 1:
284
284
  // Anything but a persisted '0' (missing key, or '1') means a rebuild is owed: a cache that
285
285
  // never built an index, or one a prior process marked stale and never got to clear.
286
- state = (_tmp.stale = _state.sent() !== '0', _tmp.orderedMacroReady = false, _tmp);
286
+ state = (_tmp.stale = _state.sent() !== '0', _tmp);
287
287
  ftsState.set(conn, state);
288
288
  _state.label = 2;
289
289
  case 2:
@@ -326,8 +326,7 @@ function markContentStale(conn) {
326
326
  switch(_state.label){
327
327
  case 0:
328
328
  ftsState.set(conn, {
329
- stale: true,
330
- orderedMacroReady: false
329
+ stale: true
331
330
  });
332
331
  return [
333
332
  4,
@@ -469,7 +468,6 @@ function rebuildFts(conn, state) {
469
468
  2
470
469
  ];
471
470
  state.stale = true;
472
- state.orderedMacroReady = false;
473
471
  return [
474
472
  4,
475
473
  (0, _transactionts.withTransaction)(conn, function() {
@@ -481,7 +479,7 @@ function rebuildFts(conn, state) {
481
479
  // 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.
482
480
  return [
483
481
  4,
484
- conn.exec("PRAGMA create_fts_index('content', 'path', 'title', 'summary', 'text', stopwords='none', overwrite=1)")
482
+ conn.exec("PRAGMA create_fts_index('content', 'path', 'title', 'summary', 'text', stemmer='".concat(_orderedbm25ts.FTS_STEMMER, "', stopwords='none', overwrite=1)"))
485
483
  ];
486
484
  case 1:
487
485
  _state.sent();
@@ -593,19 +591,19 @@ function assertFtsReady(conn) {
593
591
  }
594
592
  // 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.
595
593
  // 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).
596
- function buildScoreAndGate(words, bareWords, phraseWords, substrings) {
594
+ function buildScoreAndGate(words, nativeTerms, bareWords, phraseWords, substrings) {
597
595
  var scoreParts = [];
598
596
  var gateParts = [];
599
597
  var scoreParams = [];
600
598
  var gateParams = [];
601
599
  if (words.length > 0) {
602
- var wordQuery = words.map(_segmentts.foldForSearch).join(' ');
603
600
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
604
601
  try {
605
602
  for(var _iterator = FIELDS[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
606
603
  var field = _step.value;
607
- scoreParts.push("".concat(FIELD_WEIGHT[field], ".0 * COALESCE(").concat(_orderedbm25ts.ORDERED_BM25_MACRO, '(content."path", ?, fields := \'').concat(field, "', conjunctive := false), 0)"));
608
- scoreParams.push(wordQuery);
604
+ var _scoreParams;
605
+ scoreParts.push("".concat(FIELD_WEIGHT[field], ".0 * COALESCE(").concat((0, _orderedbm25ts.orderedBm25Sql)(field, nativeTerms.length), ", 0)"));
606
+ (_scoreParams = scoreParams).push.apply(_scoreParams, _to_consumable_array(nativeTerms));
609
607
  }
610
608
  } catch (err) {
611
609
  _didIteratorError = true;
@@ -622,13 +620,13 @@ function buildScoreAndGate(words, bareWords, phraseWords, substrings) {
622
620
  }
623
621
  }
624
622
  if (bareWords.length > 0) {
625
- var nativeGate = "".concat(_orderedbm25ts.ORDERED_BM25_MACRO, '(content."path", ?, conjunctive := true) IS NOT NULL');
623
+ var nativeGate = 'fts_main_content.match_bm25(content."path", ?, conjunctive := true) IS NOT NULL';
626
624
  gateParts.push(nativeGate);
627
625
  gateParams.push(bareWords.map(_segmentts.foldForSearch).join(' '));
628
626
  }
629
627
  if (phraseWords.length > 0) {
630
628
  var _gateParams;
631
- var nativeGate1 = "".concat(_orderedbm25ts.ORDERED_BM25_MACRO, '(content."path", ?, conjunctive := true) IS NOT NULL');
629
+ var nativeGate1 = 'fts_main_content.match_bm25(content."path", ?, conjunctive := true) IS NOT NULL';
632
630
  var fallback = phraseWords.map(function(_word) {
633
631
  return "(".concat(FIELDS.map(function(field) {
634
632
  return "contains(strip_accents(lower(content.".concat(field, ")), ?)");
@@ -698,9 +696,9 @@ function buildScoreAndGate(words, bareWords, phraseWords, substrings) {
698
696
  params: _to_consumable_array(scoreParams).concat(_to_consumable_array(gateParams))
699
697
  };
700
698
  }
701
- function queryLexical(conn, terms, opts, state) {
699
+ function queryLexical(conn, terms, opts) {
702
700
  return _async_to_generator(function() {
703
- var _stmt, unsupported, whereJoin, whereCond, scopeCond, limit, _splitTerms, words, bareWords, phraseWords, substrings, phrases, emptyPhrase, _buildScoreAndGate, scoreSql, gateSql, params, selectFields, sqlLimit, sql, stmt, rows, matches;
701
+ var _stmt, unsupported, whereJoin, whereCond, scopeCond, limit, _splitTerms, words, bareWords, phraseWords, substrings, phrases, emptyPhrase, nativeTerms, _tmp, _buildScoreAndGate, scoreSql, gateSql, params, selectFields, sqlLimit, sql, stmt, rows, matches;
704
702
  return _ts_generator(this, function(_state) {
705
703
  switch(_state.label){
706
704
  case 0:
@@ -732,13 +730,20 @@ function queryLexical(conn, terms, opts, state) {
732
730
  ];
733
731
  return [
734
732
  4,
735
- (0, _orderedbm25ts.ensureOrderedBm25)(conn, state)
733
+ (0, _orderedbm25ts.nativeQueryTerms)(conn, words.map(_segmentts.foldForSearch).join(' '))
736
734
  ];
737
735
  case 3:
738
- _state.sent();
739
- _state.label = 4;
736
+ _tmp = _state.sent();
737
+ return [
738
+ 3,
739
+ 5
740
+ ];
740
741
  case 4:
741
- _buildScoreAndGate = buildScoreAndGate(words, bareWords, phraseWords, substrings), scoreSql = _buildScoreAndGate.scoreSql, gateSql = _buildScoreAndGate.gateSql, params = _buildScoreAndGate.params;
742
+ _tmp = [];
743
+ _state.label = 5;
744
+ case 5:
745
+ nativeTerms = _tmp;
746
+ _buildScoreAndGate = buildScoreAndGate(words, nativeTerms, bareWords, phraseWords, substrings), scoreSql = _buildScoreAndGate.scoreSql, gateSql = _buildScoreAndGate.gateSql, params = _buildScoreAndGate.params;
742
747
  selectFields = phrases.length > 0 ? ', content.title, content.summary, content.text' : '';
743
748
  sqlLimit = phrases.length > 0 ? '' : ' LIMIT ?';
744
749
  sql = "SELECT path, score".concat(phrases.length > 0 ? ', title, summary, text' : '', ' FROM (\n SELECT content."path" AS path, (').concat(scoreSql, ") AS score").concat(selectFields, "\n FROM content\n ").concat(whereJoin, "\n WHERE ").concat(gateSql, "\n ").concat(whereCond, " ").concat(scopeCond, "\n ) sq ORDER BY score DESC, path").concat(sqlLimit);
@@ -746,7 +751,7 @@ function queryLexical(conn, terms, opts, state) {
746
751
  4,
747
752
  conn.prepare(sql)
748
753
  ];
749
- case 5:
754
+ case 6:
750
755
  stmt = _state.sent();
751
756
  return [
752
757
  4,
@@ -754,7 +759,7 @@ function queryLexical(conn, terms, opts, state) {
754
759
  limit
755
760
  ])))
756
761
  ];
757
- case 6:
762
+ case 7:
758
763
  rows = _state.sent();
759
764
  matches = phrases.length === 0 ? rows : rows.filter(function(row) {
760
765
  return phrases.every(function(phrase) {
@@ -781,27 +786,11 @@ function createLexicalIndex(conn) {
781
786
  return {
782
787
  query: function query(terms, opts) {
783
788
  return _async_to_generator(function() {
784
- var _tmp;
785
789
  return _ts_generator(this, function(_state) {
786
- switch(_state.label){
787
- case 0:
788
- _tmp = [
789
- conn,
790
- terms,
791
- opts
792
- ];
793
- return [
794
- 4,
795
- stateFor(conn)
796
- ];
797
- case 1:
798
- return [
799
- 2,
800
- queryLexical.apply(void 0, _tmp.concat([
801
- _state.sent()
802
- ]))
803
- ];
804
- }
790
+ return [
791
+ 2,
792
+ queryLexical(conn, terms, opts)
793
+ ];
805
794
  });
806
795
  })();
807
796
  },
@@ -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":"AAAA,yFAAyF;AACzF,8DAA8D;;;;;;;;;;;;QAuIxCA;eAAAA;;QAsFNC;eAAAA;;QAvJMC;eAAAA;;QA6DAC;eAAAA;;QA4DAC;eAAAA;;;wBA9LK;yBACwD;wBAClD;6BACD;6BAE8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE9D,IAAMC,SAAS;IAAC;IAAS;IAAW;CAAO;AAE3C,uGAAuG;AACvG,iGAAiG;AACjG,IAAMC,eAAsC;IAAEC,OAAO;IAAIC,SAAS;IAAGC,MAAM;AAAE;AAE7E,0GAA0G;AAC1G,8HAA8H;AAC9H,IAAMC,iBAAuD;IAC3D;QAAEC,OAAO;QAAgBC,IAAI;IAA4B;IACzD;QAAED,OAAO;QAAoBC,IAAI;IAAiC;IAClE;QAAED,OAAO;QAAiBC,IAAI;IAAiB;IAC/C;QAAED,OAAO;QAA0BC,IAAI;IAAgB;IACvD;QAAED,OAAO;QAAiBC,IAAI;IAA2B;IACzD;QAAED,OAAO;QAAqBC,IAAI;IAAO;CAC1C;AAED,SAASC,oBAAoBC,KAAa;IACxC,IAAMC,iBAAiBD,MAAME,OAAO,CAAC,YAAY;QAC5C,kCAAA,2BAAA;;QAAL,QAAK,YAAuBN,mCAAvB,SAAA,6BAAA,QAAA,yBAAA,iCAAuC;YAAvC,kBAAA,aAAQC,oBAAAA,OAAOC,iBAAAA;YAClB,IAAMK,IAAIF,eAAeG,KAAK,CAACN;YAC/B,IAAIK,GAAG,OAAO;gBAAEN,OAAAA;gBAAOQ,OAAOF,CAAC,CAAC,EAAE,CAACG,IAAI;YAAG;QAC5C;;QAHK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAIL,OAAO;AACT;AAMA,kGAAkG;AAClG,kGAAkG;AAClG,IAAMC,qBAAqB;AAE3B,6FAA6F;AAC7F,0GAA0G;AAC1G,IAAMC,WAAW,IAAIC;AACrB,SAAeC,SAASC,IAAgB;;YAClCC;;;;oBAAAA,QAAQJ,SAASK,GAAG,CAACF;yBACrB,CAACC,OAAD;;;;;oBAGgB;;wBAAME,IAAAA,iBAAO,EAACH,MAAMJ;;;oBAFtC,2FAA2F;oBAC3F,oFAAoF;oBACpFK,cAAUG,QAAO,AAAC,kBAA6C;oBAC/DP,SAASQ,GAAG,CAACL,MAAMC;;;oBAErB;;wBAAOA;;;;IACT;;AAEA,SAAeK,eAAeN,IAAgB;;YACtCO;;;;oBAAO;;wBAAMP,KAAKQ,OAAO,CAAC;;;oBAA1BD,OAAO;oBAQL;;wBAAMA,KAAKL,GAAG;;;oBAAtB;;wBAAQ,kBAAsBO;;;;IAChC;;AAIO,SAAehC,iBAAiBuB,IAAgB;;;;;oBACrDH,SAASQ,GAAG,CAACL,MAAM;wBAAEI,OAAO;oBAAK;oBACjC;;wBAAMM,IAAAA,iBAAO,EAACV,MAAMJ,oBAAoB;;;oBAAxC;;;;;;IACF;;AAEA,wHAAwH;AACxH,8FAA8F;AAC9F,SAASe,WAAWtB,KAAa;IAC/B,IAAMuB,QAAkB,EAAE;IAC1B,IAAMC,YAAsB,EAAE;IAC9B,IAAMC,cAAwB,EAAE;IAChC,IAAMC,aAAuB,EAAE;IAC/B,IAAMC,UAA2B,EAAE;IACnC,IAAIC,cAAc;IAClB,IAAM3B,iBAAiBD,MAAME,OAAO,CAAC,cAAc,SAAC2B,IAAIC;QACtD,IAAMC,SAASD,MAAMxB,IAAI;QACzB,IAAM0B,eAAeC,IAAAA,uBAAY,EAACF;QAClC,IAAIC,aAAaE,MAAM,KAAK,GAAG;YAC7BN,cAAc;YACd,OAAO;QACT;QACAD,QAAQQ,IAAI,CAACH;YACR,kCAAA,2BAAA;;YAAL,QAAK,YAAeA,iCAAf,SAAA,6BAAA,QAAA,yBAAA,iCAA6B;gBAA7B,IAAM3B,QAAN;gBACH,IAAIA,MAAM+B,QAAQ,EAAEV,WAAWS,IAAI,CAAC9B,MAAMV,IAAI;qBACzC;oBACH4B,MAAMY,IAAI,CAAC9B,MAAMV,IAAI;oBACrB8B,YAAYU,IAAI,CAAC9B,MAAMV,IAAI;gBAC7B;YACF;;YANK;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;QAOL,OAAO;IACT;QACK,kCAAA,2BAAA;;QAAL,QAAK,YAAaM,eAAeoC,KAAK,CAAC,2BAAlC,SAAA,6BAAA,QAAA,yBAAA,iCAA0C;YAA1C,IAAMC,MAAN;YACH,IAAIA,IAAIJ,MAAM,KAAK,GAAG;gBACjB,mCAAA,4BAAA;;gBAAL,QAAK,aAAeD,IAAAA,uBAAY,EAACK,yBAA5B,UAAA,8BAAA,SAAA,0BAAA,kCAAkC;oBAAlC,IAAMjC,QAAN;oBACH,IAAIA,MAAM+B,QAAQ,EAAEV,WAAWS,IAAI,CAAC9B,MAAMV,IAAI;yBACzC;wBACH4B,MAAMY,IAAI,CAAC9B,MAAMV,IAAI;wBACrB6B,UAAUW,IAAI,CAAC9B,MAAMV,IAAI;oBAC3B;gBACF;;gBANK;gBAAA;;;yBAAA,8BAAA;wBAAA;;;wBAAA;8BAAA;;;;QAOP;;QATK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAUL,OAAO;QAAE4B,OAAAA;QAAOC,WAAAA;QAAWC,aAAAA;QAAaC,YAAAA;QAAYC,SAAAA;QAASC,aAAAA;IAAY;AAC3E;AAEA,gGAAgG;AAChG,iHAAiH;AACjH,SAAeW,WAAW5B,IAAgB,EAAEC,KAAoB;;;;;;oBAC9D;;wBAAMD,KAAK6B,IAAI,CAAC;;;oBAAhB;2BACI,CAAC5B,MAAMG,KAAK;+BAAZ;;;;oBAAiB;;wBAAME,eAAeN;;;2BAArB;;;oBAArB,UAAkD;;;oBAClDC,MAAMG,KAAK,GAAG;oBACd;;wBAAM0B,IAAAA,8BAAe,EAAC9B,MAAM;;;;;4CAC1B,6HAA6H;4CAC7H,0JAA0J;4CAC1J;;gDAAMA,KAAK6B,IAAI,CAAC,AAAC,mFAA8F,OAAZE,0BAAW,EAAC;;;4CAA/G;4CACA,0FAA0F;4CAC1F,gFAAgF;4CAChF;;gDAAMrB,IAAAA,iBAAO,EAACV,MAAMJ,oBAAoB;;;4CAAxC;;;;;;4BACF;;;;oBAPA;oBAQAK,MAAMG,KAAK,GAAG;;;;;;IAChB;;AAEO,SAAe1B,WAAWsB,IAAgB;;;;;;;wBAC9BA;;oBAAM;;wBAAMD,SAASC;;;oBAAtC;;wBAAM4B;4BAAiB;;;;oBAAvB;;;;;;IACF;;AAEO,SAAerD,eAAeyB,IAAgB;;YAC7CC,OAOG+B;;;;oBAPK;;wBAAMjC,SAASC;;;oBAAvBC,QAAQ;oBACd,IAAIA,MAAMG,KAAK,EAAE,MAAM,IAAI6B,oBAAU,CAAC,mBAAmB;;;;;;;;;oBAEvD;;wBAAMjC,KAAK6B,IAAI,CAAC;;;oBAAhB;oBACM;;wBAAMvB,eAAeN;;;oBAA3B,IAAI,CAAE,eAA6B;wBACjC,MAAM,IAAIiC,oBAAU,CAAC,mBAAmB;oBAC1C;;;;;;oBACOD;oBACP,IAAIA,AAAG,YAAHA,KAAeC,oBAAU,GAAE,MAAMD;oBACrC,MAAM,IAAIC,oBAAU,CAAC,mBAAmB,AAAC,iDAAuE,OAAvB,AAACD,IAAcE,OAAO,EAAC;;;;;;;IAEpH;;AAEA,qKAAqK;AACrK,+OAA+O;AAC/O,SAASC,kBAAkBvB,KAAe,EAAEwB,WAAqB,EAAEvB,SAAmB,EAAEC,WAAqB,EAAEC,UAAoB;IACjI,IAAMsB,aAAuB,EAAE;IAC/B,IAAMC,YAAsB,EAAE;IAC9B,IAAMC,cAAyB,EAAE;IACjC,IAAMC,aAAwB,EAAE;IAEhC,IAAI5B,MAAMW,MAAM,GAAG,GAAG;YACf,kCAAA,2BAAA;;YAAL,QAAK,YAAe3C,2BAAf,SAAA,6BAAA,QAAA,yBAAA,iCAAuB;gBAAvB,IAAM6D,QAAN;oBAEHF;gBADAF,WAAWb,IAAI,CAAC,AAAC,GAAsCkB,OAApC7D,YAAY,CAAC4D,MAAM,EAAC,kBAA0D,OAA1CC,IAAAA,6BAAc,EAACD,OAAOL,YAAYb,MAAM,GAAE;gBACjGgB,CAAAA,eAAAA,aAAYf,IAAI,OAAhBe,cAAiB,qBAAGH;YACtB;;YAHK;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;QAIL,IAAIvB,UAAUU,MAAM,GAAG,GAAG;YACxB,IAAMoB,aAAa;YACnBL,UAAUd,IAAI,CAACmB;YACfH,WAAWhB,IAAI,CAACX,UAAU+B,GAAG,CAACC,wBAAa,EAAEC,IAAI,CAAC;QACpD;QACA,IAAIhC,YAAYS,MAAM,GAAG,GAAG;gBAK1BiB;YAJA,IAAMG,cAAa;YACnB,IAAMI,WAAWjC,YAAY8B,GAAG,CAAC,SAACI;uBAAU,AAAC,IAA6F,OAA1FpE,OAAOgE,GAAG,CAAC,SAACH;2BAAU,AAAC,wCAA6C,OAANA,OAAM;mBAASK,IAAI,CAAC,SAAQ;eAAIA,IAAI,CAAC;YACnJR,UAAUd,IAAI,CAAC,AAAC,IAAqBuB,OAAlBJ,aAAW,SAAgB,OAATI,UAAS;YAC9CP,WAAWhB,IAAI,CAACV,YAAY8B,GAAG,CAACC,wBAAa,EAAEC,IAAI,CAAC;YACpDN,CAAAA,cAAAA,YAAWhB,IAAI,OAAfgB,aAAgB,qBAAG1B,YAAYmC,OAAO,CAAC,SAACC;uBAAStE,OAAOgE,GAAG,CAAC;2BAAMC,IAAAA,wBAAa,EAACK;;;QAClF;IACF;QAEK,mCAAA,4BAAA;;;YAAA,IAAMC,MAAN;gBAOHX;YANA,IAAMY,SAASD,IAAIE,WAAW;gBACzB,kCAAA,2BAAA;;gBAAL,QAAK,YAAezE,2BAAf,SAAA,6BAAA,QAAA,yBAAA,iCAAuB;oBAAvB,IAAM6D,QAAN;oBACHJ,WAAWb,IAAI,CAAC,AAAC,GAAuEiB,OAArE5D,YAAY,CAAC4D,MAAM,EAAC,mDAAuD,OAANA,OAAM;oBAC9FF,YAAYf,IAAI,CAACqB,IAAAA,wBAAa,EAACO;gBACjC;;gBAHK;gBAAA;;;yBAAA,6BAAA;wBAAA;;;wBAAA;8BAAA;;;;YAILd,UAAUd,IAAI,CAAC,AAAC,IAA6F,OAA1F5C,OAAOgE,GAAG,CAAC,SAACH;uBAAU,AAAC,wCAA6C,OAANA,OAAM;eAASK,IAAI,CAAC,SAAQ;YAC7GN,CAAAA,cAAAA,YAAWhB,IAAI,OAAfgB,aAAgB,qBAAG5D,OAAOgE,GAAG,CAAC;uBAAMC,IAAAA,wBAAa,EAACO;;QACpD;QARA,QAAK,aAAarC,+BAAb,UAAA,8BAAA,SAAA,0BAAA;;QAAA;QAAA;;;iBAAA,8BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAUL,OAAO;QAAEuC,UAAUjB,WAAWS,IAAI,CAAC;QAAQS,SAASjB,UAAUQ,IAAI,CAAC,YAAY;QAAQU,QAAQ,AAAC,qBAAGjB,oBAAa,qBAAGC;IAAY;AACjI;AAIO,SAAe7D,aAAaqB,IAAgB,EAAEX,KAAa,EAAEoE,IAAyB;;YAuBvElD,OAtBdmD,aAIEC,WAAWC,WAAWC,WAAWC,OACmCnD,aAApEC,OAAOC,WAAWC,aAAaC,YAAYC,SAASC,aAItDmB,mBAEgCD,oBAA9BmB,UAAUC,SAASC,QACrBO,cACAC,UACAC,KAOA1D,MACA2D,MACAC;;;;oBAvBAT,cAActE,oBAAoBC;oBACxC,IAAIqE,gBAAgB,MAAM;wBACxB,MAAM,IAAIzB,oBAAU,CAAC,4BAA4B,AAAC,6CAAkEyB,OAAvBA,YAAYxE,KAAK,EAAC,OAAqDG,OAAhDqE,YAAYhE,KAAK,EAAC,gCAA2C,OAAbL,MAAMM,IAAI,IAAG;oBACnL;oBACQgE,YAA2CF,KAA3CE,WAAWC,YAAgCH,KAAhCG,WAAWC,YAAqBJ,KAArBI,WAAWC,QAAUL,KAAVK;oBACmCnD,cAAAA,WAAWtB,QAA/EuB,QAAoED,YAApEC,OAAOC,YAA6DF,YAA7DE,WAAWC,cAAkDH,YAAlDG,aAAaC,aAAqCJ,YAArCI,YAAYC,UAAyBL,YAAzBK,SAASC,cAAgBN,YAAhBM;oBAC5D,IAAIA,eAAgBL,MAAMW,MAAM,KAAK,KAAKR,WAAWQ,MAAM,KAAK,GAAI;;;;yBAEhEX,CAAAA,MAAMW,MAAM,GAAG,CAAA,GAAfX;;;;oBAAkB;;wBAAMrC,eAAeyB;;;oBAArB;;;yBACFY,CAAAA,MAAMW,MAAM,GAAG,CAAA,GAAfX;;;;oBAAmB;;wBAAMwD,IAAAA,+BAAgB,EAACpE,MAAMY,MAAMgC,GAAG,CAACC,wBAAa,EAAEC,IAAI,CAAC;;;2BAA3D;;;;;;;;;oBAAjCV;oBAEgCD,qBAAAA,kBAAkBvB,OAAOwB,aAAavB,WAAWC,aAAaC,aAA5FuC,WAA8BnB,mBAA9BmB,UAAUC,UAAoBpB,mBAApBoB,SAASC,SAAWrB,mBAAXqB;oBACrBO,eAAe/C,QAAQO,MAAM,GAAG,IAAI,mDAAmD;oBACvFyC,WAAWhD,QAAQO,MAAM,GAAG,IAAI,KAAK;oBACrC0C,MAAM,AAAC,qBACuBX,OADHtC,QAAQO,MAAM,GAAG,IAAI,2BAA2B,IAAG,iDAC3BwC,OAArBT,UAAS,cAEzCK,OAFqDI,cAAa,4BAG5DR,OADNI,WAAU,gBAEVC,OADML,SAAQ,UACDM,OAAbD,WAAU,KACoBI,OADjBH,WAAU,wCACgB,OAATG;oBACrB;;wBAAMhE,KAAKQ,OAAO,CAACyD;;;oBAA1B1D,OAAO;oBACC;;wBAAMA,CAAAA,QAAAA,MAAK8D,GAAG,OAAR9D,OAAAA,AAAS,qBAAGiD,eAAQ,qBAAIxC,QAAQO,MAAM,GAAG;4BAAUuC;;;;oBAAjEI,OAAQ;oBACRC,UAAUnD,QAAQO,MAAM,KAAK,IAAI2C,OAAOA,KAAKI,MAAM,CAAC,SAACC;+BAAQvD,QAAQwD,KAAK,CAAC,SAACpD;mCAAWxC,OAAO6F,IAAI,CAAC,SAAChC;oCAA8B8B;uCAApBG,IAAAA,8BAAmB,GAACH,aAAAA,GAAG,CAAC9B,MAAM,cAAV8B,wBAAAA,aAAc,IAAInD;;;;oBAC1J;;wBAAO+C,QAAQQ,KAAK,CAAC,GAAGb,OAAOlB,GAAG,CAAC;gCAAGgC,aAAAA;mCAAY;gCAAEA,MAAAA;4BAAK;;;;;IAC3D;;AAIO,SAASpG,mBAAmBwB,IAAgB;IACjD,OAAO;QACL6E,OAAO,SAAPA,MAAcxF,OAAOoE;;;;;wBAAS9E,aAAaqB,MAAMX,OAAOoE;;;;;QACxDqB,WAAW,SAAXA;mBAAiBrG,iBAAiBuB;;IACpC;AACF"}
@@ -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;