sensemaking 0.16.0 → 0.17.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 (322) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/chunk/extract.d.cts +2 -0
  3. package/dist/cjs/chunk/extract.d.ts +2 -0
  4. package/dist/cjs/chunk/extract.js +139 -0
  5. package/dist/cjs/chunk/extract.js.map +1 -0
  6. package/dist/cjs/chunk/group.d.cts +4 -0
  7. package/dist/cjs/chunk/group.d.ts +4 -0
  8. package/dist/cjs/chunk/group.js +489 -0
  9. package/dist/cjs/chunk/group.js.map +1 -0
  10. package/dist/cjs/chunk/index.d.cts +8 -0
  11. package/dist/cjs/chunk/index.d.ts +8 -0
  12. package/dist/cjs/chunk/index.js +44 -0
  13. package/dist/cjs/chunk/index.js.map +1 -0
  14. package/dist/cjs/chunk/parse.d.cts +2 -0
  15. package/dist/cjs/chunk/parse.d.ts +2 -0
  16. package/dist/cjs/chunk/parse.js +71 -0
  17. package/dist/cjs/chunk/parse.js.map +1 -0
  18. package/dist/cjs/chunk/types.d.cts +19 -0
  19. package/dist/cjs/chunk/types.d.ts +19 -0
  20. package/dist/cjs/chunk/types.js +5 -0
  21. package/dist/cjs/chunk/types.js.map +1 -0
  22. package/dist/cjs/chunk/version.d.cts +1 -0
  23. package/dist/cjs/chunk/version.d.ts +1 -0
  24. package/dist/cjs/chunk/version.js +14 -0
  25. package/dist/cjs/chunk/version.js.map +1 -0
  26. package/dist/cjs/cli/map.js +5 -5
  27. package/dist/cjs/cli/map.js.map +1 -1
  28. package/dist/cjs/cli/named.js +3 -3
  29. package/dist/cjs/cli/named.js.map +1 -1
  30. package/dist/cjs/cli/path.js +9 -8
  31. package/dist/cjs/cli/path.js.map +1 -1
  32. package/dist/cjs/cli/peek.js +5 -5
  33. package/dist/cjs/cli/peek.js.map +1 -1
  34. package/dist/cjs/cli/related.js +5 -5
  35. package/dist/cjs/cli/related.js.map +1 -1
  36. package/dist/cjs/cli/search.js +5 -5
  37. package/dist/cjs/cli/search.js.map +1 -1
  38. package/dist/cjs/cli/shared.d.cts +1 -1
  39. package/dist/cjs/cli/shared.d.ts +1 -1
  40. package/dist/cjs/cli/shared.js +3 -3
  41. package/dist/cjs/cli/shared.js.map +1 -1
  42. package/dist/cjs/cli/status.js +19 -19
  43. package/dist/cjs/cli/status.js.map +1 -1
  44. package/dist/cjs/commands/map.d.cts +1 -1
  45. package/dist/cjs/commands/map.d.ts +1 -1
  46. package/dist/cjs/commands/map.js.map +1 -1
  47. package/dist/cjs/commands/peek.d.cts +1 -1
  48. package/dist/cjs/commands/peek.d.ts +1 -1
  49. package/dist/cjs/commands/peek.js +13 -6
  50. package/dist/cjs/commands/peek.js.map +1 -1
  51. package/dist/cjs/commands/scope.js +1 -1
  52. package/dist/cjs/commands/scope.js.map +1 -1
  53. package/dist/cjs/commands/search.d.cts +1 -1
  54. package/dist/cjs/commands/search.d.ts +1 -1
  55. package/dist/cjs/commands/search.js +3 -3
  56. package/dist/cjs/commands/search.js.map +1 -1
  57. package/dist/cjs/commands/signals.js +1 -1
  58. package/dist/cjs/commands/signals.js.map +1 -1
  59. package/dist/cjs/config/access.d.cts +3 -1
  60. package/dist/cjs/config/access.d.ts +3 -1
  61. package/dist/cjs/config/access.js +11 -11
  62. package/dist/cjs/config/access.js.map +1 -1
  63. package/dist/cjs/config/index.d.cts +1 -0
  64. package/dist/cjs/config/index.d.ts +1 -0
  65. package/dist/cjs/config/index.js +4 -0
  66. package/dist/cjs/config/index.js.map +1 -1
  67. package/dist/cjs/config/types.d.cts +1 -0
  68. package/dist/cjs/config/types.d.ts +1 -0
  69. package/dist/cjs/config/types.js.map +1 -1
  70. package/dist/cjs/config/validate.d.cts +1 -0
  71. package/dist/cjs/config/validate.d.ts +1 -0
  72. package/dist/cjs/config/validate.js +8 -1
  73. package/dist/cjs/config/validate.js.map +1 -1
  74. package/dist/cjs/db/open.d.cts +1 -1
  75. package/dist/cjs/db/open.d.ts +1 -1
  76. package/dist/cjs/db/open.js +4 -4
  77. package/dist/cjs/db/open.js.map +1 -1
  78. package/dist/cjs/db/reconcile.js +8 -8
  79. package/dist/cjs/db/reconcile.js.map +1 -1
  80. package/dist/cjs/{sql-functions.js → db/sql-functions.js} +1 -1
  81. package/dist/cjs/db/sql-functions.js.map +1 -0
  82. package/dist/cjs/embed/distribution.d.cts +4 -0
  83. package/dist/cjs/embed/distribution.d.ts +4 -0
  84. package/dist/cjs/embed/distribution.js +30 -0
  85. package/dist/cjs/embed/distribution.js.map +1 -0
  86. package/dist/cjs/embed/langfit.d.cts +0 -3
  87. package/dist/cjs/embed/langfit.d.ts +0 -3
  88. package/dist/cjs/embed/langfit.js +53 -96
  89. package/dist/cjs/embed/langfit.js.map +1 -1
  90. package/dist/cjs/embed/languages.js.map +1 -1
  91. package/dist/cjs/embed/query.js +6 -6
  92. package/dist/cjs/embed/query.js.map +1 -1
  93. package/dist/cjs/embed/static.js +8 -35
  94. package/dist/cjs/embed/static.js.map +1 -1
  95. package/dist/cjs/features/embed.d.cts +2 -5
  96. package/dist/cjs/features/embed.d.ts +2 -5
  97. package/dist/cjs/features/embed.js +36 -58
  98. package/dist/cjs/features/embed.js.map +1 -1
  99. package/dist/cjs/{fences.js → features/fences.js} +1 -1
  100. package/dist/cjs/features/fences.js.map +1 -0
  101. package/dist/cjs/features/links.js +1 -1
  102. package/dist/cjs/features/links.js.map +1 -1
  103. package/dist/cjs/features/rank.js +1 -1
  104. package/dist/cjs/features/rank.js.map +1 -1
  105. package/dist/cjs/features/sections.js +4 -3
  106. package/dist/cjs/features/sections.js.map +1 -1
  107. package/dist/cjs/features/tags.js +1 -1
  108. package/dist/cjs/features/tags.js.map +1 -1
  109. package/dist/cjs/features/types.d.cts +4 -2
  110. package/dist/cjs/features/types.d.ts +4 -2
  111. package/dist/cjs/graph/graph.js.map +1 -0
  112. package/dist/cjs/graph/traverse.js.map +1 -0
  113. package/dist/cjs/index.d.cts +4 -4
  114. package/dist/cjs/index.d.ts +4 -4
  115. package/dist/cjs/index.js +4 -1
  116. package/dist/cjs/index.js.map +1 -1
  117. package/dist/cjs/output/column-hint.js.map +1 -0
  118. package/dist/cjs/output/output.js.map +1 -0
  119. package/dist/cjs/output/progress.js.map +1 -0
  120. package/dist/cjs/{search-error.js → output/search-error.js} +1 -1
  121. package/dist/cjs/output/search-error.js.map +1 -0
  122. package/dist/cjs/scan/frontmatter.d.cts +13 -0
  123. package/dist/cjs/scan/frontmatter.d.ts +13 -0
  124. package/dist/cjs/scan/frontmatter.js +229 -0
  125. package/dist/cjs/scan/frontmatter.js.map +1 -0
  126. package/dist/cjs/scan/index.d.cts +25 -0
  127. package/dist/cjs/scan/index.d.ts +25 -0
  128. package/dist/cjs/scan/index.js +107 -0
  129. package/dist/cjs/scan/index.js.map +1 -0
  130. package/dist/cjs/scan/list.d.cts +12 -0
  131. package/dist/cjs/scan/list.d.ts +12 -0
  132. package/dist/cjs/scan/list.js +154 -0
  133. package/dist/cjs/scan/list.js.map +1 -0
  134. package/dist/cjs/text/segment.d.cts +3 -0
  135. package/dist/cjs/text/segment.d.ts +3 -0
  136. package/dist/cjs/{segment.js → text/segment.js} +17 -14
  137. package/dist/cjs/text/segment.js.map +1 -0
  138. package/dist/cjs/text/strip.d.cts +3 -0
  139. package/dist/cjs/text/strip.d.ts +3 -0
  140. package/dist/cjs/text/strip.js +32 -0
  141. package/dist/cjs/text/strip.js.map +1 -0
  142. package/dist/esm/chunk/extract.d.ts +2 -0
  143. package/dist/esm/chunk/extract.js +114 -0
  144. package/dist/esm/chunk/extract.js.map +1 -0
  145. package/dist/esm/chunk/group.d.ts +4 -0
  146. package/dist/esm/chunk/group.js +253 -0
  147. package/dist/esm/chunk/group.js.map +1 -0
  148. package/dist/esm/chunk/index.d.ts +8 -0
  149. package/dist/esm/chunk/index.js +16 -0
  150. package/dist/esm/chunk/index.js.map +1 -0
  151. package/dist/esm/chunk/parse.d.ts +2 -0
  152. package/dist/esm/chunk/parse.js +63 -0
  153. package/dist/esm/chunk/parse.js.map +1 -0
  154. package/dist/esm/chunk/types.d.ts +19 -0
  155. package/dist/esm/chunk/types.js +2 -0
  156. package/dist/esm/chunk/types.js.map +1 -0
  157. package/dist/esm/chunk/version.d.ts +1 -0
  158. package/dist/esm/chunk/version.js +3 -0
  159. package/dist/esm/chunk/version.js.map +1 -0
  160. package/dist/esm/cli/map.js +2 -2
  161. package/dist/esm/cli/map.js.map +1 -1
  162. package/dist/esm/cli/named.js +2 -2
  163. package/dist/esm/cli/named.js.map +1 -1
  164. package/dist/esm/cli/path.js +4 -3
  165. package/dist/esm/cli/path.js.map +1 -1
  166. package/dist/esm/cli/peek.js +2 -2
  167. package/dist/esm/cli/peek.js.map +1 -1
  168. package/dist/esm/cli/related.js +2 -2
  169. package/dist/esm/cli/related.js.map +1 -1
  170. package/dist/esm/cli/search.js +2 -2
  171. package/dist/esm/cli/search.js.map +1 -1
  172. package/dist/esm/cli/shared.d.ts +1 -1
  173. package/dist/esm/cli/shared.js +3 -3
  174. package/dist/esm/cli/shared.js.map +1 -1
  175. package/dist/esm/cli/status.js +3 -3
  176. package/dist/esm/cli/status.js.map +1 -1
  177. package/dist/esm/commands/map.d.ts +1 -1
  178. package/dist/esm/commands/map.js.map +1 -1
  179. package/dist/esm/commands/peek.d.ts +1 -1
  180. package/dist/esm/commands/peek.js +8 -1
  181. package/dist/esm/commands/peek.js.map +1 -1
  182. package/dist/esm/commands/scope.js +1 -1
  183. package/dist/esm/commands/scope.js.map +1 -1
  184. package/dist/esm/commands/search.d.ts +1 -1
  185. package/dist/esm/commands/search.js +3 -3
  186. package/dist/esm/commands/search.js.map +1 -1
  187. package/dist/esm/commands/signals.js +1 -1
  188. package/dist/esm/commands/signals.js.map +1 -1
  189. package/dist/esm/config/access.d.ts +3 -1
  190. package/dist/esm/config/access.js +9 -9
  191. package/dist/esm/config/access.js.map +1 -1
  192. package/dist/esm/config/index.d.ts +1 -0
  193. package/dist/esm/config/index.js +1 -0
  194. package/dist/esm/config/index.js.map +1 -1
  195. package/dist/esm/config/types.d.ts +1 -0
  196. package/dist/esm/config/types.js.map +1 -1
  197. package/dist/esm/config/validate.d.ts +1 -0
  198. package/dist/esm/config/validate.js +8 -2
  199. package/dist/esm/config/validate.js.map +1 -1
  200. package/dist/esm/db/open.d.ts +1 -1
  201. package/dist/esm/db/open.js +5 -5
  202. package/dist/esm/db/open.js.map +1 -1
  203. package/dist/esm/db/reconcile.js +4 -4
  204. package/dist/esm/db/reconcile.js.map +1 -1
  205. package/dist/esm/{sql-functions.js → db/sql-functions.js} +1 -1
  206. package/dist/esm/db/sql-functions.js.map +1 -0
  207. package/dist/esm/embed/distribution.d.ts +4 -0
  208. package/dist/esm/embed/distribution.js +11 -0
  209. package/dist/esm/embed/distribution.js.map +1 -0
  210. package/dist/esm/embed/langfit.d.ts +0 -3
  211. package/dist/esm/embed/langfit.js +8 -8
  212. package/dist/esm/embed/langfit.js.map +1 -1
  213. package/dist/esm/embed/languages.js.map +1 -1
  214. package/dist/esm/embed/query.js +5 -5
  215. package/dist/esm/embed/query.js.map +1 -1
  216. package/dist/esm/embed/static.js +6 -2
  217. package/dist/esm/embed/static.js.map +1 -1
  218. package/dist/esm/features/embed.d.ts +2 -5
  219. package/dist/esm/features/embed.js +34 -32
  220. package/dist/esm/features/embed.js.map +1 -1
  221. package/dist/esm/{fences.js → features/fences.js} +1 -1
  222. package/dist/esm/features/fences.js.map +1 -0
  223. package/dist/esm/features/links.js +1 -1
  224. package/dist/esm/features/links.js.map +1 -1
  225. package/dist/esm/features/rank.js +1 -1
  226. package/dist/esm/features/rank.js.map +1 -1
  227. package/dist/esm/features/sections.js +4 -3
  228. package/dist/esm/features/sections.js.map +1 -1
  229. package/dist/esm/features/tags.js +1 -1
  230. package/dist/esm/features/tags.js.map +1 -1
  231. package/dist/esm/features/types.d.ts +4 -2
  232. package/dist/esm/features/types.js.map +1 -1
  233. package/dist/esm/graph/graph.js.map +1 -0
  234. package/dist/esm/graph/traverse.js.map +1 -0
  235. package/dist/esm/index.d.ts +4 -4
  236. package/dist/esm/index.js +2 -2
  237. package/dist/esm/index.js.map +1 -1
  238. package/dist/esm/output/column-hint.js.map +1 -0
  239. package/dist/esm/output/output.js.map +1 -0
  240. package/dist/esm/output/progress.js.map +1 -0
  241. package/dist/esm/{search-error.js → output/search-error.js} +1 -1
  242. package/dist/esm/output/search-error.js.map +1 -0
  243. package/dist/esm/scan/frontmatter.d.ts +13 -0
  244. package/dist/esm/{scan.js → scan/frontmatter.js} +4 -123
  245. package/dist/esm/scan/frontmatter.js.map +1 -0
  246. package/dist/esm/scan/index.d.ts +25 -0
  247. package/dist/esm/scan/index.js +58 -0
  248. package/dist/esm/scan/index.js.map +1 -0
  249. package/dist/esm/scan/list.d.ts +12 -0
  250. package/dist/esm/scan/list.js +58 -0
  251. package/dist/esm/scan/list.js.map +1 -0
  252. package/dist/esm/text/segment.d.ts +3 -0
  253. package/dist/esm/{segment.js → text/segment.js} +3 -3
  254. package/dist/esm/text/segment.js.map +1 -0
  255. package/dist/esm/text/strip.d.ts +3 -0
  256. package/dist/esm/text/strip.js +12 -0
  257. package/dist/esm/text/strip.js.map +1 -0
  258. package/package.json +15 -2
  259. package/schema.json +8 -1
  260. package/skills/sense/SKILL.md +1 -1
  261. package/skills/sense-setup/SKILL.md +3 -3
  262. package/dist/cjs/column-hint.js.map +0 -1
  263. package/dist/cjs/fences.js.map +0 -1
  264. package/dist/cjs/graph.js.map +0 -1
  265. package/dist/cjs/output.js.map +0 -1
  266. package/dist/cjs/progress.js.map +0 -1
  267. package/dist/cjs/scan.d.cts +0 -35
  268. package/dist/cjs/scan.d.ts +0 -35
  269. package/dist/cjs/scan.js +0 -436
  270. package/dist/cjs/scan.js.map +0 -1
  271. package/dist/cjs/search-error.js.map +0 -1
  272. package/dist/cjs/segment.d.cts +0 -2
  273. package/dist/cjs/segment.d.ts +0 -2
  274. package/dist/cjs/segment.js.map +0 -1
  275. package/dist/cjs/sql-functions.js.map +0 -1
  276. package/dist/cjs/traverse.js.map +0 -1
  277. package/dist/esm/column-hint.js.map +0 -1
  278. package/dist/esm/fences.js.map +0 -1
  279. package/dist/esm/graph.js.map +0 -1
  280. package/dist/esm/output.js.map +0 -1
  281. package/dist/esm/progress.js.map +0 -1
  282. package/dist/esm/scan.d.ts +0 -35
  283. package/dist/esm/scan.js.map +0 -1
  284. package/dist/esm/search-error.js.map +0 -1
  285. package/dist/esm/segment.d.ts +0 -2
  286. package/dist/esm/segment.js.map +0 -1
  287. package/dist/esm/sql-functions.js.map +0 -1
  288. package/dist/esm/traverse.js.map +0 -1
  289. /package/dist/cjs/{sql-functions.d.cts → db/sql-functions.d.cts} +0 -0
  290. /package/dist/cjs/{sql-functions.d.ts → db/sql-functions.d.ts} +0 -0
  291. /package/dist/cjs/{fences.d.cts → features/fences.d.cts} +0 -0
  292. /package/dist/cjs/{fences.d.ts → features/fences.d.ts} +0 -0
  293. /package/dist/cjs/{graph.d.cts → graph/graph.d.cts} +0 -0
  294. /package/dist/cjs/{graph.d.ts → graph/graph.d.ts} +0 -0
  295. /package/dist/cjs/{graph.js → graph/graph.js} +0 -0
  296. /package/dist/cjs/{traverse.d.cts → graph/traverse.d.cts} +0 -0
  297. /package/dist/cjs/{traverse.d.ts → graph/traverse.d.ts} +0 -0
  298. /package/dist/cjs/{traverse.js → graph/traverse.js} +0 -0
  299. /package/dist/cjs/{column-hint.d.cts → output/column-hint.d.cts} +0 -0
  300. /package/dist/cjs/{column-hint.d.ts → output/column-hint.d.ts} +0 -0
  301. /package/dist/cjs/{column-hint.js → output/column-hint.js} +0 -0
  302. /package/dist/cjs/{output.d.cts → output/output.d.cts} +0 -0
  303. /package/dist/cjs/{output.d.ts → output/output.d.ts} +0 -0
  304. /package/dist/cjs/{output.js → output/output.js} +0 -0
  305. /package/dist/cjs/{progress.d.cts → output/progress.d.cts} +0 -0
  306. /package/dist/cjs/{progress.d.ts → output/progress.d.ts} +0 -0
  307. /package/dist/cjs/{progress.js → output/progress.js} +0 -0
  308. /package/dist/cjs/{search-error.d.cts → output/search-error.d.cts} +0 -0
  309. /package/dist/cjs/{search-error.d.ts → output/search-error.d.ts} +0 -0
  310. /package/dist/esm/{sql-functions.d.ts → db/sql-functions.d.ts} +0 -0
  311. /package/dist/esm/{fences.d.ts → features/fences.d.ts} +0 -0
  312. /package/dist/esm/{graph.d.ts → graph/graph.d.ts} +0 -0
  313. /package/dist/esm/{graph.js → graph/graph.js} +0 -0
  314. /package/dist/esm/{traverse.d.ts → graph/traverse.d.ts} +0 -0
  315. /package/dist/esm/{traverse.js → graph/traverse.js} +0 -0
  316. /package/dist/esm/{column-hint.d.ts → output/column-hint.d.ts} +0 -0
  317. /package/dist/esm/{column-hint.js → output/column-hint.js} +0 -0
  318. /package/dist/esm/{output.d.ts → output/output.d.ts} +0 -0
  319. /package/dist/esm/{output.js → output/output.js} +0 -0
  320. /package/dist/esm/{progress.d.ts → output/progress.d.ts} +0 -0
  321. /package/dist/esm/{progress.js → output/progress.js} +0 -0
  322. /package/dist/esm/{search-error.d.ts → output/search-error.d.ts} +0 -0
@@ -28,9 +28,9 @@ _export(exports, {
28
28
  var _indexts = require("../config/index.js");
29
29
  var _errorsts = require("../errors.js");
30
30
  var _indexts1 = require("../features/index.js");
31
- var _progressts = require("../progress.js");
32
- var _scants = require("../scan.js");
33
- var _segmentts = require("../segment.js");
31
+ var _progressts = require("../output/progress.js");
32
+ var _indexts2 = require("../scan/index.js");
33
+ var _segmentts = require("../text/segment.js");
34
34
  var _sharedts = require("./shared.js");
35
35
  function _array_like_to_array(arr, len) {
36
36
  if (len == null || len > arr.length) len = arr.length;
@@ -112,7 +112,7 @@ function insertContentRow(insertBody, doc, segmenting) {
112
112
  insertBody.run(doc.relPath, doc.search.title, doc.search.summary, doc.search.text, doc.relPath, segmenting ? (0, _segmentts.segmentField)(doc.search.title) : '', segmenting ? (0, _segmentts.segmentField)(doc.search.summary) : '', segmenting ? (0, _segmentts.segmentField)(doc.search.text) : '');
113
113
  }
114
114
  function reconcile(db, cfg, baseDir) {
115
- var files = (0, _scants.listFiles)(cfg, baseDir);
115
+ var files = (0, _indexts2.listFiles)(cfg, baseDir);
116
116
  var currentSet = new Set(files.map(function(f) {
117
117
  return f.relPath;
118
118
  }));
@@ -155,7 +155,7 @@ function reconcile(db, cfg, baseDir) {
155
155
  var fileFeatures = features.filter(function(feature) {
156
156
  return !feature.enabledForFile || feature.enabledForFile(cfg, file);
157
157
  });
158
- var _parseFile = (0, _scants.parseFile)(file, fileFeatures), doc = _parseFile.doc, fileWarnings = _parseFile.warnings;
158
+ var _parseFile = (0, _indexts2.parseFile)(file, fileFeatures, cfg), doc = _parseFile.doc, fileWarnings = _parseFile.warnings;
159
159
  report.tick(++parsedCount);
160
160
  (_warnings = warnings).push.apply(_warnings, _to_consumable_array(fileWarnings));
161
161
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -208,7 +208,7 @@ function reconcile(db, cfg, baseDir) {
208
208
  // Columns the frontmatter upsert actually writes: core + parsed frontmatter keys, never a
209
209
  // feature-owned reserved column (see CORE_FRONTMATTER_COLUMNS above).
210
210
  var writableColumns = allColumns.filter(function(c) {
211
- return CORE_FRONTMATTER_COLUMNS.has(c) || !_scants.RESERVED_COLUMNS.has(c);
211
+ return CORE_FRONTMATTER_COLUMNS.has(c) || !_indexts2.RESERVED_COLUMNS.has(c);
212
212
  });
213
213
  // ON CONFLICT UPDATE (not OR REPLACE) keeps the row's rowid stable across reparses --
214
214
  // content rows are coupled to that rowid below.
@@ -538,7 +538,7 @@ function rebuildContentTable(db, cfg, baseDir) {
538
538
  var known = new Set(db.prepare('SELECT "path" FROM frontmatter').all().map(function(r) {
539
539
  return r.path;
540
540
  }));
541
- var files = (0, _scants.listFiles)(cfg, baseDir).filter(function(f) {
541
+ var files = (0, _indexts2.listFiles)(cfg, baseDir).filter(function(f) {
542
542
  return known.has(f.relPath);
543
543
  });
544
544
  var segmenting = (0, _indexts.contentTokenize)(cfg) === undefined;
@@ -551,7 +551,7 @@ function rebuildContentTable(db, cfg, baseDir) {
551
551
  for(var _iterator = files[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
552
552
  var file = _step.value;
553
553
  var _warnings;
554
- var _parseFile = (0, _scants.parseFile)(file), doc = _parseFile.doc, fileWarnings = _parseFile.warnings;
554
+ var _parseFile = (0, _indexts2.parseFile)(file), doc = _parseFile.doc, fileWarnings = _parseFile.warnings;
555
555
  (_warnings = warnings).push.apply(_warnings, _to_consumable_array(fileWarnings));
556
556
  insertContentRow(insertBody, doc, segmenting);
557
557
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/db/reconcile.ts"],"sourcesContent":["import type { DatabaseSync, StatementSync } from 'node:sqlite';\nimport type { Config } from '../config/index.ts';\nimport { contentTokenize } from '../config/index.ts';\nimport { SenseError } from '../errors.ts';\nimport { activeFeatures } from '../features/index.ts';\nimport type { ReconcileDelta } from '../features/types.ts';\nimport { progress } from '../progress.ts';\nimport type { ParsedDoc } from '../scan.ts';\nimport { listFiles, parseFile, RESERVED_COLUMNS } from '../scan.ts';\nimport { segmentField } from '../segment.ts';\nimport { getColumns, getMeta, quoteIdent, setMeta } from './shared.ts';\n\n// Feature-owned columns (`_rank`) must stay out of the upsert: a reparse would null the last\n// computed value on every touch, not just the reconciles that recompute it.\nconst CORE_FRONTMATTER_COLUMNS = new Set(['path', '_mtime', '_ctime', '_size', '_parse_error']);\n\n// SQLite's compile-time SQLITE_MAX_COLUMN, default 2000 (https://www.sqlite.org/limits.html).\nconst MAX_FRONTMATTER_COLUMNS = 2000;\n\n// Shared by reconcile() and the tokenize-only rebuild in open(), so both prepare the same\n// literal instead of two copies drifting apart.\nconst INSERT_CONTENT_SQL = `INSERT INTO content (rowid, title, summary, text, \"path\", title_seg, summary_seg, text_seg) VALUES ((SELECT rowid FROM frontmatter WHERE \"path\" = ?), ?, ?, ?, ?, ?, ?, ?)`;\n\n// Shared by reconcile() and the tokenize-only rebuild in open(), so content population is\n// defined once. Assumes the frontmatter row for doc.relPath already exists (rowid lookup).\nfunction insertContentRow(insertBody: StatementSync, doc: ParsedDoc, segmenting: boolean): void {\n insertBody.run(doc.relPath, doc.search.title, doc.search.summary, doc.search.text, doc.relPath, segmenting ? segmentField(doc.search.title) : '', segmenting ? segmentField(doc.search.summary) : '', segmenting ? segmentField(doc.search.text) : '');\n}\n\nexport function reconcile(db: DatabaseSync, cfg: Config, baseDir: string): { parsed: number; warnings: string[] } {\n const files = listFiles(cfg, baseDir);\n const currentSet = new Set(files.map((f) => f.relPath));\n\n const existingRows = db.prepare(`SELECT \"path\", \"_mtime\", \"_size\" FROM frontmatter`).all() as Array<{\n path: string;\n _mtime: number;\n _size: number;\n }>;\n const existing = new Map(existingRows.map((r) => [r.path, r]));\n const vanished = existingRows.filter((r) => !currentSet.has(r.path)).map((r) => r.path);\n\n const toReparse = files.filter((f) => {\n const row = existing.get(f.relPath);\n return !row || row._mtime !== f.mtimeMs || row._size !== f.size;\n });\n\n if (vanished.length === 0 && toReparse.length === 0) return { parsed: 0, warnings: [] };\n\n const features = activeFeatures(cfg);\n const seenColumns = getColumns(db);\n const newColumns: string[] = [];\n const parsedDocs: ParsedDoc[] = [];\n const warnings: string[] = [];\n\n // Bulk reparses (a sync, a cold build) are the long silences a query can hit; short\n // reconciles stay silent (progress() has a threshold).\n const report = progress('reparsing files', toReparse.length);\n let parsedCount = 0;\n for (const file of toReparse) {\n // A doc only gets extract/store from features that apply to it (currently: embed, via\n // FileStat.embed -- true iff the config names an embedding model).\n const fileFeatures = features.filter((feature) => !feature.enabledForFile || feature.enabledForFile(cfg, file));\n const { doc, warnings: fileWarnings } = parseFile(file, fileFeatures);\n report.tick(++parsedCount);\n warnings.push(...fileWarnings);\n for (const key of Object.keys(doc.data)) {\n if (!seenColumns.has(key)) {\n seenColumns.add(key);\n newColumns.push(key);\n }\n }\n parsedDocs.push(doc);\n }\n report.finish();\n\n const allColumns = [...seenColumns];\n // Fence before ALTERing: SQLite's own failure past this point is a raw\n // \"too many columns on sqlite_altertab_frontmatter\" with no indication of the boundary or the levers.\n if (allColumns.length > MAX_FRONTMATTER_COLUMNS) {\n throw new SenseError(\n 'COLUMN_LIMIT',\n `frontmatter would need ${allColumns.length} columns, crossing SQLite's compile-time SQLITE_MAX_COLUMN limit (default ${MAX_FRONTMATTER_COLUMNS}; see https://www.sqlite.org/limits.html). Narrow the presets' include globs so fewer/other files are indexed, or fix whatever is generating unbounded frontmatter keys.`\n );\n }\n // Columns the frontmatter upsert actually writes: core + parsed frontmatter keys, never a\n // feature-owned reserved column (see CORE_FRONTMATTER_COLUMNS above).\n const writableColumns = allColumns.filter((c) => CORE_FRONTMATTER_COLUMNS.has(c) || !RESERVED_COLUMNS.has(c));\n // ON CONFLICT UPDATE (not OR REPLACE) keeps the row's rowid stable across reparses --\n // content rows are coupled to that rowid below.\n const insertSql = `INSERT INTO frontmatter (${writableColumns.map(quoteIdent).join(', ')}) VALUES (${writableColumns.map(() => '?').join(', ')}) ON CONFLICT(\"path\") DO UPDATE SET ${writableColumns\n .filter((c) => c !== 'path')\n .map((c) => `${quoteIdent(c)} = excluded.${quoteIdent(c)}`)\n .join(', ')}`;\n\n const added = toReparse.filter((f) => !existing.has(f.relPath)).map((f) => f.relPath);\n const delta: ReconcileDelta = { files, reparsed: parsedDocs.map((d) => d.relPath), added, vanished };\n\n const txStart = Date.now();\n db.exec('BEGIN');\n try {\n for (const col of newColumns) db.exec(`ALTER TABLE frontmatter ADD COLUMN ${quoteIdent(col)}`);\n // FTS5 has no upsert, so delete-before-insert into `content`; coupled to the\n // frontmatter rowid (indexed via its PRIMARY KEY) instead of the UNINDEXED `path`\n // column, which a per-row DELETE would otherwise scan the whole table to find.\n const delBody = db.prepare(`DELETE FROM content WHERE rowid = (SELECT rowid FROM frontmatter WHERE \"path\" = ?)`);\n const delPresetFiles = db.prepare(`DELETE FROM preset_files WHERE \"path\" = ?`);\n const insertPresetFile = db.prepare(`INSERT INTO preset_files (\"path\", preset) VALUES (?, ?)`);\n if (vanished.length > 0) {\n const del = db.prepare(`DELETE FROM frontmatter WHERE \"path\" = ?`);\n for (const path of vanished) {\n // content delete must run first: it looks up the frontmatter rowid by path, which\n // the frontmatter delete below would otherwise have already removed.\n delBody.run(path);\n del.run(path);\n delPresetFiles.run(path);\n for (const feature of features) feature.remove?.(db, path, delta);\n }\n }\n if (parsedDocs.length > 0) {\n const insert = db.prepare(insertSql);\n const insertBody = db.prepare(INSERT_CONTENT_SQL);\n // A non-default tokenizer means the tree has chosen its own scheme; a phrase query over\n // grapheme runs would be nonsense against trigram, so the sidecars stay empty.\n const segmenting = contentTokenize(cfg) === undefined;\n for (const doc of parsedDocs) {\n const values = writableColumns.map((col) => {\n if (col === 'path') return doc.relPath;\n if (col === '_mtime') return doc.mtimeMs;\n if (col === '_ctime') return doc.ctimeMs;\n if (col === '_size') return doc.size;\n // Written per parse, unlike _rank, which a feature pass owns and the upsert skips.\n if (col === '_parse_error') return doc.parseError;\n return doc.data[col] ?? null;\n });\n // Frontmatter upsert first: content's rowid lookup below depends on this row existing.\n insert.run(...values);\n // Only for docs that have rows: an unconditional delete made cold crawls quadratic.\n if (existing.has(doc.relPath)) {\n delBody.run(doc.relPath);\n for (const feature of features) feature.remove?.(db, doc.relPath, delta);\n }\n insertContentRow(insertBody, doc, segmenting);\n // A preset edit forces a full rebuild, so an unchanged doc's coverage is already\n // correct; new docs have nothing to clear, which keeps cold builds linear.\n if (existing.has(doc.relPath)) delPresetFiles.run(doc.relPath);\n for (const presetName of doc.presets) insertPresetFile.run(doc.relPath, presetName);\n for (const feature of features) feature.store?.(db, doc.relPath, doc.extracted[feature.name], delta);\n }\n }\n for (const feature of features) feature.afterReconcile?.(db, delta);\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n\n // Reconcile's own write-transaction duration, for open()'s derived busy_timeout (F):\n // keep the observed max so a big watcher reconcile's lock hold is what the next open bounds its wait against.\n const durationMs = Date.now() - txStart;\n const prevRaw = getMeta(db, 'reconcile_max_ms');\n // -1, not 0, so a genuinely 0ms first reconcile (sub-millisecond, common on a tiny tree)\n // still gets recorded instead of losing to the \"nothing recorded yet\" default.\n const prevMax = prevRaw === null ? -1 : Number(prevRaw);\n if (durationMs > prevMax) setMeta(db, 'reconcile_max_ms', String(durationMs));\n\n return { parsed: parsedDocs.length, warnings };\n}\n\n// Segment keys that moved between two feature signatures (see config.featureSignature's\n// format: global features, embed provider, tokenize, then one segment per preset).\nexport function changedSignatureKeys(before: string, after: string): Set<string> {\n const keyOf = (part: string) => (part.startsWith('preset:') ? part.split(':').slice(0, 2).join(':') : part.split(':')[0]);\n const parse = (sig: string) => new Map(sig.split('|').map((part) => [keyOf(part), part]));\n const a = parse(before);\n const b = parse(after);\n const changed = new Set<string>();\n for (const [key, val] of b) if (a.get(key) !== val) changed.add(key);\n for (const key of a.keys()) if (!b.has(key)) changed.add(key);\n return changed;\n}\n\n// Whether the embed segment only gained its resolved weight identity: same provider and\n// model, no identity recorded before, one now -- adopted into meta without a rebuild.\nexport function embedIdentityAdopted(before: string, after: string): boolean {\n const embedPart = (sig: string) => sig.split('|').find((p) => p.startsWith('embed:'));\n const b = embedPart(before);\n const a = embedPart(after);\n if (b === undefined || a === undefined) return false;\n const at = a.indexOf('@');\n return b.indexOf('@') === -1 && at !== -1 && a.slice(0, at) === b;\n}\n\n// Names what moved, for the rebuild notice.\nexport function signatureDiff(before: string, after: string): string {\n const changed = changedSignatureKeys(before, after);\n const label = (key: string) => (key === 'embed' ? 'embed settings' : key === 'tokenize' ? 'content tokenizer' : key.startsWith('preset:') ? `preset \"${key.slice(7)}\"` : 'features');\n return changed.size === 0 ? 'features' : [...changed].map(label).join(', ');\n}\n\n// The tokenize-only rebuild in open(): content is dropped and repopulated from files already\n// listed in frontmatter, which itself is untouched. Frontmatter, links, sections, and\n// embeddings are file-derived and tokenizer-independent, so they survive. No feature extractors\n// run here -- doc.search (title/summary/text) is all content population needs. Returns\n// parseFile's per-file warnings (e.g. a bad date) so open() can surface them -- mtimes are\n// untouched, so reconcile() never reparses these files and would otherwise never emit them again.\nexport function rebuildContentTable(db: DatabaseSync, cfg: Config, baseDir: string): string[] {\n const known = new Set((db.prepare('SELECT \"path\" FROM frontmatter').all() as Array<{ path: string }>).map((r) => r.path));\n const files = listFiles(cfg, baseDir).filter((f) => known.has(f.relPath));\n const segmenting = contentTokenize(cfg) === undefined;\n const insertBody = db.prepare(INSERT_CONTENT_SQL);\n const warnings: string[] = [];\n db.exec('BEGIN');\n try {\n for (const file of files) {\n const { doc, warnings: fileWarnings } = parseFile(file);\n warnings.push(...fileWarnings);\n insertContentRow(insertBody, doc, segmenting);\n }\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n return warnings;\n}\n"],"names":["changedSignatureKeys","embedIdentityAdopted","rebuildContentTable","reconcile","signatureDiff","CORE_FRONTMATTER_COLUMNS","Set","MAX_FRONTMATTER_COLUMNS","INSERT_CONTENT_SQL","insertContentRow","insertBody","doc","segmenting","run","relPath","search","title","summary","text","segmentField","db","cfg","baseDir","files","listFiles","currentSet","map","f","existingRows","prepare","all","existing","Map","r","path","vanished","filter","has","toReparse","row","get","_mtime","mtimeMs","_size","size","length","parsed","warnings","features","activeFeatures","seenColumns","getColumns","newColumns","parsedDocs","report","progress","parsedCount","file","fileFeatures","feature","enabledForFile","parseFile","fileWarnings","tick","push","Object","keys","data","key","add","finish","allColumns","SenseError","writableColumns","c","RESERVED_COLUMNS","insertSql","quoteIdent","join","added","delta","reparsed","d","txStart","Date","now","exec","col","delBody","delPresetFiles","insertPresetFile","del","remove","insert","contentTokenize","undefined","values","ctimeMs","parseError","presets","presetName","store","extracted","name","afterReconcile","err","durationMs","prevRaw","getMeta","prevMax","Number","setMeta","String","before","after","keyOf","part","startsWith","split","slice","parse","sig","a","b","changed","val","embedPart","find","p","at","indexOf","label","known"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/db/reconcile.ts"],"sourcesContent":["import type { DatabaseSync, StatementSync } from 'node:sqlite';\nimport type { Config } from '../config/index.ts';\nimport { contentTokenize } from '../config/index.ts';\nimport { SenseError } from '../errors.ts';\nimport { activeFeatures } from '../features/index.ts';\nimport type { ReconcileDelta } from '../features/types.ts';\nimport { progress } from '../output/progress.ts';\nimport type { ParsedDoc } from '../scan/index.ts';\nimport { listFiles, parseFile, RESERVED_COLUMNS } from '../scan/index.ts';\nimport { segmentField } from '../text/segment.ts';\nimport { getColumns, getMeta, quoteIdent, setMeta } from './shared.ts';\n\n// Feature-owned columns (`_rank`) must stay out of the upsert: a reparse would null the last\n// computed value on every touch, not just the reconciles that recompute it.\nconst CORE_FRONTMATTER_COLUMNS = new Set(['path', '_mtime', '_ctime', '_size', '_parse_error']);\n\n// SQLite's compile-time SQLITE_MAX_COLUMN, default 2000 (https://www.sqlite.org/limits.html).\nconst MAX_FRONTMATTER_COLUMNS = 2000;\n\n// Shared by reconcile() and the tokenize-only rebuild in open(), so both prepare the same\n// literal instead of two copies drifting apart.\nconst INSERT_CONTENT_SQL = `INSERT INTO content (rowid, title, summary, text, \"path\", title_seg, summary_seg, text_seg) VALUES ((SELECT rowid FROM frontmatter WHERE \"path\" = ?), ?, ?, ?, ?, ?, ?, ?)`;\n\n// Shared by reconcile() and the tokenize-only rebuild in open(), so content population is\n// defined once. Assumes the frontmatter row for doc.relPath already exists (rowid lookup).\nfunction insertContentRow(insertBody: StatementSync, doc: ParsedDoc, segmenting: boolean): void {\n insertBody.run(doc.relPath, doc.search.title, doc.search.summary, doc.search.text, doc.relPath, segmenting ? segmentField(doc.search.title) : '', segmenting ? segmentField(doc.search.summary) : '', segmenting ? segmentField(doc.search.text) : '');\n}\n\nexport function reconcile(db: DatabaseSync, cfg: Config, baseDir: string): { parsed: number; warnings: string[] } {\n const files = listFiles(cfg, baseDir);\n const currentSet = new Set(files.map((f) => f.relPath));\n\n const existingRows = db.prepare(`SELECT \"path\", \"_mtime\", \"_size\" FROM frontmatter`).all() as Array<{\n path: string;\n _mtime: number;\n _size: number;\n }>;\n const existing = new Map(existingRows.map((r) => [r.path, r]));\n const vanished = existingRows.filter((r) => !currentSet.has(r.path)).map((r) => r.path);\n\n const toReparse = files.filter((f) => {\n const row = existing.get(f.relPath);\n return !row || row._mtime !== f.mtimeMs || row._size !== f.size;\n });\n\n if (vanished.length === 0 && toReparse.length === 0) return { parsed: 0, warnings: [] };\n\n const features = activeFeatures(cfg);\n const seenColumns = getColumns(db);\n const newColumns: string[] = [];\n const parsedDocs: ParsedDoc[] = [];\n const warnings: string[] = [];\n\n // Bulk reparses (a sync, a cold build) are the long silences a query can hit; short\n // reconciles stay silent (progress() has a threshold).\n const report = progress('reparsing files', toReparse.length);\n let parsedCount = 0;\n for (const file of toReparse) {\n // A doc only gets extract/store from features that apply to it (currently: embed, via\n // FileStat.embed -- true iff the config names an embedding model).\n const fileFeatures = features.filter((feature) => !feature.enabledForFile || feature.enabledForFile(cfg, file));\n const { doc, warnings: fileWarnings } = parseFile(file, fileFeatures, cfg);\n report.tick(++parsedCount);\n warnings.push(...fileWarnings);\n for (const key of Object.keys(doc.data)) {\n if (!seenColumns.has(key)) {\n seenColumns.add(key);\n newColumns.push(key);\n }\n }\n parsedDocs.push(doc);\n }\n report.finish();\n\n const allColumns = [...seenColumns];\n // Fence before ALTERing: SQLite's own failure past this point is a raw\n // \"too many columns on sqlite_altertab_frontmatter\" with no indication of the boundary or the levers.\n if (allColumns.length > MAX_FRONTMATTER_COLUMNS) {\n throw new SenseError(\n 'COLUMN_LIMIT',\n `frontmatter would need ${allColumns.length} columns, crossing SQLite's compile-time SQLITE_MAX_COLUMN limit (default ${MAX_FRONTMATTER_COLUMNS}; see https://www.sqlite.org/limits.html). Narrow the presets' include globs so fewer/other files are indexed, or fix whatever is generating unbounded frontmatter keys.`\n );\n }\n // Columns the frontmatter upsert actually writes: core + parsed frontmatter keys, never a\n // feature-owned reserved column (see CORE_FRONTMATTER_COLUMNS above).\n const writableColumns = allColumns.filter((c) => CORE_FRONTMATTER_COLUMNS.has(c) || !RESERVED_COLUMNS.has(c));\n // ON CONFLICT UPDATE (not OR REPLACE) keeps the row's rowid stable across reparses --\n // content rows are coupled to that rowid below.\n const insertSql = `INSERT INTO frontmatter (${writableColumns.map(quoteIdent).join(', ')}) VALUES (${writableColumns.map(() => '?').join(', ')}) ON CONFLICT(\"path\") DO UPDATE SET ${writableColumns\n .filter((c) => c !== 'path')\n .map((c) => `${quoteIdent(c)} = excluded.${quoteIdent(c)}`)\n .join(', ')}`;\n\n const added = toReparse.filter((f) => !existing.has(f.relPath)).map((f) => f.relPath);\n const delta: ReconcileDelta = { files, reparsed: parsedDocs.map((d) => d.relPath), added, vanished };\n\n const txStart = Date.now();\n db.exec('BEGIN');\n try {\n for (const col of newColumns) db.exec(`ALTER TABLE frontmatter ADD COLUMN ${quoteIdent(col)}`);\n // FTS5 has no upsert, so delete-before-insert into `content`; coupled to the\n // frontmatter rowid (indexed via its PRIMARY KEY) instead of the UNINDEXED `path`\n // column, which a per-row DELETE would otherwise scan the whole table to find.\n const delBody = db.prepare(`DELETE FROM content WHERE rowid = (SELECT rowid FROM frontmatter WHERE \"path\" = ?)`);\n const delPresetFiles = db.prepare(`DELETE FROM preset_files WHERE \"path\" = ?`);\n const insertPresetFile = db.prepare(`INSERT INTO preset_files (\"path\", preset) VALUES (?, ?)`);\n if (vanished.length > 0) {\n const del = db.prepare(`DELETE FROM frontmatter WHERE \"path\" = ?`);\n for (const path of vanished) {\n // content delete must run first: it looks up the frontmatter rowid by path, which\n // the frontmatter delete below would otherwise have already removed.\n delBody.run(path);\n del.run(path);\n delPresetFiles.run(path);\n for (const feature of features) feature.remove?.(db, path, delta);\n }\n }\n if (parsedDocs.length > 0) {\n const insert = db.prepare(insertSql);\n const insertBody = db.prepare(INSERT_CONTENT_SQL);\n // A non-default tokenizer means the tree has chosen its own scheme; a phrase query over\n // grapheme runs would be nonsense against trigram, so the sidecars stay empty.\n const segmenting = contentTokenize(cfg) === undefined;\n for (const doc of parsedDocs) {\n const values = writableColumns.map((col) => {\n if (col === 'path') return doc.relPath;\n if (col === '_mtime') return doc.mtimeMs;\n if (col === '_ctime') return doc.ctimeMs;\n if (col === '_size') return doc.size;\n // Written per parse, unlike _rank, which a feature pass owns and the upsert skips.\n if (col === '_parse_error') return doc.parseError;\n return doc.data[col] ?? null;\n });\n // Frontmatter upsert first: content's rowid lookup below depends on this row existing.\n insert.run(...values);\n // Only for docs that have rows: an unconditional delete made cold crawls quadratic.\n if (existing.has(doc.relPath)) {\n delBody.run(doc.relPath);\n for (const feature of features) feature.remove?.(db, doc.relPath, delta);\n }\n insertContentRow(insertBody, doc, segmenting);\n // A preset edit forces a full rebuild, so an unchanged doc's coverage is already\n // correct; new docs have nothing to clear, which keeps cold builds linear.\n if (existing.has(doc.relPath)) delPresetFiles.run(doc.relPath);\n for (const presetName of doc.presets) insertPresetFile.run(doc.relPath, presetName);\n for (const feature of features) feature.store?.(db, doc.relPath, doc.extracted[feature.name], delta);\n }\n }\n for (const feature of features) feature.afterReconcile?.(db, delta);\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n\n // Reconcile's own write-transaction duration, for open()'s derived busy_timeout (F):\n // keep the observed max so a big watcher reconcile's lock hold is what the next open bounds its wait against.\n const durationMs = Date.now() - txStart;\n const prevRaw = getMeta(db, 'reconcile_max_ms');\n // -1, not 0, so a genuinely 0ms first reconcile (sub-millisecond, common on a tiny tree)\n // still gets recorded instead of losing to the \"nothing recorded yet\" default.\n const prevMax = prevRaw === null ? -1 : Number(prevRaw);\n if (durationMs > prevMax) setMeta(db, 'reconcile_max_ms', String(durationMs));\n\n return { parsed: parsedDocs.length, warnings };\n}\n\n// Segment keys that moved between two feature signatures (see config.featureSignature's\n// format: global features, embed provider, tokenize, then one segment per preset).\nexport function changedSignatureKeys(before: string, after: string): Set<string> {\n const keyOf = (part: string) => (part.startsWith('preset:') ? part.split(':').slice(0, 2).join(':') : part.split(':')[0]);\n const parse = (sig: string) => new Map(sig.split('|').map((part) => [keyOf(part), part]));\n const a = parse(before);\n const b = parse(after);\n const changed = new Set<string>();\n for (const [key, val] of b) if (a.get(key) !== val) changed.add(key);\n for (const key of a.keys()) if (!b.has(key)) changed.add(key);\n return changed;\n}\n\n// Whether the embed segment only gained its resolved weight identity: same provider and\n// model, no identity recorded before, one now -- adopted into meta without a rebuild.\nexport function embedIdentityAdopted(before: string, after: string): boolean {\n const embedPart = (sig: string) => sig.split('|').find((p) => p.startsWith('embed:'));\n const b = embedPart(before);\n const a = embedPart(after);\n if (b === undefined || a === undefined) return false;\n const at = a.indexOf('@');\n return b.indexOf('@') === -1 && at !== -1 && a.slice(0, at) === b;\n}\n\n// Names what moved, for the rebuild notice.\nexport function signatureDiff(before: string, after: string): string {\n const changed = changedSignatureKeys(before, after);\n const label = (key: string) => (key === 'embed' ? 'embed settings' : key === 'tokenize' ? 'content tokenizer' : key.startsWith('preset:') ? `preset \"${key.slice(7)}\"` : 'features');\n return changed.size === 0 ? 'features' : [...changed].map(label).join(', ');\n}\n\n// The tokenize-only rebuild in open(): content is dropped and repopulated from files already\n// listed in frontmatter, which itself is untouched. Frontmatter, links, sections, and\n// embeddings are file-derived and tokenizer-independent, so they survive. No feature extractors\n// run here -- doc.search (title/summary/text) is all content population needs. Returns\n// parseFile's per-file warnings (e.g. a bad date) so open() can surface them -- mtimes are\n// untouched, so reconcile() never reparses these files and would otherwise never emit them again.\nexport function rebuildContentTable(db: DatabaseSync, cfg: Config, baseDir: string): string[] {\n const known = new Set((db.prepare('SELECT \"path\" FROM frontmatter').all() as Array<{ path: string }>).map((r) => r.path));\n const files = listFiles(cfg, baseDir).filter((f) => known.has(f.relPath));\n const segmenting = contentTokenize(cfg) === undefined;\n const insertBody = db.prepare(INSERT_CONTENT_SQL);\n const warnings: string[] = [];\n db.exec('BEGIN');\n try {\n for (const file of files) {\n const { doc, warnings: fileWarnings } = parseFile(file);\n warnings.push(...fileWarnings);\n insertContentRow(insertBody, doc, segmenting);\n }\n db.exec('COMMIT');\n } catch (err) {\n db.exec('ROLLBACK');\n throw err;\n }\n return warnings;\n}\n"],"names":["changedSignatureKeys","embedIdentityAdopted","rebuildContentTable","reconcile","signatureDiff","CORE_FRONTMATTER_COLUMNS","Set","MAX_FRONTMATTER_COLUMNS","INSERT_CONTENT_SQL","insertContentRow","insertBody","doc","segmenting","run","relPath","search","title","summary","text","segmentField","db","cfg","baseDir","files","listFiles","currentSet","map","f","existingRows","prepare","all","existing","Map","r","path","vanished","filter","has","toReparse","row","get","_mtime","mtimeMs","_size","size","length","parsed","warnings","features","activeFeatures","seenColumns","getColumns","newColumns","parsedDocs","report","progress","parsedCount","file","fileFeatures","feature","enabledForFile","parseFile","fileWarnings","tick","push","Object","keys","data","key","add","finish","allColumns","SenseError","writableColumns","c","RESERVED_COLUMNS","insertSql","quoteIdent","join","added","delta","reparsed","d","txStart","Date","now","exec","col","delBody","delPresetFiles","insertPresetFile","del","remove","insert","contentTokenize","undefined","values","ctimeMs","parseError","presets","presetName","store","extracted","name","afterReconcile","err","durationMs","prevRaw","getMeta","prevMax","Number","setMeta","String","before","after","keyOf","part","startsWith","split","slice","parse","sig","a","b","changed","val","embedPart","find","p","at","indexOf","label","known"],"mappings":"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"}
@@ -9,7 +9,7 @@ Object.defineProperty(exports, "registerFunctions", {
9
9
  }
10
10
  });
11
11
  var _posix = /*#__PURE__*/ _interop_require_default(require("node:path/posix"));
12
- var _segmentts = require("./segment.js");
12
+ var _segmentts = require("../text/segment.js");
13
13
  function _interop_require_default(obj) {
14
14
  return obj && obj.__esModule ? obj : {
15
15
  default: obj
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/db/sql-functions.ts"],"sourcesContent":["import posix from 'node:path/posix';\nimport type { DatabaseSync } from 'node:sqlite';\nimport { segmentMatch } from '../text/segment.ts';\n\n// has(field, value): JSON-array field -> membership, string field -> substring, NULL -> false.\nexport function registerFunctions(db: DatabaseSync, segmenting: boolean): void {\n db.function('has', { deterministic: true, varargs: false }, (field: unknown, value: unknown): number => {\n if (field === null || field === undefined) return 0;\n\n const needle = String(value);\n\n if (typeof field === 'string') {\n if (field.startsWith('[')) {\n try {\n const parsed = JSON.parse(field);\n if (Array.isArray(parsed)) {\n return parsed.some((item) => String(item) === needle) ? 1 : 0;\n }\n } catch {}\n }\n return field.includes(needle) ? 1 : 0;\n }\n\n return String(field).includes(needle) ? 1 : 0;\n });\n\n // Unix basename(path, suffix?): the filename, minus suffix when it ends with one. SQLite\n // itself has no filename function, and the LIKE tricks that fake one also match folder names.\n db.function('basename', { deterministic: true, varargs: true }, (path: unknown, suffix?: unknown): string | null => {\n if (path === null || path === undefined) return null;\n const name = posix.basename(String(path));\n const tail = suffix === null || suffix === undefined ? '' : String(suffix);\n // POSIX: a suffix identical to the whole name is not removed (node's own basename strips it).\n return tail !== '' && tail !== name && name.endsWith(tail) ? name.slice(0, -tail.length) : name;\n });\n\n // Raw `content MATCH '<unspaced text>'` cannot be rewritten behind the author's back, and\n // matches nothing, so the same transform is available to hand-written SQL by name. `segmenting`\n // is the same config predicate commands.ts's search() gates on (contentTokenize(cfg) ===\n // undefined), passed in by open() rather than read back from persisted state.\n db.function('segment', { deterministic: true, varargs: false }, (terms: unknown): string => {\n const text = terms === null || terms === undefined ? '' : String(terms);\n return segmenting ? segmentMatch(text) : text;\n });\n}\n"],"names":["registerFunctions","db","segmenting","function","deterministic","varargs","field","value","undefined","needle","String","startsWith","parsed","JSON","parse","Array","isArray","some","item","includes","path","suffix","name","posix","basename","tail","endsWith","slice","length","terms","text","segmentMatch"],"mappings":";;;;+BAKgBA;;;eAAAA;;;4DALE;yBAEW;;;;;;AAGtB,SAASA,kBAAkBC,EAAgB,EAAEC,UAAmB;IACrED,GAAGE,QAAQ,CAAC,OAAO;QAAEC,eAAe;QAAMC,SAAS;IAAM,GAAG,SAACC,OAAgBC;QAC3E,IAAID,UAAU,QAAQA,UAAUE,WAAW,OAAO;QAElD,IAAMC,SAASC,OAAOH;QAEtB,IAAI,OAAOD,UAAU,UAAU;YAC7B,IAAIA,MAAMK,UAAU,CAAC,MAAM;gBACzB,IAAI;oBACF,IAAMC,SAASC,KAAKC,KAAK,CAACR;oBAC1B,IAAIS,MAAMC,OAAO,CAACJ,SAAS;wBACzB,OAAOA,OAAOK,IAAI,CAAC,SAACC;mCAASR,OAAOQ,UAAUT;6BAAU,IAAI;oBAC9D;gBACF,EAAE,eAAM,CAAC;YACX;YACA,OAAOH,MAAMa,QAAQ,CAACV,UAAU,IAAI;QACtC;QAEA,OAAOC,OAAOJ,OAAOa,QAAQ,CAACV,UAAU,IAAI;IAC9C;IAEA,yFAAyF;IACzF,8FAA8F;IAC9FR,GAAGE,QAAQ,CAAC,YAAY;QAAEC,eAAe;QAAMC,SAAS;IAAK,GAAG,SAACe,MAAeC;QAC9E,IAAID,SAAS,QAAQA,SAASZ,WAAW,OAAO;QAChD,IAAMc,OAAOC,cAAK,CAACC,QAAQ,CAACd,OAAOU;QACnC,IAAMK,OAAOJ,WAAW,QAAQA,WAAWb,YAAY,KAAKE,OAAOW;QACnE,8FAA8F;QAC9F,OAAOI,SAAS,MAAMA,SAASH,QAAQA,KAAKI,QAAQ,CAACD,QAAQH,KAAKK,KAAK,CAAC,GAAG,CAACF,KAAKG,MAAM,IAAIN;IAC7F;IAEA,0FAA0F;IAC1F,gGAAgG;IAChG,yFAAyF;IACzF,8EAA8E;IAC9ErB,GAAGE,QAAQ,CAAC,WAAW;QAAEC,eAAe;QAAMC,SAAS;IAAM,GAAG,SAACwB;QAC/D,IAAMC,OAAOD,UAAU,QAAQA,UAAUrB,YAAY,KAAKE,OAAOmB;QACjE,OAAO3B,aAAa6B,IAAAA,uBAAY,EAACD,QAAQA;IAC3C;AACF"}
@@ -0,0 +1,4 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ export type LangCounts = Record<string, number>;
3
+ export declare function languageDistribution(db: DatabaseSync): LangCounts | undefined;
4
+ export declare function saveLanguageDistribution(db: DatabaseSync, counts: LangCounts): void;
@@ -0,0 +1,4 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ export type LangCounts = Record<string, number>;
3
+ export declare function languageDistribution(db: DatabaseSync): LangCounts | undefined;
4
+ export declare function saveLanguageDistribution(db: DatabaseSync, counts: LangCounts): void;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get languageDistribution () {
13
+ return languageDistribution;
14
+ },
15
+ get saveLanguageDistribution () {
16
+ return saveLanguageDistribution;
17
+ }
18
+ });
19
+ var _sharedts = require("../db/shared.js");
20
+ // Split out of langfit.ts so reading the persisted counts (status.ts's only need) never pulls in
21
+ // franc-min; only checkLanguageFit's classify path needs the classifier itself.
22
+ var META_KEY = 'embed_languages';
23
+ function languageDistribution(db) {
24
+ var raw = (0, _sharedts.getMeta)(db, META_KEY);
25
+ return raw ? JSON.parse(raw) : undefined;
26
+ }
27
+ function saveLanguageDistribution(db, counts) {
28
+ (0, _sharedts.setMeta)(db, META_KEY, JSON.stringify(counts));
29
+ }
30
+ /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/distribution.ts"],"sourcesContent":["import type { DatabaseSync } from 'node:sqlite';\nimport { getMeta, setMeta } from '../db/shared.ts';\n\n// Split out of langfit.ts so reading the persisted counts (status.ts's only need) never pulls in\n// franc-min; only checkLanguageFit's classify path needs the classifier itself.\nconst META_KEY = 'embed_languages';\n\nexport type LangCounts = Record<string, number>;\n\nexport function languageDistribution(db: DatabaseSync): LangCounts | undefined {\n const raw = getMeta(db, META_KEY);\n return raw ? JSON.parse(raw) : undefined;\n}\n\nexport function saveLanguageDistribution(db: DatabaseSync, counts: LangCounts): void {\n setMeta(db, META_KEY, JSON.stringify(counts));\n}\n"],"names":["languageDistribution","saveLanguageDistribution","META_KEY","db","raw","getMeta","JSON","parse","undefined","counts","setMeta","stringify"],"mappings":";;;;;;;;;;;QASgBA;eAAAA;;QAKAC;eAAAA;;;wBAbiB;AAEjC,iGAAiG;AACjG,gFAAgF;AAChF,IAAMC,WAAW;AAIV,SAASF,qBAAqBG,EAAgB;IACnD,IAAMC,MAAMC,IAAAA,iBAAO,EAACF,IAAID;IACxB,OAAOE,MAAME,KAAKC,KAAK,CAACH,OAAOI;AACjC;AAEO,SAASP,yBAAyBE,EAAgB,EAAEM,MAAkB;IAC3EC,IAAAA,iBAAO,EAACP,IAAID,UAAUI,KAAKK,SAAS,CAACF;AACvC"}
@@ -1,6 +1,3 @@
1
1
  import type { DatabaseSync } from 'node:sqlite';
2
2
  import type { EmbedProvider } from './types.js';
3
- type LangCounts = Record<string, number>;
4
- export declare function languageDistribution(db: DatabaseSync): LangCounts | undefined;
5
3
  export declare function checkLanguageFit(db: DatabaseSync, provider: EmbedProvider, texts: string[]): Promise<void>;
6
- export {};
@@ -1,6 +1,3 @@
1
1
  import type { DatabaseSync } from 'node:sqlite';
2
2
  import type { EmbedProvider } from './types.js';
3
- type LangCounts = Record<string, number>;
4
- export declare function languageDistribution(db: DatabaseSync): LangCounts | undefined;
5
3
  export declare function checkLanguageFit(db: DatabaseSync, provider: EmbedProvider, texts: string[]): Promise<void>;
6
- export {};
@@ -2,22 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: Object.getOwnPropertyDescriptor(all, name).get
9
- });
10
- }
11
- _export(exports, {
12
- get checkLanguageFit () {
5
+ Object.defineProperty(exports, "checkLanguageFit", {
6
+ enumerable: true,
7
+ get: function() {
13
8
  return checkLanguageFit;
14
- },
15
- get languageDistribution () {
16
- return languageDistribution;
17
9
  }
18
10
  });
19
- var _sharedts = require("../db/shared.js");
11
+ var _nodemodule = /*#__PURE__*/ _interop_require_default(require("node:module"));
20
12
  var _errorsts = require("../errors.js");
13
+ var _distributionts = require("./distribution.js");
21
14
  var _languagests = require("./languages.js");
22
15
  function _array_like_to_array(arr, len) {
23
16
  if (len == null || len > arr.length) len = arr.length;
@@ -64,35 +57,10 @@ function _define_property(obj, key, value) {
64
57
  } else obj[key] = value;
65
58
  return obj;
66
59
  }
67
- function _getRequireWildcardCache(nodeInterop) {
68
- if (typeof WeakMap !== "function") return null;
69
- var cacheBabelInterop = new WeakMap();
70
- var cacheNodeInterop = new WeakMap();
71
- return (_getRequireWildcardCache = function(nodeInterop) {
72
- return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
73
- })(nodeInterop);
74
- }
75
- function _interop_require_wildcard(obj, nodeInterop) {
76
- if (!nodeInterop && obj && obj.__esModule) return obj;
77
- if (obj === null || typeof obj !== "object" && typeof obj !== "function") return {
60
+ function _interop_require_default(obj) {
61
+ return obj && obj.__esModule ? obj : {
78
62
  default: obj
79
63
  };
80
- var cache = _getRequireWildcardCache(nodeInterop);
81
- if (cache && cache.has(obj)) return cache.get(obj);
82
- var newObj = {
83
- __proto__: null
84
- };
85
- var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
86
- for(var key in obj){
87
- if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
88
- var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
89
- if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc);
90
- else newObj[key] = obj[key];
91
- }
92
- }
93
- newObj.default = obj;
94
- if (cache) cache.set(obj, newObj);
95
- return newObj;
96
64
  }
97
65
  function _iterable_to_array_limit(arr, i) {
98
66
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
@@ -246,17 +214,16 @@ function _unsupported_iterable_to_array(o, minLen) {
246
214
  if (n === "Map" || n === "Set") return Array.from(n);
247
215
  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
248
216
  }
249
- var META_KEY = 'embed_languages';
250
217
  // franc's own reliability floor is a handful of characters; this is a cheap upper bound, not a
251
218
  // per-chunk minimum -- a short chunk is simply more likely to come back 'und' (unclassified).
252
219
  var SAMPLE_CHARS = 300;
253
220
  // A majority computed over a handful of chunks is noise, not a corpus signal; the decision rule
254
221
  // never fires below this many classified chunks, declared languages or not.
255
222
  var MIN_CLASSIFIED = 10;
256
- function languageDistribution(db) {
257
- var raw = (0, _sharedts.getMeta)(db, META_KEY);
258
- return raw ? JSON.parse(raw) : undefined;
259
- }
223
+ // franc-min is a 148K static import; a top-level import put it on every command's module graph
224
+ // regardless of whether the semantic path ran, shipped as the 0.17.0 regression. Deferred to a
225
+ // synchronous require inside checkLanguageFit so only the embed path pays for it.
226
+ var _require = typeof require === 'undefined' ? _nodemodule.default.createRequire(require("url").pathToFileURL(__filename).toString()) : require;
260
227
  function classify(franc, text) {
261
228
  var code = franc(text.slice(0, SAMPLE_CHARS));
262
229
  return code === 'und' ? undefined : code;
@@ -265,61 +232,51 @@ function checkLanguageFit(db, provider, texts) {
265
232
  return _async_to_generator(function() {
266
233
  var _languageDistribution, franc, persisted, merged, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, text, _merged_code, code, total, declared, _Object_entries_sort_, majorityLang, majorityCount, pct;
267
234
  return _ts_generator(this, function(_state) {
268
- switch(_state.label){
269
- case 0:
270
- if (texts.length === 0) return [
271
- 2
272
- ];
273
- return [
274
- 4,
275
- Promise.resolve().then(function() {
276
- return /*#__PURE__*/ _interop_require_wildcard(require("franc-min"));
277
- })
278
- ];
279
- case 1:
280
- franc = _state.sent().franc;
281
- persisted = (_languageDistribution = languageDistribution(db)) !== null && _languageDistribution !== void 0 ? _languageDistribution : {};
282
- merged = _object_spread({}, persisted);
283
- _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
284
- try {
285
- for(_iterator = texts[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
286
- text = _step.value;
287
- ;
288
- code = classify(franc, text);
289
- if (code) merged[code] = ((_merged_code = merged[code]) !== null && _merged_code !== void 0 ? _merged_code : 0) + 1;
290
- }
291
- } catch (err) {
292
- _didIteratorError = true;
293
- _iteratorError = err;
294
- } finally{
295
- try {
296
- if (!_iteratorNormalCompletion && _iterator.return != null) {
297
- _iterator.return();
298
- }
299
- } finally{
300
- if (_didIteratorError) {
301
- throw _iteratorError;
302
- }
303
- }
235
+ if (texts.length === 0) return [
236
+ 2
237
+ ];
238
+ franc = _require('franc-min').franc;
239
+ persisted = (_languageDistribution = (0, _distributionts.languageDistribution)(db)) !== null && _languageDistribution !== void 0 ? _languageDistribution : {};
240
+ merged = _object_spread({}, persisted);
241
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
242
+ try {
243
+ for(_iterator = texts[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
244
+ text = _step.value;
245
+ ;
246
+ code = classify(franc, text);
247
+ if (code) merged[code] = ((_merged_code = merged[code]) !== null && _merged_code !== void 0 ? _merged_code : 0) + 1;
248
+ }
249
+ } catch (err) {
250
+ _didIteratorError = true;
251
+ _iteratorError = err;
252
+ } finally{
253
+ try {
254
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
255
+ _iterator.return();
304
256
  }
305
- total = Object.values(merged).reduce(function(a, b) {
306
- return a + b;
307
- }, 0);
308
- if (provider.languages && provider.languages.length > 0 && total >= MIN_CLASSIFIED) {
309
- declared = new Set(provider.languages.map(_languagests.toIso3));
310
- _Object_entries_sort_ = _sliced_to_array(Object.entries(merged).sort(function(a, b) {
311
- return b[1] - a[1];
312
- })[0], 2), majorityLang = _Object_entries_sort_[0], majorityCount = _Object_entries_sort_[1];
313
- if (majorityCount / total >= 0.5 && !declared.has(majorityLang)) {
314
- pct = Math.round(majorityCount / total * 100);
315
- throw new _errorsts.SenseError('EMBED_MODEL_MISMATCH', "embed model ".concat(provider.id, " declares languages [").concat(provider.languages.join(', '), "], but ").concat(pct, "% of this tree's classified text is \"").concat(majorityLang, "\" (ISO 639-3), which is not among them; choose a model for this tree's languages: `sense init --model ...`, see the sense-setup skill or INTEGRATIONS.md"));
316
- }
257
+ } finally{
258
+ if (_didIteratorError) {
259
+ throw _iteratorError;
317
260
  }
318
- (0, _sharedts.setMeta)(db, META_KEY, JSON.stringify(merged));
319
- return [
320
- 2
321
- ];
261
+ }
262
+ }
263
+ total = Object.values(merged).reduce(function(a, b) {
264
+ return a + b;
265
+ }, 0);
266
+ if (provider.languages && provider.languages.length > 0 && total >= MIN_CLASSIFIED) {
267
+ declared = new Set(provider.languages.map(_languagests.toIso3));
268
+ _Object_entries_sort_ = _sliced_to_array(Object.entries(merged).sort(function(a, b) {
269
+ return b[1] - a[1];
270
+ })[0], 2), majorityLang = _Object_entries_sort_[0], majorityCount = _Object_entries_sort_[1];
271
+ if (majorityCount / total >= 0.5 && !declared.has(majorityLang)) {
272
+ pct = Math.round(majorityCount / total * 100);
273
+ throw new _errorsts.SenseError('EMBED_MODEL_MISMATCH', "embed model ".concat(provider.id, " declares languages [").concat(provider.languages.join(', '), "], but ").concat(pct, "% of this tree's classified text is \"").concat(majorityLang, "\" (ISO 639-3), which is not among them; choose a model for this tree's languages: `sense init --model ...`, see the sense-setup skill or INTEGRATIONS.md"));
274
+ }
322
275
  }
276
+ (0, _distributionts.saveLanguageDistribution)(db, merged);
277
+ return [
278
+ 2
279
+ ];
323
280
  });
324
281
  })();
325
282
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/langfit.ts"],"sourcesContent":["import type { DatabaseSync } from 'node:sqlite';\nimport { getMeta, setMeta } from '../db/shared.ts';\nimport { SenseError } from '../errors.ts';\nimport { toIso3 } from './languages.ts';\nimport type { EmbedProvider } from './types.ts';\n\nconst META_KEY = 'embed_languages';\n// franc's own reliability floor is a handful of characters; this is a cheap upper bound, not a\n// per-chunk minimum -- a short chunk is simply more likely to come back 'und' (unclassified).\nconst SAMPLE_CHARS = 300;\n// A majority computed over a handful of chunks is noise, not a corpus signal; the decision rule\n// never fires below this many classified chunks, declared languages or not.\nconst MIN_CLASSIFIED = 10;\n\ntype LangCounts = Record<string, number>;\n\nexport function languageDistribution(db: DatabaseSync): LangCounts | undefined {\n const raw = getMeta(db, META_KEY);\n return raw ? JSON.parse(raw) : undefined;\n}\n\nfunction classify(franc: (text: string) => string, text: string): string | undefined {\n const code = franc(text.slice(0, SAMPLE_CHARS));\n return code === 'und' ? undefined : code;\n}\n\n// Merges chunk texts into the persisted distribution; throws (without persisting) if the model\n// declares languages and a clear majority classified so far is not among them.\nexport async function checkLanguageFit(db: DatabaseSync, provider: EmbedProvider, texts: string[]): Promise<void> {\n if (texts.length === 0) return;\n const { franc } = await import('franc-min');\n const persisted = languageDistribution(db) ?? {};\n const merged = { ...persisted };\n for (const text of texts) {\n const code = classify(franc, text);\n if (code) merged[code] = (merged[code] ?? 0) + 1;\n }\n\n const total = Object.values(merged).reduce((a, b) => a + b, 0);\n if (provider.languages && provider.languages.length > 0 && total >= MIN_CLASSIFIED) {\n const declared = new Set(provider.languages.map(toIso3));\n const [majorityLang, majorityCount] = Object.entries(merged).sort((a, b) => b[1] - a[1])[0];\n if (majorityCount / total >= 0.5 && !declared.has(majorityLang)) {\n const pct = Math.round((majorityCount / total) * 100);\n throw new SenseError(\n 'EMBED_MODEL_MISMATCH',\n `embed model ${provider.id} declares languages [${provider.languages.join(', ')}], but ${pct}% of this tree's classified text is \"${majorityLang}\" (ISO 639-3), which is not among them; choose a model for this tree's languages: \\`sense init --model ...\\`, see the sense-setup skill or INTEGRATIONS.md`\n );\n }\n }\n setMeta(db, META_KEY, JSON.stringify(merged));\n}\n"],"names":["checkLanguageFit","languageDistribution","META_KEY","SAMPLE_CHARS","MIN_CLASSIFIED","db","raw","getMeta","JSON","parse","undefined","classify","franc","text","code","slice","provider","texts","persisted","merged","total","declared","Object","majorityLang","majorityCount","pct","length","values","reduce","a","b","languages","Set","map","toIso3","entries","sort","has","Math","round","SenseError","id","join","setMeta","stringify"],"mappings":";;;;;;;;;;;QA4BsBA;eAAAA;;QAZNC;eAAAA;;;wBAfiB;wBACN;2BACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGvB,IAAMC,WAAW;AACjB,+FAA+F;AAC/F,8FAA8F;AAC9F,IAAMC,eAAe;AACrB,gGAAgG;AAChG,4EAA4E;AAC5E,IAAMC,iBAAiB;AAIhB,SAASH,qBAAqBI,EAAgB;IACnD,IAAMC,MAAMC,IAAAA,iBAAO,EAACF,IAAIH;IACxB,OAAOI,MAAME,KAAKC,KAAK,CAACH,OAAOI;AACjC;AAEA,SAASC,SAASC,KAA+B,EAAEC,IAAY;IAC7D,IAAMC,OAAOF,MAAMC,KAAKE,KAAK,CAAC,GAAGZ;IACjC,OAAOW,SAAS,QAAQJ,YAAYI;AACtC;AAIO,SAAed,iBAAiBK,EAAgB,EAAEW,QAAuB,EAAEC,KAAe;;YAG7EhB,uBADVW,OACFM,WACAC,QACD,2BAAA,mBAAA,gBAAA,WAAA,OAAMN,MAEiBM,cADpBL,MAIFM,OAEEC,UACgCC,uBAA/BC,cAAcC,eAEbC;;;;oBAdV,IAAIR,MAAMS,MAAM,KAAK,GAAG;;;oBACN;;wBAAM;2EAAA,QAAO;;;;oBAAvBd,QAAU,cAAVA;oBACFM,aAAYjB,wBAAAA,qBAAqBI,iBAArBJ,mCAAAA,wBAA4B,CAAC;oBACzCkB,SAAS,mBAAKD;oBACf,kCAAA,2BAAA;;wBAAL,IAAK,YAAcD,4BAAd,6BAAA,QAAA,yBAAA,iCAAqB;4BAAfJ,OAAN;;4BACGC,OAAOH,SAASC,OAAOC;4BAC7B,IAAIC,MAAMK,MAAM,CAACL,KAAK,GAAG,EAACK,eAAAA,MAAM,CAACL,KAAK,cAAZK,0BAAAA,eAAgB,KAAK;wBACjD;;wBAHK;wBAAA;;;iCAAA,6BAAA;gCAAA;;;gCAAA;sCAAA;;;;oBAKCC,QAAQE,OAAOK,MAAM,CAACR,QAAQS,MAAM,CAAC,SAACC,GAAGC;+BAAMD,IAAIC;uBAAG;oBAC5D,IAAId,SAASe,SAAS,IAAIf,SAASe,SAAS,CAACL,MAAM,GAAG,KAAKN,SAAShB,gBAAgB;wBAC5EiB,WAAW,IAAIW,IAAIhB,SAASe,SAAS,CAACE,GAAG,CAACC,mBAAM;wBAChBZ,yCAAAA,OAAOa,OAAO,CAAChB,QAAQiB,IAAI,CAAC,SAACP,GAAGC;mCAAMA,CAAC,CAAC,EAAE,GAAGD,CAAC,CAAC,EAAE;0BAAC,CAAC,EAAE,MAApFN,eAA+BD,0BAAjBE,gBAAiBF;wBACtC,IAAIE,gBAAgBJ,SAAS,OAAO,CAACC,SAASgB,GAAG,CAACd,eAAe;4BACzDE,MAAMa,KAAKC,KAAK,CAAC,AAACf,gBAAgBJ,QAAS;4BACjD,MAAM,IAAIoB,oBAAU,CAClB,wBACA,AAAC,eAAiDxB,OAAnCA,SAASyB,EAAE,EAAC,yBAA8DhB,OAAvCT,SAASe,SAAS,CAACW,IAAI,CAAC,OAAM,WAAoDnB,OAA3CE,KAAI,0CAAoD,OAAbF,cAAa;wBAErJ;oBACF;oBACAoB,IAAAA,iBAAO,EAACtC,IAAIH,UAAUM,KAAKoC,SAAS,CAACzB;;;;;;IACvC"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/langfit.ts"],"sourcesContent":["import Module from 'node:module';\nimport type { DatabaseSync } from 'node:sqlite';\nimport { SenseError } from '../errors.ts';\nimport { languageDistribution, saveLanguageDistribution } from './distribution.ts';\nimport { toIso3 } from './languages.ts';\nimport type { EmbedProvider } from './types.ts';\n\n// franc's own reliability floor is a handful of characters; this is a cheap upper bound, not a\n// per-chunk minimum -- a short chunk is simply more likely to come back 'und' (unclassified).\nconst SAMPLE_CHARS = 300;\n// A majority computed over a handful of chunks is noise, not a corpus signal; the decision rule\n// never fires below this many classified chunks, declared languages or not.\nconst MIN_CLASSIFIED = 10;\n\n// franc-min is a 148K static import; a top-level import put it on every command's module graph\n// regardless of whether the semantic path ran, shipped as the 0.17.0 regression. Deferred to a\n// synchronous require inside checkLanguageFit so only the embed path pays for it.\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\nfunction classify(franc: typeof import('franc-min')['franc'], text: string): string | undefined {\n const code = franc(text.slice(0, SAMPLE_CHARS));\n return code === 'und' ? undefined : code;\n}\n\n// Merges chunk texts into the persisted distribution; throws (without persisting) if the model\n// declares languages and a clear majority classified so far is not among them.\nexport async function checkLanguageFit(db: DatabaseSync, provider: EmbedProvider, texts: string[]): Promise<void> {\n if (texts.length === 0) return;\n const { franc } = _require('franc-min') as typeof import('franc-min');\n const persisted = languageDistribution(db) ?? {};\n const merged = { ...persisted };\n for (const text of texts) {\n const code = classify(franc, text);\n if (code) merged[code] = (merged[code] ?? 0) + 1;\n }\n\n const total = Object.values(merged).reduce((a, b) => a + b, 0);\n if (provider.languages && provider.languages.length > 0 && total >= MIN_CLASSIFIED) {\n const declared = new Set(provider.languages.map(toIso3));\n const [majorityLang, majorityCount] = Object.entries(merged).sort((a, b) => b[1] - a[1])[0];\n if (majorityCount / total >= 0.5 && !declared.has(majorityLang)) {\n const pct = Math.round((majorityCount / total) * 100);\n throw new SenseError(\n 'EMBED_MODEL_MISMATCH',\n `embed model ${provider.id} declares languages [${provider.languages.join(', ')}], but ${pct}% of this tree's classified text is \"${majorityLang}\" (ISO 639-3), which is not among them; choose a model for this tree's languages: \\`sense init --model ...\\`, see the sense-setup skill or INTEGRATIONS.md`\n );\n }\n }\n saveLanguageDistribution(db, merged);\n}\n"],"names":["checkLanguageFit","SAMPLE_CHARS","MIN_CLASSIFIED","_require","require","Module","createRequire","classify","franc","text","code","slice","undefined","db","provider","texts","languageDistribution","persisted","merged","total","declared","Object","majorityLang","majorityCount","pct","length","values","reduce","a","b","languages","Set","map","toIso3","entries","sort","has","Math","round","SenseError","id","join","saveLanguageDistribution"],"mappings":";;;;+BA0BsBA;;;eAAAA;;;iEA1BH;wBAEQ;8BACoC;2BACxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGvB,+FAA+F;AAC/F,8FAA8F;AAC9F,IAAMC,eAAe;AACrB,gGAAgG;AAChG,4EAA4E;AAC5E,IAAMC,iBAAiB;AAEvB,+FAA+F;AAC/F,+FAA+F;AAC/F,kFAAkF;AAClF,IAAMC,WAAW,OAAOC,YAAY,cAAcC,mBAAM,CAACC,aAAa,CAAC,uDAAmBF;AAE1F,SAASG,SAASC,KAA0C,EAAEC,IAAY;IACxE,IAAMC,OAAOF,MAAMC,KAAKE,KAAK,CAAC,GAAGV;IACjC,OAAOS,SAAS,QAAQE,YAAYF;AACtC;AAIO,SAAeV,iBAAiBa,EAAgB,EAAEC,QAAuB,EAAEC,KAAe;;YAG7EC,uBADVR,OACFS,WACAC,QACD,2BAAA,mBAAA,gBAAA,WAAA,OAAMT,MAEiBS,cADpBR,MAIFS,OAEEC,UACgCC,uBAA/BC,cAAcC,eAEbC;;YAdV,IAAIT,MAAMU,MAAM,KAAK,GAAG;;;YAChBjB,QAAUL,SAAS,aAAnBK;YACFS,aAAYD,wBAAAA,IAAAA,oCAAoB,EAACH,iBAArBG,mCAAAA,wBAA4B,CAAC;YACzCE,SAAS,mBAAKD;YACf,kCAAA,2BAAA;;gBAAL,IAAK,YAAcF,4BAAd,6BAAA,QAAA,yBAAA,iCAAqB;oBAAfN,OAAN;;oBACGC,OAAOH,SAASC,OAAOC;oBAC7B,IAAIC,MAAMQ,MAAM,CAACR,KAAK,GAAG,EAACQ,eAAAA,MAAM,CAACR,KAAK,cAAZQ,0BAAAA,eAAgB,KAAK;gBACjD;;gBAHK;gBAAA;;;yBAAA,6BAAA;wBAAA;;;wBAAA;8BAAA;;;;YAKCC,QAAQE,OAAOK,MAAM,CAACR,QAAQS,MAAM,CAAC,SAACC,GAAGC;uBAAMD,IAAIC;eAAG;YAC5D,IAAIf,SAASgB,SAAS,IAAIhB,SAASgB,SAAS,CAACL,MAAM,GAAG,KAAKN,SAASjB,gBAAgB;gBAC5EkB,WAAW,IAAIW,IAAIjB,SAASgB,SAAS,CAACE,GAAG,CAACC,mBAAM;gBAChBZ,yCAAAA,OAAOa,OAAO,CAAChB,QAAQiB,IAAI,CAAC,SAACP,GAAGC;2BAAMA,CAAC,CAAC,EAAE,GAAGD,CAAC,CAAC,EAAE;kBAAC,CAAC,EAAE,MAApFN,eAA+BD,0BAAjBE,gBAAiBF;gBACtC,IAAIE,gBAAgBJ,SAAS,OAAO,CAACC,SAASgB,GAAG,CAACd,eAAe;oBACzDE,MAAMa,KAAKC,KAAK,CAAC,AAACf,gBAAgBJ,QAAS;oBACjD,MAAM,IAAIoB,oBAAU,CAClB,wBACA,AAAC,eAAiDzB,OAAnCA,SAAS0B,EAAE,EAAC,yBAA8DhB,OAAvCV,SAASgB,SAAS,CAACW,IAAI,CAAC,OAAM,WAAoDnB,OAA3CE,KAAI,0CAAoD,OAAbF,cAAa;gBAErJ;YACF;YACAoB,IAAAA,wCAAwB,EAAC7B,IAAIK;;;;;IAC/B"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/languages.ts"],"sourcesContent":["// HF model cards declare languages as ISO 639-1 tags (e.g. \"zh\"); franc-min reports ISO 639-3\n// (e.g. \"cmn\"). This bridges the two for comparison. Limited to franc-min's own 82-language\n// data (README table, https://github.com/wooorm/franc), so every value here is a code franc-min\n// can actually emit; a declared tag with no entry here is compared as-is.\nconst ISO_639_1_TO_3: Record<string, string> = {\n ar: 'arb',\n am: 'amh',\n az: 'azj',\n be: 'bel',\n bg: 'bul',\n bn: 'ben',\n bs: 'bos',\n cs: 'ces',\n de: 'deu',\n el: 'ell',\n en: 'eng',\n es: 'spa',\n fa: 'pes',\n fr: 'fra',\n gu: 'guj',\n ha: 'hau',\n hi: 'hin',\n hr: 'hrv',\n hu: 'hun',\n id: 'ind',\n ig: 'ibo',\n it: 'ita',\n ja: 'jpn',\n jv: 'jav',\n kk: 'kaz',\n kn: 'kan',\n ko: 'kor',\n ml: 'mal',\n mr: 'mar',\n ms: 'zlm',\n my: 'mya',\n ne: 'npi',\n nl: 'nld',\n pa: 'pan',\n pl: 'pol',\n pt: 'por',\n ro: 'ron',\n ru: 'rus',\n rw: 'kin',\n si: 'sin',\n so: 'som',\n sr: 'srp',\n su: 'sun',\n sv: 'swe',\n sw: 'swh',\n ta: 'tam',\n te: 'tel',\n th: 'tha',\n tl: 'tgl',\n tr: 'tur',\n uk: 'ukr',\n ur: 'urd',\n uz: 'uzn',\n vi: 'vie',\n yo: 'yor',\n zh: 'cmn',\n zu: 'zul',\n};\n\nexport function isKnownLanguageTag(tag: string): boolean {\n return tag in ISO_639_1_TO_3;\n}\n\n// Normalizes a declared or detected language code to ISO 639-3 for comparison; strips a\n// region/script subtag (\"zh-cn\" -> \"zh\") first. Codes already in 639-3 form pass through.\nexport function toIso3(code: string): string {\n const base = code.toLowerCase().split('-')[0];\n return ISO_639_1_TO_3[base] ?? base;\n}\n\n// Languages this project measured for models whose cards declare none, so the fit check is\n// not silently off for the shipped default; asserted here because it was measured, not attested.\nexport const MEASURED_MODEL_LANGUAGES: Record<string, string[]> = {\n 'minishlab/potion-retrieval-32M': ['en'], // BENCHMARKING.md bake-off; token-loss measurements\n};\n"],"names":["MEASURED_MODEL_LANGUAGES","isKnownLanguageTag","toIso3","ISO_639_1_TO_3","ar","am","az","be","bg","bn","bs","cs","de","el","en","es","fa","fr","gu","ha","hi","hr","hu","id","ig","it","ja","jv","kk","kn","ko","ml","mr","ms","my","ne","nl","pa","pl","pt","ro","ru","rw","si","so","sr","su","sv","sw","ta","te","th","tl","tr","uk","ur","uz","vi","yo","zh","zu","tag","code","base","toLowerCase","split"],"mappings":";;;;;;;;;;;QA6EaA;eAAAA;;QAbGC;eAAAA;;QAMAC;eAAAA;;;AAtEhB,8FAA8F;AAC9F,4FAA4F;AAC5F,gGAAgG;AAChG,0EAA0E;AAC1E,IAAMC,iBAAyC;IAC7CC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;AACN;AAEO,SAAS3D,mBAAmB4D,GAAW;IAC5C,OAAOA,OAAO1D;AAChB;AAIO,SAASD,OAAO4D,IAAY;QAE1B3D;IADP,IAAM4D,OAAOD,KAAKE,WAAW,GAAGC,KAAK,CAAC,IAAI,CAAC,EAAE;IAC7C,QAAO9D,uBAAAA,cAAc,CAAC4D,KAAK,cAApB5D,kCAAAA,uBAAwB4D;AACjC;AAIO,IAAM/D,2BAAqD;IAChE,kCAAkC;QAAC;KAAK;AAC1C"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/embed/languages.ts"],"sourcesContent":["// HF model cards declare languages as ISO 639-1 tags (e.g. \"zh\"); franc-min reports ISO 639-3\n// (e.g. \"cmn\"). This bridges the two for comparison. Limited to franc-min's own 82-language\n// data (README table, https://github.com/wooorm/franc), so every value here is a code franc-min\n// can actually emit; a declared tag with no entry here is compared as-is.\nconst ISO_639_1_TO_3: Record<string, string> = {\n ar: 'arb',\n am: 'amh',\n az: 'azj',\n be: 'bel',\n bg: 'bul',\n bn: 'ben',\n bs: 'bos',\n cs: 'ces',\n de: 'deu',\n el: 'ell',\n en: 'eng',\n es: 'spa',\n fa: 'pes',\n fr: 'fra',\n gu: 'guj',\n ha: 'hau',\n hi: 'hin',\n hr: 'hrv',\n hu: 'hun',\n id: 'ind',\n ig: 'ibo',\n it: 'ita',\n ja: 'jpn',\n jv: 'jav',\n kk: 'kaz',\n kn: 'kan',\n ko: 'kor',\n ml: 'mal',\n mr: 'mar',\n ms: 'zlm',\n my: 'mya',\n ne: 'npi',\n nl: 'nld',\n pa: 'pan',\n pl: 'pol',\n pt: 'por',\n ro: 'ron',\n ru: 'rus',\n rw: 'kin',\n si: 'sin',\n so: 'som',\n sr: 'srp',\n su: 'sun',\n sv: 'swe',\n sw: 'swh',\n ta: 'tam',\n te: 'tel',\n th: 'tha',\n tl: 'tgl',\n tr: 'tur',\n uk: 'ukr',\n ur: 'urd',\n uz: 'uzn',\n vi: 'vie',\n yo: 'yor',\n zh: 'cmn',\n zu: 'zul',\n};\n\nexport function isKnownLanguageTag(tag: string): boolean {\n return tag in ISO_639_1_TO_3;\n}\n\n// Normalizes a declared or detected language code to ISO 639-3 for comparison; strips a\n// region/script subtag (\"zh-cn\" -> \"zh\") first. Codes already in 639-3 form pass through.\nexport function toIso3(code: string): string {\n const base = code.toLowerCase().split('-')[0];\n return ISO_639_1_TO_3[base] ?? base;\n}\n\n// Languages this project measured for models whose cards declare none, so the fit check is\n// not silently off for the shipped default; asserted here because it was measured, not attested.\nexport const MEASURED_MODEL_LANGUAGES: Record<string, string[]> = {\n 'minishlab/potion-retrieval-32M': ['en'], // benchmark/reports/2026-08-27-embedding-model-selection.md\n};\n"],"names":["MEASURED_MODEL_LANGUAGES","isKnownLanguageTag","toIso3","ISO_639_1_TO_3","ar","am","az","be","bg","bn","bs","cs","de","el","en","es","fa","fr","gu","ha","hi","hr","hu","id","ig","it","ja","jv","kk","kn","ko","ml","mr","ms","my","ne","nl","pa","pl","pt","ro","ru","rw","si","so","sr","su","sv","sw","ta","te","th","tl","tr","uk","ur","uz","vi","yo","zh","zu","tag","code","base","toLowerCase","split"],"mappings":";;;;;;;;;;;QA6EaA;eAAAA;;QAbGC;eAAAA;;QAMAC;eAAAA;;;AAtEhB,8FAA8F;AAC9F,4FAA4F;AAC5F,gGAAgG;AAChG,0EAA0E;AAC1E,IAAMC,iBAAyC;IAC7CC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;IACJC,IAAI;AACN;AAEO,SAAS3D,mBAAmB4D,GAAW;IAC5C,OAAOA,OAAO1D;AAChB;AAIO,SAASD,OAAO4D,IAAY;QAE1B3D;IADP,IAAM4D,OAAOD,KAAKE,WAAW,GAAGC,KAAK,CAAC,IAAI,CAAC,EAAE;IAC7C,QAAO9D,uBAAAA,cAAc,CAAC4D,KAAK,cAApB5D,kCAAAA,uBAAwB4D;AACjC;AAIO,IAAM/D,2BAAqD;IAChE,kCAAkC;QAAC;KAAK;AAC1C"}
@@ -28,8 +28,8 @@ _export(exports, {
28
28
  var _nodepath = require("node:path");
29
29
  var _errorsts = require("../errors.js");
30
30
  var _embedts = require("../features/embed.js");
31
- var _progressts = require("../progress.js");
32
- var _scants = require("../scan.js");
31
+ var _progressts = require("../output/progress.js");
32
+ var _indexts = require("../scan/index.js");
33
33
  var _langfitts = require("./langfit.js");
34
34
  var _registryts = require("./registry.js");
35
35
  function _array_like_to_array(arr, len) {
@@ -237,8 +237,8 @@ function _unsupported_iterable_to_array(o, minLen) {
237
237
  if (n === "Map" || n === "Set") return Array.from(n);
238
238
  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
239
239
  }
240
- // Storage lever fixed by the bake-off (BENCHMARKING.md): int8 at 256 dims is
241
- // quality-free vs f32-512 when fused. Queries stay f32 at the same dims.
240
+ // Storage lever fixed by the bake-off (benchmark/reports/2026-08-13-static-model-bakeoff.md):
241
+ // int8 at 256 dims is quality-free vs f32-512 when fused. Queries stay f32 at the same dims.
242
242
  var STORE_DIMS = 256;
243
243
  // Seed chunks that participate in a `related` scan; see similarNotes for the measurement.
244
244
  var TARGET_CHUNK_CAP = 16;
@@ -343,7 +343,7 @@ function embedPending(db, cfg, baseDir) {
343
343
  try {
344
344
  // presets/embed are irrelevant here -- re-deriving chunk text for a doc that already
345
345
  // has embeddings rows means the tree had an embedding model at reconcile time.
346
- chunks = (0, _scants.parseFile)({
346
+ chunks = (0, _indexts.parseFile)({
347
347
  relPath: path,
348
348
  absPath: (0, _nodepath.join)(baseDir, path),
349
349
  mtimeMs: 0,
@@ -353,7 +353,7 @@ function embedPending(db, cfg, baseDir) {
353
353
  embed: true
354
354
  }, [
355
355
  _embedts.embed
356
- ]).doc.extracted.embed;
356
+ ], cfg).doc.extracted.embed;
357
357
  } catch (unused) {
358
358
  continue; // vanished since reconcile; the next reconcile removes its rows
359
359
  }