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/output/search-error.ts"],"sourcesContent":["import { SenseError } from '../errors.ts';\nimport { hasUnspacedRun } from '../text/segment.ts';\n\n// FTS5 reads punctuation as syntax, so `end-to-end` parses as a filter on column `to` and\n// errors `no such column: to` -- true about the parse, misleading about the input.\nconst FTS5_PUNCTUATION = /[^\\p{L}\\p{M}\\p{N}_\\s]/u;\n\nfunction hasBalancedGrouping(text: string): boolean {\n let depth = 0;\n let grouped = false;\n for (const char of text) {\n if (char === '(') {\n depth++;\n grouped = true;\n } else if (char === ')') {\n depth--;\n if (depth < 0) return false;\n }\n }\n return grouped && depth === 0;\n}\n\n// Detects routing intent only. SQLite parses the complete expression, while other stores name\n// the unsupported operator; neither path silently interprets its punctuation as literal text.\nfunction hasExplicitFts5Syntax(terms: string): boolean {\n const text = terms.replace(/\"[^\"]*\"/g, 'phrase');\n return /[\\p{L}\\p{N}_]+\\*(?=\\s|$)/u.test(text) || /(?:^|[\\s(])(?:AND|OR|NOT)(?=\\s|\\)|$)/u.test(text) || /(?:^|[\\s(])NEAR\\b/u.test(text) || /(?:^|[\\s(])\\^\\S+/u.test(text) || /(?:^|[\\s(])[\\p{L}_]\\w*\\s*:/u.test(text) || hasBalancedGrouping(text);\n}\n\n// SQLite treats punctuation in an unquoted spaced-script token as MATCH syntax. Validate that\n// boundary before dispatch so DuckDB and Tantivy do not silently interpret the same input as text.\nexport function bareTermSyntaxError(terms: string): Error | null {\n if (hasExplicitFts5Syntax(terms)) return null;\n const outsideQuotes = terms.replace(/\"[^\"]*\"/g, ' ');\n const suspects = (outsideQuotes.match(/\\S+/g) ?? []).filter((token) => {\n if (!FTS5_PUNCTUATION.test(token) || hasUnspacedRun(token)) return false;\n if (/^[\\p{L}_]\\w*\\s*:/u.test(token)) return false;\n if (/^[\\p{L}\\p{N}_]+\\*(?:\\s|$)/u.test(token)) return false;\n if (/^(?:AND|OR|NOT)$/u.test(token)) return false;\n return true;\n });\n if (suspects.length === 0) return null;\n return new SenseError('SEARCH_SYNTAX', `the punctuation in ${suspects.map((term) => `\\`${term}\\``).join(', ')} is FTS5 syntax, not literal text; search for it literally by double-quoting: '\"${suspects[0]}\"'. Searchable columns are title, summary, text.`);\n}\n\nexport function searchError(err: Error, terms: string, scope?: string): Error {\n const message = err.message;\n if (!/no such column|fts5: syntax error|malformed MATCH/.test(message)) return err;\n const suspects = (terms.match(/\\S+/g) ?? []).filter((t) => !t.startsWith('\"') && FTS5_PUNCTUATION.test(t));\n // Blame the terms only when the failing token actually came from one -- a typo'd column\n // in --where can raise \"no such column\" through this same statement.\n const col = /no such column: (\\S+)/.exec(message)?.[1];\n const fromTerms = col === undefined ? suspects.length > 0 : suspects.some((t) => t.split(/[^\\p{L}\\p{N}]+/u).includes(col));\n if (fromTerms && suspects.length > 0) {\n return new SenseError('SEARCH_SYNTAX', `${message} -- the punctuation in ${suspects.map((t) => `\\`${t}\\``).join(', ')} is FTS5 syntax, not literal text; search for it literally by double-quoting: '\"${suspects[0]}\"'. Searchable columns are title, summary, text.`);\n }\n if (col !== undefined && scope !== undefined) {\n return new SenseError('SEARCH_SYNTAX', `${message} -- the where condition (${scope}) references it; frontmatter columns are listed by sense sql \"SELECT name FROM pragma_table_info('frontmatter')\".`);\n }\n return new SenseError('SEARCH_SYNTAX', `${message} -- searchable columns are title, summary, text; frontmatter fields are queried with --where or sense sql (list them with pragma_table_info('frontmatter')).`);\n}\n"],"names":["bareTermSyntaxError","searchError","FTS5_PUNCTUATION","hasBalancedGrouping","text","depth","grouped","char","hasExplicitFts5Syntax","terms","replace","test","outsideQuotes","suspects","match","filter","token","hasUnspacedRun","length","SenseError","map","term","join","err","scope","message","t","startsWith","col","exec","fromTerms","undefined","some","split","includes"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/output/search-error.ts"],"sourcesContent":["import { SenseError } from '../errors.ts';\nimport { hasUnspacedRun } from '../text/segment.ts';\n\n// FTS5 reads punctuation as syntax, so `end-to-end` parses as a filter on column `to` and\n// errors `no such column: to` -- true about the parse, misleading about the input.\nconst FTS5_PUNCTUATION = /[^\\p{L}\\p{M}\\p{N}_\\s]/u;\n\nfunction hasBalancedGrouping(text: string): boolean {\n let depth = 0;\n let grouped = false;\n for (const char of text) {\n if (char === '(') {\n depth++;\n grouped = true;\n } else if (char === ')') {\n depth--;\n if (depth < 0) return false;\n }\n }\n return grouped && depth === 0;\n}\n\n// Detects routing intent only. SQLite parses the complete expression, while other stores name\n// the unsupported operator; neither path silently interprets its punctuation as literal text.\nfunction hasExplicitFts5Syntax(terms: string): boolean {\n const text = terms.replace(/\"[^\"]*\"/g, 'phrase');\n return /[\\p{L}\\p{N}_]+\\*(?=\\s|$)/u.test(text) || /(?:^|[\\s(])(?:AND|OR|NOT)(?=\\s|\\)|$)/u.test(text) || /(?:^|[\\s(])NEAR\\b/u.test(text) || /(?:^|[\\s(])\\^\\S+/u.test(text) || /(?:^|[\\s(])[\\p{L}_]\\w*\\s*:/u.test(text) || hasBalancedGrouping(text);\n}\n\n// SQLite treats punctuation in an unquoted spaced-script token as MATCH syntax. Validate that\n// boundary before dispatch so DuckDB and Tantivy do not silently interpret the same input as text.\nexport function bareTermSyntaxError(terms: string): Error | null {\n if (hasExplicitFts5Syntax(terms)) return null;\n const outsideQuotes = terms.replace(/\"[^\"]*\"/g, ' ');\n const suspects = (outsideQuotes.match(/\\S+/g) ?? []).filter((token) => {\n if (!FTS5_PUNCTUATION.test(token) || hasUnspacedRun(token)) return false;\n if (/^[\\p{L}_]\\w*\\s*:/u.test(token)) return false;\n if (/^[\\p{L}\\p{N}_]+\\*(?:\\s|$)/u.test(token)) return false;\n if (/^(?:AND|OR|NOT)$/u.test(token)) return false;\n return true;\n });\n if (suspects.length === 0) return null;\n return new SenseError('SEARCH_SYNTAX', `the punctuation in ${suspects.map((term) => `\\`${term}\\``).join(', ')} is FTS5 syntax, not literal text; search for it literally by double-quoting: '\"${suspects[0]}\"'. Searchable columns are title, summary, text.`);\n}\n\nexport function searchError(err: Error, terms: string, scope?: string): Error {\n const message = err.message;\n if (!/no such column|fts5: syntax error|malformed MATCH/.test(message)) return err;\n const suspects = (terms.match(/\\S+/g) ?? []).filter((t) => !t.startsWith('\"') && FTS5_PUNCTUATION.test(t));\n // Blame the terms only when the failing token actually came from one -- a typo'd column\n // in --where can raise \"no such column\" through this same statement.\n const col = /no such column: (\\S+)/.exec(message)?.[1];\n const fromTerms = col === undefined ? suspects.length > 0 : suspects.some((t) => t.split(/[^\\p{L}\\p{N}]+/u).includes(col));\n if (fromTerms && suspects.length > 0) {\n return new SenseError('SEARCH_SYNTAX', `${message} -- the punctuation in ${suspects.map((t) => `\\`${t}\\``).join(', ')} is FTS5 syntax, not literal text; search for it literally by double-quoting: '\"${suspects[0]}\"'. Searchable columns are title, summary, text.`);\n }\n if (col !== undefined && scope !== undefined) {\n return new SenseError('SEARCH_SYNTAX', `${message} -- the where condition (${scope}) references it; frontmatter columns are listed by sense sql \"SELECT name FROM pragma_table_info('frontmatter')\".`);\n }\n return new SenseError('SEARCH_SYNTAX', `${message} -- searchable columns are title, summary, text; frontmatter fields are queried with --where or sense sql (list them with pragma_table_info('frontmatter')).`);\n}\n"],"names":["bareTermSyntaxError","searchError","FTS5_PUNCTUATION","hasBalancedGrouping","text","depth","grouped","char","hasExplicitFts5Syntax","terms","replace","test","outsideQuotes","suspects","match","filter","token","hasUnspacedRun","length","SenseError","map","term","join","err","scope","message","t","startsWith","col","exec","fromTerms","undefined","some","split","includes"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/scan/frontmatter.ts"],"sourcesContent":["import { isCollection, parseDocument, visit } from 'yaml';\n\n// Frontmatter keys that would collide with table columns. Exported so reconcile.ts's upsert can tell\n// a feature-owned column (`_rank`) from a parsed one and leave it alone on reparse.\nexport const RESERVED_COLUMNS = new Set(['path', '_mtime', '_ctime', '_size', '_rank', '_parse_error', 'content', 'links', 'sections']);\n\n// Only BAD_SCALAR_START qualifies: YAML 1.2 reserves `@` and `` ` `` at the start of a plain scalar, so `aliases: [@handle]` can only mean [\"@handle\"].\n// Every other code has a second reading (a swallowed key, a dropped URL, a silently overwritten duplicate) that would write values nobody wrote.\nconst ACCEPTED_YAML_CODES = new Set(['BAD_SCALAR_START']);\n\nexport function normalizeText(value: unknown): string {\n if (value === null || value === undefined) return '';\n return String(value).replace(/\\s+/g, ' ').trim();\n}\n\n// SQLite's datetime() rejects a colonless offset (`-0800`) and a space separator, which ISO 8601\n// allows and producers emit. A rejected date is invisible, not excluded: every comparison is NULL.\nconst ISO_DATETIME = /^(\\d{4}-\\d{2}-\\d{2})[T ](\\d{2}:\\d{2}(?::\\d{2})?(?:\\.\\d+)?)(Z|[+-]\\d{2}(?::?\\d{2})?)?$/;\n\n// A value opening `YYYY-MM-DDT` was meant to be a datetime; prose never is. Reported when it\n// cannot be normalized, so a typo surfaces on the next crawl instead of at some later audit.\nconst MEANT_AS_DATETIME = /^\\d{4}-\\d{2}-\\d{2}[T ]\\d/;\n\nexport function looksLikeDatetime(value: string): boolean {\n return MEANT_AS_DATETIME.test(value);\n}\n\n// Punctuation only, never a timezone conversion: the offset survives, so substr(d,1,10) is still\n// the local date. A shape that is not a real instant is left as written, and stays auditable.\nexport function normalizeDate(value: string): string {\n const m = ISO_DATETIME.exec(value);\n if (m === null) return value;\n const [, date, time, zone] = m;\n const digits = zone === undefined || zone === 'Z' ? '' : zone.replace(':', '');\n const offset = digits === '' ? (zone ?? '') : digits.length === 3 ? `${digits}:00` : `${digits.slice(0, 3)}:${digits.slice(3)}`;\n const normalized = `${date}T${time}${offset}`;\n return Number.isNaN(Date.parse(normalized)) ? value : normalized;\n}\n\n// Storage class follows the YAML scalar. Booleans store as 1/0, so `WHERE flag = 1` matches\n// and `WHERE flag = 'true'` cannot; `map` prints observed types so the mismatch is visible.\nexport function mapValue(value: unknown): string | number | bigint | null {\n if (value === null || value === undefined) return null;\n if (typeof value === 'boolean') return BigInt(value ? 1 : 0);\n if (typeof value === 'number') return Number.isSafeInteger(value) ? BigInt(value) : value;\n if (typeof value === 'string') return normalizeDate(value);\n return JSON.stringify(value);\n}\n\n// Exactly `s.split('\\n').length` without allocating the array: callers that need only the count\n// run it per file per feature on the parse hot path.\nexport function countLines(s: string): number {\n let n = 1;\n for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) === 10) n++;\n return n;\n}\n\n// The delimiter split is all this package used gray-matter for.\nexport function splitFrontmatter(raw: string): { fm: string | null; body: string } {\n const open = raw.match(/^---\\r?\\n/);\n if (!open) return { fm: null, body: raw };\n const rest = raw.slice(open[0].length);\n const close = rest.match(/^---\\r?(\\n|$)/m);\n if (!close || close.index === undefined) return { fm: null, body: raw };\n return { fm: rest.slice(0, close.index), body: rest.slice(close.index + close[0].length) };\n}\n\n// A well-formed document can hold a value nobody meant: `created: {{date}}` is valid YAML for a flow map used as a mapping key, so it raises no error and stores {\"{ date }\": null}.\n// No error code catches that; yaml's own warning lacks a path and fires once per document, so this reports it here instead, with the path.\nfunction warnStringifiedKeys(relPath: string, doc: ReturnType<typeof parseDocument>, warnings: string[]): void {\n let found = false;\n // Nested, not top level: `created: {{date}}` puts the collection key one level down, inside\n // the flow map that `{{...}}` parses as.\n visit(doc, {\n Pair(_key, pair) {\n if (!isCollection(pair.key)) return undefined;\n found = true;\n return visit.BREAK;\n },\n });\n // One per file: a template repeats the same mistake on every field it stamps.\n if (found) warnings.push(`warning: ${relPath} frontmatter has a key that is itself a list or mapping, stored as text; this is usually an unrendered template placeholder like {{date}}`);\n}\n\n// Anything past ACCEPTED_YAML_CODES is quarantined: no frontmatter columns, `_parse_error` carries the reason. Recovering it would write values nobody wrote, worse than absence since no query can see it; content, links and sections never touch frontmatter, so a broken note stays searchable.\n// yaml's message continues onto a source snippet, so the first line is the sentence, minus the colon that introduced the part being dropped.\nfunction firstLine(message: string): string {\n return message.split('\\n')[0].replace(/:\\s*$/, '');\n}\n\nexport function parseFrontmatter(relPath: string, fm: string, warnings: string[]): { data: Record<string, unknown>; parseError: string | null } {\n // logLevel silences yaml's own pathless warnings; warnStringifiedKeys re-reports the one\n // that carries information, with the file it came from.\n const doc = parseDocument(fm, { logLevel: 'silent' });\n const refused = doc.errors.filter((err) => !ACCEPTED_YAML_CODES.has(err.code));\n if (refused.length > 0) {\n const detail = refused.length > 1 ? ` (and ${refused.length - 1} more)` : '';\n const parseError = `${firstLine(refused[0].message)}${detail}`;\n warnings.push(`warning: ${relPath} frontmatter did not parse, so none of it is indexed: ${parseError}`);\n return { data: {}, parseError };\n }\n\n let data: unknown;\n try {\n data = doc.toJS();\n } catch (err) {\n // Reaches here with doc.errors empty: `title: **Bold**` parses, then opens an alias on\n // materialisation. An empty error list is not a successful parse.\n const parseError = firstLine((err as Error).message);\n warnings.push(`warning: ${relPath} frontmatter did not parse, so none of it is indexed: ${parseError}`);\n return { data: {}, parseError };\n }\n\n if (data === null || data === undefined) return { data: {}, parseError: null };\n if (typeof data !== 'object' || Array.isArray(data)) {\n const parseError = 'frontmatter is not a key-value mapping';\n warnings.push(`warning: ${relPath} ${parseError}; none of it is indexed`);\n return { data: {}, parseError };\n }\n warnStringifiedKeys(relPath, doc, warnings);\n return { data: data as Record<string, unknown>, parseError: null };\n}\n"],"names":["RESERVED_COLUMNS","countLines","looksLikeDatetime","mapValue","normalizeDate","normalizeText","parseFrontmatter","splitFrontmatter","Set","ACCEPTED_YAML_CODES","value","undefined","String","replace","trim","ISO_DATETIME","MEANT_AS_DATETIME","test","m","exec","date","time","zone","digits","offset","length","slice","normalized","Number","isNaN","Date","parse","BigInt","isSafeInteger","JSON","stringify","s","n","i","charCodeAt","raw","open","match","fm","body","rest","close","index","warnStringifiedKeys","relPath","doc","warnings","found","visit","Pair","_key","pair","isCollection","key","BREAK","push","firstLine","message","split","parseDocument","logLevel","refused","errors","filter","err","has","code","detail","parseError","data","toJS","Array","isArray"],"mappings":";;;;;;;;;;;QAIaA;eAAAA;;QA+CGC;eAAAA;;QA5BAC;eAAAA;;QAkBAC;eAAAA;;QAZAC;eAAAA;;QAnBAC;eAAAA;;QAgFAC;eAAAA;;QAhCAC;eAAAA;;;oBA1DmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAI5C,IAAMP,mBAAmB,IAAIQ,IAAI;IAAC;IAAQ;IAAU;IAAU;IAAS;IAAS;IAAgB;IAAW;IAAS;CAAW;AAEtI,wJAAwJ;AACxJ,iJAAiJ;AACjJ,IAAMC,sBAAsB,IAAID,IAAI;IAAC;CAAmB;AAEjD,SAASH,cAAcK,KAAc;IAC1C,IAAIA,UAAU,QAAQA,UAAUC,WAAW,OAAO;IAClD,OAAOC,OAAOF,OAAOG,OAAO,CAAC,QAAQ,KAAKC,IAAI;AAChD;AAEA,iGAAiG;AACjG,mGAAmG;AACnG,IAAMC,eAAe;AAErB,6FAA6F;AAC7F,6FAA6F;AAC7F,IAAMC,oBAAoB;AAEnB,SAASd,kBAAkBQ,KAAa;IAC7C,OAAOM,kBAAkBC,IAAI,CAACP;AAChC;AAIO,SAASN,cAAcM,KAAa;IACzC,IAAMQ,IAAIH,aAAaI,IAAI,CAACT;IAC5B,IAAIQ,MAAM,MAAM,OAAOR;IACvB,IAA6BQ,sBAAAA,OAApBE,OAAoBF,OAAdG,OAAcH,OAARI,OAAQJ;IAC7B,IAAMK,SAASD,SAASX,aAAaW,SAAS,MAAM,KAAKA,KAAKT,OAAO,CAAC,KAAK;IAC3E,IAAMW,SAASD,WAAW,KAAMD,iBAAAA,kBAAAA,OAAQ,KAAMC,OAAOE,MAAM,KAAK,IAAI,AAAC,GAAS,OAAPF,QAAO,SAAO,AAAC,GAAwBA,OAAtBA,OAAOG,KAAK,CAAC,GAAG,IAAG,KAAmB,OAAhBH,OAAOG,KAAK,CAAC;IAC3H,IAAMC,aAAa,AAAC,GAAUN,OAARD,MAAK,KAAUI,OAAPH,MAAc,OAAPG;IACrC,OAAOI,OAAOC,KAAK,CAACC,KAAKC,KAAK,CAACJ,eAAejB,QAAQiB;AACxD;AAIO,SAASxB,SAASO,KAAc;IACrC,IAAIA,UAAU,QAAQA,UAAUC,WAAW,OAAO;IAClD,IAAI,OAAOD,UAAU,WAAW,OAAOsB,OAAOtB,QAAQ,IAAI;IAC1D,IAAI,OAAOA,UAAU,UAAU,OAAOkB,OAAOK,aAAa,CAACvB,SAASsB,OAAOtB,SAASA;IACpF,IAAI,OAAOA,UAAU,UAAU,OAAON,cAAcM;IACpD,OAAOwB,KAAKC,SAAS,CAACzB;AACxB;AAIO,SAAST,WAAWmC,CAAS;IAClC,IAAIC,IAAI;IACR,IAAK,IAAIC,IAAI,GAAGA,IAAIF,EAAEX,MAAM,EAAEa,IAAK,IAAIF,EAAEG,UAAU,CAACD,OAAO,IAAID;IAC/D,OAAOA;AACT;AAGO,SAAS9B,iBAAiBiC,GAAW;IAC1C,IAAMC,OAAOD,IAAIE,KAAK,CAAC;IACvB,IAAI,CAACD,MAAM,OAAO;QAAEE,IAAI;QAAMC,MAAMJ;IAAI;IACxC,IAAMK,OAAOL,IAAId,KAAK,CAACe,IAAI,CAAC,EAAE,CAAChB,MAAM;IACrC,IAAMqB,QAAQD,KAAKH,KAAK,CAAC;IACzB,IAAI,CAACI,SAASA,MAAMC,KAAK,KAAKpC,WAAW,OAAO;QAAEgC,IAAI;QAAMC,MAAMJ;IAAI;IACtE,OAAO;QAAEG,IAAIE,KAAKnB,KAAK,CAAC,GAAGoB,MAAMC,KAAK;QAAGH,MAAMC,KAAKnB,KAAK,CAACoB,MAAMC,KAAK,GAAGD,KAAK,CAAC,EAAE,CAACrB,MAAM;IAAE;AAC3F;AAEA,qLAAqL;AACrL,2IAA2I;AAC3I,SAASuB,oBAAoBC,OAAe,EAAEC,GAAqC,EAAEC,QAAkB;IACrG,IAAIC,QAAQ;IACZ,4FAA4F;IAC5F,yCAAyC;IACzCC,IAAAA,WAAK,EAACH,KAAK;QACTI,MAAAA,SAAAA,KAAKC,IAAI,EAAEC,IAAI;YACb,IAAI,CAACC,IAAAA,kBAAY,EAACD,KAAKE,GAAG,GAAG,OAAO/C;YACpCyC,QAAQ;YACR,OAAOC,WAAK,CAACM,KAAK;QACpB;IACF;IACA,8EAA8E;IAC9E,IAAIP,OAAOD,SAASS,IAAI,CAAC,AAAC,YAAmB,OAARX,SAAQ;AAC/C;AAEA,oSAAoS;AACpS,6IAA6I;AAC7I,SAASY,UAAUC,OAAe;IAChC,OAAOA,QAAQC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAClD,OAAO,CAAC,SAAS;AACjD;AAEO,SAASP,iBAAiB2C,OAAe,EAAEN,EAAU,EAAEQ,QAAkB;IAC9E,yFAAyF;IACzF,wDAAwD;IACxD,IAAMD,MAAMc,IAAAA,mBAAa,EAACrB,IAAI;QAAEsB,UAAU;IAAS;IACnD,IAAMC,UAAUhB,IAAIiB,MAAM,CAACC,MAAM,CAAC,SAACC;eAAQ,CAAC5D,oBAAoB6D,GAAG,CAACD,IAAIE,IAAI;;IAC5E,IAAIL,QAAQzC,MAAM,GAAG,GAAG;QACtB,IAAM+C,SAASN,QAAQzC,MAAM,GAAG,IAAI,AAAC,SAA2B,OAAnByC,QAAQzC,MAAM,GAAG,GAAE,YAAU;QAC1E,IAAMgD,aAAa,AAAC,GAAkCD,OAAhCX,UAAUK,OAAO,CAAC,EAAE,CAACJ,OAAO,GAAW,OAAPU;QACtDrB,SAASS,IAAI,CAAC,AAAC,YAA2Ea,OAAhExB,SAAQ,0DAAmE,OAAXwB;QAC1F,OAAO;YAAEC,MAAM,CAAC;YAAGD,YAAAA;QAAW;IAChC;IAEA,IAAIC;IACJ,IAAI;QACFA,OAAOxB,IAAIyB,IAAI;IACjB,EAAE,OAAON,KAAK;QACZ,uFAAuF;QACvF,kEAAkE;QAClE,IAAMI,cAAaZ,UAAU,AAACQ,IAAcP,OAAO;QACnDX,SAASS,IAAI,CAAC,AAAC,YAA2Ea,OAAhExB,SAAQ,0DAAmE,OAAXwB;QAC1F,OAAO;YAAEC,MAAM,CAAC;YAAGD,YAAAA;QAAW;IAChC;IAEA,IAAIC,SAAS,QAAQA,SAAS/D,WAAW,OAAO;QAAE+D,MAAM,CAAC;QAAGD,YAAY;IAAK;IAC7E,IAAI,CAAA,OAAOC,qCAAP,SAAOA,KAAG,MAAM,YAAYE,MAAMC,OAAO,CAACH,OAAO;QACnD,IAAMD,cAAa;QACnBtB,SAASS,IAAI,CAAC,AAAC,YAAsBa,OAAXxB,SAAQ,KAAc,OAAXwB,aAAW;QAChD,OAAO;YAAEC,MAAM,CAAC;YAAGD,YAAAA;QAAW;IAChC;IACAzB,oBAAoBC,SAASC,KAAKC;IAClC,OAAO;QAAEuB,MAAMA;QAAiCD,YAAY;IAAK;AACnE"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/scan/frontmatter.ts"],"sourcesContent":["import { isCollection, parseDocument, visit } from 'yaml';\n\n// Frontmatter keys that would collide with table columns. Exported so reconcile.ts's upsert can tell\n// a feature-owned column (`_rank`) from a parsed one and leave it alone on reparse.\nexport const RESERVED_COLUMNS = new Set(['path', '_mtime', '_ctime', '_size', '_rank', '_parse_error', 'content', 'links', 'sections']);\n\n// Only BAD_SCALAR_START qualifies: YAML 1.2 reserves `@` and `` ` `` at the start of a plain scalar, so `aliases: [@handle]` can only mean [\"@handle\"].\n// Every other code has a second reading (a swallowed key, a dropped URL, a silently overwritten duplicate) that would write values nobody wrote.\nconst ACCEPTED_YAML_CODES = new Set(['BAD_SCALAR_START']);\n\nexport function normalizeText(value: unknown): string {\n if (value === null || value === undefined) return '';\n return String(value).replace(/\\s+/g, ' ').trim();\n}\n\n// SQLite's datetime() rejects a colonless offset (`-0800`) and a space separator, which ISO 8601\n// allows and producers emit. A rejected date is invisible, not excluded: every comparison is NULL.\nconst ISO_DATETIME = /^(\\d{4}-\\d{2}-\\d{2})[T ](\\d{2}:\\d{2}(?::\\d{2})?(?:\\.\\d+)?)(Z|[+-]\\d{2}(?::?\\d{2})?)?$/;\n\n// A value opening `YYYY-MM-DDT` was meant to be a datetime; prose never is. Reported when it\n// cannot be normalized, so a typo surfaces on the next crawl instead of at some later audit.\nconst MEANT_AS_DATETIME = /^\\d{4}-\\d{2}-\\d{2}[T ]\\d/;\n\nexport function looksLikeDatetime(value: string): boolean {\n return MEANT_AS_DATETIME.test(value);\n}\n\n// Punctuation only, never a timezone conversion: the offset survives, so substr(d,1,10) is still\n// the local date. A shape that is not a real instant is left as written, and stays auditable.\nexport function normalizeDate(value: string): string {\n const m = ISO_DATETIME.exec(value);\n if (m === null) return value;\n const [, date, time, zone] = m;\n const digits = zone === undefined || zone === 'Z' ? '' : zone.replace(':', '');\n const offset = digits === '' ? (zone ?? '') : digits.length === 3 ? `${digits}:00` : `${digits.slice(0, 3)}:${digits.slice(3)}`;\n const normalized = `${date}T${time}${offset}`;\n return Number.isNaN(Date.parse(normalized)) ? value : normalized;\n}\n\n// Storage class follows the YAML scalar. Booleans store as 1/0, so `WHERE flag = 1` matches\n// and `WHERE flag = 'true'` cannot; `map` prints observed types so the mismatch is visible.\nexport function mapValue(value: unknown): string | number | bigint | null {\n if (value === null || value === undefined) return null;\n if (typeof value === 'boolean') return BigInt(value ? 1 : 0);\n if (typeof value === 'number') return Number.isSafeInteger(value) ? BigInt(value) : value;\n if (typeof value === 'string') return normalizeDate(value);\n return JSON.stringify(value);\n}\n\n// Exactly `s.split('\\n').length` without allocating the array: callers that need only the count\n// run it per file per feature on the parse hot path.\nexport function countLines(s: string): number {\n let n = 1;\n for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) === 10) n++;\n return n;\n}\n\n// The delimiter split is all this package used gray-matter for.\nexport function splitFrontmatter(raw: string): { fm: string | null; body: string } {\n const open = raw.match(/^---\\r?\\n/);\n if (!open) return { fm: null, body: raw };\n const rest = raw.slice(open[0].length);\n const close = rest.match(/^---\\r?(\\n|$)/m);\n if (!close || close.index === undefined) return { fm: null, body: raw };\n return { fm: rest.slice(0, close.index), body: rest.slice(close.index + close[0].length) };\n}\n\n// A well-formed document can hold a value nobody meant: `created: {{date}}` is valid YAML for a flow map used as a mapping key, so it raises no error and stores {\"{ date }\": null}.\n// No error code catches that; yaml's own warning lacks a path and fires once per document, so this reports it here instead, with the path.\nfunction warnStringifiedKeys(relPath: string, doc: ReturnType<typeof parseDocument>, warnings: string[]): void {\n let found = false;\n // Nested, not top level: `created: {{date}}` puts the collection key one level down, inside\n // the flow map that `{{...}}` parses as.\n visit(doc, {\n Pair(_key, pair) {\n if (!isCollection(pair.key)) return undefined;\n found = true;\n return visit.BREAK;\n },\n });\n // One per file: a template repeats the same mistake on every field it stamps.\n if (found) warnings.push(`warning: ${relPath} frontmatter has a key that is itself a list or mapping, stored as text; this is usually an unrendered template placeholder like {{date}}`);\n}\n\n// Anything past ACCEPTED_YAML_CODES is quarantined: no frontmatter columns, `_parse_error` carries the reason. Recovering it would write values nobody wrote, worse than absence since no query can see it; content, links and sections never touch frontmatter, so a broken note stays searchable.\n// yaml's message continues onto a source snippet, so the first line is the sentence, minus the colon that introduced the part being dropped.\nfunction firstLine(message: string): string {\n return message.split('\\n')[0].replace(/:\\s*$/, '');\n}\n\nexport function parseFrontmatter(relPath: string, fm: string, warnings: string[]): { data: Record<string, unknown>; parseError: string | null } {\n // logLevel silences yaml's own pathless warnings; warnStringifiedKeys re-reports the one\n // that carries information, with the file it came from.\n const doc = parseDocument(fm, { logLevel: 'silent' });\n const refused = doc.errors.filter((err) => !ACCEPTED_YAML_CODES.has(err.code));\n if (refused.length > 0) {\n const detail = refused.length > 1 ? ` (and ${refused.length - 1} more)` : '';\n const parseError = `${firstLine(refused[0].message)}${detail}`;\n warnings.push(`warning: ${relPath} frontmatter did not parse, so none of it is indexed: ${parseError}`);\n return { data: {}, parseError };\n }\n\n let data: unknown;\n try {\n data = doc.toJS();\n } catch (err) {\n // Reaches here with doc.errors empty: `title: **Bold**` parses, then opens an alias on\n // materialisation. An empty error list is not a successful parse.\n const parseError = firstLine((err as Error).message);\n warnings.push(`warning: ${relPath} frontmatter did not parse, so none of it is indexed: ${parseError}`);\n return { data: {}, parseError };\n }\n\n if (data === null || data === undefined) return { data: {}, parseError: null };\n if (typeof data !== 'object' || Array.isArray(data)) {\n const parseError = 'frontmatter is not a key-value mapping';\n warnings.push(`warning: ${relPath} ${parseError}; none of it is indexed`);\n return { data: {}, parseError };\n }\n warnStringifiedKeys(relPath, doc, warnings);\n return { data: data as Record<string, unknown>, parseError: null };\n}\n"],"names":["RESERVED_COLUMNS","countLines","looksLikeDatetime","mapValue","normalizeDate","normalizeText","parseFrontmatter","splitFrontmatter","Set","ACCEPTED_YAML_CODES","value","undefined","String","replace","trim","ISO_DATETIME","MEANT_AS_DATETIME","test","m","exec","date","time","zone","digits","offset","length","slice","normalized","Number","isNaN","Date","parse","BigInt","isSafeInteger","JSON","stringify","s","n","i","charCodeAt","raw","open","match","fm","body","rest","close","index","warnStringifiedKeys","relPath","doc","warnings","found","visit","Pair","_key","pair","isCollection","key","BREAK","push","firstLine","message","split","parseDocument","logLevel","refused","errors","filter","err","has","code","detail","parseError","data","toJS","Array","isArray"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/scan/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { parse } from '../chunk/index.ts';\nimport type { Config } from '../config/index.ts';\nimport type { Feature } from '../features/types.ts';\nimport { textFromBlocks } from '../text/strip.ts';\nimport { looksLikeDatetime, mapValue, normalizeText, parseFrontmatter, RESERVED_COLUMNS, splitFrontmatter } from './frontmatter.ts';\nimport type { FileStat } from './list.ts';\n\n// Filesystem -> rows. Pure data in, data + warnings out; store/sqlite/reconcile.ts does the SQL.\n\nexport { looksLikeDatetime, normalizeDate, RESERVED_COLUMNS } from './frontmatter.ts';\nexport type { FileStat } from './list.ts';\nexport { listFiles, toPosixPath } from './list.ts';\n\nexport interface ParsedDoc {\n relPath: string;\n mtimeMs: number;\n ctimeMs: number;\n size: number;\n presets: string[];\n data: Record<string, string | number | bigint | null>;\n // NULL when the frontmatter parsed, the first YAML message otherwise. In the row rather than\n // a side table so `SELECT *` and any `IS NULL` investigation trip over it without being asked.\n parseError: string | null;\n // Exact decoded source bytes read for this parse generation. Stored outside the FTS table so\n // snippets and delayed embedding never consult a newer filesystem generation.\n source: string;\n // title/summary are duplicated from frontmatter so bm25() can weight them above the body text.\n search: { title: string; summary: string; text: string };\n // Per-feature extraction results, keyed by feature name; features store them at reconcile.\n extracted: Record<string, unknown>;\n}\n\nexport function parseSource(file: FileStat, raw: string, extractors: Feature[] = [], cfg?: Config): { doc: ParsedDoc; warnings: string[] } {\n const warnings: string[] = [];\n\n const { fm, body: content } = splitFrontmatter(raw);\n const { data, parseError } = fm === null ? { data: {} as Record<string, unknown>, parseError: null } : parseFrontmatter(file.relPath, fm, warnings);\n const mapped: Record<string, string | number | bigint | null> = {};\n\n for (const key of Object.keys(data)) {\n if (RESERVED_COLUMNS.has(key)) {\n warnings.push(`warning: ${file.relPath} has a frontmatter key named \"${key}\", which is reserved; ignoring it`);\n continue;\n }\n const value = mapValue(data[key]);\n if (typeof value === 'string' && looksLikeDatetime(value) && Number.isNaN(Date.parse(value))) {\n warnings.push(`warning: ${file.relPath}: ${key} is not a valid date (${value}), so it is invisible to every date comparison`);\n }\n mapped[key] = value;\n }\n\n // Parsed once and shared: the FTS text path (textFromBlocks, ~ strip.ts) and any feature\n // that needs a parse tree (embed's chunker) both read this same block list.\n const blocks = parse(content);\n\n // title/summary are plain YAML strings -- whitespace-collapse only;\n // the prose gets the full markdown strip.\n const search = { title: normalizeText(data.title), summary: normalizeText(data.summary), text: textFromBlocks(blocks) };\n\n return {\n doc: {\n relPath: file.relPath,\n mtimeMs: file.mtimeMs,\n ctimeMs: file.ctimeMs,\n size: file.size,\n presets: file.presets,\n data: mapped,\n parseError,\n source: raw,\n search,\n extracted: Object.fromEntries(extractors.filter((f) => f.extract).map((f) => [f.name, f.extract?.(raw, content, search, data, cfg, blocks)])),\n },\n warnings,\n };\n}\n\nexport function parseFile(file: FileStat, extractors: Feature[] = [], cfg?: Config): { doc: ParsedDoc; warnings: string[] } {\n // Preserve the authored bytes: feature extractors, indexed snippets, and section offsets use\n // the same decoded string from this one read.\n return parseSource(file, readFileSync(file.absPath, 'utf8'), extractors, cfg);\n}\n"],"names":["RESERVED_COLUMNS","listFiles","looksLikeDatetime","normalizeDate","parseFile","parseSource","toPosixPath","file","raw","extractors","cfg","warnings","splitFrontmatter","fm","body","content","data","parseError","parseFrontmatter","relPath","mapped","Object","keys","key","has","push","value","mapValue","Number","isNaN","Date","parse","blocks","search","title","normalizeText","summary","text","textFromBlocks","doc","mtimeMs","ctimeMs","size","presets","source","extracted","fromEntries","filter","f","extract","map","name","readFileSync","absPath"],"mappings":";;;;;;;;;;;QAU2CA;eAAAA,+BAAgB;;QAElDC;eAAAA,iBAAS;;QAFTC;eAAAA,gCAAiB;;QAAEC;eAAAA,4BAAa;;QAmEzBC;eAAAA;;QA5CAC;eAAAA;;QArBIC;eAAAA,mBAAW;;;sBAZF;uBACP;uBAGS;6BACkF;sBAO1E;AAqBhC,SAASD,YAAYE,IAAc,EAAEC,GAAW;QAAEC,aAAAA,iEAAwB,EAAE,EAAEC;IACnF,IAAMC,WAAqB,EAAE;IAE7B,IAA8BC,oBAAAA,IAAAA,+BAAgB,EAACJ,MAAvCK,KAAsBD,kBAAtBC,IAAIC,AAAMC,UAAYH,kBAAlBE;IACZ,IAA6BD,OAAAA,OAAO,OAAO;QAAEG,MAAM,CAAC;QAA8BC,YAAY;IAAK,IAAIC,IAAAA,+BAAgB,EAACX,KAAKY,OAAO,EAAEN,IAAIF,WAAlIK,OAAqBH,KAArBG,MAAMC,aAAeJ,KAAfI;IACd,IAAMG,SAA0D,CAAC;QAE5D,kCAAA,2BAAA;;QAAL,QAAK,YAAaC,OAAOC,IAAI,CAACN,0BAAzB,SAAA,6BAAA,QAAA,yBAAA,iCAAgC;YAAhC,IAAMO,MAAN;YACH,IAAIvB,+BAAgB,CAACwB,GAAG,CAACD,MAAM;gBAC7BZ,SAASc,IAAI,CAAC,AAAC,YAAwDF,OAA7ChB,KAAKY,OAAO,EAAC,kCAAoC,OAAJI,KAAI;gBAC3E;YACF;YACA,IAAMG,QAAQC,IAAAA,uBAAQ,EAACX,IAAI,CAACO,IAAI;YAChC,IAAI,OAAOG,UAAU,YAAYxB,IAAAA,gCAAiB,EAACwB,UAAUE,OAAOC,KAAK,CAACC,KAAKC,KAAK,CAACL,SAAS;gBAC5Ff,SAASc,IAAI,CAAC,AAAC,YAA4BF,OAAjBhB,KAAKY,OAAO,EAAC,MAAgCO,OAA5BH,KAAI,0BAA8B,OAANG,OAAM;YAC/E;YACAN,MAAM,CAACG,IAAI,GAAGG;QAChB;;QAVK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAYL,yFAAyF;IACzF,4EAA4E;IAC5E,IAAMM,SAASD,IAAAA,cAAK,EAAChB;IAErB,oEAAoE;IACpE,0CAA0C;IAC1C,IAAMkB,SAAS;QAAEC,OAAOC,IAAAA,4BAAa,EAACnB,KAAKkB,KAAK;QAAGE,SAASD,IAAAA,4BAAa,EAACnB,KAAKoB,OAAO;QAAGC,MAAMC,IAAAA,uBAAc,EAACN;IAAQ;IAEtH,OAAO;QACLO,KAAK;YACHpB,SAASZ,KAAKY,OAAO;YACrBqB,SAASjC,KAAKiC,OAAO;YACrBC,SAASlC,KAAKkC,OAAO;YACrBC,MAAMnC,KAAKmC,IAAI;YACfC,SAASpC,KAAKoC,OAAO;YACrB3B,MAAMI;YACNH,YAAAA;YACA2B,QAAQpC;YACRyB,QAAAA;YACAY,WAAWxB,OAAOyB,WAAW,CAACrC,WAAWsC,MAAM,CAAC,SAACC;uBAAMA,EAAEC,OAAO;eAAEC,GAAG,CAAC,SAACF;oBAAeA;uBAAT;oBAACA,EAAEG,IAAI;qBAAEH,aAAAA,EAAEC,OAAO,cAATD,iCAAAA,gBAAAA,GAAYxC,KAAKO,SAASkB,QAAQjB,MAAMN,KAAKsB;iBAAQ;;QAC7I;QACArB,UAAAA;IACF;AACF;AAEO,SAASP,UAAUG,IAAc;QAAEE,aAAAA,iEAAwB,EAAE,EAAEC;IACpE,6FAA6F;IAC7F,8CAA8C;IAC9C,OAAOL,YAAYE,MAAM6C,IAAAA,oBAAY,EAAC7C,KAAK8C,OAAO,EAAE,SAAS5C,YAAYC;AAC3E"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/scan/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { parse } from '../chunk/index.ts';\nimport type { Config } from '../config/index.ts';\nimport type { Feature } from '../features/types.ts';\nimport { textFromBlocks } from '../text/strip.ts';\nimport { looksLikeDatetime, mapValue, normalizeText, parseFrontmatter, RESERVED_COLUMNS, splitFrontmatter } from './frontmatter.ts';\nimport type { FileStat } from './list.ts';\n\n// Filesystem -> rows. Pure data in, data + warnings out; store/sqlite/reconcile.ts does the SQL.\n\nexport { looksLikeDatetime, normalizeDate, RESERVED_COLUMNS } from './frontmatter.ts';\nexport type { FileStat } from './list.ts';\nexport { listFiles, toPosixPath } from './list.ts';\n\nexport interface ParsedDoc {\n relPath: string;\n mtimeMs: number;\n ctimeMs: number;\n size: number;\n presets: string[];\n data: Record<string, string | number | bigint | null>;\n // NULL when the frontmatter parsed, the first YAML message otherwise. In the row rather than\n // a side table so `SELECT *` and any `IS NULL` investigation trip over it without being asked.\n parseError: string | null;\n // Exact decoded source bytes read for this parse generation. Stored outside the FTS table so\n // snippets and delayed embedding never consult a newer filesystem generation.\n source: string;\n // title/summary are duplicated from frontmatter so bm25() can weight them above the body text.\n search: { title: string; summary: string; text: string };\n // Per-feature extraction results, keyed by feature name; features store them at reconcile.\n extracted: Record<string, unknown>;\n}\n\nexport function parseSource(file: FileStat, raw: string, extractors: Feature[] = [], cfg?: Config): { doc: ParsedDoc; warnings: string[] } {\n const warnings: string[] = [];\n\n const { fm, body: content } = splitFrontmatter(raw);\n const { data, parseError } = fm === null ? { data: {} as Record<string, unknown>, parseError: null } : parseFrontmatter(file.relPath, fm, warnings);\n const mapped: Record<string, string | number | bigint | null> = {};\n\n for (const key of Object.keys(data)) {\n if (RESERVED_COLUMNS.has(key)) {\n warnings.push(`warning: ${file.relPath} has a frontmatter key named \"${key}\", which is reserved; ignoring it`);\n continue;\n }\n const value = mapValue(data[key]);\n if (typeof value === 'string' && looksLikeDatetime(value) && Number.isNaN(Date.parse(value))) {\n warnings.push(`warning: ${file.relPath}: ${key} is not a valid date (${value}), so it is invisible to every date comparison`);\n }\n mapped[key] = value;\n }\n\n // Parsed once and shared: the FTS text path (textFromBlocks, ~ strip.ts) and any feature\n // that needs a parse tree (embed's chunker) both read this same block list.\n const blocks = parse(content);\n\n // title/summary are plain YAML strings -- whitespace-collapse only;\n // the prose gets the full markdown strip.\n const search = { title: normalizeText(data.title), summary: normalizeText(data.summary), text: textFromBlocks(blocks) };\n\n return {\n doc: {\n relPath: file.relPath,\n mtimeMs: file.mtimeMs,\n ctimeMs: file.ctimeMs,\n size: file.size,\n presets: file.presets,\n data: mapped,\n parseError,\n source: raw,\n search,\n extracted: Object.fromEntries(extractors.filter((f) => f.extract).map((f) => [f.name, f.extract?.(raw, content, search, data, cfg, blocks)])),\n },\n warnings,\n };\n}\n\nexport function parseFile(file: FileStat, extractors: Feature[] = [], cfg?: Config): { doc: ParsedDoc; warnings: string[] } {\n // Preserve the authored bytes: feature extractors, indexed snippets, and section offsets use\n // the same decoded string from this one read.\n return parseSource(file, readFileSync(file.absPath, 'utf8'), extractors, cfg);\n}\n"],"names":["RESERVED_COLUMNS","listFiles","looksLikeDatetime","normalizeDate","parseFile","parseSource","toPosixPath","file","raw","extractors","cfg","warnings","splitFrontmatter","fm","body","content","data","parseError","parseFrontmatter","relPath","mapped","Object","keys","key","has","push","value","mapValue","Number","isNaN","Date","parse","blocks","search","title","normalizeText","summary","text","textFromBlocks","doc","mtimeMs","ctimeMs","size","presets","source","extracted","fromEntries","filter","f","extract","map","name","readFileSync","absPath"],"mappings":";;;;;;;;;;;QAU2CA;eAAAA,+BAAgB;;QAElDC;eAAAA,iBAAS;;QAFTC;eAAAA,gCAAiB;;QAAEC;eAAAA,4BAAa;;QAmEzBC;eAAAA;;QA5CAC;eAAAA;;QArBIC;eAAAA,mBAAW;;;sBAZF;uBACP;uBAGS;6BACkF;sBAO1E;AAqBhC,SAASD,YAAYE,IAAc,EAAEC,GAAW;QAAEC,aAAAA,iEAAwB,EAAE,EAAEC;IACnF,IAAMC,WAAqB,EAAE;IAE7B,IAA8BC,oBAAAA,IAAAA,+BAAgB,EAACJ,MAAvCK,KAAsBD,kBAAtBC,IAAIC,AAAMC,UAAYH,kBAAlBE;IACZ,IAA6BD,OAAAA,OAAO,OAAO;QAAEG,MAAM,CAAC;QAA8BC,YAAY;IAAK,IAAIC,IAAAA,+BAAgB,EAACX,KAAKY,OAAO,EAAEN,IAAIF,WAAlIK,OAAqBH,KAArBG,MAAMC,aAAeJ,KAAfI;IACd,IAAMG,SAA0D,CAAC;QAE5D,kCAAA,2BAAA;;QAAL,QAAK,YAAaC,OAAOC,IAAI,CAACN,0BAAzB,SAAA,6BAAA,QAAA,yBAAA,iCAAgC;YAAhC,IAAMO,MAAN;YACH,IAAIvB,+BAAgB,CAACwB,GAAG,CAACD,MAAM;gBAC7BZ,SAASc,IAAI,CAAC,AAAC,YAAwDF,OAA7ChB,KAAKY,OAAO,EAAC,kCAAoC,OAAJI,KAAI;gBAC3E;YACF;YACA,IAAMG,QAAQC,IAAAA,uBAAQ,EAACX,IAAI,CAACO,IAAI;YAChC,IAAI,OAAOG,UAAU,YAAYxB,IAAAA,gCAAiB,EAACwB,UAAUE,OAAOC,KAAK,CAACC,KAAKC,KAAK,CAACL,SAAS;gBAC5Ff,SAASc,IAAI,CAAC,AAAC,YAA4BF,OAAjBhB,KAAKY,OAAO,EAAC,MAAgCO,OAA5BH,KAAI,0BAA8B,OAANG,OAAM;YAC/E;YACAN,MAAM,CAACG,IAAI,GAAGG;QAChB;;QAVK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAYL,yFAAyF;IACzF,4EAA4E;IAC5E,IAAMM,SAASD,IAAAA,cAAK,EAAChB;IAErB,oEAAoE;IACpE,0CAA0C;IAC1C,IAAMkB,SAAS;QAAEC,OAAOC,IAAAA,4BAAa,EAACnB,KAAKkB,KAAK;QAAGE,SAASD,IAAAA,4BAAa,EAACnB,KAAKoB,OAAO;QAAGC,MAAMC,IAAAA,uBAAc,EAACN;IAAQ;IAEtH,OAAO;QACLO,KAAK;YACHpB,SAASZ,KAAKY,OAAO;YACrBqB,SAASjC,KAAKiC,OAAO;YACrBC,SAASlC,KAAKkC,OAAO;YACrBC,MAAMnC,KAAKmC,IAAI;YACfC,SAASpC,KAAKoC,OAAO;YACrB3B,MAAMI;YACNH,YAAAA;YACA2B,QAAQpC;YACRyB,QAAAA;YACAY,WAAWxB,OAAOyB,WAAW,CAACrC,WAAWsC,MAAM,CAAC,SAACC;uBAAMA,EAAEC,OAAO;eAAEC,GAAG,CAAC,SAACF;oBAAeA;uBAAT;oBAACA,EAAEG,IAAI;qBAAEH,aAAAA,EAAEC,OAAO,cAATD,iCAAAA,gBAAAA,GAAYxC,KAAKO,SAASkB,QAAQjB,MAAMN,KAAKsB;iBAAQ;;QAC7I;QACArB,UAAAA;IACF;AACF;AAEO,SAASP,UAAUG,IAAc;QAAEE,aAAAA,iEAAwB,EAAE,EAAEC;IACpE,6FAA6F;IAC7F,8CAA8C;IAC9C,OAAOL,YAAYE,MAAM6C,IAAAA,oBAAY,EAAC7C,KAAK8C,OAAO,EAAE,SAAS5C,YAAYC;AAC3E"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/scan/list.ts"],"sourcesContent":["import { globSync, statSync } from 'node:fs';\nimport { join, sep } from 'node:path';\nimport type { Config } from '../config/index.ts';\nimport { embedEnabled, presetHasSignal, presetNames } from '../config/index.ts';\n\nexport interface FileStat {\n relPath: string;\n absPath: string;\n mtimeMs: number;\n ctimeMs: number; // filesystem birthtime; a clone or copy resets it, like _mtime\n size: number;\n presets: string[]; // every declared preset covering this file (>= 1; union, overlap allowed)\n embed: boolean; // true iff a model is named and some covering preset's signals include vectors\n}\n\n// Presets are views, not partitions: they overlap freely, and a file's covering set (not one\n// owner) drives indexing. Globs resolve relative to baseDir; unmatched files are not indexed.\nexport function toPosixPath(relPath: string, separator: string = sep): string {\n return separator === '\\\\' ? relPath.split(separator).join('/') : relPath;\n}\n\n// Every command pays listFiles before it answers (the freshness check stats each file), so per-file work here is the hottest path in the package.\n// Everything derivable from the config alone is computed once, above the loop.\nconst NO_THROW = { throwIfNoEntry: false } as const;\n\nexport function listFiles(cfg: Config, baseDir: string): FileStat[] {\n const coverage = new Map<string, Set<string>>();\n const posixNeeded = sep === '\\\\';\n for (const name of presetNames(cfg)) {\n const preset = cfg.presets[name];\n for (const matched of globSync(preset.include, { cwd: baseDir, exclude: preset.exclude })) {\n const relPath = posixNeeded ? toPosixPath(matched) : matched;\n const set = coverage.get(relPath) ?? new Set<string>();\n set.add(name);\n coverage.set(relPath, set);\n }\n }\n\n // Which presets want vectors is a property of the config, not of any file.\n const embedding = embedEnabled(cfg);\n const vectorPresets = embedding ? new Set(presetNames(cfg).filter((name) => presetHasSignal(cfg, name, 'vectors'))) : null;\n\n const files: FileStat[] = [];\n for (const relPath of [...coverage.keys()].sort()) {\n const absPath = join(baseDir, relPath); // join re-applies the platform separator for fs calls\n // node:fs glob matches directories and dangling symlinks; fast-glob returned neither, so\n // one stat filters both back out (throwIfNoEntry keeps a dangling link from throwing).\n const st = statSync(absPath, NO_THROW);\n if (!st?.isFile()) continue;\n const presets = [...(coverage.get(relPath) as Set<string>)].sort();\n const embed = vectorPresets !== null && presets.some((name) => vectorPresets.has(name));\n files.push({ relPath, absPath, mtimeMs: st.mtimeMs, ctimeMs: st.birthtimeMs, size: st.size, presets, embed });\n }\n return files;\n}\n"],"names":["listFiles","toPosixPath","relPath","separator","sep","split","join","NO_THROW","throwIfNoEntry","cfg","baseDir","coverage","Map","posixNeeded","presetNames","name","preset","presets","globSync","include","cwd","exclude","matched","set","get","Set","add","embedding","embedEnabled","vectorPresets","filter","presetHasSignal","files","keys","sort","absPath","st","statSync","isFile","embed","some","has","push","mtimeMs","ctimeMs","birthtimeMs","size"],"mappings":";;;;;;;;;;;QAyBgBA;eAAAA;;QARAC;eAAAA;;;sBAjBmB;wBACT;uBAEiC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcpD,SAASA,YAAYC,OAAe;QAAEC,YAAAA,iEAAoBC,aAAG;IAClE,OAAOD,cAAc,OAAOD,QAAQG,KAAK,CAACF,WAAWG,IAAI,CAAC,OAAOJ;AACnE;AAEA,kJAAkJ;AAClJ,+EAA+E;AAC/E,IAAMK,WAAW;IAAEC,gBAAgB;AAAM;AAElC,SAASR,UAAUS,GAAW,EAAEC,OAAe;IACpD,IAAMC,WAAW,IAAIC;IACrB,IAAMC,cAAcT,aAAG,KAAK;QACvB,kCAAA,2BAAA;;QAAL,QAAK,YAAcU,IAAAA,oBAAW,EAACL,yBAA1B,SAAA,6BAAA,QAAA,yBAAA,iCAAgC;YAAhC,IAAMM,OAAN;YACH,IAAMC,SAASP,IAAIQ,OAAO,CAACF,KAAK;gBAC3B,mCAAA,4BAAA;;gBAAL,QAAK,aAAiBG,IAAAA,gBAAQ,EAACF,OAAOG,OAAO,EAAE;oBAAEC,KAAKV;oBAASW,SAASL,OAAOK,OAAO;gBAAC,uBAAlF,UAAA,8BAAA,SAAA,0BAAA,kCAAsF;oBAAtF,IAAMC,UAAN;wBAESX;oBADZ,IAAMT,UAAUW,cAAcZ,YAAYqB,WAAWA;oBACrD,IAAMC,OAAMZ,gBAAAA,SAASa,GAAG,CAACtB,sBAAbS,2BAAAA,gBAAyB,IAAIc;oBACzCF,IAAIG,GAAG,CAACX;oBACRJ,SAASY,GAAG,CAACrB,SAASqB;gBACxB;;gBALK;gBAAA;;;yBAAA,8BAAA;wBAAA;;;wBAAA;8BAAA;;;;QAMP;;QARK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAUL,2EAA2E;IAC3E,IAAMI,YAAYC,IAAAA,qBAAY,EAACnB;IAC/B,IAAMoB,gBAAgBF,YAAY,IAAIF,IAAIX,IAAAA,oBAAW,EAACL,KAAKqB,MAAM,CAAC,SAACf;eAASgB,IAAAA,wBAAe,EAACtB,KAAKM,MAAM;UAAe;IAEtH,IAAMiB,QAAoB,EAAE;QACvB,mCAAA,4BAAA;;QAAL,QAAK,aAAiB,AAAC,qBAAGrB,SAASsB,IAAI,IAAIC,IAAI,uBAA1C,UAAA,8BAAA,SAAA,0BAAA,kCAA8C;YAA9C,IAAMhC,WAAN;YACH,IAAMiC,UAAU7B,IAAAA,cAAI,EAACI,SAASR,WAAU,sDAAsD;YAC9F,yFAAyF;YACzF,uFAAuF;YACvF,IAAMkC,KAAKC,IAAAA,gBAAQ,EAACF,SAAS5B;YAC7B,IAAI,EAAC6B,eAAAA,yBAAAA,GAAIE,MAAM,KAAI;YACnB,IAAMrB,UAAU,AAAC,qBAAIN,SAASa,GAAG,CAACtB,WAA0BgC,IAAI;YAChE,IAAMK,QAAQV,kBAAkB,QAAQZ,QAAQuB,IAAI,CAAC,SAACzB;uBAASc,cAAcY,GAAG,CAAC1B;;YACjFiB,MAAMU,IAAI,CAAC;gBAAExC,SAAAA;gBAASiC,SAAAA;gBAASQ,SAASP,GAAGO,OAAO;gBAAEC,SAASR,GAAGS,WAAW;gBAAEC,MAAMV,GAAGU,IAAI;gBAAE7B,SAAAA;gBAASsB,OAAAA;YAAM;QAC7G;;QATK;QAAA;;;iBAAA,8BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAUL,OAAOP;AACT"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/scan/list.ts"],"sourcesContent":["import { globSync, statSync } from 'node:fs';\nimport { join, sep } from 'node:path';\nimport type { Config } from '../config/index.ts';\nimport { embedEnabled, presetHasSignal, presetNames } from '../config/index.ts';\n\nexport interface FileStat {\n relPath: string;\n absPath: string;\n mtimeMs: number;\n ctimeMs: number; // filesystem birthtime; a clone or copy resets it, like _mtime\n size: number;\n presets: string[]; // every declared preset covering this file (>= 1; union, overlap allowed)\n embed: boolean; // true iff a model is named and some covering preset's signals include vectors\n}\n\n// Presets are views, not partitions: they overlap freely, and a file's covering set (not one\n// owner) drives indexing. Globs resolve relative to baseDir; unmatched files are not indexed.\nexport function toPosixPath(relPath: string, separator: string = sep): string {\n return separator === '\\\\' ? relPath.split(separator).join('/') : relPath;\n}\n\n// Every command pays listFiles before it answers (the freshness check stats each file), so per-file work here is the hottest path in the package.\n// Everything derivable from the config alone is computed once, above the loop.\nconst NO_THROW = { throwIfNoEntry: false } as const;\n\nexport function listFiles(cfg: Config, baseDir: string): FileStat[] {\n const coverage = new Map<string, Set<string>>();\n const posixNeeded = sep === '\\\\';\n for (const name of presetNames(cfg)) {\n const preset = cfg.presets[name];\n for (const matched of globSync(preset.include, { cwd: baseDir, exclude: preset.exclude })) {\n const relPath = posixNeeded ? toPosixPath(matched) : matched;\n const set = coverage.get(relPath) ?? new Set<string>();\n set.add(name);\n coverage.set(relPath, set);\n }\n }\n\n // Which presets want vectors is a property of the config, not of any file.\n const embedding = embedEnabled(cfg);\n const vectorPresets = embedding ? new Set(presetNames(cfg).filter((name) => presetHasSignal(cfg, name, 'vectors'))) : null;\n\n const files: FileStat[] = [];\n for (const relPath of [...coverage.keys()].sort()) {\n const absPath = join(baseDir, relPath); // join re-applies the platform separator for fs calls\n // node:fs glob matches directories and dangling symlinks; fast-glob returned neither, so\n // one stat filters both back out (throwIfNoEntry keeps a dangling link from throwing).\n const st = statSync(absPath, NO_THROW);\n if (!st?.isFile()) continue;\n const presets = [...(coverage.get(relPath) as Set<string>)].sort();\n const embed = vectorPresets !== null && presets.some((name) => vectorPresets.has(name));\n files.push({ relPath, absPath, mtimeMs: st.mtimeMs, ctimeMs: st.birthtimeMs, size: st.size, presets, embed });\n }\n return files;\n}\n"],"names":["listFiles","toPosixPath","relPath","separator","sep","split","join","NO_THROW","throwIfNoEntry","cfg","baseDir","coverage","Map","posixNeeded","presetNames","name","preset","presets","globSync","include","cwd","exclude","matched","set","get","Set","add","embedding","embedEnabled","vectorPresets","filter","presetHasSignal","files","keys","sort","absPath","st","statSync","isFile","embed","some","has","push","mtimeMs","ctimeMs","birthtimeMs","size"],"mappings":";;;;;;;;;;;QAyBgBA;eAAAA;;QARAC;eAAAA;;;sBAjBmB;wBACT;uBAEiC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcpD,SAASA,YAAYC,OAAe;QAAEC,YAAAA,iEAAoBC,aAAG;IAClE,OAAOD,cAAc,OAAOD,QAAQG,KAAK,CAACF,WAAWG,IAAI,CAAC,OAAOJ;AACnE;AAEA,kJAAkJ;AAClJ,+EAA+E;AAC/E,IAAMK,WAAW;IAAEC,gBAAgB;AAAM;AAElC,SAASR,UAAUS,GAAW,EAAEC,OAAe;IACpD,IAAMC,WAAW,IAAIC;IACrB,IAAMC,cAAcT,aAAG,KAAK;QACvB,kCAAA,2BAAA;;QAAL,QAAK,YAAcU,IAAAA,oBAAW,EAACL,yBAA1B,SAAA,6BAAA,QAAA,yBAAA,iCAAgC;YAAhC,IAAMM,OAAN;YACH,IAAMC,SAASP,IAAIQ,OAAO,CAACF,KAAK;gBAC3B,mCAAA,4BAAA;;gBAAL,QAAK,aAAiBG,IAAAA,gBAAQ,EAACF,OAAOG,OAAO,EAAE;oBAAEC,KAAKV;oBAASW,SAASL,OAAOK,OAAO;gBAAC,uBAAlF,UAAA,8BAAA,SAAA,0BAAA,kCAAsF;oBAAtF,IAAMC,UAAN;wBAESX;oBADZ,IAAMT,UAAUW,cAAcZ,YAAYqB,WAAWA;oBACrD,IAAMC,OAAMZ,gBAAAA,SAASa,GAAG,CAACtB,sBAAbS,2BAAAA,gBAAyB,IAAIc;oBACzCF,IAAIG,GAAG,CAACX;oBACRJ,SAASY,GAAG,CAACrB,SAASqB;gBACxB;;gBALK;gBAAA;;;yBAAA,8BAAA;wBAAA;;;wBAAA;8BAAA;;;;QAMP;;QARK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAUL,2EAA2E;IAC3E,IAAMI,YAAYC,IAAAA,qBAAY,EAACnB;IAC/B,IAAMoB,gBAAgBF,YAAY,IAAIF,IAAIX,IAAAA,oBAAW,EAACL,KAAKqB,MAAM,CAAC,SAACf;eAASgB,IAAAA,wBAAe,EAACtB,KAAKM,MAAM;UAAe;IAEtH,IAAMiB,QAAoB,EAAE;QACvB,mCAAA,4BAAA;;QAAL,QAAK,aAAiB,AAAC,qBAAGrB,SAASsB,IAAI,IAAIC,IAAI,uBAA1C,UAAA,8BAAA,SAAA,0BAAA,kCAA8C;YAA9C,IAAMhC,WAAN;YACH,IAAMiC,UAAU7B,IAAAA,cAAI,EAACI,SAASR,WAAU,sDAAsD;YAC9F,yFAAyF;YACzF,uFAAuF;YACvF,IAAMkC,KAAKC,IAAAA,gBAAQ,EAACF,SAAS5B;YAC7B,IAAI,EAAC6B,eAAAA,yBAAAA,GAAIE,MAAM,KAAI;YACnB,IAAMrB,UAAU,AAAC,qBAAIN,SAASa,GAAG,CAACtB,WAA0BgC,IAAI;YAChE,IAAMK,QAAQV,kBAAkB,QAAQZ,QAAQuB,IAAI,CAAC,SAACzB;uBAASc,cAAcY,GAAG,CAAC1B;;YACjFiB,MAAMU,IAAI,CAAC;gBAAExC,SAAAA;gBAASiC,SAAAA;gBAASQ,SAASP,GAAGO,OAAO;gBAAEC,SAASR,GAAGS,WAAW;gBAAEC,MAAMV,GAAGU,IAAI;gBAAE7B,SAAAA;gBAASsB,OAAAA;YAAM;QAC7G;;QATK;QAAA;;;iBAAA,8BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAUL,OAAOP;AACT"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/scan/pool.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { isDeepStrictEqual } from 'node:util';\n// Type-only: erased at build, but keeps depcheck's usage check satisfied for the tier-2\n// `_require` below (see coding-standards' deferral tiers).\nimport type * as TinypoolNS from 'tinypool';\nimport type { Config } from '../config/index.ts';\nimport type { Feature } from '../features/types.ts';\nimport { resolveWorkerFile } from '../lib/worker-file.ts';\nimport type { ParsedDoc } from '../scan/index.ts';\nimport type { ParseTaskResult, ParseWorkerData } from '../workers/parse.ts';\nimport type { FileStat } from './list.ts';\nimport { reviveError } from './worker-error.ts';\n\n// Tinypool is ESM-only; our floor (>=22.20) has native require(esm), so the tier-2 house deferral reaches it.\nconst _require = typeof require === 'undefined' ? createRequire(import.meta.url) : require;\n// Candidate queue depth gives uneven files more than one scheduling turn per worker.\n// The bounded parser comparison decides whether this value ships.\nconst BATCHES_PER_WORKER = 4;\n\n// parseMs is worker-side only (see workers/parse.ts); absent on the serial path.\nexport type FileResult = { doc: ParsedDoc; warnings: string[]; parseMs?: number };\n\n// Created lazily and reused while dispatch context stays equivalent. A builder owns one instance\n// for its lifetime instead of paying pool startup for unchanged reconciles.\nexport class ParsePool {\n private pool: TinypoolNS.Tinypool | undefined;\n private workerData: ParseWorkerData | undefined;\n private workerCount: number | undefined;\n private operation: Promise<void> = Promise.resolve();\n // Tinypools this instance has constructed. Repeated equivalent dispatches leave this unchanged;\n // a context/count change or close followed by run constructs another pool.\n poolsCreated = 0;\n\n private enqueue<T>(operation: () => Promise<T>): Promise<T> {\n const result = this.operation.then(operation);\n this.operation = result.then(\n () => undefined,\n () => undefined\n );\n return result;\n }\n\n private async ensure(workerData: ParseWorkerData, workerCount: number): Promise<TinypoolNS.Tinypool> {\n if (this.pool && (!isDeepStrictEqual(this.workerData, workerData) || this.workerCount !== workerCount)) await this.destroy();\n if (!this.pool) {\n const { Tinypool } = _require('tinypool') as typeof TinypoolNS;\n this.pool = new Tinypool({ filename: resolveWorkerFile('parse'), minThreads: workerCount, maxThreads: workerCount, workerData });\n this.workerData = workerData;\n this.workerCount = workerCount;\n this.poolsCreated++;\n }\n return this.pool;\n }\n\n // Never the tree: a worker task carries a bounded FileStat batch and returns only what\n // parseFile returns for each file, never the token tree.\n run(files: FileStat[], features: Feature[], cfg: Config, onParsed: ((done: number) => void) | undefined, requestedWorkers: number): Promise<FileResult[]> {\n if (files.length === 0) return Promise.resolve([]);\n // Snapshot at invocation so caller mutation cannot change queued work or its reuse baseline.\n const workerData: ParseWorkerData = { cfg: structuredClone(cfg), featureNames: [...new Set(features.map((feature) => feature.name))].sort() };\n const workerCount = Math.max(1, Math.min(requestedWorkers, files.length));\n return this.enqueue(() => this.dispatch(files, workerData, onParsed, workerCount));\n }\n\n private async dispatch(files: FileStat[], workerData: ParseWorkerData, onParsed: ((done: number) => void) | undefined, workerCount: number): Promise<FileResult[]> {\n const pool = await this.ensure(workerData, workerCount);\n const batches = batchFiles(files, Math.min(files.length, workerCount * BATCHES_PER_WORKER));\n let done = 0;\n const settled = await Promise.all(\n batches.map(async (batch): Promise<{ results: FileResult[]; failures: unknown[] }> => {\n let taskResults: ParseTaskResult;\n try {\n taskResults = (await pool.run(batch)) as ParseTaskResult;\n } catch (err) {\n return { results: [], failures: [err] };\n }\n\n const results: FileResult[] = [];\n const failures: unknown[] = [];\n for (const result of taskResults) {\n if (!result.ok) {\n failures.push(reviveError(result.error));\n continue;\n }\n results.push({ doc: result.doc, warnings: result.warnings, parseMs: result.parseMs });\n try {\n onParsed?.(++done);\n } catch (err) {\n failures.push(err);\n }\n }\n return { results, failures };\n })\n );\n const results: FileResult[] = [];\n const failures: unknown[] = [];\n for (const batch of settled) {\n results.push(...batch.results);\n failures.push(...batch.failures);\n }\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1) throw new AggregateError(failures, `${failures.length} parse tasks failed`);\n // Promise.all and contiguous batches preserve the input order that first-seen columns use.\n return results;\n }\n\n private async destroy(): Promise<void> {\n if (!this.pool) return;\n const pool = this.pool;\n await pool.destroy();\n this.pool = undefined;\n this.workerData = undefined;\n this.workerCount = undefined;\n }\n\n // A pool never created costs nothing to destroy. Queuing lets active dispatches drain first.\n close(): Promise<void> {\n return this.enqueue(() => this.destroy());\n }\n}\n\nfunction batchFiles(files: FileStat[], batchCount: number): FileStat[][] {\n const batches: FileStat[][] = [];\n let start = 0;\n let remainingBytes = files.reduce((sum, file) => sum + file.size, 0);\n\n for (let batchIndex = 0; batchIndex < batchCount; batchIndex++) {\n const remainingBatches = batchCount - batchIndex;\n if (remainingBatches === 1) {\n batches.push(files.slice(start));\n break;\n }\n\n const targetBytes = remainingBytes / remainingBatches;\n const lastEnd = files.length - (remainingBatches - 1);\n let end = start;\n let bytes = 0;\n while (end < lastEnd && (end === start || bytes < targetBytes)) {\n bytes += files[end].size;\n end++;\n }\n batches.push(files.slice(start, end));\n start = end;\n remainingBytes -= bytes;\n }\n return batches;\n}\n"],"names":["ParsePool","_require","require","createRequire","BATCHES_PER_WORKER","operation","Promise","resolve","poolsCreated","enqueue","result","then","undefined","ensure","workerData","workerCount","Tinypool","pool","isDeepStrictEqual","destroy","filename","resolveWorkerFile","minThreads","maxThreads","run","files","features","cfg","onParsed","requestedWorkers","length","structuredClone","featureNames","Set","map","feature","name","sort","Math","max","min","dispatch","batches","done","settled","results","failures","batch","batchFiles","all","taskResults","err","ok","push","reviveError","error","doc","warnings","parseMs","AggregateError","close","batchCount","start","remainingBytes","reduce","sum","file","size","batchIndex","remainingBatches","slice","targetBytes","lastEnd","end","bytes"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/scan/pool.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { isDeepStrictEqual } from 'node:util';\n// Type-only: erased at build, but keeps depcheck's usage check satisfied for the tier-2\n// `_require` below (see coding-standards' deferral tiers).\nimport type * as TinypoolNS from 'tinypool';\nimport type { Config } from '../config/index.ts';\nimport type { Feature } from '../features/types.ts';\nimport { resolveWorkerFile } from '../lib/worker-file.ts';\nimport type { ParsedDoc } from '../scan/index.ts';\nimport type { ParseTaskResult, ParseWorkerData } from '../workers/parse.ts';\nimport type { FileStat } from './list.ts';\nimport { reviveError } from './worker-error.ts';\n\n// Tinypool is ESM-only; our floor (>=22.20) has native require(esm), so the tier-2 house deferral reaches it.\nconst _require = typeof require === 'undefined' ? createRequire(import.meta.url) : require;\n// Candidate queue depth gives uneven files more than one scheduling turn per worker.\n// The bounded parser comparison decides whether this value ships.\nconst BATCHES_PER_WORKER = 4;\n\n// parseMs is worker-side only (see workers/parse.ts); absent on the serial path.\nexport type FileResult = { doc: ParsedDoc; warnings: string[]; parseMs?: number };\n\n// Created lazily and reused while dispatch context stays equivalent. A builder owns one instance\n// for its lifetime instead of paying pool startup for unchanged reconciles.\nexport class ParsePool {\n private pool: TinypoolNS.Tinypool | undefined;\n private workerData: ParseWorkerData | undefined;\n private workerCount: number | undefined;\n private operation: Promise<void> = Promise.resolve();\n // Tinypools this instance has constructed. Repeated equivalent dispatches leave this unchanged;\n // a context/count change or close followed by run constructs another pool.\n poolsCreated = 0;\n\n private enqueue<T>(operation: () => Promise<T>): Promise<T> {\n const result = this.operation.then(operation);\n this.operation = result.then(\n () => undefined,\n () => undefined\n );\n return result;\n }\n\n private async ensure(workerData: ParseWorkerData, workerCount: number): Promise<TinypoolNS.Tinypool> {\n if (this.pool && (!isDeepStrictEqual(this.workerData, workerData) || this.workerCount !== workerCount)) await this.destroy();\n if (!this.pool) {\n const { Tinypool } = _require('tinypool') as typeof TinypoolNS;\n this.pool = new Tinypool({ filename: resolveWorkerFile('parse'), minThreads: workerCount, maxThreads: workerCount, workerData });\n this.workerData = workerData;\n this.workerCount = workerCount;\n this.poolsCreated++;\n }\n return this.pool;\n }\n\n // Never the tree: a worker task carries a bounded FileStat batch and returns only what\n // parseFile returns for each file, never the token tree.\n run(files: FileStat[], features: Feature[], cfg: Config, onParsed: ((done: number) => void) | undefined, requestedWorkers: number): Promise<FileResult[]> {\n if (files.length === 0) return Promise.resolve([]);\n // Snapshot at invocation so caller mutation cannot change queued work or its reuse baseline.\n const workerData: ParseWorkerData = { cfg: structuredClone(cfg), featureNames: [...new Set(features.map((feature) => feature.name))].sort() };\n const workerCount = Math.max(1, Math.min(requestedWorkers, files.length));\n return this.enqueue(() => this.dispatch(files, workerData, onParsed, workerCount));\n }\n\n private async dispatch(files: FileStat[], workerData: ParseWorkerData, onParsed: ((done: number) => void) | undefined, workerCount: number): Promise<FileResult[]> {\n const pool = await this.ensure(workerData, workerCount);\n const batches = batchFiles(files, Math.min(files.length, workerCount * BATCHES_PER_WORKER));\n let done = 0;\n const settled = await Promise.all(\n batches.map(async (batch): Promise<{ results: FileResult[]; failures: unknown[] }> => {\n let taskResults: ParseTaskResult;\n try {\n taskResults = (await pool.run(batch)) as ParseTaskResult;\n } catch (err) {\n return { results: [], failures: [err] };\n }\n\n const results: FileResult[] = [];\n const failures: unknown[] = [];\n for (const result of taskResults) {\n if (!result.ok) {\n failures.push(reviveError(result.error));\n continue;\n }\n results.push({ doc: result.doc, warnings: result.warnings, parseMs: result.parseMs });\n try {\n onParsed?.(++done);\n } catch (err) {\n failures.push(err);\n }\n }\n return { results, failures };\n })\n );\n const results: FileResult[] = [];\n const failures: unknown[] = [];\n for (const batch of settled) {\n results.push(...batch.results);\n failures.push(...batch.failures);\n }\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1) throw new AggregateError(failures, `${failures.length} parse tasks failed`);\n // Promise.all and contiguous batches preserve the input order that first-seen columns use.\n return results;\n }\n\n private async destroy(): Promise<void> {\n if (!this.pool) return;\n const pool = this.pool;\n await pool.destroy();\n this.pool = undefined;\n this.workerData = undefined;\n this.workerCount = undefined;\n }\n\n // A pool never created costs nothing to destroy. Queuing lets active dispatches drain first.\n close(): Promise<void> {\n return this.enqueue(() => this.destroy());\n }\n}\n\nfunction batchFiles(files: FileStat[], batchCount: number): FileStat[][] {\n const batches: FileStat[][] = [];\n let start = 0;\n let remainingBytes = files.reduce((sum, file) => sum + file.size, 0);\n\n for (let batchIndex = 0; batchIndex < batchCount; batchIndex++) {\n const remainingBatches = batchCount - batchIndex;\n if (remainingBatches === 1) {\n batches.push(files.slice(start));\n break;\n }\n\n const targetBytes = remainingBytes / remainingBatches;\n const lastEnd = files.length - (remainingBatches - 1);\n let end = start;\n let bytes = 0;\n while (end < lastEnd && (end === start || bytes < targetBytes)) {\n bytes += files[end].size;\n end++;\n }\n batches.push(files.slice(start, end));\n start = end;\n remainingBytes -= bytes;\n }\n return batches;\n}\n"],"names":["ParsePool","_require","require","createRequire","BATCHES_PER_WORKER","operation","Promise","resolve","poolsCreated","enqueue","result","then","undefined","ensure","workerData","workerCount","Tinypool","pool","isDeepStrictEqual","destroy","filename","resolveWorkerFile","minThreads","maxThreads","run","files","features","cfg","onParsed","requestedWorkers","length","structuredClone","featureNames","Set","map","feature","name","sort","Math","max","min","dispatch","batches","done","settled","results","failures","batch","batchFiles","all","taskResults","err","ok","push","reviveError","error","doc","warnings","parseMs","AggregateError","close","batchCount","start","remainingBytes","reduce","sum","file","size","batchIndex","remainingBatches","slice","targetBytes","lastEnd","end","bytes"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/scan/reparse.ts"],"sourcesContent":["import { availableParallelism } from 'node:os';\nimport type { Config } from '../config/index.ts';\nimport type { Feature } from '../features/types.ts';\nimport type { ParsedDoc } from './index.ts';\nimport { parseFile } from './index.ts';\nimport type { FileStat } from './list.ts';\nimport type { FileResult } from './pool.ts';\nimport { ParsePool } from './pool.ts';\n\n// Store-agnostic per-file parse pass shared by every store's reconcile(). Index-preserving:\n// one pass over `files`, pushed in order.\nexport interface ReparseResult {\n docs: ParsedDoc[];\n warnings: string[];\n // Frontmatter keys not in `knownColumns`, first-seen order -- the order callers ALTER TABLE ADD COLUMN in.\n newColumns: string[];\n // Sum of worker-side parseFile time (workers/parse.ts) across files; 0 on the serial path.\n workerParseMs: number;\n}\n\nexport interface ReparseOptions {\n // Overrides PARSE_BYTES_PER_WORKER below. Zero forces worker dispatch in tests.\n // Internal: no caller in src/ passes it.\n threshold?: number;\n // Overrides DEFAULT_MAX_WORKERS below.\n maxWorkers?: number;\n // A builder-owned pool to dispatch through instead of creating and destroying one for this\n // call alone (see store/builder.ts). Absent, reparseFiles manages its own ephemeral pool.\n pool?: ParsePool;\n}\n\n// The 2026-09-26 comparison kept ~326 KiB updates serial and 5.86 MiB work pooled.\n// Companion byte shares prevent one dominant file from selecting workers for a tiny remainder.\nexport const PARSE_BYTES_PER_WORKER = 512 * 1024;\nconst DEFAULT_MAX_WORKERS = 8;\n\n// Per-file feature filtering, shared by the serial loop (reads `features` from the caller) and\n// the worker path (can only pass `cfg` across the thread boundary, so derives `features` itself).\nexport function featuresForFile(features: Feature[], cfg: Config, file: FileStat): Feature[] {\n return features.filter((feature) => !feature.enabledForFile || feature.enabledForFile(cfg, file));\n}\n\nfunction reparseSerial(files: FileStat[], features: Feature[], cfg: Config, onParsed?: (done: number) => void): FileResult[] {\n const results: FileResult[] = [];\n let done = 0;\n for (const file of files) {\n const fileFeatures = featuresForFile(features, cfg, file);\n results.push(parseFile(file, fileFeatures, cfg));\n onParsed?.(++done);\n }\n return results;\n}\n\n// Dispatches through `pool` when the caller owns one (a builder, kept alive across calls); with\n// none given, opens an ephemeral ParsePool for this call alone and always closes it.\nasync function reparsePooled(files: FileStat[], features: Feature[], cfg: Config, onParsed: ((done: number) => void) | undefined, maxWorkers: number, pool: ParsePool | undefined): Promise<FileResult[]> {\n if (pool) return pool.run(files, features, cfg, onParsed, maxWorkers);\n const ephemeral = new ParsePool();\n let results: FileResult[] | undefined;\n let dispatchError: unknown;\n let dispatchFailed = false;\n try {\n results = await ephemeral.run(files, features, cfg, onParsed, maxWorkers);\n } catch (err) {\n dispatchFailed = true;\n dispatchError = err;\n }\n try {\n await ephemeral.close();\n } catch (closeError) {\n if (dispatchFailed) throw new AggregateError([dispatchError, closeError], 'parse dispatch and pool close failed');\n throw closeError;\n }\n if (dispatchFailed) throw dispatchError;\n if (results === undefined) throw new Error('parse dispatch finished without results');\n return results;\n}\n\nfunction parseWorkerCount(files: FileStat[], bytesPerWorker: number, maxWorkers: number): number {\n if (files.length === 0) return 0;\n const available = Math.max(1, Math.min(maxWorkers, files.length));\n if (bytesPerWorker === 0) return available;\n let totalBytes = 0;\n let largestBytes = 0;\n for (const file of files) {\n totalBytes += file.size;\n largestBytes = Math.max(largestBytes, file.size);\n }\n const aggregateWorkers = Math.floor(totalBytes / bytesPerWorker);\n // The largest file is indivisible, so extra workers need full shares among the remainder.\n const companionWorkers = 1 + Math.floor((totalBytes - largestBytes) / bytesPerWorker);\n return Math.min(available, aggregateWorkers, companionWorkers);\n}\n\n// `onParsed` receives the running count (1-based) after each file, mirroring a Progress.tick\n// call; pass one in to keep progress reporting working without this module owning a reporter.\nexport async function reparseFiles(files: FileStat[], features: Feature[], cfg: Config, knownColumns: ReadonlySet<string>, onParsed?: (done: number) => void, options: ReparseOptions = {}): Promise<ReparseResult> {\n const threshold = options.threshold ?? PARSE_BYTES_PER_WORKER;\n const maxWorkers = options.maxWorkers ?? Math.min(DEFAULT_MAX_WORKERS, availableParallelism());\n const workerCount = parseWorkerCount(files, threshold, maxWorkers);\n const pooled = files.length > 0 && (threshold === 0 || workerCount >= 2);\n const results = pooled ? await reparsePooled(files, features, cfg, onParsed, workerCount, options.pool) : reparseSerial(files, features, cfg, onParsed);\n\n const docs: ParsedDoc[] = [];\n const warnings: string[] = [];\n const newColumns: string[] = [];\n const seen = new Set(knownColumns);\n let workerParseMs = 0;\n for (const { doc, warnings: fileWarnings, parseMs } of results) {\n warnings.push(...fileWarnings);\n workerParseMs += parseMs ?? 0;\n for (const key of Object.keys(doc.data)) {\n if (!seen.has(key)) {\n seen.add(key);\n newColumns.push(key);\n }\n }\n docs.push(doc);\n }\n\n return { docs, warnings, newColumns, workerParseMs };\n}\n"],"names":["PARSE_BYTES_PER_WORKER","featuresForFile","reparseFiles","DEFAULT_MAX_WORKERS","features","cfg","file","filter","feature","enabledForFile","reparseSerial","files","onParsed","results","done","fileFeatures","push","parseFile","reparsePooled","maxWorkers","pool","ephemeral","dispatchError","dispatchFailed","err","closeError","run","ParsePool","close","AggregateError","undefined","Error","parseWorkerCount","bytesPerWorker","length","available","Math","max","min","totalBytes","largestBytes","size","aggregateWorkers","floor","companionWorkers","knownColumns","options","threshold","workerCount","pooled","docs","warnings","newColumns","seen","workerParseMs","doc","fileWarnings","parseMs","key","availableParallelism","Set","Object","keys","data","has","add"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/scan/reparse.ts"],"sourcesContent":["import { availableParallelism } from 'node:os';\nimport type { Config } from '../config/index.ts';\nimport type { Feature } from '../features/types.ts';\nimport type { ParsedDoc } from './index.ts';\nimport { parseFile } from './index.ts';\nimport type { FileStat } from './list.ts';\nimport type { FileResult } from './pool.ts';\nimport { ParsePool } from './pool.ts';\n\n// Store-agnostic per-file parse pass shared by every store's reconcile(). Index-preserving:\n// one pass over `files`, pushed in order.\nexport interface ReparseResult {\n docs: ParsedDoc[];\n warnings: string[];\n // Frontmatter keys not in `knownColumns`, first-seen order -- the order callers ALTER TABLE ADD COLUMN in.\n newColumns: string[];\n // Sum of worker-side parseFile time (workers/parse.ts) across files; 0 on the serial path.\n workerParseMs: number;\n}\n\nexport interface ReparseOptions {\n // Overrides PARSE_BYTES_PER_WORKER below. Zero forces worker dispatch in tests.\n // Internal: no caller in src/ passes it.\n threshold?: number;\n // Overrides DEFAULT_MAX_WORKERS below.\n maxWorkers?: number;\n // A builder-owned pool to dispatch through instead of creating and destroying one for this\n // call alone (see store/builder.ts). Absent, reparseFiles manages its own ephemeral pool.\n pool?: ParsePool;\n}\n\n// The 2026-09-26 comparison kept ~326 KiB updates serial and 5.86 MiB work pooled.\n// Companion byte shares prevent one dominant file from selecting workers for a tiny remainder.\nexport const PARSE_BYTES_PER_WORKER = 512 * 1024;\nconst DEFAULT_MAX_WORKERS = 8;\n\n// Per-file feature filtering, shared by the serial loop (reads `features` from the caller) and\n// the worker path (can only pass `cfg` across the thread boundary, so derives `features` itself).\nexport function featuresForFile(features: Feature[], cfg: Config, file: FileStat): Feature[] {\n return features.filter((feature) => !feature.enabledForFile || feature.enabledForFile(cfg, file));\n}\n\nfunction reparseSerial(files: FileStat[], features: Feature[], cfg: Config, onParsed?: (done: number) => void): FileResult[] {\n const results: FileResult[] = [];\n let done = 0;\n for (const file of files) {\n const fileFeatures = featuresForFile(features, cfg, file);\n results.push(parseFile(file, fileFeatures, cfg));\n onParsed?.(++done);\n }\n return results;\n}\n\n// Dispatches through `pool` when the caller owns one (a builder, kept alive across calls); with\n// none given, opens an ephemeral ParsePool for this call alone and always closes it.\nasync function reparsePooled(files: FileStat[], features: Feature[], cfg: Config, onParsed: ((done: number) => void) | undefined, maxWorkers: number, pool: ParsePool | undefined): Promise<FileResult[]> {\n if (pool) return pool.run(files, features, cfg, onParsed, maxWorkers);\n const ephemeral = new ParsePool();\n let results: FileResult[] | undefined;\n let dispatchError: unknown;\n let dispatchFailed = false;\n try {\n results = await ephemeral.run(files, features, cfg, onParsed, maxWorkers);\n } catch (err) {\n dispatchFailed = true;\n dispatchError = err;\n }\n try {\n await ephemeral.close();\n } catch (closeError) {\n if (dispatchFailed) throw new AggregateError([dispatchError, closeError], 'parse dispatch and pool close failed');\n throw closeError;\n }\n if (dispatchFailed) throw dispatchError;\n if (results === undefined) throw new Error('parse dispatch finished without results');\n return results;\n}\n\nfunction parseWorkerCount(files: FileStat[], bytesPerWorker: number, maxWorkers: number): number {\n if (files.length === 0) return 0;\n const available = Math.max(1, Math.min(maxWorkers, files.length));\n if (bytesPerWorker === 0) return available;\n let totalBytes = 0;\n let largestBytes = 0;\n for (const file of files) {\n totalBytes += file.size;\n largestBytes = Math.max(largestBytes, file.size);\n }\n const aggregateWorkers = Math.floor(totalBytes / bytesPerWorker);\n // The largest file is indivisible, so extra workers need full shares among the remainder.\n const companionWorkers = 1 + Math.floor((totalBytes - largestBytes) / bytesPerWorker);\n return Math.min(available, aggregateWorkers, companionWorkers);\n}\n\n// `onParsed` receives the running count (1-based) after each file, mirroring a Progress.tick\n// call; pass one in to keep progress reporting working without this module owning a reporter.\nexport async function reparseFiles(files: FileStat[], features: Feature[], cfg: Config, knownColumns: ReadonlySet<string>, onParsed?: (done: number) => void, options: ReparseOptions = {}): Promise<ReparseResult> {\n const threshold = options.threshold ?? PARSE_BYTES_PER_WORKER;\n const maxWorkers = options.maxWorkers ?? Math.min(DEFAULT_MAX_WORKERS, availableParallelism());\n const workerCount = parseWorkerCount(files, threshold, maxWorkers);\n const pooled = files.length > 0 && (threshold === 0 || workerCount >= 2);\n const results = pooled ? await reparsePooled(files, features, cfg, onParsed, workerCount, options.pool) : reparseSerial(files, features, cfg, onParsed);\n\n const docs: ParsedDoc[] = [];\n const warnings: string[] = [];\n const newColumns: string[] = [];\n const seen = new Set(knownColumns);\n let workerParseMs = 0;\n for (const { doc, warnings: fileWarnings, parseMs } of results) {\n warnings.push(...fileWarnings);\n workerParseMs += parseMs ?? 0;\n for (const key of Object.keys(doc.data)) {\n if (!seen.has(key)) {\n seen.add(key);\n newColumns.push(key);\n }\n }\n docs.push(doc);\n }\n\n return { docs, warnings, newColumns, workerParseMs };\n}\n"],"names":["PARSE_BYTES_PER_WORKER","featuresForFile","reparseFiles","DEFAULT_MAX_WORKERS","features","cfg","file","filter","feature","enabledForFile","reparseSerial","files","onParsed","results","done","fileFeatures","push","parseFile","reparsePooled","maxWorkers","pool","ephemeral","dispatchError","dispatchFailed","err","closeError","run","ParsePool","close","AggregateError","undefined","Error","parseWorkerCount","bytesPerWorker","length","available","Math","max","min","totalBytes","largestBytes","size","aggregateWorkers","floor","companionWorkers","knownColumns","options","threshold","workerCount","pooled","docs","warnings","newColumns","seen","workerParseMs","doc","fileWarnings","parseMs","key","availableParallelism","Set","Object","keys","data","has","add"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/scan/worker-error.ts"],"sourcesContent":["import { SenseError, type SenseErrorCode } from '../errors.ts';\n\n// Structured clone across a worker_threads boundary drops a subclass and its custom properties, so\n// a SenseError arrives as a plain Error with `code` undefined (and `code` drives caller behavior): the worker serializes explicitly and the main thread rebuilds by hand.\nexport interface WorkerErrorPayload {\n name: string;\n code?: SenseErrorCode;\n message: string;\n stack?: string;\n}\n\nexport function serializeError(err: unknown): WorkerErrorPayload {\n if (err instanceof Error) return { name: err.name, code: err instanceof SenseError ? err.code : undefined, message: err.message, stack: err.stack };\n return { name: 'Error', message: String(err) };\n}\n\nexport function reviveError(payload: WorkerErrorPayload): Error {\n const err = payload.code ? new SenseError(payload.code, payload.message) : new Error(payload.message);\n err.name = payload.name;\n if (payload.stack) err.stack = payload.stack;\n return err;\n}\n"],"names":["reviveError","serializeError","err","Error","name","code","SenseError","undefined","message","stack","String","payload"],"mappings":";;;;;;;;;;;QAgBgBA;eAAAA;;QALAC;eAAAA;;;wBAXgC;;;;;;;AAWzC,SAASA,eAAeC,GAAY;IACzC,IAAIA,AAAG,YAAHA,KAAeC,QAAO,OAAO;QAAEC,MAAMF,IAAIE,IAAI;QAAEC,MAAMH,AAAG,YAAHA,KAAeI,oBAAU,IAAGJ,IAAIG,IAAI,GAAGE;QAAWC,SAASN,IAAIM,OAAO;QAAEC,OAAOP,IAAIO,KAAK;IAAC;IAClJ,OAAO;QAAEL,MAAM;QAASI,SAASE,OAAOR;IAAK;AAC/C;AAEO,SAASF,YAAYW,OAA2B;IACrD,IAAMT,MAAMS,QAAQN,IAAI,GAAG,IAAIC,oBAAU,CAACK,QAAQN,IAAI,EAAEM,QAAQH,OAAO,IAAI,IAAIL,MAAMQ,QAAQH,OAAO;IACpGN,IAAIE,IAAI,GAAGO,QAAQP,IAAI;IACvB,IAAIO,QAAQF,KAAK,EAAEP,IAAIO,KAAK,GAAGE,QAAQF,KAAK;IAC5C,OAAOP;AACT"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/scan/worker-error.ts"],"sourcesContent":["import { SenseError, type SenseErrorCode } from '../errors.ts';\n\n// Structured clone across a worker_threads boundary drops a subclass and its custom properties, so\n// a SenseError arrives as a plain Error with `code` undefined (and `code` drives caller behavior): the worker serializes explicitly and the main thread rebuilds by hand.\nexport interface WorkerErrorPayload {\n name: string;\n code?: SenseErrorCode;\n message: string;\n stack?: string;\n}\n\nexport function serializeError(err: unknown): WorkerErrorPayload {\n if (err instanceof Error) return { name: err.name, code: err instanceof SenseError ? err.code : undefined, message: err.message, stack: err.stack };\n return { name: 'Error', message: String(err) };\n}\n\nexport function reviveError(payload: WorkerErrorPayload): Error {\n const err = payload.code ? new SenseError(payload.code, payload.message) : new Error(payload.message);\n err.name = payload.name;\n if (payload.stack) err.stack = payload.stack;\n return err;\n}\n"],"names":["reviveError","serializeError","err","Error","name","code","SenseError","undefined","message","stack","String","payload"],"mappings":";;;;;;;;;;;QAgBgBA;eAAAA;;QALAC;eAAAA;;;wBAXgC;;;;;;;AAWzC,SAASA,eAAeC,GAAY;IACzC,IAAIA,AAAG,YAAHA,KAAeC,QAAO,OAAO;QAAEC,MAAMF,IAAIE,IAAI;QAAEC,MAAMH,AAAG,YAAHA,KAAeI,oBAAU,IAAGJ,IAAIG,IAAI,GAAGE;QAAWC,SAASN,IAAIM,OAAO;QAAEC,OAAOP,IAAIO,KAAK;IAAC;IAClJ,OAAO;QAAEL,MAAM;QAASI,SAASE,OAAOR;IAAK;AAC/C;AAEO,SAASF,YAAYW,OAA2B;IACrD,IAAMT,MAAMS,QAAQN,IAAI,GAAG,IAAIC,oBAAU,CAACK,QAAQN,IAAI,EAAEM,QAAQH,OAAO,IAAI,IAAIL,MAAMQ,QAAQH,OAAO;IACpGN,IAAIE,IAAI,GAAGO,QAAQP,IAAI;IACvB,IAAIO,QAAQF,KAAK,EAAEP,IAAIO,KAAK,GAAGE,QAAQF,KAAK;IAC5C,OAAOP;AACT"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/batch.ts"],"sourcesContent":["// Rewrites a single-row parameterized INSERT into one multi-row statement. Engine-neutral string\n// work, shared by duckdb (batch.ts's rewriteBatch) and turso (turso/connection.ts's runBatch).\n\nconst INSERT_RE = /^(INSERT\\s+(?:OR\\s+\\w+\\s+)?INTO\\s+\\S+\\s*\\([^)]*\\)\\s*VALUES\\s*)\\(([^()]*)\\)(.*)$/is;\n\nfunction placeholderCount(tuple: string): number {\n return (tuple.match(/\\?/g) ?? []).length;\n}\n\nexport function rewriteInsert(sql: string, rowCount: number): { sql: string; width: number } | null {\n const m = INSERT_RE.exec(sql.trim());\n if (!m) return null;\n const [, head, tuple, tail] = m;\n const width = placeholderCount(tuple);\n if (width === 0) return null;\n const rows = Array.from({ length: rowCount }, () => `(${tuple})`).join(', ');\n return { sql: `${head}${rows}${tail}`, width };\n}\n"],"names":["rewriteInsert","INSERT_RE","placeholderCount","tuple","match","length","sql","rowCount","m","exec","trim","head","tail","width","rows","Array","from","join"],"mappings":";;;;+BASgBA;;;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAThB,iGAAiG;AACjG,+FAA+F;AAE/F,IAAMC,YAAY;AAElB,SAASC,iBAAiBC,KAAa;QAC7BA;IAAR,OAAO,EAACA,eAAAA,MAAMC,KAAK,CAAC,oBAAZD,0BAAAA,eAAsB,EAAE,EAAEE,MAAM;AAC1C;AAEO,SAASL,cAAcM,GAAW,EAAEC,QAAgB;IACzD,IAAMC,IAAIP,UAAUQ,IAAI,CAACH,IAAII,IAAI;IACjC,IAAI,CAACF,GAAG,OAAO;IACf,IAA8BA,sBAAAA,OAArBG,OAAqBH,OAAfL,QAAeK,OAARI,OAAQJ;IAC9B,IAAMK,QAAQX,iBAAiBC;IAC/B,IAAIU,UAAU,GAAG,OAAO;IACxB,IAAMC,OAAOC,MAAMC,IAAI,CAAC;QAAEX,QAAQE;IAAS,GAAG;eAAM,AAAC,IAAS,OAANJ,OAAM;OAAIc,IAAI,CAAC;IACvE,OAAO;QAAEX,KAAK,AAAC,GAASQ,OAAPH,MAAcC,OAAPE,MAAY,OAALF;QAAQC,OAAAA;IAAM;AAC/C"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/batch.ts"],"sourcesContent":["// Rewrites a single-row parameterized INSERT into one multi-row statement. Engine-neutral string\n// work, shared by duckdb (batch.ts's rewriteBatch) and turso (turso/connection.ts's runBatch).\n\nconst INSERT_RE = /^(INSERT\\s+(?:OR\\s+\\w+\\s+)?INTO\\s+\\S+\\s*\\([^)]*\\)\\s*VALUES\\s*)\\(([^()]*)\\)(.*)$/is;\n\nfunction placeholderCount(tuple: string): number {\n return (tuple.match(/\\?/g) ?? []).length;\n}\n\nexport function rewriteInsert(sql: string, rowCount: number): { sql: string; width: number } | null {\n const m = INSERT_RE.exec(sql.trim());\n if (!m) return null;\n const [, head, tuple, tail] = m;\n const width = placeholderCount(tuple);\n if (width === 0) return null;\n const rows = Array.from({ length: rowCount }, () => `(${tuple})`).join(', ');\n return { sql: `${head}${rows}${tail}`, width };\n}\n"],"names":["rewriteInsert","INSERT_RE","placeholderCount","tuple","match","length","sql","rowCount","m","exec","trim","head","tail","width","rows","Array","from","join"],"mappings":";;;;+BASgBA;;;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAThB,iGAAiG;AACjG,+FAA+F;AAE/F,IAAMC,YAAY;AAElB,SAASC,iBAAiBC,KAAa;QAC7BA;IAAR,OAAO,EAACA,eAAAA,MAAMC,KAAK,CAAC,oBAAZD,0BAAAA,eAAsB,EAAE,EAAEE,MAAM;AAC1C;AAEO,SAASL,cAAcM,GAAW,EAAEC,QAAgB;IACzD,IAAMC,IAAIP,UAAUQ,IAAI,CAACH,IAAII,IAAI;IACjC,IAAI,CAACF,GAAG,OAAO;IACf,IAA8BA,sBAAAA,OAArBG,OAAqBH,OAAfL,QAAeK,OAARI,OAAQJ;IAC9B,IAAMK,QAAQX,iBAAiBC;IAC/B,IAAIU,UAAU,GAAG,OAAO;IACxB,IAAMC,OAAOC,MAAMC,IAAI,CAAC;QAAEX,QAAQE;IAAS,GAAG;eAAM,AAAC,IAAS,OAANJ,OAAM;OAAIc,IAAI,CAAC;IACvE,OAAO;QAAEX,KAAK,AAAC,GAASQ,OAAPH,MAAcC,OAAPE,MAAY,OAALF;QAAQC,OAAAA;IAAM;AAC/C"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/builder.ts"],"sourcesContent":["import { channel } from 'node:diagnostics_channel';\nimport { type Config, featureEnabled, featureSignature, type ResolvedConfig } from '../config/index.ts';\nimport { SenseError } from '../errors.ts';\nimport { embed } from '../features/embed.ts';\nimport { FEATURES } from '../features/index.ts';\nimport { rank } from '../features/rank.ts';\nimport type { ReconcileDelta } from '../features/types.ts';\nimport { listFiles } from '../scan/index.ts';\nimport { ParsePool } from '../scan/pool.ts';\nimport { reparseFiles } from '../scan/reparse.ts';\nimport { classifyEmbedChange } from './embed-scope.ts';\nimport { classifyFeatureToggles, type FeatureToggle, isFeatureOnlyChange, NARROW_FEATURE_TABLE } from './feature-scope.ts';\nimport { forcedPresetPaths, isPresetOnlyChange } from './preset-scope.ts';\nimport { CORE_GENERATION_META_KEY, CORE_READY_META_KEY, FEATURE_SIGNATURE_META_KEY } from './readiness.ts';\nimport { createReconcileTiming, prepareReconcile, type ReconcilePaths, type ReconcileSnapshot, type ReconcileTiming, readReconcileSnapshot } from './reconcile.ts';\nimport { setMeta } from './shared.ts';\nimport { changedSignatureKeys, embedIdentityAdopted, signatureDiff } from './signature.ts';\nimport type { Stages } from './stages.ts';\nimport { withTransaction } from './transaction.ts';\nimport type { Connection, ReconcileDialect } from './types.ts';\n\ninterface BuildResult {\n parsed: number;\n warnings: string[];\n stages: Stages;\n messages: string[];\n}\n\nexport interface Builder {\n build(): Promise<BuildResult>;\n close(): Promise<void>;\n readonly poolsCreated: number;\n}\n\ninterface CoreBaseline {\n schemaVersion: string | null;\n features: string | null;\n ready: string | null;\n generation: string | null;\n}\n\ninterface PlanningSnapshot {\n baseline: CoreBaseline;\n reconcile: ReconcileSnapshot;\n tables: Set<string>;\n}\n\ninterface PreparedInvalidation {\n mutated: boolean;\n parsed: number;\n apply(conn: Connection): Promise<void>;\n}\n\ninterface BuildClassification {\n embedKind: ReturnType<typeof classifyEmbedChange>;\n featureToggles: FeatureToggle[];\n forcedPaths?: ReadonlySet<string>;\n fullRebuild: boolean;\n messages: string[];\n}\n\ntype EnsureFeatureSchema = (cfg: ResolvedConfig) => Promise<void>;\n\nclass StaleBuildPlan extends Error {}\n\nconst buildPlan = channel('sensemaking.store.build-plan');\nconst SCHEMA_VERSION_META_KEY = 'schema_version';\n\nasync function readCoreBaseline(conn: Connection): Promise<CoreBaseline> {\n const keys = [SCHEMA_VERSION_META_KEY, FEATURE_SIGNATURE_META_KEY, CORE_READY_META_KEY, CORE_GENERATION_META_KEY];\n const stmt = await conn.prepare(`SELECT key, value FROM meta WHERE key IN (${keys.map(() => '?').join(', ')})`);\n const values = new Map(((await stmt.all(...keys)) as Array<{ key: string; value: string }>).map((row) => [row.key, row.value]));\n return {\n schemaVersion: values.get(SCHEMA_VERSION_META_KEY) ?? null,\n features: values.get(FEATURE_SIGNATURE_META_KEY) ?? null,\n ready: values.get(CORE_READY_META_KEY) ?? null,\n generation: values.get(CORE_GENERATION_META_KEY) ?? null,\n };\n}\n\nfunction sameBaseline(a: CoreBaseline, b: CoreBaseline): boolean {\n return a.schemaVersion === b.schemaVersion && a.features === b.features && a.ready === b.ready && a.generation === b.generation;\n}\n\nfunction nextGeneration(value: string | null): string {\n const current = value === null ? 0 : Number(value);\n if (!Number.isSafeInteger(current) || current < 0 || current === Number.MAX_SAFE_INTEGER) throw new SenseError('INDEX_NOT_READY', `the durable core generation is invalid (${value ?? 'missing'}); run sense build --force to recreate the derived index`);\n return String(current + 1);\n}\n\nasync function readPlanningSnapshot(conn: Connection, timing: ReconcileTiming): Promise<PlanningSnapshot> {\n return withTransaction(conn, async () => {\n const baseline = await readCoreBaseline(conn);\n const reconcile = await readReconcileSnapshot(conn, timing);\n const tablesStmt = await conn.prepare(\"SELECT name FROM sqlite_master WHERE type = 'table'\");\n const tables = new Set(((await tablesStmt.all()) as Array<{ name: string }>).map((row) => row.name));\n return { baseline, reconcile, tables };\n });\n}\n\nfunction activeSchemaMissing(snapshot: PlanningSnapshot, cfg: Config): boolean {\n for (const feature of FEATURES) {\n if (!featureEnabled(cfg, feature.name)) continue;\n if (feature.name === 'rank') {\n if (!snapshot.reconcile.seenColumns.has('_rank')) return true;\n continue;\n }\n const table = feature.name === 'embed' ? 'embeddings' : NARROW_FEATURE_TABLE[feature.name];\n if (table && !snapshot.tables.has(table)) return true;\n }\n return false;\n}\n\nfunction classifyBuild(snapshot: PlanningSnapshot, cfg: Config, paths: ReconcilePaths, wanted: string): BuildClassification {\n const before = snapshot.baseline.features;\n const recover = snapshot.baseline.ready === '0';\n const messages: string[] = [];\n if (recover) messages.push('sense: recovering an incomplete index generation in place');\n if (!recover && before !== null && before === wanted && activeSchemaMissing(snapshot, cfg)) {\n messages.push('sense: recovering missing feature schema in place');\n return { embedKind: null, featureToggles: [], fullRebuild: true, messages };\n }\n if (recover || before === null || before === wanted) return { embedKind: null, featureToggles: [], fullRebuild: recover, messages };\n\n const changedKeys = changedSignatureKeys(before, wanted);\n if (changedKeys.size === 1 && changedKeys.has('embed') && embedIdentityAdopted(before, wanted)) {\n messages.push(\"sense: recorded the embedding model's resolved identity; vectors are unaffected\");\n return { embedKind: null, featureToggles: [], fullRebuild: false, messages };\n }\n\n const embedKind = changedKeys.size === 1 && changedKeys.has('embed') ? classifyEmbedChange(before, wanted) : null;\n if (embedKind !== null) {\n messages.push(embedKind === 'model' ? 'sense: config change (embed settings) invalidates only the stale vectors' : 'sense: config change (embed settings) rebuilds only the embeddings it affects');\n return { embedKind, featureToggles: [], fullRebuild: false, messages };\n }\n\n const presetForced = isPresetOnlyChange(changedKeys) ? forcedPresetPaths(cfg, paths.rootDir, before, changedKeys) : null;\n if (presetForced !== null) {\n messages.push(`sense: config change (${signatureDiff(before, wanted)}) reparses only the files it affects`);\n return { embedKind: null, featureToggles: [], forcedPaths: presetForced, fullRebuild: false, messages };\n }\n\n const toggles = isFeatureOnlyChange(changedKeys) ? classifyFeatureToggles(before, wanted, changedKeys) : null;\n if (toggles !== null) {\n messages.push(`sense: config change (${signatureDiff(before, wanted)}) reparses only the feature it affects`);\n return { embedKind: null, featureToggles: toggles, fullRebuild: false, messages };\n }\n\n messages.push(`sense: config change (${signatureDiff(before, wanted)}) rebuilds the index`);\n return { embedKind: null, featureToggles: [], fullRebuild: true, messages };\n}\n\nasync function prepareEmbedInvalidation(kind: NonNullable<BuildClassification['embedKind']>, snapshot: PlanningSnapshot, cfg: Config, paths: ReconcilePaths, pool: ParsePool): Promise<PreparedInvalidation> {\n if (kind === 'model') {\n return { mutated: true, parsed: 0, apply: (conn) => conn.exec('UPDATE embeddings SET vector = NULL, scale = NULL') };\n }\n\n const existing = new Set(snapshot.reconcile.existingRows.map((row) => row.path));\n const files = listFiles(cfg, paths.rootDir).filter((file) => file.embed && existing.has(file.relPath));\n const { docs } = await reparseFiles(files, [embed], cfg, new Set(), undefined, { pool });\n const pathsChanged = docs.map((doc) => doc.relPath);\n const delta: ReconcileDelta = { files, reparsed: pathsChanged, added: [], vanished: [] };\n return {\n mutated: true,\n parsed: docs.length,\n async apply(conn) {\n // Chunk changes can also change the model. Clear every affected row even when\n // its text identity happens to match under the new configuration.\n if (pathsChanged.length > 0)\n await conn.runBatch(\n 'DELETE FROM embeddings WHERE \"path\" = ?',\n pathsChanged.map((path) => [path])\n );\n await embed.store?.(\n conn,\n docs.map((doc) => ({ path: doc.relPath, extracted: doc.extracted.embed })),\n delta\n );\n },\n };\n}\n\nasync function prepareFeatureInvalidation(toggles: FeatureToggle[], snapshot: PlanningSnapshot, cfg: Config, paths: ReconcilePaths, pool: ParsePool): Promise<PreparedInvalidation> {\n if (toggles.length === 0) return { mutated: false, parsed: 0, apply: async () => {} };\n const prepared = new Map<string, { feature: (typeof FEATURES)[number]; docs: Awaited<ReturnType<typeof reparseFiles>>['docs']; files: ReturnType<typeof listFiles> }>();\n let parsed = 0;\n for (const toggle of toggles) {\n if (!toggle.turnedOn || toggle.name === 'rank') continue;\n const feature = FEATURES.find((candidate) => candidate.name === toggle.name);\n if (!feature) throw new Error(`prepareFeatureInvalidation: no registered feature named \"${toggle.name}\"`);\n const files = listFiles(cfg, paths.rootDir);\n const { docs } = await reparseFiles(files, [feature], cfg, new Set(), undefined, { pool });\n parsed += docs.length;\n prepared.set(toggle.name, { feature, docs, files });\n }\n\n const applyTable = async (conn: Connection, toggle: FeatureToggle): Promise<void> => {\n const table = NARROW_FEATURE_TABLE[toggle.name];\n if (!table) return;\n if (!toggle.turnedOn) {\n if (snapshot.tables.has(table)) await conn.exec(`DELETE FROM ${table}`);\n return;\n }\n const plan = prepared.get(toggle.name);\n if (!plan) throw new Error(`prepareFeatureInvalidation: missing prepared feature \"${toggle.name}\"`);\n const pathsChanged = plan.docs.map((doc) => doc.relPath);\n const delta: ReconcileDelta = { files: plan.files, reparsed: pathsChanged, added: pathsChanged, vanished: [] };\n await conn.exec(`DELETE FROM ${table}`);\n await plan.feature.store?.(\n conn,\n plan.docs.map((doc) => ({ path: doc.relPath, extracted: doc.extracted[plan.feature.name] })),\n delta\n );\n await plan.feature.afterReconcile?.(conn, delta);\n };\n\n const nullRank = async (conn: Connection): Promise<void> => {\n if (snapshot.reconcile.seenColumns.has('_rank')) await conn.exec('UPDATE frontmatter SET \"_rank\" = NULL');\n };\n\n return {\n mutated: true,\n parsed,\n async apply(conn) {\n const byName = new Map(toggles.map((toggle) => [toggle.name, toggle]));\n const linksToggle = byName.get('links');\n if (linksToggle) {\n await applyTable(conn, linksToggle);\n if (!linksToggle.turnedOn) await nullRank(conn);\n }\n const rankToggle = byName.get('rank');\n if (rankToggle) {\n if (rankToggle.turnedOn) await rank.afterReconcile?.(conn, { files: [], reparsed: [], added: [], vanished: [] });\n else await nullRank(conn);\n }\n for (const toggle of toggles) {\n if (toggle.name !== 'links' && toggle.name !== 'rank') await applyTable(conn, toggle);\n }\n },\n };\n}\n\nfunction recoveryToggles(cfg: Config, snapshot: PlanningSnapshot): FeatureToggle[] {\n const toggles: FeatureToggle[] = [];\n for (const feature of FEATURES) {\n const table = NARROW_FEATURE_TABLE[feature.name];\n if (table && !featureEnabled(cfg, feature.name) && snapshot.tables.has(table)) toggles.push({ name: feature.name, turnedOn: false });\n }\n return toggles;\n}\n\nasync function prepareInvalidation(classification: BuildClassification, snapshot: PlanningSnapshot, cfg: Config, paths: ReconcilePaths, pool: ParsePool): Promise<PreparedInvalidation> {\n const plans: PreparedInvalidation[] = [];\n if (classification.embedKind) plans.push(await prepareEmbedInvalidation(classification.embedKind, snapshot, cfg, paths, pool));\n if (classification.featureToggles.length > 0) plans.push(await prepareFeatureInvalidation(classification.featureToggles, snapshot, cfg, paths, pool));\n if (classification.fullRebuild) {\n plans.push(await prepareFeatureInvalidation(recoveryToggles(cfg, snapshot), snapshot, cfg, paths, pool));\n // Full rebuild and recovery must not reuse vectors from the prior generation.\n if (snapshot.tables.has('embeddings')) {\n plans.push({ mutated: true, parsed: 0, apply: (conn) => conn.exec('DELETE FROM embeddings') });\n }\n if (!featureEnabled(cfg, 'rank') && snapshot.reconcile.seenColumns.has('_rank')) {\n plans.push({ mutated: true, parsed: 0, apply: (conn) => conn.exec('UPDATE frontmatter SET \"_rank\" = NULL') });\n }\n }\n return {\n mutated: plans.some((plan) => plan.mutated),\n parsed: plans.reduce((sum, plan) => sum + plan.parsed, 0),\n async apply(conn) {\n for (const plan of plans) await plan.apply(conn);\n },\n };\n}\n\nfunction forcedPaths(classification: BuildClassification, snapshot: PlanningSnapshot): ReadonlySet<string> | undefined {\n if (!classification.fullRebuild) return classification.forcedPaths;\n // New paths are reparsed by definition. Forcing every previously indexed path makes every\n // survivor a reparse without a second filesystem scan outside prepareReconcile's one listing.\n return new Set(snapshot.reconcile.existingRows.map((row) => row.path));\n}\n\nasync function publishAttempt(conn: Connection, liveCfg: ResolvedConfig, dialect: ReconcileDialect, pool: ParsePool, ensureFeatureSchema: EnsureFeatureSchema, timing: ReconcileTiming, attempt: number): Promise<BuildResult> {\n const cfg = structuredClone(liveCfg);\n const configIdentity = JSON.stringify(cfg);\n const paths: ReconcilePaths = { rootDir: cfg.rootDir ?? cfg.baseDir, configDir: cfg.configDir ?? cfg.baseDir };\n const wanted = featureSignature(cfg, FEATURES);\n const snapshot = await readPlanningSnapshot(conn, timing);\n const classification = classifyBuild(snapshot, cfg, paths, wanted);\n const invalidation = await prepareInvalidation(classification, snapshot, cfg, paths, pool);\n const reconcile = await prepareReconcile(snapshot.reconcile, cfg, paths, dialect, timing, pool, forcedPaths(classification, snapshot));\n const mutated = classification.fullRebuild || invalidation.mutated || reconcile.mutated || snapshot.baseline.features !== wanted || snapshot.baseline.ready !== '1';\n\n if (buildPlan.hasSubscribers) buildPlan.publish({ attempt, baseline: snapshot.baseline, wantedSignature: wanted });\n const txStart = Date.now();\n let txMs: number;\n try {\n await withTransaction(\n conn,\n async () => {\n const current = await readCoreBaseline(conn);\n const currentWanted = featureSignature(liveCfg, FEATURES);\n if (!sameBaseline(current, snapshot.baseline) || JSON.stringify(liveCfg) !== configIdentity || currentWanted !== wanted) {\n throw new StaleBuildPlan('core generation or configuration changed while this build was planning');\n }\n if (!mutated) return;\n await ensureFeatureSchema(cfg);\n await invalidation.apply(conn);\n await reconcile.apply(conn);\n const publishedWanted = featureSignature(liveCfg, FEATURES);\n if (JSON.stringify(liveCfg) !== configIdentity || publishedWanted !== wanted) throw new StaleBuildPlan('configuration changed while this build was publishing');\n await setMeta(conn, FEATURE_SIGNATURE_META_KEY, wanted);\n await setMeta(conn, CORE_READY_META_KEY, '1');\n await setMeta(conn, CORE_GENERATION_META_KEY, nextGeneration(snapshot.baseline.generation));\n },\n dialect.beginMode()\n );\n } finally {\n txMs = Date.now() - txStart;\n timing.txMs += txMs;\n }\n if (reconcile.mutated) await reconcile.record(conn, txMs);\n return {\n parsed: invalidation.parsed + reconcile.parsed,\n warnings: reconcile.warnings,\n stages: reconcile.finish(timing.txMs),\n messages: classification.messages,\n };\n}\n\nexport function createBuilder(conn: Connection, cfg: ResolvedConfig, dialect: ReconcileDialect, ensureFeatureSchema: EnsureFeatureSchema): Builder {\n const pool = new ParsePool();\n return {\n async build() {\n // One clock and recorder span both bounded attempts. Baseline/catalog reads and feature\n // invalidation preparation are included in totalMs but remain intentionally unlabelled;\n // existing/list/parse and publication stages accumulate under their established labels.\n const timing = createReconcileTiming(cfg);\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n return await publishAttempt(conn, cfg, dialect, pool, ensureFeatureSchema, timing, attempt);\n } catch (err) {\n if (!(err instanceof StaleBuildPlan)) throw err;\n if (attempt === 1) throw new SenseError('STORE_BUSY', 'the index changed during both bounded publication attempts; wait for the competing build to finish and retry');\n }\n }\n throw new Error('unreachable build attempt state');\n },\n close: () => pool.close(),\n get poolsCreated() {\n return pool.poolsCreated;\n },\n };\n}\n"],"names":["createBuilder","StaleBuildPlan","Error","buildPlan","channel","SCHEMA_VERSION_META_KEY","readCoreBaseline","conn","stmt","values","keys","FEATURE_SIGNATURE_META_KEY","CORE_READY_META_KEY","CORE_GENERATION_META_KEY","prepare","map","join","Map","all","row","key","value","schemaVersion","get","features","ready","generation","sameBaseline","a","b","nextGeneration","current","Number","isSafeInteger","MAX_SAFE_INTEGER","SenseError","String","readPlanningSnapshot","timing","withTransaction","baseline","reconcile","tablesStmt","tables","readReconcileSnapshot","Set","name","activeSchemaMissing","snapshot","cfg","FEATURES","feature","featureEnabled","seenColumns","has","table","NARROW_FEATURE_TABLE","classifyBuild","paths","wanted","before","recover","messages","push","embedKind","featureToggles","fullRebuild","changedKeys","changedSignatureKeys","size","embedIdentityAdopted","classifyEmbedChange","presetForced","isPresetOnlyChange","forcedPresetPaths","rootDir","signatureDiff","forcedPaths","toggles","isFeatureOnlyChange","classifyFeatureToggles","prepareEmbedInvalidation","kind","pool","existing","files","docs","pathsChanged","delta","mutated","parsed","apply","exec","existingRows","path","listFiles","filter","file","embed","relPath","reparseFiles","undefined","doc","reparsed","added","vanished","length","runBatch","store","extracted","prepareFeatureInvalidation","prepared","applyTable","nullRank","toggle","turnedOn","find","candidate","set","plan","afterReconcile","byName","linksToggle","rankToggle","rank","recoveryToggles","prepareInvalidation","classification","plans","some","reduce","sum","publishAttempt","liveCfg","dialect","ensureFeatureSchema","attempt","configIdentity","invalidation","txStart","txMs","structuredClone","JSON","stringify","baseDir","configDir","featureSignature","prepareReconcile","hasSubscribers","publish","wantedSignature","Date","now","currentWanted","publishedWanted","setMeta","beginMode","record","warnings","stages","finish","ParsePool","build","err","createReconcileTiming","close","poolsCreated"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/builder.ts"],"sourcesContent":["import { channel } from 'node:diagnostics_channel';\nimport { type Config, featureEnabled, featureSignature, type ResolvedConfig } from '../config/index.ts';\nimport { SenseError } from '../errors.ts';\nimport { embed } from '../features/embed.ts';\nimport { FEATURES } from '../features/index.ts';\nimport { rank } from '../features/rank.ts';\nimport type { ReconcileDelta } from '../features/types.ts';\nimport { listFiles } from '../scan/index.ts';\nimport { ParsePool } from '../scan/pool.ts';\nimport { reparseFiles } from '../scan/reparse.ts';\nimport { classifyEmbedChange } from './embed-scope.ts';\nimport { classifyFeatureToggles, type FeatureToggle, isFeatureOnlyChange, NARROW_FEATURE_TABLE } from './feature-scope.ts';\nimport { forcedPresetPaths, isPresetOnlyChange } from './preset-scope.ts';\nimport { CORE_GENERATION_META_KEY, CORE_READY_META_KEY, FEATURE_SIGNATURE_META_KEY } from './readiness.ts';\nimport { createReconcileTiming, prepareReconcile, type ReconcilePaths, type ReconcileSnapshot, type ReconcileTiming, readReconcileSnapshot } from './reconcile.ts';\nimport { setMeta } from './shared.ts';\nimport { changedSignatureKeys, embedIdentityAdopted, signatureDiff } from './signature.ts';\nimport type { Stages } from './stages.ts';\nimport { withTransaction } from './transaction.ts';\nimport type { Connection, ReconcileDialect } from './types.ts';\n\ninterface BuildResult {\n parsed: number;\n warnings: string[];\n stages: Stages;\n messages: string[];\n}\n\nexport interface Builder {\n build(): Promise<BuildResult>;\n close(): Promise<void>;\n readonly poolsCreated: number;\n}\n\ninterface CoreBaseline {\n schemaVersion: string | null;\n features: string | null;\n ready: string | null;\n generation: string | null;\n}\n\ninterface PlanningSnapshot {\n baseline: CoreBaseline;\n reconcile: ReconcileSnapshot;\n tables: Set<string>;\n}\n\ninterface PreparedInvalidation {\n mutated: boolean;\n parsed: number;\n apply(conn: Connection): Promise<void>;\n}\n\ninterface BuildClassification {\n embedKind: ReturnType<typeof classifyEmbedChange>;\n featureToggles: FeatureToggle[];\n forcedPaths?: ReadonlySet<string>;\n fullRebuild: boolean;\n messages: string[];\n}\n\ntype EnsureFeatureSchema = (cfg: ResolvedConfig) => Promise<void>;\n\nclass StaleBuildPlan extends Error {}\n\nconst buildPlan = channel('sensemaking.store.build-plan');\nconst SCHEMA_VERSION_META_KEY = 'schema_version';\n\nasync function readCoreBaseline(conn: Connection): Promise<CoreBaseline> {\n const keys = [SCHEMA_VERSION_META_KEY, FEATURE_SIGNATURE_META_KEY, CORE_READY_META_KEY, CORE_GENERATION_META_KEY];\n const stmt = await conn.prepare(`SELECT key, value FROM meta WHERE key IN (${keys.map(() => '?').join(', ')})`);\n const values = new Map(((await stmt.all(...keys)) as Array<{ key: string; value: string }>).map((row) => [row.key, row.value]));\n return {\n schemaVersion: values.get(SCHEMA_VERSION_META_KEY) ?? null,\n features: values.get(FEATURE_SIGNATURE_META_KEY) ?? null,\n ready: values.get(CORE_READY_META_KEY) ?? null,\n generation: values.get(CORE_GENERATION_META_KEY) ?? null,\n };\n}\n\nfunction sameBaseline(a: CoreBaseline, b: CoreBaseline): boolean {\n return a.schemaVersion === b.schemaVersion && a.features === b.features && a.ready === b.ready && a.generation === b.generation;\n}\n\nfunction nextGeneration(value: string | null): string {\n const current = value === null ? 0 : Number(value);\n if (!Number.isSafeInteger(current) || current < 0 || current === Number.MAX_SAFE_INTEGER) throw new SenseError('INDEX_NOT_READY', `the durable core generation is invalid (${value ?? 'missing'}); run sense build --force to recreate the derived index`);\n return String(current + 1);\n}\n\nasync function readPlanningSnapshot(conn: Connection, timing: ReconcileTiming): Promise<PlanningSnapshot> {\n return withTransaction(conn, async () => {\n const baseline = await readCoreBaseline(conn);\n const reconcile = await readReconcileSnapshot(conn, timing);\n const tablesStmt = await conn.prepare(\"SELECT name FROM sqlite_master WHERE type = 'table'\");\n const tables = new Set(((await tablesStmt.all()) as Array<{ name: string }>).map((row) => row.name));\n return { baseline, reconcile, tables };\n });\n}\n\nfunction activeSchemaMissing(snapshot: PlanningSnapshot, cfg: Config): boolean {\n for (const feature of FEATURES) {\n if (!featureEnabled(cfg, feature.name)) continue;\n if (feature.name === 'rank') {\n if (!snapshot.reconcile.seenColumns.has('_rank')) return true;\n continue;\n }\n const table = feature.name === 'embed' ? 'embeddings' : NARROW_FEATURE_TABLE[feature.name];\n if (table && !snapshot.tables.has(table)) return true;\n }\n return false;\n}\n\nfunction classifyBuild(snapshot: PlanningSnapshot, cfg: Config, paths: ReconcilePaths, wanted: string): BuildClassification {\n const before = snapshot.baseline.features;\n const recover = snapshot.baseline.ready === '0';\n const messages: string[] = [];\n if (recover) messages.push('sense: recovering an incomplete index generation in place');\n if (!recover && before !== null && before === wanted && activeSchemaMissing(snapshot, cfg)) {\n messages.push('sense: recovering missing feature schema in place');\n return { embedKind: null, featureToggles: [], fullRebuild: true, messages };\n }\n if (recover || before === null || before === wanted) return { embedKind: null, featureToggles: [], fullRebuild: recover, messages };\n\n const changedKeys = changedSignatureKeys(before, wanted);\n if (changedKeys.size === 1 && changedKeys.has('embed') && embedIdentityAdopted(before, wanted)) {\n messages.push(\"sense: recorded the embedding model's resolved identity; vectors are unaffected\");\n return { embedKind: null, featureToggles: [], fullRebuild: false, messages };\n }\n\n const embedKind = changedKeys.size === 1 && changedKeys.has('embed') ? classifyEmbedChange(before, wanted) : null;\n if (embedKind !== null) {\n messages.push(embedKind === 'model' ? 'sense: config change (embed settings) invalidates only the stale vectors' : 'sense: config change (embed settings) rebuilds only the embeddings it affects');\n return { embedKind, featureToggles: [], fullRebuild: false, messages };\n }\n\n const presetForced = isPresetOnlyChange(changedKeys) ? forcedPresetPaths(cfg, paths.rootDir, before, changedKeys) : null;\n if (presetForced !== null) {\n messages.push(`sense: config change (${signatureDiff(before, wanted)}) reparses only the files it affects`);\n return { embedKind: null, featureToggles: [], forcedPaths: presetForced, fullRebuild: false, messages };\n }\n\n const toggles = isFeatureOnlyChange(changedKeys) ? classifyFeatureToggles(before, wanted, changedKeys) : null;\n if (toggles !== null) {\n messages.push(`sense: config change (${signatureDiff(before, wanted)}) reparses only the feature it affects`);\n return { embedKind: null, featureToggles: toggles, fullRebuild: false, messages };\n }\n\n messages.push(`sense: config change (${signatureDiff(before, wanted)}) rebuilds the index`);\n return { embedKind: null, featureToggles: [], fullRebuild: true, messages };\n}\n\nasync function prepareEmbedInvalidation(kind: NonNullable<BuildClassification['embedKind']>, snapshot: PlanningSnapshot, cfg: Config, paths: ReconcilePaths, pool: ParsePool): Promise<PreparedInvalidation> {\n if (kind === 'model') {\n return { mutated: true, parsed: 0, apply: (conn) => conn.exec('UPDATE embeddings SET vector = NULL, scale = NULL') };\n }\n\n const existing = new Set(snapshot.reconcile.existingRows.map((row) => row.path));\n const files = listFiles(cfg, paths.rootDir).filter((file) => file.embed && existing.has(file.relPath));\n const { docs } = await reparseFiles(files, [embed], cfg, new Set(), undefined, { pool });\n const pathsChanged = docs.map((doc) => doc.relPath);\n const delta: ReconcileDelta = { files, reparsed: pathsChanged, added: [], vanished: [] };\n return {\n mutated: true,\n parsed: docs.length,\n async apply(conn) {\n // Chunk changes can also change the model. Clear every affected row even when\n // its text identity happens to match under the new configuration.\n if (pathsChanged.length > 0)\n await conn.runBatch(\n 'DELETE FROM embeddings WHERE \"path\" = ?',\n pathsChanged.map((path) => [path])\n );\n await embed.store?.(\n conn,\n docs.map((doc) => ({ path: doc.relPath, extracted: doc.extracted.embed })),\n delta\n );\n },\n };\n}\n\nasync function prepareFeatureInvalidation(toggles: FeatureToggle[], snapshot: PlanningSnapshot, cfg: Config, paths: ReconcilePaths, pool: ParsePool): Promise<PreparedInvalidation> {\n if (toggles.length === 0) return { mutated: false, parsed: 0, apply: async () => {} };\n const prepared = new Map<string, { feature: (typeof FEATURES)[number]; docs: Awaited<ReturnType<typeof reparseFiles>>['docs']; files: ReturnType<typeof listFiles> }>();\n let parsed = 0;\n for (const toggle of toggles) {\n if (!toggle.turnedOn || toggle.name === 'rank') continue;\n const feature = FEATURES.find((candidate) => candidate.name === toggle.name);\n if (!feature) throw new Error(`prepareFeatureInvalidation: no registered feature named \"${toggle.name}\"`);\n const files = listFiles(cfg, paths.rootDir);\n const { docs } = await reparseFiles(files, [feature], cfg, new Set(), undefined, { pool });\n parsed += docs.length;\n prepared.set(toggle.name, { feature, docs, files });\n }\n\n const applyTable = async (conn: Connection, toggle: FeatureToggle): Promise<void> => {\n const table = NARROW_FEATURE_TABLE[toggle.name];\n if (!table) return;\n if (!toggle.turnedOn) {\n if (snapshot.tables.has(table)) await conn.exec(`DELETE FROM ${table}`);\n return;\n }\n const plan = prepared.get(toggle.name);\n if (!plan) throw new Error(`prepareFeatureInvalidation: missing prepared feature \"${toggle.name}\"`);\n const pathsChanged = plan.docs.map((doc) => doc.relPath);\n const delta: ReconcileDelta = { files: plan.files, reparsed: pathsChanged, added: pathsChanged, vanished: [] };\n await conn.exec(`DELETE FROM ${table}`);\n await plan.feature.store?.(\n conn,\n plan.docs.map((doc) => ({ path: doc.relPath, extracted: doc.extracted[plan.feature.name] })),\n delta\n );\n await plan.feature.afterReconcile?.(conn, delta);\n };\n\n const nullRank = async (conn: Connection): Promise<void> => {\n if (snapshot.reconcile.seenColumns.has('_rank')) await conn.exec('UPDATE frontmatter SET \"_rank\" = NULL');\n };\n\n return {\n mutated: true,\n parsed,\n async apply(conn) {\n const byName = new Map(toggles.map((toggle) => [toggle.name, toggle]));\n const linksToggle = byName.get('links');\n if (linksToggle) {\n await applyTable(conn, linksToggle);\n if (!linksToggle.turnedOn) await nullRank(conn);\n }\n const rankToggle = byName.get('rank');\n if (rankToggle) {\n if (rankToggle.turnedOn) await rank.afterReconcile?.(conn, { files: [], reparsed: [], added: [], vanished: [] });\n else await nullRank(conn);\n }\n for (const toggle of toggles) {\n if (toggle.name !== 'links' && toggle.name !== 'rank') await applyTable(conn, toggle);\n }\n },\n };\n}\n\nfunction recoveryToggles(cfg: Config, snapshot: PlanningSnapshot): FeatureToggle[] {\n const toggles: FeatureToggle[] = [];\n for (const feature of FEATURES) {\n const table = NARROW_FEATURE_TABLE[feature.name];\n if (table && !featureEnabled(cfg, feature.name) && snapshot.tables.has(table)) toggles.push({ name: feature.name, turnedOn: false });\n }\n return toggles;\n}\n\nasync function prepareInvalidation(classification: BuildClassification, snapshot: PlanningSnapshot, cfg: Config, paths: ReconcilePaths, pool: ParsePool): Promise<PreparedInvalidation> {\n const plans: PreparedInvalidation[] = [];\n if (classification.embedKind) plans.push(await prepareEmbedInvalidation(classification.embedKind, snapshot, cfg, paths, pool));\n if (classification.featureToggles.length > 0) plans.push(await prepareFeatureInvalidation(classification.featureToggles, snapshot, cfg, paths, pool));\n if (classification.fullRebuild) {\n plans.push(await prepareFeatureInvalidation(recoveryToggles(cfg, snapshot), snapshot, cfg, paths, pool));\n // Full rebuild and recovery must not reuse vectors from the prior generation.\n if (snapshot.tables.has('embeddings')) {\n plans.push({ mutated: true, parsed: 0, apply: (conn) => conn.exec('DELETE FROM embeddings') });\n }\n if (!featureEnabled(cfg, 'rank') && snapshot.reconcile.seenColumns.has('_rank')) {\n plans.push({ mutated: true, parsed: 0, apply: (conn) => conn.exec('UPDATE frontmatter SET \"_rank\" = NULL') });\n }\n }\n return {\n mutated: plans.some((plan) => plan.mutated),\n parsed: plans.reduce((sum, plan) => sum + plan.parsed, 0),\n async apply(conn) {\n for (const plan of plans) await plan.apply(conn);\n },\n };\n}\n\nfunction forcedPaths(classification: BuildClassification, snapshot: PlanningSnapshot): ReadonlySet<string> | undefined {\n if (!classification.fullRebuild) return classification.forcedPaths;\n // New paths are reparsed by definition. Forcing every previously indexed path makes every\n // survivor a reparse without a second filesystem scan outside prepareReconcile's one listing.\n return new Set(snapshot.reconcile.existingRows.map((row) => row.path));\n}\n\nasync function publishAttempt(conn: Connection, liveCfg: ResolvedConfig, dialect: ReconcileDialect, pool: ParsePool, ensureFeatureSchema: EnsureFeatureSchema, timing: ReconcileTiming, attempt: number): Promise<BuildResult> {\n const cfg = structuredClone(liveCfg);\n const configIdentity = JSON.stringify(cfg);\n const paths: ReconcilePaths = { rootDir: cfg.rootDir ?? cfg.baseDir, configDir: cfg.configDir ?? cfg.baseDir };\n const wanted = featureSignature(cfg, FEATURES);\n const snapshot = await readPlanningSnapshot(conn, timing);\n const classification = classifyBuild(snapshot, cfg, paths, wanted);\n const invalidation = await prepareInvalidation(classification, snapshot, cfg, paths, pool);\n const reconcile = await prepareReconcile(snapshot.reconcile, cfg, paths, dialect, timing, pool, forcedPaths(classification, snapshot));\n const mutated = classification.fullRebuild || invalidation.mutated || reconcile.mutated || snapshot.baseline.features !== wanted || snapshot.baseline.ready !== '1';\n\n if (buildPlan.hasSubscribers) buildPlan.publish({ attempt, baseline: snapshot.baseline, wantedSignature: wanted });\n const txStart = Date.now();\n let txMs: number;\n try {\n await withTransaction(\n conn,\n async () => {\n const current = await readCoreBaseline(conn);\n const currentWanted = featureSignature(liveCfg, FEATURES);\n if (!sameBaseline(current, snapshot.baseline) || JSON.stringify(liveCfg) !== configIdentity || currentWanted !== wanted) {\n throw new StaleBuildPlan('core generation or configuration changed while this build was planning');\n }\n if (!mutated) return;\n await ensureFeatureSchema(cfg);\n await invalidation.apply(conn);\n await reconcile.apply(conn);\n const publishedWanted = featureSignature(liveCfg, FEATURES);\n if (JSON.stringify(liveCfg) !== configIdentity || publishedWanted !== wanted) throw new StaleBuildPlan('configuration changed while this build was publishing');\n await setMeta(conn, FEATURE_SIGNATURE_META_KEY, wanted);\n await setMeta(conn, CORE_READY_META_KEY, '1');\n await setMeta(conn, CORE_GENERATION_META_KEY, nextGeneration(snapshot.baseline.generation));\n },\n dialect.beginMode()\n );\n } finally {\n txMs = Date.now() - txStart;\n timing.txMs += txMs;\n }\n if (reconcile.mutated) await reconcile.record(conn, txMs);\n return {\n parsed: invalidation.parsed + reconcile.parsed,\n warnings: reconcile.warnings,\n stages: reconcile.finish(timing.txMs),\n messages: classification.messages,\n };\n}\n\nexport function createBuilder(conn: Connection, cfg: ResolvedConfig, dialect: ReconcileDialect, ensureFeatureSchema: EnsureFeatureSchema): Builder {\n const pool = new ParsePool();\n return {\n async build() {\n // One clock and recorder span both bounded attempts. Baseline/catalog reads and feature\n // invalidation preparation are included in totalMs but remain intentionally unlabelled;\n // existing/list/parse and publication stages accumulate under their established labels.\n const timing = createReconcileTiming(cfg);\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n return await publishAttempt(conn, cfg, dialect, pool, ensureFeatureSchema, timing, attempt);\n } catch (err) {\n if (!(err instanceof StaleBuildPlan)) throw err;\n if (attempt === 1) throw new SenseError('STORE_BUSY', 'the index changed during both bounded publication attempts; wait for the competing build to finish and retry');\n }\n }\n throw new Error('unreachable build attempt state');\n },\n close: () => pool.close(),\n get poolsCreated() {\n return pool.poolsCreated;\n },\n };\n}\n"],"names":["createBuilder","StaleBuildPlan","Error","buildPlan","channel","SCHEMA_VERSION_META_KEY","readCoreBaseline","conn","stmt","values","keys","FEATURE_SIGNATURE_META_KEY","CORE_READY_META_KEY","CORE_GENERATION_META_KEY","prepare","map","join","Map","all","row","key","value","schemaVersion","get","features","ready","generation","sameBaseline","a","b","nextGeneration","current","Number","isSafeInteger","MAX_SAFE_INTEGER","SenseError","String","readPlanningSnapshot","timing","withTransaction","baseline","reconcile","tablesStmt","tables","readReconcileSnapshot","Set","name","activeSchemaMissing","snapshot","cfg","FEATURES","feature","featureEnabled","seenColumns","has","table","NARROW_FEATURE_TABLE","classifyBuild","paths","wanted","before","recover","messages","push","embedKind","featureToggles","fullRebuild","changedKeys","changedSignatureKeys","size","embedIdentityAdopted","classifyEmbedChange","presetForced","isPresetOnlyChange","forcedPresetPaths","rootDir","signatureDiff","forcedPaths","toggles","isFeatureOnlyChange","classifyFeatureToggles","prepareEmbedInvalidation","kind","pool","existing","files","docs","pathsChanged","delta","mutated","parsed","apply","exec","existingRows","path","listFiles","filter","file","embed","relPath","reparseFiles","undefined","doc","reparsed","added","vanished","length","runBatch","store","extracted","prepareFeatureInvalidation","prepared","applyTable","nullRank","toggle","turnedOn","find","candidate","set","plan","afterReconcile","byName","linksToggle","rankToggle","rank","recoveryToggles","prepareInvalidation","classification","plans","some","reduce","sum","publishAttempt","liveCfg","dialect","ensureFeatureSchema","attempt","configIdentity","invalidation","txStart","txMs","structuredClone","JSON","stringify","baseDir","configDir","featureSignature","prepareReconcile","hasSubscribers","publish","wantedSignature","Date","now","currentWanted","publishedWanted","setMeta","beginMode","record","warnings","stages","finish","ParsePool","build","err","createReconcileTiming","close","poolsCreated"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/cache.ts"],"sourcesContent":["import { rmSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { ResolvedConfig } from '../config/index.ts';\nimport { STATE_DIR } from '../config/index.ts';\n\n// Deletes the cache directory and nothing else: the next open() reconciles anyway. Engine-neutral,\n// since every store keeps its files under the same STATE_DIR.\nexport function clearCache(cfg: ResolvedConfig): void {\n rmSync(join(cfg.configDir ?? cfg.baseDir, STATE_DIR), { recursive: true, force: true });\n}\n"],"names":["clearCache","cfg","rmSync","join","configDir","baseDir","STATE_DIR","recursive","force"],"mappings":";;;;+BAOgBA;;;eAAAA;;;sBAPO;wBACF;uBAEK;AAInB,SAASA,WAAWC,GAAmB;QAChCA;IAAZC,IAAAA,cAAM,EAACC,IAAAA,cAAI,GAACF,iBAAAA,IAAIG,SAAS,cAAbH,4BAAAA,iBAAiBA,IAAII,OAAO,EAAEC,kBAAS,GAAG;QAAEC,WAAW;QAAMC,OAAO;IAAK;AACvF"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/cache.ts"],"sourcesContent":["import { rmSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { ResolvedConfig } from '../config/index.ts';\nimport { STATE_DIR } from '../config/index.ts';\n\n// Deletes the cache directory and nothing else: the next open() reconciles anyway. Engine-neutral,\n// since every store keeps its files under the same STATE_DIR.\nexport function clearCache(cfg: ResolvedConfig): void {\n rmSync(join(cfg.configDir ?? cfg.baseDir, STATE_DIR), { recursive: true, force: true });\n}\n"],"names":["clearCache","cfg","rmSync","join","configDir","baseDir","STATE_DIR","recursive","force"],"mappings":";;;;+BAOgBA;;;eAAAA;;;sBAPO;wBACF;uBAEK;AAInB,SAASA,WAAWC,GAAmB;QAChCA;IAAZC,IAAAA,cAAM,EAACC,IAAAA,cAAI,GAACF,iBAAAA,IAAIG,SAAS,cAAbH,4BAAAA,iBAAiBA,IAAII,OAAO,EAAEC,kBAAS,GAAG;QAAEC,WAAW;QAAMC,OAAO;IAAK;AACvF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/duckdb/batch.ts"],"sourcesContent":["// Rewrites the store's single-row parameterized INSERT/UPDATE/DELETE into one multi-row statement --\n// DuckDB's columnar engine pays for row-at-a-time writes, not just the round trip (PRINCIPLES: documented-means-tested).\n// rewriteInsert itself lives in the shared ../batch.ts: turso folds INSERTs the same way (3.36 B).\n\nimport { rewriteInsert } from '../batch.ts';\n\nconst UPDATE_RE = /^UPDATE\\s+(\\S+)\\s+SET\\s+(.+?)\\s+WHERE\\s+(.+)$/is;\nconst DELETE_RE = /^DELETE\\s+FROM\\s+(\\S+)\\s+WHERE\\s+(.+)$/is;\n\n// \"a = ?, b = ?\" or \"a = ? AND b = ?\" -> [\"a\", \"b\"]. A clause that doesn't fit yields a shorter\n// list, which rewriteUpdate/rewriteDelete reject as a width mismatch.\nfunction equalityColumns(clause: string, sep: RegExp): string[] | null {\n const parts = clause.split(sep).map((p) => p.trim());\n const cols: string[] = [];\n for (const part of parts) {\n const m = /^(.+?)=\\s*\\?$/.exec(part);\n if (!m) return null;\n cols.push(m[1].trim());\n }\n return cols;\n}\n\nfunction tuples(rowCount: number, width: number): string {\n const row = `(${Array.from({ length: width }, () => '?').join(', ')})`;\n return Array.from({ length: rowCount }, () => row).join(', ');\n}\n\nexport function rewriteUpdate(sql: string, rowCount: number): { sql: string; width: number } | null {\n const m = UPDATE_RE.exec(sql.trim());\n if (!m) return null;\n const [, table, setClause, whereClause] = m;\n const setCols = equalityColumns(setClause, /,/);\n const whereCols = equalityColumns(whereClause, /\\bAND\\b/i);\n if (!setCols || !whereCols) return null;\n const dataCols = [...setCols, ...whereCols];\n const setAssign = setCols.map((c) => `${c} = data.${c}`).join(', ');\n const joinCond = whereCols.map((c) => `${table}.${c} = data.${c}`).join(' AND ');\n return { sql: `UPDATE ${table} SET ${setAssign} FROM (VALUES ${tuples(rowCount, dataCols.length)}) AS data(${dataCols.join(', ')}) WHERE ${joinCond}`, width: dataCols.length };\n}\n\nexport function rewriteDelete(sql: string, rowCount: number): { sql: string; width: number } | null {\n const m = DELETE_RE.exec(sql.trim());\n if (!m) return null;\n const [, table, whereClause] = m;\n const cols = equalityColumns(whereClause, /\\bAND\\b/i);\n if (!cols) return null;\n if (cols.length === 1) {\n return { sql: `DELETE FROM ${table} WHERE ${cols[0]} IN (${Array.from({ length: rowCount }, () => '?').join(', ')})`, width: 1 };\n }\n return { sql: `DELETE FROM ${table} WHERE (${cols.join(', ')}) IN (VALUES ${tuples(rowCount, cols.length)})`, width: cols.length };\n}\n\n// Tries each shape in turn; null means the caller should fall back to a per-row loop.\nexport function rewriteBatch(sql: string, rowCount: number): { sql: string; width: number } | null {\n return rewriteInsert(sql, rowCount) ?? rewriteUpdate(sql, rowCount) ?? rewriteDelete(sql, rowCount);\n}\n"],"names":["rewriteBatch","rewriteDelete","rewriteUpdate","UPDATE_RE","DELETE_RE","equalityColumns","clause","sep","parts","split","map","p","trim","cols","part","m","exec","push","tuples","rowCount","width","row","Array","from","length","join","sql","table","setClause","whereClause","setCols","whereCols","dataCols","setAssign","c","joinCond","rewriteInsert"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/batch.ts"],"sourcesContent":["// Rewrites the store's single-row parameterized INSERT/UPDATE/DELETE into one multi-row statement --\n// DuckDB's columnar engine pays for row-at-a-time writes, not just the round trip (PRINCIPLES: documented-means-tested).\n// rewriteInsert itself lives in the shared ../batch.ts: turso folds INSERTs the same way (3.36 B).\n\nimport { rewriteInsert } from '../batch.ts';\n\nconst UPDATE_RE = /^UPDATE\\s+(\\S+)\\s+SET\\s+(.+?)\\s+WHERE\\s+(.+)$/is;\nconst DELETE_RE = /^DELETE\\s+FROM\\s+(\\S+)\\s+WHERE\\s+(.+)$/is;\n\n// \"a = ?, b = ?\" or \"a = ? AND b = ?\" -> [\"a\", \"b\"]. A clause that doesn't fit yields a shorter\n// list, which rewriteUpdate/rewriteDelete reject as a width mismatch.\nfunction equalityColumns(clause: string, sep: RegExp): string[] | null {\n const parts = clause.split(sep).map((p) => p.trim());\n const cols: string[] = [];\n for (const part of parts) {\n const m = /^(.+?)=\\s*\\?$/.exec(part);\n if (!m) return null;\n cols.push(m[1].trim());\n }\n return cols;\n}\n\nfunction tuples(rowCount: number, width: number): string {\n const row = `(${Array.from({ length: width }, () => '?').join(', ')})`;\n return Array.from({ length: rowCount }, () => row).join(', ');\n}\n\nexport function rewriteUpdate(sql: string, rowCount: number): { sql: string; width: number } | null {\n const m = UPDATE_RE.exec(sql.trim());\n if (!m) return null;\n const [, table, setClause, whereClause] = m;\n const setCols = equalityColumns(setClause, /,/);\n const whereCols = equalityColumns(whereClause, /\\bAND\\b/i);\n if (!setCols || !whereCols) return null;\n const dataCols = [...setCols, ...whereCols];\n const setAssign = setCols.map((c) => `${c} = data.${c}`).join(', ');\n const joinCond = whereCols.map((c) => `${table}.${c} = data.${c}`).join(' AND ');\n return { sql: `UPDATE ${table} SET ${setAssign} FROM (VALUES ${tuples(rowCount, dataCols.length)}) AS data(${dataCols.join(', ')}) WHERE ${joinCond}`, width: dataCols.length };\n}\n\nexport function rewriteDelete(sql: string, rowCount: number): { sql: string; width: number } | null {\n const m = DELETE_RE.exec(sql.trim());\n if (!m) return null;\n const [, table, whereClause] = m;\n const cols = equalityColumns(whereClause, /\\bAND\\b/i);\n if (!cols) return null;\n if (cols.length === 1) {\n return { sql: `DELETE FROM ${table} WHERE ${cols[0]} IN (${Array.from({ length: rowCount }, () => '?').join(', ')})`, width: 1 };\n }\n return { sql: `DELETE FROM ${table} WHERE (${cols.join(', ')}) IN (VALUES ${tuples(rowCount, cols.length)})`, width: cols.length };\n}\n\n// Tries each shape in turn; null means the caller should fall back to a per-row loop.\nexport function rewriteBatch(sql: string, rowCount: number): { sql: string; width: number } | null {\n return rewriteInsert(sql, rowCount) ?? rewriteUpdate(sql, rowCount) ?? rewriteDelete(sql, rowCount);\n}\n"],"names":["rewriteBatch","rewriteDelete","rewriteUpdate","UPDATE_RE","DELETE_RE","equalityColumns","clause","sep","parts","split","map","p","trim","cols","part","m","exec","push","tuples","rowCount","width","row","Array","from","length","join","sql","table","setClause","whereClause","setCols","whereCols","dataCols","setAssign","c","joinCond","rewriteInsert"],"mappings":"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"}