sensemaking 0.24.7 → 0.25.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 (242) hide show
  1. package/README.md +21 -12
  2. package/dist/cjs/cli/build.d.cts +3 -0
  3. package/dist/cjs/cli/build.d.ts +3 -0
  4. package/dist/cjs/cli/build.js +195 -0
  5. package/dist/cjs/cli/build.js.map +1 -0
  6. package/dist/cjs/cli/index.d.cts +7 -6
  7. package/dist/cjs/cli/index.d.ts +7 -6
  8. package/dist/cjs/cli/index.js +12 -6
  9. package/dist/cjs/cli/index.js.map +1 -1
  10. package/dist/cjs/cli/init.js +2 -2
  11. package/dist/cjs/cli/init.js.map +1 -1
  12. package/dist/cjs/cli/map.js +7 -2
  13. package/dist/cjs/cli/map.js.map +1 -1
  14. package/dist/cjs/cli/named.js +63 -21
  15. package/dist/cjs/cli/named.js.map +1 -1
  16. package/dist/cjs/cli/path.js +7 -2
  17. package/dist/cjs/cli/path.js.map +1 -1
  18. package/dist/cjs/cli/peek.js +7 -2
  19. package/dist/cjs/cli/peek.js.map +1 -1
  20. package/dist/cjs/cli/related.js +55 -6
  21. package/dist/cjs/cli/related.js.map +1 -1
  22. package/dist/cjs/cli/search.js +54 -15
  23. package/dist/cjs/cli/search.js.map +1 -1
  24. package/dist/cjs/cli/shared.d.cts +9 -3
  25. package/dist/cjs/cli/shared.d.ts +9 -3
  26. package/dist/cjs/cli/shared.js +109 -74
  27. package/dist/cjs/cli/shared.js.map +1 -1
  28. package/dist/cjs/cli/sql.js +8 -3
  29. package/dist/cjs/cli/sql.js.map +1 -1
  30. package/dist/cjs/cli/status.js +142 -50
  31. package/dist/cjs/cli/status.js.map +1 -1
  32. package/dist/cjs/cli/types.d.cts +4 -2
  33. package/dist/cjs/cli/types.d.ts +4 -2
  34. package/dist/cjs/cli.js +10 -4
  35. package/dist/cjs/cli.js.map +1 -1
  36. package/dist/cjs/commands/map.js +10 -6
  37. package/dist/cjs/commands/map.js.map +1 -1
  38. package/dist/cjs/commands/peek.js +10 -6
  39. package/dist/cjs/commands/peek.js.map +1 -1
  40. package/dist/cjs/commands/related.d.cts +1 -0
  41. package/dist/cjs/commands/related.d.ts +1 -0
  42. package/dist/cjs/commands/related.js +56 -21
  43. package/dist/cjs/commands/related.js.map +1 -1
  44. package/dist/cjs/commands/scope.js +1 -1
  45. package/dist/cjs/commands/scope.js.map +1 -1
  46. package/dist/cjs/commands/search.js +102 -84
  47. package/dist/cjs/commands/search.js.map +1 -1
  48. package/dist/cjs/config/index.d.cts +1 -1
  49. package/dist/cjs/config/index.d.ts +1 -1
  50. package/dist/cjs/config/index.js.map +1 -1
  51. package/dist/cjs/config/load.d.cts +6 -1
  52. package/dist/cjs/config/load.d.ts +6 -1
  53. package/dist/cjs/config/load.js +38 -1
  54. package/dist/cjs/config/load.js.map +1 -1
  55. package/dist/cjs/config/types.d.cts +2 -1
  56. package/dist/cjs/config/types.d.ts +2 -1
  57. package/dist/cjs/config/types.js +1 -1
  58. package/dist/cjs/config/types.js.map +1 -1
  59. package/dist/cjs/config/validate.js +20 -0
  60. package/dist/cjs/config/validate.js.map +1 -1
  61. package/dist/cjs/embed/query.d.cts +2 -1
  62. package/dist/cjs/embed/query.d.ts +2 -1
  63. package/dist/cjs/embed/query.js +186 -109
  64. package/dist/cjs/embed/query.js.map +1 -1
  65. package/dist/cjs/errors.d.cts +1 -1
  66. package/dist/cjs/errors.d.ts +1 -1
  67. package/dist/cjs/errors.js.map +1 -1
  68. package/dist/cjs/features/embed.js.map +1 -1
  69. package/dist/cjs/graph/traverse.js +11 -6
  70. package/dist/cjs/graph/traverse.js.map +1 -1
  71. package/dist/cjs/index.d.cts +3 -3
  72. package/dist/cjs/index.d.ts +3 -3
  73. package/dist/cjs/index.js +3 -0
  74. package/dist/cjs/index.js.map +1 -1
  75. package/dist/cjs/lib/atomic-write.js +20 -6
  76. package/dist/cjs/lib/atomic-write.js.map +1 -1
  77. package/dist/cjs/lib/serial-query.d.cts +1 -0
  78. package/dist/cjs/lib/serial-query.d.ts +1 -0
  79. package/dist/cjs/lib/serial-query.js +22 -0
  80. package/dist/cjs/lib/serial-query.js.map +1 -0
  81. package/dist/cjs/scan/index.d.cts +5 -0
  82. package/dist/cjs/scan/index.d.ts +5 -0
  83. package/dist/cjs/scan/index.js +12 -4
  84. package/dist/cjs/scan/index.js.map +1 -1
  85. package/dist/cjs/scan/pool.d.cts +5 -0
  86. package/dist/cjs/scan/pool.d.ts +5 -0
  87. package/dist/cjs/scan/pool.js +167 -55
  88. package/dist/cjs/scan/pool.js.map +1 -1
  89. package/dist/cjs/store/builder.d.cts +6 -1
  90. package/dist/cjs/store/builder.d.ts +6 -1
  91. package/dist/cjs/store/builder.js +135 -5
  92. package/dist/cjs/store/builder.js.map +1 -1
  93. package/dist/cjs/store/duckdb/lexical.d.cts +2 -0
  94. package/dist/cjs/store/duckdb/lexical.d.ts +2 -0
  95. package/dist/cjs/store/duckdb/lexical.js +139 -7
  96. package/dist/cjs/store/duckdb/lexical.js.map +1 -1
  97. package/dist/cjs/store/duckdb/open.d.cts +3 -3
  98. package/dist/cjs/store/duckdb/open.d.ts +3 -3
  99. package/dist/cjs/store/duckdb/open.js +53 -41
  100. package/dist/cjs/store/duckdb/open.js.map +1 -1
  101. package/dist/cjs/store/duckdb/reconcile.js +2 -2
  102. package/dist/cjs/store/duckdb/reconcile.js.map +1 -1
  103. package/dist/cjs/store/index.d.cts +23 -4
  104. package/dist/cjs/store/index.d.ts +23 -4
  105. package/dist/cjs/store/index.js +224 -15
  106. package/dist/cjs/store/index.js.map +1 -1
  107. package/dist/cjs/store/open.d.cts +9 -1
  108. package/dist/cjs/store/open.d.ts +9 -1
  109. package/dist/cjs/store/open.js +479 -128
  110. package/dist/cjs/store/open.js.map +1 -1
  111. package/dist/cjs/store/reconcile.js +93 -63
  112. package/dist/cjs/store/reconcile.js.map +1 -1
  113. package/dist/cjs/store/sqlite/open.d.cts +3 -3
  114. package/dist/cjs/store/sqlite/open.d.ts +3 -3
  115. package/dist/cjs/store/sqlite/open.js +44 -36
  116. package/dist/cjs/store/sqlite/open.js.map +1 -1
  117. package/dist/cjs/store/turso/open.d.cts +3 -3
  118. package/dist/cjs/store/turso/open.d.ts +3 -3
  119. package/dist/cjs/store/turso/open.js +83 -66
  120. package/dist/cjs/store/turso/open.js.map +1 -1
  121. package/dist/cjs/store/turso/store.d.cts +3 -1
  122. package/dist/cjs/store/turso/store.d.ts +3 -1
  123. package/dist/cjs/store/turso/store.js +46 -31
  124. package/dist/cjs/store/turso/store.js.map +1 -1
  125. package/dist/cjs/store/types.d.cts +12 -3
  126. package/dist/cjs/store/types.d.ts +12 -3
  127. package/dist/cjs/store/types.js.map +1 -1
  128. package/dist/cjs/watch.js +155 -35
  129. package/dist/cjs/watch.js.map +1 -1
  130. package/dist/esm/cli/build.d.ts +3 -0
  131. package/dist/esm/cli/build.js +18 -0
  132. package/dist/esm/cli/build.js.map +1 -0
  133. package/dist/esm/cli/index.d.ts +7 -6
  134. package/dist/esm/cli/index.js +8 -6
  135. package/dist/esm/cli/index.js.map +1 -1
  136. package/dist/esm/cli/init.js +2 -2
  137. package/dist/esm/cli/init.js.map +1 -1
  138. package/dist/esm/cli/map.js +8 -2
  139. package/dist/esm/cli/map.js.map +1 -1
  140. package/dist/esm/cli/named.js +38 -14
  141. package/dist/esm/cli/named.js.map +1 -1
  142. package/dist/esm/cli/path.js +8 -2
  143. package/dist/esm/cli/path.js.map +1 -1
  144. package/dist/esm/cli/peek.js +8 -2
  145. package/dist/esm/cli/peek.js.map +1 -1
  146. package/dist/esm/cli/related.js +21 -3
  147. package/dist/esm/cli/related.js.map +1 -1
  148. package/dist/esm/cli/search.js +28 -7
  149. package/dist/esm/cli/search.js.map +1 -1
  150. package/dist/esm/cli/shared.d.ts +9 -3
  151. package/dist/esm/cli/shared.js +44 -24
  152. package/dist/esm/cli/shared.js.map +1 -1
  153. package/dist/esm/cli/sql.js +8 -2
  154. package/dist/esm/cli/sql.js.map +1 -1
  155. package/dist/esm/cli/status.js +166 -111
  156. package/dist/esm/cli/status.js.map +1 -1
  157. package/dist/esm/cli/types.d.ts +4 -2
  158. package/dist/esm/cli/types.js.map +1 -1
  159. package/dist/esm/cli.js +9 -4
  160. package/dist/esm/cli.js.map +1 -1
  161. package/dist/esm/commands/map.js +5 -1
  162. package/dist/esm/commands/map.js.map +1 -1
  163. package/dist/esm/commands/peek.js +5 -1
  164. package/dist/esm/commands/peek.js.map +1 -1
  165. package/dist/esm/commands/related.d.ts +1 -0
  166. package/dist/esm/commands/related.js +19 -10
  167. package/dist/esm/commands/related.js.map +1 -1
  168. package/dist/esm/commands/scope.js +1 -1
  169. package/dist/esm/commands/scope.js.map +1 -1
  170. package/dist/esm/commands/search.js +11 -10
  171. package/dist/esm/commands/search.js.map +1 -1
  172. package/dist/esm/config/index.d.ts +1 -1
  173. package/dist/esm/config/index.js.map +1 -1
  174. package/dist/esm/config/load.d.ts +6 -1
  175. package/dist/esm/config/load.js +32 -3
  176. package/dist/esm/config/load.js.map +1 -1
  177. package/dist/esm/config/types.d.ts +2 -1
  178. package/dist/esm/config/types.js +1 -1
  179. package/dist/esm/config/types.js.map +1 -1
  180. package/dist/esm/config/validate.js +20 -0
  181. package/dist/esm/config/validate.js.map +1 -1
  182. package/dist/esm/embed/query.d.ts +2 -1
  183. package/dist/esm/embed/query.js +40 -34
  184. package/dist/esm/embed/query.js.map +1 -1
  185. package/dist/esm/errors.d.ts +1 -1
  186. package/dist/esm/errors.js.map +1 -1
  187. package/dist/esm/features/embed.js.map +1 -1
  188. package/dist/esm/graph/traverse.js +5 -1
  189. package/dist/esm/graph/traverse.js.map +1 -1
  190. package/dist/esm/index.d.ts +3 -3
  191. package/dist/esm/index.js +1 -1
  192. package/dist/esm/index.js.map +1 -1
  193. package/dist/esm/lib/atomic-write.js +14 -6
  194. package/dist/esm/lib/atomic-write.js.map +1 -1
  195. package/dist/esm/lib/serial-query.d.ts +1 -0
  196. package/dist/esm/lib/serial-query.js +13 -0
  197. package/dist/esm/lib/serial-query.js.map +1 -0
  198. package/dist/esm/scan/index.d.ts +5 -0
  199. package/dist/esm/scan/index.js +7 -3
  200. package/dist/esm/scan/index.js.map +1 -1
  201. package/dist/esm/scan/pool.d.ts +5 -0
  202. package/dist/esm/scan/pool.js +41 -16
  203. package/dist/esm/scan/pool.js.map +1 -1
  204. package/dist/esm/store/builder.d.ts +6 -1
  205. package/dist/esm/store/builder.js +19 -0
  206. package/dist/esm/store/builder.js.map +1 -1
  207. package/dist/esm/store/duckdb/lexical.d.ts +2 -0
  208. package/dist/esm/store/duckdb/lexical.js +32 -4
  209. package/dist/esm/store/duckdb/lexical.js.map +1 -1
  210. package/dist/esm/store/duckdb/open.d.ts +3 -3
  211. package/dist/esm/store/duckdb/open.js +13 -6
  212. package/dist/esm/store/duckdb/open.js.map +1 -1
  213. package/dist/esm/store/duckdb/reconcile.js +2 -2
  214. package/dist/esm/store/duckdb/reconcile.js.map +1 -1
  215. package/dist/esm/store/index.d.ts +23 -4
  216. package/dist/esm/store/index.js +80 -15
  217. package/dist/esm/store/index.js.map +1 -1
  218. package/dist/esm/store/open.d.ts +9 -1
  219. package/dist/esm/store/open.js +175 -84
  220. package/dist/esm/store/open.js.map +1 -1
  221. package/dist/esm/store/reconcile.js +12 -0
  222. package/dist/esm/store/reconcile.js.map +1 -1
  223. package/dist/esm/store/sqlite/open.d.ts +3 -3
  224. package/dist/esm/store/sqlite/open.js +9 -6
  225. package/dist/esm/store/sqlite/open.js.map +1 -1
  226. package/dist/esm/store/turso/open.d.ts +3 -3
  227. package/dist/esm/store/turso/open.js +14 -10
  228. package/dist/esm/store/turso/open.js.map +1 -1
  229. package/dist/esm/store/turso/store.d.ts +3 -1
  230. package/dist/esm/store/turso/store.js +5 -1
  231. package/dist/esm/store/turso/store.js.map +1 -1
  232. package/dist/esm/store/types.d.ts +12 -3
  233. package/dist/esm/store/types.js.map +1 -1
  234. package/dist/esm/watch.js +57 -19
  235. package/dist/esm/watch.js.map +1 -1
  236. package/package.json +1 -1
  237. package/schema.json +7 -2
  238. package/skills/sense/SKILL.md +3 -3
  239. package/skills/sense-bases/SKILL.md +1 -2
  240. package/skills/sense-setup/SKILL.md +1 -1
  241. package/skills/sense-setup/references/embeddings.md +1 -1
  242. package/skills/sense-setup/references/store-benchmarks.md +6 -6
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/search.ts"],"sourcesContent":["import { search } from '../commands/search.ts';\nimport { printRows } from '../output/output.ts';\nimport { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, parse, parseK, parseSnippetCharLimit, parseSnippetCountLimit, rowFormatOf, SEARCH_FLAGS, scopeOf, withDb } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst searchCmd: Command = async (ctx) => {\n const usage = `usage: ${ctx.name} ${USAGE.search}`;\n const { values, positionals } = parse(ctx.argv, usage, { ...SEARCH_FLAGS, ...FORMAT, ...CONFIG });\n const [terms] = positionals;\n if (!terms) ctx.usageError(usage);\n const k = parseK(values.k as string | undefined, ctx.usageError);\n const snippetCharLimit = parseSnippetCharLimit(values['snippet-char-limit'] as string | undefined, ctx.usageError);\n const snippetCountLimit = parseSnippetCountLimit(values['snippet-count-limit'] as string | undefined, ctx.usageError);\n const format = rowFormatOf(values);\n await withDb(ctx, values.config as string | undefined, async (store, cfg) => printRows(await search(store, cfg, terms, { k, snippetCharLimit, snippetCountLimit, ...scopeOf(values) }), format));\n};\nexport default searchCmd;\n"],"names":["search","printRows","USAGE","CONFIG","FORMAT","parse","parseK","parseSnippetCharLimit","parseSnippetCountLimit","rowFormatOf","SEARCH_FLAGS","scopeOf","withDb","searchCmd","ctx","usage","name","values","positionals","argv","terms","usageError","k","snippetCharLimit","snippetCountLimit","format","config","store","cfg"],"mappings":"AAAA,SAASA,MAAM,QAAQ,wBAAwB;AAC/C,SAASC,SAAS,QAAQ,sBAAsB;AAChD,SAASC,KAAK,QAAQ,aAAa;AACnC,SAASC,MAAM,EAAEC,MAAM,EAAEC,KAAK,EAAEC,MAAM,EAAEC,qBAAqB,EAAEC,sBAAsB,EAAEC,WAAW,EAAEC,YAAY,EAAEC,OAAO,EAAEC,MAAM,QAAQ,cAAc;AAGvJ,MAAMC,YAAqB,OAAOC;IAChC,MAAMC,QAAQ,CAAC,OAAO,EAAED,IAAIE,IAAI,CAAC,CAAC,EAAEd,MAAMF,MAAM,EAAE;IAClD,MAAM,EAAEiB,MAAM,EAAEC,WAAW,EAAE,GAAGb,MAAMS,IAAIK,IAAI,EAAEJ,OAAO;QAAE,GAAGL,YAAY;QAAE,GAAGN,MAAM;QAAE,GAAGD,MAAM;IAAC;IAC/F,MAAM,CAACiB,MAAM,GAAGF;IAChB,IAAI,CAACE,OAAON,IAAIO,UAAU,CAACN;IAC3B,MAAMO,IAAIhB,OAAOW,OAAOK,CAAC,EAAwBR,IAAIO,UAAU;IAC/D,MAAME,mBAAmBhB,sBAAsBU,MAAM,CAAC,qBAAqB,EAAwBH,IAAIO,UAAU;IACjH,MAAMG,oBAAoBhB,uBAAuBS,MAAM,CAAC,sBAAsB,EAAwBH,IAAIO,UAAU;IACpH,MAAMI,SAAShB,YAAYQ;IAC3B,MAAML,OAAOE,KAAKG,OAAOS,MAAM,EAAwB,OAAOC,OAAOC,MAAQ3B,UAAU,MAAMD,OAAO2B,OAAOC,KAAKR,OAAO;YAAEE;YAAGC;YAAkBC;YAAmB,GAAGb,QAAQM,OAAO;QAAC,IAAIQ;AAC1L;AACA,eAAeZ,UAAU"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/search.ts"],"sourcesContent":["import { scopedPaths } from '../commands/scope.ts';\nimport { search } from '../commands/search.ts';\nimport { resolveSearch } from '../config/index.ts';\nimport { printRows } from '../output/output.ts';\nimport { type BuildRequirement, prepareDocumentEmbeddings } from '../store/open.ts';\nimport { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, NO_BUILD, parse, parseK, parseSnippetCharLimit, parseSnippetCountLimit, rowFormatOf, SEARCH_FLAGS, scopeOf, withDb } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst searchCmd: Command = async (ctx) => {\n const usage = `usage: ${ctx.name} ${USAGE.search}`;\n const { values, positionals } = parse(ctx.argv, usage, { ...SEARCH_FLAGS, ...NO_BUILD, ...FORMAT, ...CONFIG });\n const [terms] = positionals;\n if (!terms) ctx.usageError(usage);\n const k = parseK(values.k as string | undefined, ctx.usageError);\n const snippetCharLimit = parseSnippetCharLimit(values['snippet-char-limit'] as string | undefined, ctx.usageError);\n const snippetCountLimit = parseSnippetCountLimit(values['snippet-count-limit'] as string | undefined, ctx.usageError);\n const format = rowFormatOf(values);\n const overrides = { k, snippetCharLimit, snippetCountLimit, ...scopeOf(values) };\n const noBuild = values['no-build'] === true;\n await withDb(\n ctx,\n values.config as string | undefined,\n {\n noBuild,\n requirements: (cfg) => {\n const signals = resolveSearch(cfg, overrides).signals;\n const requirements = new Set<BuildRequirement>(['core']);\n if (signals.words !== undefined) requirements.add('lexical');\n return requirements;\n },\n },\n async (store, cfg, build) => {\n if (build && resolveSearch(cfg, overrides).signals.vectors !== undefined) {\n await prepareDocumentEmbeddings(store, cfg, await scopedPaths(store, cfg, overrides));\n }\n printRows(await search(store, cfg, terms, overrides), format);\n }\n );\n};\nexport default searchCmd;\n"],"names":["scopedPaths","search","resolveSearch","printRows","prepareDocumentEmbeddings","USAGE","CONFIG","FORMAT","NO_BUILD","parse","parseK","parseSnippetCharLimit","parseSnippetCountLimit","rowFormatOf","SEARCH_FLAGS","scopeOf","withDb","searchCmd","ctx","usage","name","values","positionals","argv","terms","usageError","k","snippetCharLimit","snippetCountLimit","format","overrides","noBuild","config","requirements","cfg","signals","Set","words","undefined","add","store","build","vectors"],"mappings":"AAAA,SAASA,WAAW,QAAQ,uBAAuB;AACnD,SAASC,MAAM,QAAQ,wBAAwB;AAC/C,SAASC,aAAa,QAAQ,qBAAqB;AACnD,SAASC,SAAS,QAAQ,sBAAsB;AAChD,SAAgCC,yBAAyB,QAAQ,mBAAmB;AACpF,SAASC,KAAK,QAAQ,aAAa;AACnC,SAASC,MAAM,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,KAAK,EAAEC,MAAM,EAAEC,qBAAqB,EAAEC,sBAAsB,EAAEC,WAAW,EAAEC,YAAY,EAAEC,OAAO,EAAEC,MAAM,QAAQ,cAAc;AAGjK,MAAMC,YAAqB,OAAOC;IAChC,MAAMC,QAAQ,CAAC,OAAO,EAAED,IAAIE,IAAI,CAAC,CAAC,EAAEf,MAAMJ,MAAM,EAAE;IAClD,MAAM,EAAEoB,MAAM,EAAEC,WAAW,EAAE,GAAGb,MAAMS,IAAIK,IAAI,EAAEJ,OAAO;QAAE,GAAGL,YAAY;QAAE,GAAGN,QAAQ;QAAE,GAAGD,MAAM;QAAE,GAAGD,MAAM;IAAC;IAC5G,MAAM,CAACkB,MAAM,GAAGF;IAChB,IAAI,CAACE,OAAON,IAAIO,UAAU,CAACN;IAC3B,MAAMO,IAAIhB,OAAOW,OAAOK,CAAC,EAAwBR,IAAIO,UAAU;IAC/D,MAAME,mBAAmBhB,sBAAsBU,MAAM,CAAC,qBAAqB,EAAwBH,IAAIO,UAAU;IACjH,MAAMG,oBAAoBhB,uBAAuBS,MAAM,CAAC,sBAAsB,EAAwBH,IAAIO,UAAU;IACpH,MAAMI,SAAShB,YAAYQ;IAC3B,MAAMS,YAAY;QAAEJ;QAAGC;QAAkBC;QAAmB,GAAGb,QAAQM,OAAO;IAAC;IAC/E,MAAMU,UAAUV,MAAM,CAAC,WAAW,KAAK;IACvC,MAAML,OACJE,KACAG,OAAOW,MAAM,EACb;QACED;QACAE,cAAc,CAACC;YACb,MAAMC,UAAUjC,cAAcgC,KAAKJ,WAAWK,OAAO;YACrD,MAAMF,eAAe,IAAIG,IAAsB;gBAAC;aAAO;YACvD,IAAID,QAAQE,KAAK,KAAKC,WAAWL,aAAaM,GAAG,CAAC;YAClD,OAAON;QACT;IACF,GACA,OAAOO,OAAON,KAAKO;QACjB,IAAIA,SAASvC,cAAcgC,KAAKJ,WAAWK,OAAO,CAACO,OAAO,KAAKJ,WAAW;YACxE,MAAMlC,0BAA0BoC,OAAON,KAAK,MAAMlC,YAAYwC,OAAON,KAAKJ;QAC5E;QACA3B,UAAU,MAAMF,OAAOuC,OAAON,KAAKV,OAAOM,YAAYD;IACxD;AAEJ;AACA,eAAeZ,UAAU"}
@@ -1,10 +1,11 @@
1
1
  import type { ParseArgsOptionsConfig } from 'node:util';
2
2
  import type { ResolvedConfig, SearchOverrides } from '../config/index.js';
3
3
  import type { RowFormat } from '../output/output.js';
4
- import type { OpenResult } from '../store/index.js';
4
+ import type { BuildRequirement, OpenResult } from '../store/open.js';
5
5
  import type { Ctx } from './types.js';
6
6
  export declare const FORMAT: ParseArgsOptionsConfig;
7
7
  export declare const CONFIG: ParseArgsOptionsConfig;
8
+ export declare const NO_BUILD: ParseArgsOptionsConfig;
8
9
  export declare const SCOPE: ParseArgsOptionsConfig;
9
10
  export declare const SEARCH_FLAGS: ParseArgsOptionsConfig;
10
11
  type Values = Record<string, string | boolean | string[] | undefined>;
@@ -19,6 +20,11 @@ export declare function parseK(k: string | undefined, usageError: (message: stri
19
20
  export declare function parseSnippetCharLimit(value: string | undefined, usageError: (message: string) => never): number | undefined;
20
21
  export declare function parseSnippetCountLimit(value: string | undefined, usageError: (message: string) => never): number | undefined;
21
22
  export declare function printWarnings(warnings: string[]): void;
22
- export declare function withDb(ctx: Ctx, configPath: string | undefined, fn: (store: OpenResult['store'], cfg: ResolvedConfig) => void | Promise<void>): Promise<void>;
23
- export declare function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: RowFormat, label: string, preset?: string): Promise<void>;
23
+ export interface DbOpenOptions {
24
+ noBuild: boolean;
25
+ requirements: ReadonlySet<BuildRequirement> | ((cfg: ResolvedConfig) => ReadonlySet<BuildRequirement>);
26
+ }
27
+ export declare function withResolvedDb(cfg: ResolvedConfig, options: DbOpenOptions, fn: (store: OpenResult['store'], cfg: ResolvedConfig, build: boolean) => void | Promise<void>): Promise<void>;
28
+ export declare function withDb(ctx: Ctx, configPath: string | undefined, options: DbOpenOptions, fn: (store: OpenResult['store'], cfg: ResolvedConfig, build: boolean) => void | Promise<void>): Promise<void>;
29
+ export declare function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: RowFormat, label: string, noBuild: boolean, preset?: string): Promise<void>;
24
30
  export {};
@@ -3,7 +3,7 @@ import { resolvePreset } from '../config/index.js';
3
3
  import { columnHint } from '../output/column-hint.js';
4
4
  import { printRowStream } from '../output/output.js';
5
5
  import { searchError } from '../output/search-error.js';
6
- import { openStore } from '../store/index.js';
6
+ import { openStoreFor } from '../store/index.js';
7
7
  // Spreadable option fragments -- one flag name keeps one meaning across every command's table.
8
8
  export const FORMAT = {
9
9
  format: {
@@ -16,6 +16,12 @@ export const CONFIG = {
16
16
  type: 'string'
17
17
  }
18
18
  };
19
+ export const NO_BUILD = {
20
+ 'no-build': {
21
+ type: 'boolean',
22
+ default: false
23
+ }
24
+ };
19
25
  // The scope vocabulary every scoped command shares: named preset, ad hoc include/exclude
20
26
  // globs, a where SQL condition. search adds k on top.
21
27
  export const SCOPE = {
@@ -143,16 +149,27 @@ export function parseSnippetCountLimit(value, usageError) {
143
149
  export function printWarnings(warnings) {
144
150
  for (const w of warnings)console.warn(w);
145
151
  }
146
- export async function withDb(ctx, configPath, fn) {
147
- const cfg = ctx.resolveConfig(configPath);
148
- const { store, warnings } = await openStore(cfg);
152
+ export async function withResolvedDb(cfg, options, fn) {
153
+ const requirements = typeof options.requirements === 'function' ? options.requirements(cfg) : options.requirements;
154
+ const build = !options.noBuild && cfg.build !== false;
155
+ const { store, warnings } = await openStoreFor(cfg, {
156
+ build,
157
+ requirements
158
+ });
149
159
  printWarnings(warnings);
150
160
  try {
151
- await fn(store, cfg);
161
+ await fn(store, cfg, build);
152
162
  } finally{
153
163
  await store.close();
154
164
  }
155
165
  }
166
+ export async function withDb(ctx, configPath, options, fn) {
167
+ const cfg = ctx.resolveConfig(configPath, {
168
+ writeMigration: !options.noBuild,
169
+ query: true
170
+ });
171
+ return withResolvedDb(cfg, options, fn);
172
+ }
156
173
  // `--preset` on SQL binds a temp `scope` table rather than transparently filtering: temp views shadowing the base tables can't cover `content`, since FTS5 MATCH treats the table name as a hidden column.
157
174
  // A flag that silently scoped three tables of four would look scoped and not be.
158
175
  async function bindScope(store, cfg, preset) {
@@ -163,7 +180,7 @@ async function bindScope(store, cfg, preset) {
163
180
  await insert.run(name);
164
181
  }
165
182
  // An unbound `?` silently binds NULL, so mismatched param counts fail loudly instead.
166
- export async function runSql(cfg, sql, params, format, label, preset) {
183
+ export async function runSql(cfg, sql, params, format, label, noBuild, preset) {
167
184
  var _sql_match;
168
185
  const placeholderCount = ((_sql_match = sql.match(/\?/g)) !== null && _sql_match !== void 0 ? _sql_match : []).length;
169
186
  if (params.length !== placeholderCount) {
@@ -177,22 +194,25 @@ export async function runSql(cfg, sql, params, format, label, preset) {
177
194
  console.error(`add: JOIN scope ON scope."path" = <table>."path"`);
178
195
  process.exit(2);
179
196
  }
180
- const { store, warnings } = await openStore(cfg);
181
- printWarnings(warnings);
182
- if (preset !== undefined) await bindScope(store, cfg, preset);
183
- // Streamed, not collected: `sql`'s result size is the caller's business, not ours. columns() reads the statement's own metadata, so a 0-row csv gets a header too.
184
- // A mid-stream SQLite error (e.g. SQLITE_BUSY outlasting busy_timeout) may leave partial output; the nonzero exit code is the failure signal, not a completeness guarantee.
185
- try {
186
- const statement = await store.raw.prepare(sql);
187
- const columns = statement.columns().map((c)=>c.name);
188
- await printRowStream(statement.iterate(...params), format, columns);
189
- } catch (err) {
190
- const hinted = columnHint(await store.docs.columns(), err); // columns read while the store is still open
191
- await store.close();
192
- // A saved query or ad-hoc SQL can carry `content MATCH ?` too, so the same FTS5 punctuation trap applies to its bound parameters.
193
- // SQL without MATCH gets its error verbatim; search advice on a plain typo would mislead.
194
- if (/\bMATCH\b/i.test(sql)) throw searchError(hinted, params.join(' '));
195
- throw hinted;
196
- }
197
- await store.close();
197
+ await withResolvedDb(cfg, {
198
+ noBuild,
199
+ requirements: new Set([
200
+ 'core'
201
+ ])
202
+ }, async (store)=>{
203
+ if (preset !== undefined) await bindScope(store, cfg, preset);
204
+ // Streamed, not collected: `sql`'s result size is the caller's business, not ours. columns() reads the statement's own metadata, so a 0-row csv gets a header too.
205
+ // A mid-stream SQLite error (e.g. SQLITE_BUSY outlasting busy_timeout) may leave partial output; the nonzero exit code is the failure signal, not a completeness guarantee.
206
+ try {
207
+ const statement = await store.raw.prepare(sql);
208
+ const columns = statement.columns().map((c)=>c.name);
209
+ await printRowStream(statement.iterate(...params), format, columns);
210
+ } catch (err) {
211
+ const hinted = columnHint(await store.docs.columns(), err); // columns read while the store is still open
212
+ // A saved query or ad-hoc SQL can carry `content MATCH ?` too, so the same FTS5 punctuation trap applies to its bound parameters.
213
+ // SQL without MATCH gets its error verbatim; search advice on a plain typo would mislead.
214
+ if (/\bMATCH\b/i.test(sql)) throw searchError(hinted, params.join(' '));
215
+ throw hinted;
216
+ }
217
+ });
198
218
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/shared.ts"],"sourcesContent":["import type { ParseArgsOptionsConfig } from 'node:util';\nimport { parseArgs } from 'node:util';\nimport type { ResolvedConfig, SearchOverrides } from '../config/index.ts';\nimport { resolvePreset } from '../config/index.ts';\nimport { columnHint } from '../output/column-hint.ts';\nimport type { Row, RowFormat } from '../output/output.ts';\nimport { printRowStream } from '../output/output.ts';\nimport { searchError } from '../output/search-error.ts';\nimport type { OpenResult } from '../store/index.ts';\nimport { openStore } from '../store/index.ts';\nimport type { Store } from '../store/types.ts';\nimport type { Ctx } from './types.ts';\n\n// Spreadable option fragments -- one flag name keeps one meaning across every command's table.\nexport const FORMAT: ParseArgsOptionsConfig = { format: { type: 'string', default: 'table' } };\nexport const CONFIG: ParseArgsOptionsConfig = { config: { type: 'string' } };\n// The scope vocabulary every scoped command shares: named preset, ad hoc include/exclude\n// globs, a where SQL condition. search adds k on top.\nexport const SCOPE: ParseArgsOptionsConfig = {\n where: { type: 'string' },\n preset: { type: 'string' },\n include: { type: 'string', multiple: true },\n exclude: { type: 'string', multiple: true },\n // Widening, which no other flag can express: --include and --exclude each override their\n // own side of the preset, so neither can drop an exclusion the preset declares.\n 'no-exclude': { type: 'boolean', default: false },\n};\nexport const SEARCH_FLAGS: ParseArgsOptionsConfig = { ...SCOPE, k: { type: 'string' }, 'snippet-char-limit': { type: 'string' }, 'snippet-count-limit': { type: 'string' } };\n\ntype Values = Record<string, string | boolean | string[] | undefined>;\n\n// The SCOPE fragment's parsed values as the overrides every scoped command passes down.\n// One place to read them: a new scope field is added to the fragment and here, not per-command.\nexport function scopeOf(values: Values): SearchOverrides {\n return {\n preset: values.preset as string | undefined,\n include: values.include as string[] | undefined,\n exclude: values.exclude as string[] | undefined,\n where: values.where as string | undefined,\n noExclude: values['no-exclude'] === true,\n };\n}\n\n// parseArgs is strict about flag names; this applies the same strictness to the value.\n// An unrecognised --format is a usage error, not a silent fallback to `table`.\nfunction pickFormat<T extends string>(values: Values, allowed: readonly T[]): T {\n const format = String(values.format);\n if ((allowed as readonly string[]).includes(format)) return format as T;\n console.error(`unknown --format \"${format}\"; expected ${allowed.join(', ')}`);\n process.exit(2);\n}\n\nexport function formatOf(values: Values): 'table' | 'json' {\n return pickFormat(values, ['table', 'json'] as const);\n}\n\n// csv is a row set rendered as rows; map, peek, status, and path render structures instead,\n// and take formatOf.\nexport function rowFormatOf(values: Values): RowFormat {\n return pickFormat(values, ['table', 'json', 'csv'] as const);\n}\n\n// Per-command parseArgs: strict (a foreign flag exits 2), and every table gets --help for free.\nexport function parse(argv: string[], usage: string, options: ParseArgsOptionsConfig): { values: Values; positionals: string[] } {\n let values: Values;\n let positionals: string[];\n try {\n ({ values, positionals } = parseArgs({\n args: argv,\n options: { ...options, help: { type: 'boolean', default: false, short: 'h' } },\n strict: true,\n allowPositionals: true,\n }));\n } catch (err) {\n console.error((err as Error).message);\n console.error(usage);\n process.exit(2);\n }\n if (values.help) {\n console.log(usage);\n process.exit(0);\n }\n return { values, positionals };\n}\n\n// --k must be a positive integer: SQLite reads a bound LIMIT of -1 as \"unlimited\" and 0 as \"nothing\", and parseInt would silently truncate \"5.9\".\n// All three are caller mistakes worth a usage error, matching the config-level SavedSearch validation.\nexport function parseK(k: string | undefined, usageError: (message: string) => never): number | undefined {\n if (k === undefined) return undefined;\n const parsed = Number(k);\n if (!Number.isInteger(parsed) || parsed <= 0) usageError(`--k expects a positive integer, got \"${k}\"`);\n return parsed;\n}\n\n// Same positive-integer rule as --k, beside it since both flags come from SEARCH_FLAGS.\nexport function parseSnippetCharLimit(value: string | undefined, usageError: (message: string) => never): number | undefined {\n if (value === undefined) return undefined;\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) usageError(`--snippet-char-limit expects a positive integer, got \"${value}\"`);\n return parsed;\n}\n\nexport function parseSnippetCountLimit(value: string | undefined, usageError: (message: string) => never): number | undefined {\n if (value === undefined) return undefined;\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) usageError(`--snippet-count-limit expects a positive integer, got \"${value}\"`);\n return parsed;\n}\n\n// Shared open-query-close envelope for commands that touch the tree.\n\nexport function printWarnings(warnings: string[]): void {\n for (const w of warnings) console.warn(w);\n}\n\nexport async function withDb(ctx: Ctx, configPath: string | undefined, fn: (store: OpenResult['store'], cfg: ResolvedConfig) => void | Promise<void>): Promise<void> {\n const cfg = ctx.resolveConfig(configPath);\n const { store, warnings } = await openStore(cfg);\n printWarnings(warnings);\n try {\n await fn(store, cfg);\n } finally {\n await store.close();\n }\n}\n\n// `--preset` on SQL binds a temp `scope` table rather than transparently filtering: temp views shadowing the base tables can't cover `content`, since FTS5 MATCH treats the table name as a hidden column.\n// A flag that silently scoped three tables of four would look scoped and not be.\nasync function bindScope(store: Store, cfg: ResolvedConfig, preset: string): Promise<void> {\n const { name } = resolvePreset(cfg, preset); // unknown names throw, listing what is declared\n await store.exec('DROP TABLE IF EXISTS temp.scope');\n await store.exec('CREATE TEMP TABLE scope (\"path\" TEXT PRIMARY KEY)');\n const insert = await store.prepare('INSERT INTO temp.scope (\"path\") SELECT \"path\" FROM preset_files WHERE preset = ?');\n await insert.run(name);\n}\n\n// An unbound `?` silently binds NULL, so mismatched param counts fail loudly instead.\nexport async function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: RowFormat, label: string, preset?: string): Promise<void> {\n const placeholderCount = (sql.match(/\\?/g) ?? []).length;\n if (params.length !== placeholderCount) {\n console.error(`${label} expects ${placeholderCount} parameter(s), got ${params.length}`);\n process.exit(2);\n }\n // Naming a preset and never joining it would return the whole index while reading as scoped,\n // which is the one hazard of binding rather than applying. Refuse instead.\n if (preset !== undefined && !/\\bscope\\b/i.test(sql)) {\n console.error(`--preset binds a temporary \"scope\" table of the preset's paths, and ${label} never joins it, so the preset would have no effect`);\n console.error(`add: JOIN scope ON scope.\"path\" = <table>.\"path\"`);\n process.exit(2);\n }\n const { store, warnings } = await openStore(cfg);\n printWarnings(warnings);\n if (preset !== undefined) await bindScope(store, cfg, preset);\n // Streamed, not collected: `sql`'s result size is the caller's business, not ours. columns() reads the statement's own metadata, so a 0-row csv gets a header too.\n // A mid-stream SQLite error (e.g. SQLITE_BUSY outlasting busy_timeout) may leave partial output; the nonzero exit code is the failure signal, not a completeness guarantee.\n try {\n const statement = await store.raw.prepare(sql);\n const columns = statement.columns().map((c) => c.name);\n await printRowStream(statement.iterate(...params) as AsyncIterable<Row>, format, columns);\n } catch (err) {\n const hinted = columnHint(await store.docs.columns(), err as Error); // columns read while the store is still open\n await store.close();\n // A saved query or ad-hoc SQL can carry `content MATCH ?` too, so the same FTS5 punctuation trap applies to its bound parameters.\n // SQL without MATCH gets its error verbatim; search advice on a plain typo would mislead.\n if (/\\bMATCH\\b/i.test(sql)) throw searchError(hinted, params.join(' '));\n throw hinted;\n }\n await store.close();\n}\n"],"names":["parseArgs","resolvePreset","columnHint","printRowStream","searchError","openStore","FORMAT","format","type","default","CONFIG","config","SCOPE","where","preset","include","multiple","exclude","SEARCH_FLAGS","k","scopeOf","values","noExclude","pickFormat","allowed","String","includes","console","error","join","process","exit","formatOf","rowFormatOf","parse","argv","usage","options","positionals","args","help","short","strict","allowPositionals","err","message","log","parseK","usageError","undefined","parsed","Number","isInteger","parseSnippetCharLimit","value","parseSnippetCountLimit","printWarnings","warnings","w","warn","withDb","ctx","configPath","fn","cfg","resolveConfig","store","close","bindScope","name","exec","insert","prepare","run","runSql","sql","params","label","placeholderCount","match","length","test","statement","raw","columns","map","c","iterate","hinted","docs"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/shared.ts"],"sourcesContent":["import type { ParseArgsOptionsConfig } from 'node:util';\nimport { parseArgs } from 'node:util';\nimport type { ResolvedConfig, SearchOverrides } from '../config/index.ts';\nimport { resolvePreset } from '../config/index.ts';\nimport { columnHint } from '../output/column-hint.ts';\nimport type { Row, RowFormat } from '../output/output.ts';\nimport { printRowStream } from '../output/output.ts';\nimport { searchError } from '../output/search-error.ts';\nimport { openStoreFor } from '../store/index.ts';\nimport type { BuildRequirement, OpenResult } from '../store/open.ts';\nimport type { Store } from '../store/types.ts';\nimport type { Ctx } from './types.ts';\n\n// Spreadable option fragments -- one flag name keeps one meaning across every command's table.\nexport const FORMAT: ParseArgsOptionsConfig = { format: { type: 'string', default: 'table' } };\nexport const CONFIG: ParseArgsOptionsConfig = { config: { type: 'string' } };\nexport const NO_BUILD: ParseArgsOptionsConfig = { 'no-build': { type: 'boolean', default: false } };\n// The scope vocabulary every scoped command shares: named preset, ad hoc include/exclude\n// globs, a where SQL condition. search adds k on top.\nexport const SCOPE: ParseArgsOptionsConfig = {\n where: { type: 'string' },\n preset: { type: 'string' },\n include: { type: 'string', multiple: true },\n exclude: { type: 'string', multiple: true },\n // Widening, which no other flag can express: --include and --exclude each override their\n // own side of the preset, so neither can drop an exclusion the preset declares.\n 'no-exclude': { type: 'boolean', default: false },\n};\nexport const SEARCH_FLAGS: ParseArgsOptionsConfig = { ...SCOPE, k: { type: 'string' }, 'snippet-char-limit': { type: 'string' }, 'snippet-count-limit': { type: 'string' } };\n\ntype Values = Record<string, string | boolean | string[] | undefined>;\n\n// The SCOPE fragment's parsed values as the overrides every scoped command passes down.\n// One place to read them: a new scope field is added to the fragment and here, not per-command.\nexport function scopeOf(values: Values): SearchOverrides {\n return {\n preset: values.preset as string | undefined,\n include: values.include as string[] | undefined,\n exclude: values.exclude as string[] | undefined,\n where: values.where as string | undefined,\n noExclude: values['no-exclude'] === true,\n };\n}\n\n// parseArgs is strict about flag names; this applies the same strictness to the value.\n// An unrecognised --format is a usage error, not a silent fallback to `table`.\nfunction pickFormat<T extends string>(values: Values, allowed: readonly T[]): T {\n const format = String(values.format);\n if ((allowed as readonly string[]).includes(format)) return format as T;\n console.error(`unknown --format \"${format}\"; expected ${allowed.join(', ')}`);\n process.exit(2);\n}\n\nexport function formatOf(values: Values): 'table' | 'json' {\n return pickFormat(values, ['table', 'json'] as const);\n}\n\n// csv is a row set rendered as rows; map, peek, status, and path render structures instead,\n// and take formatOf.\nexport function rowFormatOf(values: Values): RowFormat {\n return pickFormat(values, ['table', 'json', 'csv'] as const);\n}\n\n// Per-command parseArgs: strict (a foreign flag exits 2), and every table gets --help for free.\nexport function parse(argv: string[], usage: string, options: ParseArgsOptionsConfig): { values: Values; positionals: string[] } {\n let values: Values;\n let positionals: string[];\n try {\n ({ values, positionals } = parseArgs({\n args: argv,\n options: { ...options, help: { type: 'boolean', default: false, short: 'h' } },\n strict: true,\n allowPositionals: true,\n }));\n } catch (err) {\n console.error((err as Error).message);\n console.error(usage);\n process.exit(2);\n }\n if (values.help) {\n console.log(usage);\n process.exit(0);\n }\n return { values, positionals };\n}\n\n// --k must be a positive integer: SQLite reads a bound LIMIT of -1 as \"unlimited\" and 0 as \"nothing\", and parseInt would silently truncate \"5.9\".\n// All three are caller mistakes worth a usage error, matching the config-level SavedSearch validation.\nexport function parseK(k: string | undefined, usageError: (message: string) => never): number | undefined {\n if (k === undefined) return undefined;\n const parsed = Number(k);\n if (!Number.isInteger(parsed) || parsed <= 0) usageError(`--k expects a positive integer, got \"${k}\"`);\n return parsed;\n}\n\n// Same positive-integer rule as --k, beside it since both flags come from SEARCH_FLAGS.\nexport function parseSnippetCharLimit(value: string | undefined, usageError: (message: string) => never): number | undefined {\n if (value === undefined) return undefined;\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) usageError(`--snippet-char-limit expects a positive integer, got \"${value}\"`);\n return parsed;\n}\n\nexport function parseSnippetCountLimit(value: string | undefined, usageError: (message: string) => never): number | undefined {\n if (value === undefined) return undefined;\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) usageError(`--snippet-count-limit expects a positive integer, got \"${value}\"`);\n return parsed;\n}\n\n// Shared open-query-close envelope for commands that touch the tree.\n\nexport function printWarnings(warnings: string[]): void {\n for (const w of warnings) console.warn(w);\n}\n\nexport interface DbOpenOptions {\n noBuild: boolean;\n requirements: ReadonlySet<BuildRequirement> | ((cfg: ResolvedConfig) => ReadonlySet<BuildRequirement>);\n}\n\nexport async function withResolvedDb(cfg: ResolvedConfig, options: DbOpenOptions, fn: (store: OpenResult['store'], cfg: ResolvedConfig, build: boolean) => void | Promise<void>): Promise<void> {\n const requirements = typeof options.requirements === 'function' ? options.requirements(cfg) : options.requirements;\n const build = !options.noBuild && cfg.build !== false;\n const { store, warnings } = await openStoreFor(cfg, {\n build,\n requirements,\n });\n printWarnings(warnings);\n try {\n await fn(store, cfg, build);\n } finally {\n await store.close();\n }\n}\n\nexport async function withDb(ctx: Ctx, configPath: string | undefined, options: DbOpenOptions, fn: (store: OpenResult['store'], cfg: ResolvedConfig, build: boolean) => void | Promise<void>): Promise<void> {\n const cfg = ctx.resolveConfig(configPath, { writeMigration: !options.noBuild, query: true });\n return withResolvedDb(cfg, options, fn);\n}\n\n// `--preset` on SQL binds a temp `scope` table rather than transparently filtering: temp views shadowing the base tables can't cover `content`, since FTS5 MATCH treats the table name as a hidden column.\n// A flag that silently scoped three tables of four would look scoped and not be.\nasync function bindScope(store: Store, cfg: ResolvedConfig, preset: string): Promise<void> {\n const { name } = resolvePreset(cfg, preset); // unknown names throw, listing what is declared\n await store.exec('DROP TABLE IF EXISTS temp.scope');\n await store.exec('CREATE TEMP TABLE scope (\"path\" TEXT PRIMARY KEY)');\n const insert = await store.prepare('INSERT INTO temp.scope (\"path\") SELECT \"path\" FROM preset_files WHERE preset = ?');\n await insert.run(name);\n}\n\n// An unbound `?` silently binds NULL, so mismatched param counts fail loudly instead.\nexport async function runSql(cfg: ResolvedConfig, sql: string, params: string[], format: RowFormat, label: string, noBuild: boolean, preset?: string): Promise<void> {\n const placeholderCount = (sql.match(/\\?/g) ?? []).length;\n if (params.length !== placeholderCount) {\n console.error(`${label} expects ${placeholderCount} parameter(s), got ${params.length}`);\n process.exit(2);\n }\n // Naming a preset and never joining it would return the whole index while reading as scoped,\n // which is the one hazard of binding rather than applying. Refuse instead.\n if (preset !== undefined && !/\\bscope\\b/i.test(sql)) {\n console.error(`--preset binds a temporary \"scope\" table of the preset's paths, and ${label} never joins it, so the preset would have no effect`);\n console.error(`add: JOIN scope ON scope.\"path\" = <table>.\"path\"`);\n process.exit(2);\n }\n await withResolvedDb(cfg, { noBuild, requirements: new Set<BuildRequirement>(['core']) }, async (store) => {\n if (preset !== undefined) await bindScope(store, cfg, preset);\n // Streamed, not collected: `sql`'s result size is the caller's business, not ours. columns() reads the statement's own metadata, so a 0-row csv gets a header too.\n // A mid-stream SQLite error (e.g. SQLITE_BUSY outlasting busy_timeout) may leave partial output; the nonzero exit code is the failure signal, not a completeness guarantee.\n try {\n const statement = await store.raw.prepare(sql);\n const columns = statement.columns().map((c) => c.name);\n await printRowStream(statement.iterate(...params) as AsyncIterable<Row>, format, columns);\n } catch (err) {\n const hinted = columnHint(await store.docs.columns(), err as Error); // columns read while the store is still open\n // A saved query or ad-hoc SQL can carry `content MATCH ?` too, so the same FTS5 punctuation trap applies to its bound parameters.\n // SQL without MATCH gets its error verbatim; search advice on a plain typo would mislead.\n if (/\\bMATCH\\b/i.test(sql)) throw searchError(hinted, params.join(' '));\n throw hinted;\n }\n });\n}\n"],"names":["parseArgs","resolvePreset","columnHint","printRowStream","searchError","openStoreFor","FORMAT","format","type","default","CONFIG","config","NO_BUILD","SCOPE","where","preset","include","multiple","exclude","SEARCH_FLAGS","k","scopeOf","values","noExclude","pickFormat","allowed","String","includes","console","error","join","process","exit","formatOf","rowFormatOf","parse","argv","usage","options","positionals","args","help","short","strict","allowPositionals","err","message","log","parseK","usageError","undefined","parsed","Number","isInteger","parseSnippetCharLimit","value","parseSnippetCountLimit","printWarnings","warnings","w","warn","withResolvedDb","cfg","fn","requirements","build","noBuild","store","close","withDb","ctx","configPath","resolveConfig","writeMigration","query","bindScope","name","exec","insert","prepare","run","runSql","sql","params","label","placeholderCount","match","length","test","Set","statement","raw","columns","map","c","iterate","hinted","docs"],"mappings":"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"}
@@ -1,8 +1,9 @@
1
1
  import { USAGE } from './index.js';
2
- import { CONFIG, FORMAT, parse, rowFormatOf, runSql } from './shared.js';
2
+ import { CONFIG, FORMAT, NO_BUILD, parse, rowFormatOf, runSql } from './shared.js';
3
3
  const sqlCmd = async (ctx)=>{
4
4
  const usage = `usage: ${ctx.name} ${USAGE.sql}`;
5
5
  const { values, positionals } = parse(ctx.argv, usage, {
6
+ ...NO_BUILD,
6
7
  ...FORMAT,
7
8
  ...CONFIG,
8
9
  preset: {
@@ -12,6 +13,11 @@ const sqlCmd = async (ctx)=>{
12
13
  const [sql, ...params] = positionals;
13
14
  if (!sql) ctx.usageError(usage);
14
15
  const format = rowFormatOf(values);
15
- await runSql(ctx.resolveConfig(values.config), sql, params, format, 'ad-hoc statement', values.preset);
16
+ const noBuild = values['no-build'] === true;
17
+ const cfg = ctx.resolveConfig(values.config, {
18
+ writeMigration: !noBuild,
19
+ query: true
20
+ });
21
+ await runSql(cfg, sql, params, format, 'ad-hoc statement', noBuild, values.preset);
16
22
  };
17
23
  export default sqlCmd;
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/sql.ts"],"sourcesContent":["import { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, parse, rowFormatOf, runSql } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst sqlCmd: Command = async (ctx) => {\n const usage = `usage: ${ctx.name} ${USAGE.sql}`;\n const { values, positionals } = parse(ctx.argv, usage, { ...FORMAT, ...CONFIG, preset: { type: 'string' } });\n const [sql, ...params] = positionals;\n if (!sql) ctx.usageError(usage);\n const format = rowFormatOf(values);\n await runSql(ctx.resolveConfig(values.config as string | undefined), sql, params, format, 'ad-hoc statement', values.preset as string | undefined);\n};\nexport default sqlCmd;\n"],"names":["USAGE","CONFIG","FORMAT","parse","rowFormatOf","runSql","sqlCmd","ctx","usage","name","sql","values","positionals","argv","preset","type","params","usageError","format","resolveConfig","config"],"mappings":"AAAA,SAASA,KAAK,QAAQ,aAAa;AACnC,SAASC,MAAM,EAAEC,MAAM,EAAEC,KAAK,EAAEC,WAAW,EAAEC,MAAM,QAAQ,cAAc;AAGzE,MAAMC,SAAkB,OAAOC;IAC7B,MAAMC,QAAQ,CAAC,OAAO,EAAED,IAAIE,IAAI,CAAC,CAAC,EAAET,MAAMU,GAAG,EAAE;IAC/C,MAAM,EAAEC,MAAM,EAAEC,WAAW,EAAE,GAAGT,MAAMI,IAAIM,IAAI,EAAEL,OAAO;QAAE,GAAGN,MAAM;QAAE,GAAGD,MAAM;QAAEa,QAAQ;YAAEC,MAAM;QAAS;IAAE;IAC1G,MAAM,CAACL,KAAK,GAAGM,OAAO,GAAGJ;IACzB,IAAI,CAACF,KAAKH,IAAIU,UAAU,CAACT;IACzB,MAAMU,SAASd,YAAYO;IAC3B,MAAMN,OAAOE,IAAIY,aAAa,CAACR,OAAOS,MAAM,GAAyBV,KAAKM,QAAQE,QAAQ,oBAAoBP,OAAOG,MAAM;AAC7H;AACA,eAAeR,OAAO"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/sql.ts"],"sourcesContent":["import { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, NO_BUILD, parse, rowFormatOf, runSql } from './shared.ts';\nimport type { Command } from './types.ts';\n\nconst sqlCmd: Command = async (ctx) => {\n const usage = `usage: ${ctx.name} ${USAGE.sql}`;\n const { values, positionals } = parse(ctx.argv, usage, { ...NO_BUILD, ...FORMAT, ...CONFIG, preset: { type: 'string' } });\n const [sql, ...params] = positionals;\n if (!sql) ctx.usageError(usage);\n const format = rowFormatOf(values);\n const noBuild = values['no-build'] === true;\n const cfg = ctx.resolveConfig(values.config as string | undefined, { writeMigration: !noBuild, query: true });\n await runSql(cfg, sql, params, format, 'ad-hoc statement', noBuild, values.preset as string | undefined);\n};\nexport default sqlCmd;\n"],"names":["USAGE","CONFIG","FORMAT","NO_BUILD","parse","rowFormatOf","runSql","sqlCmd","ctx","usage","name","sql","values","positionals","argv","preset","type","params","usageError","format","noBuild","cfg","resolveConfig","config","writeMigration","query"],"mappings":"AAAA,SAASA,KAAK,QAAQ,aAAa;AACnC,SAASC,MAAM,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,KAAK,EAAEC,WAAW,EAAEC,MAAM,QAAQ,cAAc;AAGnF,MAAMC,SAAkB,OAAOC;IAC7B,MAAMC,QAAQ,CAAC,OAAO,EAAED,IAAIE,IAAI,CAAC,CAAC,EAAEV,MAAMW,GAAG,EAAE;IAC/C,MAAM,EAAEC,MAAM,EAAEC,WAAW,EAAE,GAAGT,MAAMI,IAAIM,IAAI,EAAEL,OAAO;QAAE,GAAGN,QAAQ;QAAE,GAAGD,MAAM;QAAE,GAAGD,MAAM;QAAEc,QAAQ;YAAEC,MAAM;QAAS;IAAE;IACvH,MAAM,CAACL,KAAK,GAAGM,OAAO,GAAGJ;IACzB,IAAI,CAACF,KAAKH,IAAIU,UAAU,CAACT;IACzB,MAAMU,SAASd,YAAYO;IAC3B,MAAMQ,UAAUR,MAAM,CAAC,WAAW,KAAK;IACvC,MAAMS,MAAMb,IAAIc,aAAa,CAACV,OAAOW,MAAM,EAAwB;QAAEC,gBAAgB,CAACJ;QAASK,OAAO;IAAK;IAC3G,MAAMnB,OAAOe,KAAKV,KAAKM,QAAQE,QAAQ,oBAAoBC,SAASR,OAAOG,MAAM;AACnF;AACA,eAAeR,OAAO"}
@@ -1,18 +1,19 @@
1
- import { dirname } from 'node:path';
1
+ import { dirname, join } from 'node:path';
2
2
  import { presetCoverage } from '../commands/status.js';
3
- import { embedConfig, featureStates, SUPPORTED_CONFIG_VERSION } from '../config/index.js';
3
+ import { embedConfig, featureStates, STATE_DIR, SUPPORTED_CONFIG_VERSION } from '../config/index.js';
4
4
  import { languageDistribution } from '../embed/distribution.js';
5
5
  import { probeReachable } from '../embed/http.js';
6
6
  import { isDownloadable, MODEL_FILENAMES, modelDir, modelPresent, readLanguages } from '../embed/store.js';
7
+ import { SenseError } from '../errors.js';
7
8
  import { featuresLine, presetsLines, stringifyJson } from '../output/output.js';
8
- import { docCount, getMeta, openStore } from '../store/index.js';
9
+ import { docCount, getMeta, lexicalReadiness, openStore, storeFilename } from '../store/index.js';
9
10
  import { readWatchClaim } from '../watch-claim.js';
10
11
  import { USAGE } from './index.js';
11
12
  import { CONFIG, FORMAT, formatOf, parse, printWarnings } from './shared.js';
12
13
  // status names what you cannot read off the config file: locations sense chose, values it derived, state it stored. Config content itself is not echoed, since duplicating its globs here would create two places that disagree after an edit.
13
14
  // The exception is the embed block's url and key, whose effect is remote and otherwise invisible.
14
- // Vectors are computed on the first semantic query, not at reconcile, so a tree can have a semantic-on preset with nothing embedded yet.
15
- // Reported here because a fast reconcile on such a tree otherwise reads as "the feature isn't on".
15
+ // A failed or interrupted vector preparation can leave core and lexical state usable. Status is
16
+ // observational, so it reports that pending capability instead of repairing it.
16
17
  async function vectorState(store) {
17
18
  try {
18
19
  const stmt = await store.prepare('SELECT COUNT(vector) AS embedded, COUNT(*) - COUNT(vector) AS pending FROM embeddings');
@@ -77,119 +78,173 @@ function languagesInfo(e) {
77
78
  };
78
79
  }
79
80
  const status = async (ctx)=>{
80
- var _ref, _ref1, _cfg_configDir, _process_env_e_key, _cfg_migratedFrom, _cfg_unknownKeys, _cfg_rootDir, _cfg_rootDir1, _cfg_configDir1, _cfg_queries;
81
81
  const { values } = parse(ctx.argv, `usage: ${ctx.name} ${USAGE.status}`, {
82
82
  ...FORMAT,
83
83
  ...CONFIG
84
84
  });
85
85
  const format = formatOf(values);
86
- const cfg = ctx.resolveConfig(values.config);
87
- const { store, dbPath, warnings } = await openStore(cfg);
88
- printWarnings(warnings);
89
- const features = featureStates(cfg);
90
- const e = embedConfig(cfg);
91
- const hasModel = e ? modelPresent(cfg) : false;
92
- const reachable = e ? await embedReachable(e) : null;
93
- const vectors = e ? await vectorState(store) : null;
94
- const presets = await presetCoverage(store, cfg);
95
- const { languages: declaredLanguages, state: languagesState, source: languagesSource } = e ? languagesInfo(e) : {
96
- languages: null,
97
- state: null,
98
- source: null
99
- };
100
- const detectedLanguages = (_ref = await languageDistribution(store)) !== null && _ref !== void 0 ? _ref : null;
101
- // Written by the store's open() on every open, so it is this cache's true version on either
102
- // store (sqlite 18, duckdb 2); a version mismatch already triggered a rebuild before this read.
103
- const cacheSchema = await getMeta(store, 'schema_version');
104
- // Each store owns what it reports and how it is worded (Store.engineStatus); this command
105
- // prints entries generically, without branching on any store's name.
106
- const engine = await store.engineStatus();
107
- const watcher = readWatchClaim((_ref1 = (_cfg_configDir = cfg.configDir) !== null && _cfg_configDir !== void 0 ? _cfg_configDir : cfg.rootDir) !== null && _ref1 !== void 0 ? _ref1 : cfg.baseDir);
108
- // The env var holds the token; only its name and whether it is set are ever reported.
109
- const keyEnv = (e === null || e === void 0 ? void 0 : e.key) ? {
110
- name: e.key,
111
- set: ((_process_env_e_key = process.env[e.key]) !== null && _process_env_e_key !== void 0 ? _process_env_e_key : '') !== ''
112
- } : null;
113
- const result = {
114
- config: cfg.configPath,
115
- configVersion: SUPPORTED_CONFIG_VERSION,
116
- migratedFrom: (_cfg_migratedFrom = cfg.migratedFrom) !== null && _cfg_migratedFrom !== void 0 ? _cfg_migratedFrom : null,
117
- unknownConfigKeys: (_cfg_unknownKeys = cfg.unknownKeys) !== null && _cfg_unknownKeys !== void 0 ? _cfg_unknownKeys : null,
118
- tree: (_cfg_rootDir = cfg.rootDir) !== null && _cfg_rootDir !== void 0 ? _cfg_rootDir : cfg.baseDir,
119
- treeRoot: (_cfg_rootDir1 = cfg.rootDir) !== null && _cfg_rootDir1 !== void 0 ? _cfg_rootDir1 : cfg.baseDir,
120
- configDir: (_cfg_configDir1 = cfg.configDir) !== null && _cfg_configDir1 !== void 0 ? _cfg_configDir1 : cfg.baseDir,
121
- cache: dirname(dbPath),
122
- db: dbPath,
123
- cacheSchema,
124
- docs: await docCount(store),
125
- unparseableFrontmatter: await parseErrorCount(store),
126
- features: features.on,
127
- featuresOff: features.off,
128
- embed: e ? {
129
- provider: e.provider,
130
- model: e.model,
131
- dir: e.provider === 'static' ? modelDir(e.model) : null,
132
- url: e.url ? redactUrl(e.url) : null,
133
- reachable,
134
- keyEnv,
135
- downloaded: hasModel,
136
- languages: declaredLanguages,
137
- languagesState,
138
- detectedLanguages,
139
- ...vectors !== null && vectors !== void 0 ? vectors : {}
140
- } : null,
141
- presets,
142
- queries: Object.keys((_cfg_queries = cfg.queries) !== null && _cfg_queries !== void 0 ? _cfg_queries : {}).length,
143
- watcherPid: watcher ? String(watcher.pid) : null,
144
- watcherHeartbeatSecondsAgo: watcher ? Math.round((Date.now() - watcher.heartbeatMs) / 1000) : null,
145
- engine
146
- };
147
- if (format === 'json') {
148
- console.log(stringifyJson(result, 2));
149
- } else {
150
- const migrated = cfg.migratedFrom !== undefined ? `, migrated from v${cfg.migratedFrom} on this run` : '';
151
- console.log(`config: ${result.config} (v${SUPPORTED_CONFIG_VERSION}${migrated})`);
152
- // A load-time stderr warning has scrolled away by the time anyone looks here.
153
- if (cfg.unknownKeys) console.log(` unknown keys, ignored: ${cfg.unknownKeys.join(', ')}`);
154
- console.log(`tree root: ${result.treeRoot}`);
155
- console.log(`configDir: ${result.configDir}`);
156
- console.log(`cache: ${result.cache} (schema ${result.cacheSchema}; delete this directory to reset)`);
157
- console.log(`docs: ${result.docs}${result.unparseableFrontmatter > 0 ? ` (${result.unparseableFrontmatter} with unparseable frontmatter: WHERE _parse_error IS NOT NULL)` : ''}`);
158
- console.log('');
159
- console.log(featuresLine(features));
160
- // One authoritative block, off states included: an absent model reads as a degraded search,
161
- // not as an empty corpus.
162
- if (!e) console.log('embed: off (no preset asks for vectors)');
163
- else {
164
- console.log(`embed: ${e.provider} ${e.model}`);
165
- if (e.provider === 'static') console.log(` model: ${modelDir(e.model)} (${hasModel ? 'present' : `missing, ${isDownloadable(e.model) ? `fetches automatically at first search, or run \`${ctx.name} download\` to prefetch` : `no ${MODEL_FILENAMES} in that directory`}`})`);
166
- if (declaredLanguages && languagesSource === 'config') console.log(` languages: ${declaredLanguages.join(', ')} (declared in embed.languages)`);
167
- else if (declaredLanguages && languagesSource === 'card') console.log(` languages: ${declaredLanguages.join(', ')} (declared by the model card)`);
168
- else if (languagesState === 'none') console.log(' languages: none declared by the model card');
169
- else if (languagesState === 'unresolved') console.log(` languages: unresolved (model card unreachable; run \`${ctx.name} download\`)`);
170
- // Cohere defaults to api.cohere.com with no url in the config; show it anyway so the
171
- // reachability probe below has something to name.
172
- if (e.url || reachable !== null) {
173
- const shown = e.url ? redactUrl(e.url) : 'https://api.cohere.com (default)';
174
- console.log(` url: ${shown}${reachable === null ? '' : reachable ? ' (reachable)' : ' (unreachable)'}`);
175
- }
176
- if (keyEnv) console.log(` key: env ${keyEnv.name} (${keyEnv.set ? 'set' : 'NOT SET'})`);
177
- if (!hasModel) console.log(' vectors: off until the model is present; search runs on words and links');
178
- else if (vectors) console.log(` vectors: ${vectors.embedded} embedded, ${vectors.pending} pending (embedded on the first semantic search)`);
179
- if (detectedLanguages) {
180
- const total = Object.values(detectedLanguages).reduce((a, b)=>a + b, 0);
181
- const breakdown = Object.entries(detectedLanguages).sort((a, b)=>b[1] - a[1]).map(([code, n])=>`${code} ${Math.round(n / total * 100)}%`).join(', ');
182
- console.log(` detected: ${breakdown} (${total} chunks classified)`);
86
+ const cfg = ctx.resolveConfig(values.config, {
87
+ writeMigration: false
88
+ });
89
+ const lexical = await lexicalReadiness(cfg);
90
+ let opened;
91
+ try {
92
+ opened = await openStore(cfg, {
93
+ build: false
94
+ });
95
+ } catch (err) {
96
+ var _ref, _cfg_configDir, _cfg_migratedFrom, _cfg_unknownKeys, _cfg_rootDir, _cfg_rootDir1;
97
+ if (!(err instanceof SenseError) || err.code !== 'INDEX_NOT_READY') throw err;
98
+ const configDir = (_ref = (_cfg_configDir = cfg.configDir) !== null && _cfg_configDir !== void 0 ? _cfg_configDir : cfg.rootDir) !== null && _ref !== void 0 ? _ref : cfg.baseDir;
99
+ const dbPath = join(configDir, STATE_DIR, storeFilename(cfg));
100
+ const watcher = readWatchClaim(configDir);
101
+ const result = {
102
+ config: cfg.configPath,
103
+ configVersion: SUPPORTED_CONFIG_VERSION,
104
+ migratedFrom: (_cfg_migratedFrom = cfg.migratedFrom) !== null && _cfg_migratedFrom !== void 0 ? _cfg_migratedFrom : null,
105
+ unknownConfigKeys: (_cfg_unknownKeys = cfg.unknownKeys) !== null && _cfg_unknownKeys !== void 0 ? _cfg_unknownKeys : null,
106
+ tree: (_cfg_rootDir = cfg.rootDir) !== null && _cfg_rootDir !== void 0 ? _cfg_rootDir : cfg.baseDir,
107
+ treeRoot: (_cfg_rootDir1 = cfg.rootDir) !== null && _cfg_rootDir1 !== void 0 ? _cfg_rootDir1 : cfg.baseDir,
108
+ configDir,
109
+ cache: dirname(dbPath),
110
+ db: dbPath,
111
+ indexReady: false,
112
+ indexError: err.message,
113
+ lexicalReady: lexical.ready,
114
+ lexicalError: lexical.error,
115
+ watcherPid: watcher ? String(watcher.pid) : null,
116
+ watcherHeartbeatSecondsAgo: watcher ? Math.round((Date.now() - watcher.heartbeatMs) / 1000) : null
117
+ };
118
+ if (format === 'json') {
119
+ console.log(stringifyJson(result, 2));
120
+ } else {
121
+ const migrated = cfg.migratedFrom !== undefined ? `, migration from v${cfg.migratedFrom} pending` : '';
122
+ console.log(`config: ${result.config} (v${SUPPORTED_CONFIG_VERSION}${migrated})`);
123
+ console.log(`tree root: ${result.treeRoot}`);
124
+ console.log(`configDir: ${result.configDir}`);
125
+ console.log(`cache: ${result.cache}`);
126
+ console.log(`index: not ready (${result.indexError})`);
127
+ console.log(`lexical: ${result.lexicalReady ? 'ready' : `not ready (${result.lexicalError})`}`);
128
+ const pid = result.watcherPid ? `pid ${result.watcherPid}, ` : '';
129
+ console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: none' : `watcher: ${pid}last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);
130
+ }
131
+ return;
132
+ }
133
+ const { store, dbPath, warnings } = opened;
134
+ try {
135
+ var _ref1, _ref2, _cfg_configDir1, _process_env_e_key, _cfg_migratedFrom1, _cfg_unknownKeys1, _cfg_rootDir2, _cfg_rootDir3, _cfg_configDir2, _cfg_queries;
136
+ printWarnings(warnings);
137
+ const features = featureStates(cfg);
138
+ const e = embedConfig(cfg);
139
+ const hasModel = e ? modelPresent(cfg) : false;
140
+ const reachable = e ? await embedReachable(e) : null;
141
+ const vectors = e ? await vectorState(store) : null;
142
+ const presets = await presetCoverage(store, cfg);
143
+ const { languages: declaredLanguages, state: languagesState, source: languagesSource } = e ? languagesInfo(e) : {
144
+ languages: null,
145
+ state: null,
146
+ source: null
147
+ };
148
+ const detectedLanguages = (_ref1 = await languageDistribution(store)) !== null && _ref1 !== void 0 ? _ref1 : null;
149
+ // This is the compatible cache's stored version. Observational open refuses a mismatch rather
150
+ // than rebuilding it before this read.
151
+ const cacheSchema = await getMeta(store, 'schema_version');
152
+ // Each store owns what it reports and how it is worded (Store.engineStatus); this command
153
+ // prints entries generically, without branching on any store's name.
154
+ const engine = await store.engineStatus();
155
+ const watcher = readWatchClaim((_ref2 = (_cfg_configDir1 = cfg.configDir) !== null && _cfg_configDir1 !== void 0 ? _cfg_configDir1 : cfg.rootDir) !== null && _ref2 !== void 0 ? _ref2 : cfg.baseDir);
156
+ // The env var holds the token; only its name and whether it is set are ever reported.
157
+ const keyEnv = (e === null || e === void 0 ? void 0 : e.key) ? {
158
+ name: e.key,
159
+ set: ((_process_env_e_key = process.env[e.key]) !== null && _process_env_e_key !== void 0 ? _process_env_e_key : '') !== ''
160
+ } : null;
161
+ const result = {
162
+ config: cfg.configPath,
163
+ configVersion: SUPPORTED_CONFIG_VERSION,
164
+ migratedFrom: (_cfg_migratedFrom1 = cfg.migratedFrom) !== null && _cfg_migratedFrom1 !== void 0 ? _cfg_migratedFrom1 : null,
165
+ unknownConfigKeys: (_cfg_unknownKeys1 = cfg.unknownKeys) !== null && _cfg_unknownKeys1 !== void 0 ? _cfg_unknownKeys1 : null,
166
+ tree: (_cfg_rootDir2 = cfg.rootDir) !== null && _cfg_rootDir2 !== void 0 ? _cfg_rootDir2 : cfg.baseDir,
167
+ treeRoot: (_cfg_rootDir3 = cfg.rootDir) !== null && _cfg_rootDir3 !== void 0 ? _cfg_rootDir3 : cfg.baseDir,
168
+ configDir: (_cfg_configDir2 = cfg.configDir) !== null && _cfg_configDir2 !== void 0 ? _cfg_configDir2 : cfg.baseDir,
169
+ cache: dirname(dbPath),
170
+ db: dbPath,
171
+ indexReady: true,
172
+ indexError: null,
173
+ lexicalReady: lexical.ready,
174
+ lexicalError: lexical.error,
175
+ cacheSchema,
176
+ docs: await docCount(store),
177
+ unparseableFrontmatter: await parseErrorCount(store),
178
+ features: features.on,
179
+ featuresOff: features.off,
180
+ embed: e ? {
181
+ provider: e.provider,
182
+ model: e.model,
183
+ dir: e.provider === 'static' ? modelDir(e.model) : null,
184
+ url: e.url ? redactUrl(e.url) : null,
185
+ reachable,
186
+ keyEnv,
187
+ downloaded: hasModel,
188
+ languages: declaredLanguages,
189
+ languagesState,
190
+ detectedLanguages,
191
+ ...vectors !== null && vectors !== void 0 ? vectors : {}
192
+ } : null,
193
+ presets,
194
+ queries: Object.keys((_cfg_queries = cfg.queries) !== null && _cfg_queries !== void 0 ? _cfg_queries : {}).length,
195
+ watcherPid: watcher ? String(watcher.pid) : null,
196
+ watcherHeartbeatSecondsAgo: watcher ? Math.round((Date.now() - watcher.heartbeatMs) / 1000) : null,
197
+ engine
198
+ };
199
+ if (format === 'json') {
200
+ console.log(stringifyJson(result, 2));
201
+ } else {
202
+ const migrated = cfg.migratedFrom !== undefined ? `, migration from v${cfg.migratedFrom} applied in memory` : '';
203
+ console.log(`config: ${result.config} (v${SUPPORTED_CONFIG_VERSION}${migrated})`);
204
+ // A load-time stderr warning has scrolled away by the time anyone looks here.
205
+ if (cfg.unknownKeys) console.log(` unknown keys, ignored: ${cfg.unknownKeys.join(', ')}`);
206
+ console.log(`tree root: ${result.treeRoot}`);
207
+ console.log(`configDir: ${result.configDir}`);
208
+ console.log(`cache: ${result.cache} (schema ${result.cacheSchema}; ${ctx.name} build --force to recreate)`);
209
+ console.log(`lexical: ${result.lexicalReady ? 'ready' : `not ready (${result.lexicalError})`}`);
210
+ console.log(`docs: ${result.docs}${result.unparseableFrontmatter > 0 ? ` (${result.unparseableFrontmatter} with unparseable frontmatter: WHERE _parse_error IS NOT NULL)` : ''}`);
211
+ console.log('');
212
+ console.log(featuresLine(features));
213
+ // One authoritative block, off states included: an absent model reads as a degraded search,
214
+ // not as an empty corpus.
215
+ if (!e) console.log('embed: off (no preset asks for vectors)');
216
+ else {
217
+ console.log(`embed: ${e.provider} ${e.model}`);
218
+ if (e.provider === 'static') console.log(` model: ${modelDir(e.model)} (${hasModel ? 'present' : `missing, ${isDownloadable(e.model) ? `fetches when build, watch, or a vector query needs it; run \`${ctx.name} download\` to prefetch` : `no ${MODEL_FILENAMES} in that directory`}`})`);
219
+ if (declaredLanguages && languagesSource === 'config') console.log(` languages: ${declaredLanguages.join(', ')} (declared in embed.languages)`);
220
+ else if (declaredLanguages && languagesSource === 'card') console.log(` languages: ${declaredLanguages.join(', ')} (declared by the model card)`);
221
+ else if (languagesState === 'none') console.log(' languages: none declared by the model card');
222
+ else if (languagesState === 'unresolved') console.log(` languages: unresolved (model card unreachable; run \`${ctx.name} download\`)`);
223
+ // Cohere defaults to api.cohere.com with no url in the config; show it anyway so the
224
+ // reachability probe below has something to name.
225
+ if (e.url || reachable !== null) {
226
+ const shown = e.url ? redactUrl(e.url) : 'https://api.cohere.com (default)';
227
+ console.log(` url: ${shown}${reachable === null ? '' : reachable ? ' (reachable)' : ' (unreachable)'}`);
228
+ }
229
+ if (keyEnv) console.log(` key: env ${keyEnv.name} (${keyEnv.set ? 'set' : 'NOT SET'})`);
230
+ if (!hasModel) console.log(' vectors: unavailable until the model is present; semantic queries fail, while lexical-only presets remain usable');
231
+ else if (vectors) console.log(` vectors: ${vectors.embedded} embedded, ${vectors.pending} pending${vectors.pending > 0 ? ` (run \`${ctx.name} build\` to prepare all configured vectors)` : ''}`);
232
+ if (detectedLanguages) {
233
+ const total = Object.values(detectedLanguages).reduce((a, b)=>a + b, 0);
234
+ const breakdown = Object.entries(detectedLanguages).sort((a, b)=>b[1] - a[1]).map(([code, n])=>`${code} ${Math.round(n / total * 100)}%`).join(', ');
235
+ console.log(` detected: ${breakdown} (${total} chunks classified)`);
236
+ }
183
237
  }
238
+ console.log('');
239
+ for (const line of presetsLines(presets))console.log(line);
240
+ console.log('');
241
+ console.log(`queries: ${result.queries} saved (${ctx.name} --list)`);
242
+ const pid = result.watcherPid ? `pid ${result.watcherPid}, ` : '';
243
+ console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: none' : `watcher: ${pid}last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);
244
+ for (const [key, value] of Object.entries(result.engine))console.log(`${`${store.name}:`.padEnd(10)}${key} ${value}`);
184
245
  }
185
- console.log('');
186
- for (const line of presetsLines(presets))console.log(line);
187
- console.log('');
188
- console.log(`queries: ${result.queries} saved (${ctx.name} --list)`);
189
- const pid = result.watcherPid ? `pid ${result.watcherPid}, ` : '';
190
- console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: none' : `watcher: ${pid}last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);
191
- for (const [key, value] of Object.entries(result.engine))console.log(`${`${store.name}:`.padEnd(10)}${key} ${value}`);
246
+ } finally{
247
+ await store.close();
192
248
  }
193
- await store.close();
194
249
  };
195
250
  export default status;