sensemaking 0.18.2 → 0.18.3

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 (179) hide show
  1. package/dist/cjs/cli/status.js +32 -31
  2. package/dist/cjs/cli/status.js.map +1 -1
  3. package/dist/cjs/commands/map.js +50 -67
  4. package/dist/cjs/commands/map.js.map +1 -1
  5. package/dist/cjs/config/access.d.cts +2 -2
  6. package/dist/cjs/config/access.d.ts +2 -2
  7. package/dist/cjs/config/access.js.map +1 -1
  8. package/dist/cjs/config/index.d.cts +1 -1
  9. package/dist/cjs/config/index.d.ts +1 -1
  10. package/dist/cjs/config/index.js.map +1 -1
  11. package/dist/cjs/config/load.js +3 -2
  12. package/dist/cjs/config/load.js.map +1 -1
  13. package/dist/cjs/config/types.d.cts +2 -1
  14. package/dist/cjs/config/types.d.ts +2 -1
  15. package/dist/cjs/config/types.js.map +1 -1
  16. package/dist/cjs/config/validate.js +3 -0
  17. package/dist/cjs/config/validate.js.map +1 -1
  18. package/dist/cjs/embed/identity.js +3 -2
  19. package/dist/cjs/embed/identity.js.map +1 -1
  20. package/dist/cjs/embed/store.js +3 -3
  21. package/dist/cjs/embed/store.js.map +1 -1
  22. package/dist/cjs/index.d.cts +2 -2
  23. package/dist/cjs/index.d.ts +2 -2
  24. package/dist/cjs/index.js.map +1 -1
  25. package/dist/cjs/lib/atomic-write.d.cts +1 -0
  26. package/dist/cjs/lib/atomic-write.d.ts +1 -0
  27. package/dist/cjs/lib/atomic-write.js +26 -0
  28. package/dist/cjs/lib/atomic-write.js.map +1 -0
  29. package/dist/cjs/store/duckdb/batch.js +3 -2
  30. package/dist/cjs/store/duckdb/batch.js.map +1 -1
  31. package/dist/cjs/store/duckdb/connection.js +12 -0
  32. package/dist/cjs/store/duckdb/connection.js.map +1 -1
  33. package/dist/cjs/store/duckdb/fieldStats.d.cts +2 -0
  34. package/dist/cjs/store/duckdb/fieldStats.d.ts +2 -0
  35. package/dist/cjs/store/duckdb/fieldStats.js +219 -0
  36. package/dist/cjs/store/duckdb/fieldStats.js.map +1 -0
  37. package/dist/cjs/store/duckdb/lexical.js +3 -2
  38. package/dist/cjs/store/duckdb/lexical.js.map +1 -1
  39. package/dist/cjs/store/duckdb/native.d.cts +0 -1
  40. package/dist/cjs/store/duckdb/native.d.ts +0 -1
  41. package/dist/cjs/store/duckdb/native.js +7 -336
  42. package/dist/cjs/store/duckdb/native.js.map +1 -1
  43. package/dist/cjs/store/duckdb/sql-functions.js +1 -1
  44. package/dist/cjs/store/duckdb/sql-functions.js.map +1 -1
  45. package/dist/cjs/store/duckdb/store.js +16 -1
  46. package/dist/cjs/store/duckdb/store.js.map +1 -1
  47. package/dist/cjs/store/duckdb/vectors.js +5 -17
  48. package/dist/cjs/store/duckdb/vectors.js.map +1 -1
  49. package/dist/cjs/store/index.js +6 -0
  50. package/dist/cjs/store/index.js.map +1 -1
  51. package/dist/cjs/store/native.d.cts +7 -0
  52. package/dist/cjs/store/native.d.ts +7 -0
  53. package/dist/cjs/store/native.js +350 -0
  54. package/dist/cjs/store/native.js.map +1 -0
  55. package/dist/cjs/store/sqlite/fieldStats.d.cts +2 -0
  56. package/dist/cjs/store/sqlite/fieldStats.d.ts +2 -0
  57. package/dist/cjs/store/sqlite/fieldStats.js +201 -0
  58. package/dist/cjs/store/sqlite/fieldStats.js.map +1 -0
  59. package/dist/cjs/store/sqlite/open.js +82 -29
  60. package/dist/cjs/store/sqlite/open.js.map +1 -1
  61. package/dist/cjs/store/sqlite/store.js +32 -4
  62. package/dist/cjs/store/sqlite/store.js.map +1 -1
  63. package/dist/cjs/store/sqlite/vectors.d.cts +0 -5
  64. package/dist/cjs/store/sqlite/vectors.d.ts +0 -5
  65. package/dist/cjs/store/sqlite/vectors.js +5 -71
  66. package/dist/cjs/store/sqlite/vectors.js.map +1 -1
  67. package/dist/cjs/store/turso/connection.d.cts +3 -0
  68. package/dist/cjs/store/turso/connection.d.ts +3 -0
  69. package/dist/cjs/store/turso/connection.js +529 -0
  70. package/dist/cjs/store/turso/connection.js.map +1 -0
  71. package/dist/cjs/store/turso/fieldStats.d.cts +2 -0
  72. package/dist/cjs/store/turso/fieldStats.d.ts +2 -0
  73. package/dist/cjs/store/turso/fieldStats.js +201 -0
  74. package/dist/cjs/store/turso/fieldStats.js.map +1 -0
  75. package/dist/cjs/store/turso/native.d.cts +2 -0
  76. package/dist/cjs/store/turso/native.d.ts +2 -0
  77. package/dist/cjs/store/turso/native.js +31 -0
  78. package/dist/cjs/store/turso/native.js.map +1 -0
  79. package/dist/cjs/store/turso/open.d.cts +12 -0
  80. package/dist/cjs/store/turso/open.d.ts +12 -0
  81. package/dist/cjs/store/turso/open.js +500 -0
  82. package/dist/cjs/store/turso/open.js.map +1 -0
  83. package/dist/cjs/store/turso/reconcile.d.cts +6 -0
  84. package/dist/cjs/store/turso/reconcile.d.ts +6 -0
  85. package/dist/cjs/store/turso/reconcile.js +793 -0
  86. package/dist/cjs/store/turso/reconcile.js.map +1 -0
  87. package/dist/cjs/store/turso/store.d.cts +5 -0
  88. package/dist/cjs/store/turso/store.d.ts +5 -0
  89. package/dist/cjs/store/turso/store.js +609 -0
  90. package/dist/cjs/store/turso/store.js.map +1 -0
  91. package/dist/cjs/store/types.d.cts +9 -1
  92. package/dist/cjs/store/types.d.ts +9 -1
  93. package/dist/cjs/store/types.js +0 -7
  94. package/dist/cjs/store/types.js.map +1 -1
  95. package/dist/cjs/store/vectors.d.cts +9 -0
  96. package/dist/cjs/store/vectors.d.ts +9 -0
  97. package/dist/cjs/store/vectors.js +215 -0
  98. package/dist/cjs/store/vectors.js.map +1 -0
  99. package/dist/esm/cli/status.js +5 -7
  100. package/dist/esm/cli/status.js.map +1 -1
  101. package/dist/esm/commands/map.js +7 -19
  102. package/dist/esm/commands/map.js.map +1 -1
  103. package/dist/esm/config/access.d.ts +2 -2
  104. package/dist/esm/config/access.js.map +1 -1
  105. package/dist/esm/config/index.d.ts +1 -1
  106. package/dist/esm/config/index.js.map +1 -1
  107. package/dist/esm/config/load.js +4 -3
  108. package/dist/esm/config/load.js.map +1 -1
  109. package/dist/esm/config/types.d.ts +2 -1
  110. package/dist/esm/config/types.js.map +1 -1
  111. package/dist/esm/config/validate.js +3 -0
  112. package/dist/esm/config/validate.js.map +1 -1
  113. package/dist/esm/embed/identity.js +4 -3
  114. package/dist/esm/embed/identity.js.map +1 -1
  115. package/dist/esm/embed/store.js +3 -3
  116. package/dist/esm/embed/store.js.map +1 -1
  117. package/dist/esm/index.d.ts +2 -2
  118. package/dist/esm/index.js.map +1 -1
  119. package/dist/esm/lib/atomic-write.d.ts +1 -0
  120. package/dist/esm/lib/atomic-write.js +17 -0
  121. package/dist/esm/lib/atomic-write.js.map +1 -0
  122. package/dist/esm/store/duckdb/batch.js +3 -2
  123. package/dist/esm/store/duckdb/batch.js.map +1 -1
  124. package/dist/esm/store/duckdb/connection.js +12 -0
  125. package/dist/esm/store/duckdb/connection.js.map +1 -1
  126. package/dist/esm/store/duckdb/fieldStats.d.ts +2 -0
  127. package/dist/esm/store/duckdb/fieldStats.js +39 -0
  128. package/dist/esm/store/duckdb/fieldStats.js.map +1 -0
  129. package/dist/esm/store/duckdb/lexical.js +3 -2
  130. package/dist/esm/store/duckdb/lexical.js.map +1 -1
  131. package/dist/esm/store/duckdb/native.d.ts +0 -1
  132. package/dist/esm/store/duckdb/native.js +7 -84
  133. package/dist/esm/store/duckdb/native.js.map +1 -1
  134. package/dist/esm/store/duckdb/sql-functions.js +1 -1
  135. package/dist/esm/store/duckdb/sql-functions.js.map +1 -1
  136. package/dist/esm/store/duckdb/store.js +8 -5
  137. package/dist/esm/store/duckdb/store.js.map +1 -1
  138. package/dist/esm/store/duckdb/vectors.js +2 -12
  139. package/dist/esm/store/duckdb/vectors.js.map +1 -1
  140. package/dist/esm/store/index.js +6 -0
  141. package/dist/esm/store/index.js.map +1 -1
  142. package/dist/esm/store/native.d.ts +7 -0
  143. package/dist/esm/store/native.js +83 -0
  144. package/dist/esm/store/native.js.map +1 -0
  145. package/dist/esm/store/sqlite/fieldStats.d.ts +2 -0
  146. package/dist/esm/store/sqlite/fieldStats.js +25 -0
  147. package/dist/esm/store/sqlite/fieldStats.js.map +1 -0
  148. package/dist/esm/store/sqlite/open.js +21 -8
  149. package/dist/esm/store/sqlite/open.js.map +1 -1
  150. package/dist/esm/store/sqlite/store.js +14 -1
  151. package/dist/esm/store/sqlite/store.js.map +1 -1
  152. package/dist/esm/store/sqlite/vectors.d.ts +0 -5
  153. package/dist/esm/store/sqlite/vectors.js +2 -22
  154. package/dist/esm/store/sqlite/vectors.js.map +1 -1
  155. package/dist/esm/store/turso/connection.d.ts +3 -0
  156. package/dist/esm/store/turso/connection.js +52 -0
  157. package/dist/esm/store/turso/connection.js.map +1 -0
  158. package/dist/esm/store/turso/fieldStats.d.ts +2 -0
  159. package/dist/esm/store/turso/fieldStats.js +24 -0
  160. package/dist/esm/store/turso/fieldStats.js.map +1 -0
  161. package/dist/esm/store/turso/native.d.ts +2 -0
  162. package/dist/esm/store/turso/native.js +19 -0
  163. package/dist/esm/store/turso/native.js.map +1 -0
  164. package/dist/esm/store/turso/open.d.ts +12 -0
  165. package/dist/esm/store/turso/open.js +113 -0
  166. package/dist/esm/store/turso/open.js.map +1 -0
  167. package/dist/esm/store/turso/reconcile.d.ts +6 -0
  168. package/dist/esm/store/turso/reconcile.js +158 -0
  169. package/dist/esm/store/turso/reconcile.js.map +1 -0
  170. package/dist/esm/store/turso/store.d.ts +5 -0
  171. package/dist/esm/store/turso/store.js +93 -0
  172. package/dist/esm/store/turso/store.js.map +1 -0
  173. package/dist/esm/store/types.d.ts +9 -1
  174. package/dist/esm/store/types.js +0 -7
  175. package/dist/esm/store/types.js.map +1 -1
  176. package/dist/esm/store/vectors.d.ts +9 -0
  177. package/dist/esm/store/vectors.js +26 -0
  178. package/dist/esm/store/vectors.js.map +1 -0
  179. package/package.json +2 -1
@@ -1,3 +1,4 @@
1
+ import type { StoreName } from '../config/index.js';
1
2
  export type Capability = 'phrases' | 'snippets' | 'watch-concurrency' | 'lexical' | 'vectors';
2
3
  export interface RunResult {
3
4
  changes: number | bigint;
@@ -18,8 +19,14 @@ export interface Connection {
18
19
  prepare(sql: string): Promise<Statement>;
19
20
  runBatch(sql: string, paramRows: unknown[][]): Promise<void>;
20
21
  }
22
+ export interface FieldStat {
23
+ field: string;
24
+ coverage: number;
25
+ type: string;
26
+ }
21
27
  export interface DocumentStore {
22
28
  columns(): Promise<string[]>;
29
+ fieldStats(columns: string[], scopeWhere: string): Promise<FieldStat[]>;
23
30
  }
24
31
  export interface LexicalHit {
25
32
  path: string;
@@ -73,7 +80,7 @@ export interface SqlSession {
73
80
  prepare(sql: string): Promise<RawStatement>;
74
81
  }
75
82
  export interface Store {
76
- readonly name: 'sqlite' | 'duckdb';
83
+ readonly name: StoreName;
77
84
  readonly capabilities: ReadonlySet<Capability>;
78
85
  exec(sql: string): Promise<void>;
79
86
  prepare(sql: string): Promise<Statement>;
@@ -87,5 +94,6 @@ export interface Store {
87
94
  lexical: LexicalIndex;
88
95
  vectors: VectorStore;
89
96
  raw: SqlSession;
97
+ engineStatus(): Promise<Record<string, string>>;
90
98
  close(): Promise<void>;
91
99
  }
@@ -1,3 +1,4 @@
1
+ import type { StoreName } from '../config/index.js';
1
2
  export type Capability = 'phrases' | 'snippets' | 'watch-concurrency' | 'lexical' | 'vectors';
2
3
  export interface RunResult {
3
4
  changes: number | bigint;
@@ -18,8 +19,14 @@ export interface Connection {
18
19
  prepare(sql: string): Promise<Statement>;
19
20
  runBatch(sql: string, paramRows: unknown[][]): Promise<void>;
20
21
  }
22
+ export interface FieldStat {
23
+ field: string;
24
+ coverage: number;
25
+ type: string;
26
+ }
21
27
  export interface DocumentStore {
22
28
  columns(): Promise<string[]>;
29
+ fieldStats(columns: string[], scopeWhere: string): Promise<FieldStat[]>;
23
30
  }
24
31
  export interface LexicalHit {
25
32
  path: string;
@@ -73,7 +80,7 @@ export interface SqlSession {
73
80
  prepare(sql: string): Promise<RawStatement>;
74
81
  }
75
82
  export interface Store {
76
- readonly name: 'sqlite' | 'duckdb';
83
+ readonly name: StoreName;
77
84
  readonly capabilities: ReadonlySet<Capability>;
78
85
  exec(sql: string): Promise<void>;
79
86
  prepare(sql: string): Promise<Statement>;
@@ -87,5 +94,6 @@ export interface Store {
87
94
  lexical: LexicalIndex;
88
95
  vectors: VectorStore;
89
96
  raw: SqlSession;
97
+ engineStatus(): Promise<Record<string, string>>;
90
98
  close(): Promise<void>;
91
99
  }
@@ -1,13 +1,6 @@
1
1
  // The backing-store interface: a minimal portable statement surface (exec/prepare, used as-is
2
2
  // by feature-owned tables and ad hoc queries) plus dedicated interfaces exactly where engines
3
3
  // diverge (lexical index, vector scan, raw sql passthrough).
4
- // 'lexical'/'vectors' mean the store's LexicalIndex/VectorStore are functionally implemented
5
- // (rather than present-but-inert); 'phrases'/'snippets'/'watch-concurrency' are the finer
6
- // behaviors sqlite's FTS5 path carries. A tree whose config needs a capability the chosen
7
- // store lacks fails at open (or at first use for a lazily-detected need), named.
8
- // 'phrases' means quoted-phrase (`"..."`) matching only -- not FTS5's wider query grammar
9
- // (prefix `*`, boolean AND/OR/NOT, NEAR, `^`, column filters), which duckdb's lexical path
10
- // rejects loudly rather than interpret (see store/duckdb/lexical.ts).
11
4
  "use strict";
12
5
  Object.defineProperty(exports, "__esModule", {
13
6
  value: true
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/types.ts"],"sourcesContent":["// The backing-store interface: a minimal portable statement surface (exec/prepare, used as-is\n// by feature-owned tables and ad hoc queries) plus dedicated interfaces exactly where engines\n// diverge (lexical index, vector scan, raw sql passthrough).\n\n// 'lexical'/'vectors' mean the store's LexicalIndex/VectorStore are functionally implemented\n// (rather than present-but-inert); 'phrases'/'snippets'/'watch-concurrency' are the finer\n// behaviors sqlite's FTS5 path carries. A tree whose config needs a capability the chosen\n// store lacks fails at open (or at first use for a lazily-detected need), named.\n// 'phrases' means quoted-phrase (`\"...\"`) matching only -- not FTS5's wider query grammar\n// (prefix `*`, boolean AND/OR/NOT, NEAR, `^`, column filters), which duckdb's lexical path\n// rejects loudly rather than interpret (see store/duckdb/lexical.ts).\nexport type Capability = 'phrases' | 'snippets' | 'watch-concurrency' | 'lexical' | 'vectors';\n\nexport interface RunResult {\n changes: number | bigint;\n lastInsertRowid: number | bigint;\n}\n\n// A prepared statement's async surface: every engine this store supports has to cross a real\n// async boundary for a query (DuckDB has no synchronous client at all), so run/get/all return\n// Promises. iterate() stays an async iterable for the same reason `sense sql` streams.\nexport interface Statement {\n run(...params: unknown[]): Promise<RunResult>;\n get(...params: unknown[]): Promise<unknown>;\n all(...params: unknown[]): Promise<unknown[]>;\n iterate(...params: unknown[]): AsyncIterable<unknown>;\n columns(): Array<{ name: string }>;\n setReadBigInts(enabled: boolean): void;\n}\n\n// Connection surface feature-owned SQL runs against inside a store's own hot loops (schema,\n// reconcile). Portable so a feature never imports an engine-specific client type. `runBatch`\n// is the one call a write loop goes through instead of preparing once and calling `run()` per\n// row itself: one crossing per loop, the engine's own bulk idiom underneath (see each store's\n// implementation for what that idiom is).\nexport interface Connection {\n exec(sql: string): Promise<void>;\n prepare(sql: string): Promise<Statement>;\n runBatch(sql: string, paramRows: unknown[][]): Promise<void>;\n}\n\nexport interface DocumentStore {\n // Frontmatter column names (including internal ones; callers filter).\n columns(): Promise<string[]>;\n}\n\nexport interface LexicalHit {\n path: string;\n hit: string | null;\n}\n\nexport interface LexicalQueryOptions {\n whereJoin: string;\n whereCond: string;\n scopeCond: string;\n limit: number;\n}\n\nexport interface LexicalIndex {\n // Ranked word-match query with excerpt, scoped by the caller-built SQL fragments (the same\n // fragments narrowByWhere/materializeScope produce elsewhere).\n query(terms: string, opts: LexicalQueryOptions): Promise<LexicalHit[]>;\n}\n\nexport interface VectorCandidate {\n path: string;\n lines: string;\n similarity: number;\n}\n\nexport interface VectorSimilar {\n path: string;\n similarity: number;\n}\n\nexport interface VectorWriteRow {\n path: string;\n chunk: number;\n scale: number;\n vector: Buffer;\n}\n\nexport interface VectorStore {\n // Rows whose vector is still NULL (never embedded, or added since).\n pending(): Promise<Array<{ path: string; chunk: number }>>;\n // One batch write per call (never per row) so a provider's embedding batch stays inside a\n // single store method.\n writeVectors(rows: VectorWriteRow[]): Promise<void>;\n candidates(queryVector: Float32Array, storeDims: number, fetch: number, allowed?: Set<string>): Promise<VectorCandidate[]>;\n similar(path: string, opts: { exclude: Set<string>; allowed?: Set<string>; k: number }): Promise<VectorSimilar[]>;\n hasVector(path: string): Promise<boolean>;\n}\n\n// The `sense sql` passthrough: string in, streamed rows out. Each store registers the same\n// sense-supplied functions and applies its own read-bigints/error-translation behavior.\nexport interface RawStatement {\n columns(): Array<{ name: string }>;\n iterate(...params: unknown[]): AsyncIterable<unknown>;\n}\n\nexport interface SqlSession {\n prepare(sql: string): Promise<RawStatement>;\n}\n\nexport interface Store {\n readonly name: 'sqlite' | 'duckdb';\n readonly capabilities: ReadonlySet<Capability>;\n exec(sql: string): Promise<void>;\n prepare(sql: string): Promise<Statement>;\n // One crossing, N rows: every external write loop (search's candidate insert, the graph\n // ring's temp-table writes, etc.) goes through this instead of looping over `run()` itself.\n // See Connection.runBatch -- same contract, same per-store implementation.\n runBatch(sql: string, paramRows: unknown[][]): Promise<void>;\n // Pins one snapshot across multi-statement reads; `map` and `peek` use it. A command whose\n // scope holds a network-bound write (search's embedding top-up) must stay outside it.\n // Nesting joins the enclosing transaction rather than opening a second one.\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n // The whole file-sync pass (parse changed files, run every feature hook, resolve links,\n // recompute rank) behind one method: per-file iteration never crosses the async boundary.\n reconcile(): Promise<{ parsed: number; warnings: string[] }>;\n docs: DocumentStore;\n lexical: LexicalIndex;\n vectors: VectorStore;\n raw: SqlSession;\n close(): Promise<void>;\n}\n"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,8FAA8F;AAC9F,6DAA6D;AAE7D,6FAA6F;AAC7F,0FAA0F;AAC1F,0FAA0F;AAC1F,iFAAiF;AACjF,0FAA0F;AAC1F,2FAA2F;AAC3F,sEAAsE"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/types.ts"],"sourcesContent":["// The backing-store interface: a minimal portable statement surface (exec/prepare, used as-is\n// by feature-owned tables and ad hoc queries) plus dedicated interfaces exactly where engines\n// diverge (lexical index, vector scan, raw sql passthrough).\n\nimport type { StoreName } from '../config/index.ts';\n\n// 'lexical'/'vectors' mean the store's LexicalIndex/VectorStore are functionally implemented\n// (rather than present-but-inert); 'phrases'/'snippets'/'watch-concurrency' are the finer\n// behaviors sqlite's FTS5 path carries. A tree whose config needs a capability the chosen\n// store lacks fails at open (or at first use for a lazily-detected need), named.\n// 'phrases' means quoted-phrase (`\"...\"`) matching only -- not FTS5's wider query grammar\n// (prefix `*`, boolean AND/OR/NOT, NEAR, `^`, column filters), which duckdb's lexical path\n// rejects loudly rather than interpret (see store/duckdb/lexical.ts).\nexport type Capability = 'phrases' | 'snippets' | 'watch-concurrency' | 'lexical' | 'vectors';\n\nexport interface RunResult {\n changes: number | bigint;\n lastInsertRowid: number | bigint;\n}\n\n// A prepared statement's async surface: every engine this store supports has to cross a real\n// async boundary for a query (DuckDB has no synchronous client at all), so run/get/all return\n// Promises. iterate() stays an async iterable for the same reason `sense sql` streams.\nexport interface Statement {\n run(...params: unknown[]): Promise<RunResult>;\n get(...params: unknown[]): Promise<unknown>;\n all(...params: unknown[]): Promise<unknown[]>;\n iterate(...params: unknown[]): AsyncIterable<unknown>;\n columns(): Array<{ name: string }>;\n setReadBigInts(enabled: boolean): void;\n}\n\n// Connection surface feature-owned SQL runs against inside a store's own hot loops (schema,\n// reconcile). Portable so a feature never imports an engine-specific client type. `runBatch`\n// is the one call a write loop goes through instead of preparing once and calling `run()` per\n// row itself: one crossing per loop, the engine's own bulk idiom underneath (see each store's\n// implementation for what that idiom is).\nexport interface Connection {\n exec(sql: string): Promise<void>;\n prepare(sql: string): Promise<Statement>;\n runBatch(sql: string, paramRows: unknown[][]): Promise<void>;\n}\n\nexport interface FieldStat {\n field: string;\n coverage: number;\n type: string;\n}\n\nexport interface DocumentStore {\n // Frontmatter column names (including internal ones; callers filter).\n columns(): Promise<string[]>;\n // Per-column coverage (non-null count) and observed type set, aggregated in SQL -- one query\n // per call, never one row per note. `columns` is one chunk (caller owns the chunk size, a\n // result-row column limit); `scopeWhere` is a caller-built WHERE fragment, same convention as\n // LexicalQueryOptions. Each store expresses \"observed type\" through its own engine mechanism\n // (native-not-emulated) but returns the shared integer/real/text vocabulary.\n fieldStats(columns: string[], scopeWhere: string): Promise<FieldStat[]>;\n}\n\nexport interface LexicalHit {\n path: string;\n hit: string | null;\n}\n\nexport interface LexicalQueryOptions {\n whereJoin: string;\n whereCond: string;\n scopeCond: string;\n limit: number;\n}\n\nexport interface LexicalIndex {\n // Ranked word-match query with excerpt, scoped by the caller-built SQL fragments (the same\n // fragments narrowByWhere/materializeScope produce elsewhere).\n query(terms: string, opts: LexicalQueryOptions): Promise<LexicalHit[]>;\n}\n\nexport interface VectorCandidate {\n path: string;\n lines: string;\n similarity: number;\n}\n\nexport interface VectorSimilar {\n path: string;\n similarity: number;\n}\n\nexport interface VectorWriteRow {\n path: string;\n chunk: number;\n scale: number;\n vector: Buffer;\n}\n\nexport interface VectorStore {\n // Rows whose vector is still NULL (never embedded, or added since).\n pending(): Promise<Array<{ path: string; chunk: number }>>;\n // One batch write per call (never per row) so a provider's embedding batch stays inside a\n // single store method.\n writeVectors(rows: VectorWriteRow[]): Promise<void>;\n candidates(queryVector: Float32Array, storeDims: number, fetch: number, allowed?: Set<string>): Promise<VectorCandidate[]>;\n similar(path: string, opts: { exclude: Set<string>; allowed?: Set<string>; k: number }): Promise<VectorSimilar[]>;\n hasVector(path: string): Promise<boolean>;\n}\n\n// The `sense sql` passthrough: string in, streamed rows out. Each store registers the same\n// sense-supplied functions and applies its own read-bigints/error-translation behavior.\nexport interface RawStatement {\n columns(): Array<{ name: string }>;\n iterate(...params: unknown[]): AsyncIterable<unknown>;\n}\n\nexport interface SqlSession {\n prepare(sql: string): Promise<RawStatement>;\n}\n\nexport interface Store {\n readonly name: StoreName;\n readonly capabilities: ReadonlySet<Capability>;\n exec(sql: string): Promise<void>;\n prepare(sql: string): Promise<Statement>;\n // One crossing, N rows: every external write loop (search's candidate insert, the graph\n // ring's temp-table writes, etc.) goes through this instead of looping over `run()` itself.\n // See Connection.runBatch -- same contract, same per-store implementation.\n runBatch(sql: string, paramRows: unknown[][]): Promise<void>;\n // Pins one snapshot across multi-statement reads; `map` and `peek` use it. A command whose\n // scope holds a network-bound write (search's embedding top-up) must stay outside it.\n // Nesting joins the enclosing transaction rather than opening a second one.\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n // The whole file-sync pass (parse changed files, run every feature hook, resolve links,\n // recompute rank) behind one method: per-file iteration never crosses the async boundary.\n reconcile(): Promise<{ parsed: number; warnings: string[] }>;\n docs: DocumentStore;\n lexical: LexicalIndex;\n vectors: VectorStore;\n raw: SqlSession;\n // Engine-level facts for `sense status` (e.g. a derived busy_timeout PRAGMA reading), each\n // store owning what it reports and how it is worded; the command prints entries generically,\n // one line per fact, without knowing any store's name. Empty when there is nothing to report.\n engineStatus(): Promise<Record<string, string>>;\n close(): Promise<void>;\n}\n"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,8FAA8F;AAC9F,6DAA6D"}
@@ -0,0 +1,9 @@
1
+ import type { Connection } from './types.js';
2
+ export declare const TARGET_CHUNK_CAP = 16;
3
+ export declare function sampleEvenly<T>(rows: T[], cap?: number): T[];
4
+ export declare function asCosine(score: number): number;
5
+ export declare function pendingRows(conn: Connection): Promise<Array<{
6
+ path: string;
7
+ chunk: number;
8
+ }>>;
9
+ export declare function hasVectorRow(conn: Connection, path: string): Promise<boolean>;
@@ -0,0 +1,9 @@
1
+ import type { Connection } from './types.js';
2
+ export declare const TARGET_CHUNK_CAP = 16;
3
+ export declare function sampleEvenly<T>(rows: T[], cap?: number): T[];
4
+ export declare function asCosine(score: number): number;
5
+ export declare function pendingRows(conn: Connection): Promise<Array<{
6
+ path: string;
7
+ chunk: number;
8
+ }>>;
9
+ export declare function hasVectorRow(conn: Connection, path: string): Promise<boolean>;
@@ -0,0 +1,215 @@
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 TARGET_CHUNK_CAP () {
13
+ return TARGET_CHUNK_CAP;
14
+ },
15
+ get asCosine () {
16
+ return asCosine;
17
+ },
18
+ get hasVectorRow () {
19
+ return hasVectorRow;
20
+ },
21
+ get pendingRows () {
22
+ return pendingRows;
23
+ },
24
+ get sampleEvenly () {
25
+ return sampleEvenly;
26
+ }
27
+ });
28
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
29
+ try {
30
+ var info = gen[key](arg);
31
+ var value = info.value;
32
+ } catch (error) {
33
+ reject(error);
34
+ return;
35
+ }
36
+ if (info.done) resolve(value);
37
+ else Promise.resolve(value).then(_next, _throw);
38
+ }
39
+ function _async_to_generator(fn) {
40
+ return function() {
41
+ var self = this, args = arguments;
42
+ return new Promise(function(resolve, reject) {
43
+ var gen = fn.apply(self, args);
44
+ function _next(value) {
45
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
46
+ }
47
+ function _throw(err) {
48
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
49
+ }
50
+ _next(undefined);
51
+ });
52
+ };
53
+ }
54
+ function _ts_generator(thisArg, body) {
55
+ var f, y, t, _ = {
56
+ label: 0,
57
+ sent: function() {
58
+ if (t[0] & 1) throw t[1];
59
+ return t[1];
60
+ },
61
+ trys: [],
62
+ ops: []
63
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
64
+ return d(g, "next", {
65
+ value: verb(0)
66
+ }), d(g, "throw", {
67
+ value: verb(1)
68
+ }), d(g, "return", {
69
+ value: verb(2)
70
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
71
+ value: function() {
72
+ return this;
73
+ }
74
+ }), g;
75
+ function verb(n) {
76
+ return function(v) {
77
+ return step([
78
+ n,
79
+ v
80
+ ]);
81
+ };
82
+ }
83
+ function step(op) {
84
+ if (f) throw new TypeError("Generator is already executing.");
85
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
86
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
87
+ if (y = 0, t) op = [
88
+ op[0] & 2,
89
+ t.value
90
+ ];
91
+ switch(op[0]){
92
+ case 0:
93
+ case 1:
94
+ t = op;
95
+ break;
96
+ case 4:
97
+ _.label++;
98
+ return {
99
+ value: op[1],
100
+ done: false
101
+ };
102
+ case 5:
103
+ _.label++;
104
+ y = op[1];
105
+ op = [
106
+ 0
107
+ ];
108
+ continue;
109
+ case 7:
110
+ op = _.ops.pop();
111
+ _.trys.pop();
112
+ continue;
113
+ default:
114
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
115
+ _ = 0;
116
+ continue;
117
+ }
118
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
119
+ _.label = op[1];
120
+ break;
121
+ }
122
+ if (op[0] === 6 && _.label < t[1]) {
123
+ _.label = t[1];
124
+ t = op;
125
+ break;
126
+ }
127
+ if (t && _.label < t[2]) {
128
+ _.label = t[2];
129
+ _.ops.push(op);
130
+ break;
131
+ }
132
+ if (t[2]) _.ops.pop();
133
+ _.trys.pop();
134
+ continue;
135
+ }
136
+ op = body.call(thisArg, _);
137
+ } catch (e) {
138
+ op = [
139
+ 6,
140
+ e
141
+ ];
142
+ y = 0;
143
+ } finally{
144
+ f = t = 0;
145
+ }
146
+ if (op[0] & 5) throw op[1];
147
+ return {
148
+ value: op[0] ? op[1] : void 0,
149
+ done: true
150
+ };
151
+ }
152
+ }
153
+ var TARGET_CHUNK_CAP = 16;
154
+ function sampleEvenly(rows) {
155
+ var cap = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : TARGET_CHUNK_CAP;
156
+ var step = Math.max(1, Math.ceil(rows.length / cap));
157
+ return rows.filter(function(_, i) {
158
+ return i % step === 0;
159
+ });
160
+ }
161
+ function asCosine(score) {
162
+ return Math.round(Math.min(1, Math.max(-1, score)) * 1000) / 1000;
163
+ }
164
+ function pendingRows(conn) {
165
+ return _async_to_generator(function() {
166
+ var stmt;
167
+ return _ts_generator(this, function(_state) {
168
+ switch(_state.label){
169
+ case 0:
170
+ return [
171
+ 4,
172
+ conn.prepare('SELECT "path", chunk FROM embeddings WHERE vector IS NULL ORDER BY "path", chunk')
173
+ ];
174
+ case 1:
175
+ stmt = _state.sent();
176
+ return [
177
+ 4,
178
+ stmt.all()
179
+ ];
180
+ case 2:
181
+ return [
182
+ 2,
183
+ _state.sent()
184
+ ];
185
+ }
186
+ });
187
+ })();
188
+ }
189
+ function hasVectorRow(conn, path) {
190
+ return _async_to_generator(function() {
191
+ var stmt, row;
192
+ return _ts_generator(this, function(_state) {
193
+ switch(_state.label){
194
+ case 0:
195
+ return [
196
+ 4,
197
+ conn.prepare('SELECT 1 AS ok FROM embeddings WHERE "path" = ? AND vector IS NOT NULL LIMIT 1')
198
+ ];
199
+ case 1:
200
+ stmt = _state.sent();
201
+ return [
202
+ 4,
203
+ stmt.get(path)
204
+ ];
205
+ case 2:
206
+ row = _state.sent();
207
+ return [
208
+ 2,
209
+ row !== undefined
210
+ ];
211
+ }
212
+ });
213
+ })();
214
+ }
215
+ /* 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/store/vectors.ts"],"sourcesContent":["import type { Connection } from './types.ts';\n\n// Seed chunks that participate in a `related` scan. Cost is target_chunks x stored_chunks, so a\n// heading-dense seed multiplies a full-corpus scan (12.7s at 201 chunks/note unsampled).\nexport const TARGET_CHUNK_CAP = 16;\n\n// Evenly samples down to at most `cap` rows, so late sections of a long note still get a vote\n// instead of being cut off by a fixed prefix.\nexport function sampleEvenly<T>(rows: T[], cap: number = TARGET_CHUNK_CAP): T[] {\n const step = Math.max(1, Math.ceil(rows.length / cap));\n return rows.filter((_, i) => i % step === 0);\n}\n\n// Dequantised int8 dot products (sqlite) land a little either side of a true cosine, so an\n// identical pair can print 1.001; array_cosine_similarity (duckdb) has no such error but is\n// rounded the same way, so both stores print the same bounded number.\nexport function asCosine(score: number): number {\n return Math.round(Math.min(1, Math.max(-1, score)) * 1000) / 1000;\n}\n\nexport async function pendingRows(conn: Connection): Promise<Array<{ path: string; chunk: number }>> {\n const stmt = await conn.prepare('SELECT \"path\", chunk FROM embeddings WHERE vector IS NULL ORDER BY \"path\", chunk');\n return (await stmt.all()) as Array<{ path: string; chunk: number }>;\n}\n\n// Whether a note has any chunk with a vector. Distinguishes \"nothing is near this note\" from\n// \"this note has no text\", which look the same in an empty result.\nexport async function hasVectorRow(conn: Connection, path: string): Promise<boolean> {\n const stmt = await conn.prepare('SELECT 1 AS ok FROM embeddings WHERE \"path\" = ? AND vector IS NOT NULL LIMIT 1');\n const row = (await stmt.get(path)) as { ok: number } | undefined;\n return row !== undefined;\n}\n"],"names":["TARGET_CHUNK_CAP","asCosine","hasVectorRow","pendingRows","sampleEvenly","rows","cap","step","Math","max","ceil","length","filter","_","i","score","round","min","conn","stmt","prepare","all","path","row","get","undefined"],"mappings":";;;;;;;;;;;QAIaA;eAAAA;;QAYGC;eAAAA;;QAWMC;eAAAA;;QAPAC;eAAAA;;QAZNC;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAJT,IAAMJ,mBAAmB;AAIzB,SAASI,aAAgBC,IAAS;QAAEC,MAAAA,iEAAcN;IACvD,IAAMO,OAAOC,KAAKC,GAAG,CAAC,GAAGD,KAAKE,IAAI,CAACL,KAAKM,MAAM,GAAGL;IACjD,OAAOD,KAAKO,MAAM,CAAC,SAACC,GAAGC;eAAMA,IAAIP,SAAS;;AAC5C;AAKO,SAASN,SAASc,KAAa;IACpC,OAAOP,KAAKQ,KAAK,CAACR,KAAKS,GAAG,CAAC,GAAGT,KAAKC,GAAG,CAAC,CAAC,GAAGM,UAAU,QAAQ;AAC/D;AAEO,SAAeZ,YAAYe,IAAgB;;YAC1CC;;;;oBAAO;;wBAAMD,KAAKE,OAAO,CAAC;;;oBAA1BD,OAAO;oBACL;;wBAAMA,KAAKE,GAAG;;;oBAAtB;;wBAAQ;;;;IACV;;AAIO,SAAenB,aAAagB,IAAgB,EAAEI,IAAY;;YACzDH,MACAI;;;;oBADO;;wBAAML,KAAKE,OAAO,CAAC;;;oBAA1BD,OAAO;oBACA;;wBAAMA,KAAKK,GAAG,CAACF;;;oBAAtBC,MAAO;oBACb;;wBAAOA,QAAQE;;;;IACjB"}
@@ -71,11 +71,9 @@ const status = async (ctx)=>{
71
71
  // Written by the store's open() on every open, so it is this cache's true version on either
72
72
  // store (sqlite 18, duckdb 2); a version mismatch already triggered a rebuild before this read.
73
73
  const cacheSchema = await getMeta(store, 'schema_version');
74
- // Derived at open() (F): 3x the largest reconcile this cache has ever held its write
75
- // transaction for, floored at 30s -- read back from the connection rather than
76
- // recomputed here, so this always reports what open() actually set. The pragma is
77
- // sqlite-engine-specific; other stores have no such setting and report null.
78
- const busyTimeoutMs = store.name === 'sqlite' ? (await (await store.prepare('PRAGMA busy_timeout')).get()).timeout : null;
74
+ // Each store owns what it reports and how it is worded (Store.engineStatus); this command
75
+ // prints entries generically, without branching on any store's name.
76
+ const engine = await store.engineStatus();
79
77
  // The env var holds the token; only its name and whether it is set are ever reported.
80
78
  const keyEnv = (e === null || e === void 0 ? void 0 : e.key) ? {
81
79
  name: e.key,
@@ -110,7 +108,7 @@ const status = async (ctx)=>{
110
108
  queries: Object.keys((_cfg_queries = cfg.queries) !== null && _cfg_queries !== void 0 ? _cfg_queries : {}).length,
111
109
  watcherPid: await getMeta(store, 'watch_pid'),
112
110
  watcherHeartbeatSecondsAgo: heartbeat ? Math.round((Date.now() - Date.parse(heartbeat)) / 1000) : null,
113
- busyTimeoutMs
111
+ engine
114
112
  };
115
113
  if (format === 'json') {
116
114
  console.log(stringifyJson(result, 2));
@@ -152,7 +150,7 @@ const status = async (ctx)=>{
152
150
  console.log(`queries: ${result.queries} saved (${ctx.name} --list)`);
153
151
  const pid = result.watcherPid ? `pid ${result.watcherPid}, ` : '';
154
152
  console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: none' : `watcher: ${pid}last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);
155
- if (result.busyTimeoutMs !== null) console.log(`sqlite: busy_timeout ${result.busyTimeoutMs}ms (derived: 3x the largest reconcile this cache has recorded, floored at 30000ms)`);
153
+ for (const [key, value] of Object.entries(result.engine))console.log(`${`${store.name}:`.padEnd(10)}${key} ${value}`);
156
154
  }
157
155
  await store.close();
158
156
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/status.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { presetCoverage } from '../commands/status.ts';\nimport { embedConfig, featureStates, SUPPORTED_CONFIG_VERSION } from '../config/index.ts';\nimport { languageDistribution } from '../embed/distribution.ts';\nimport { probeReachable } from '../embed/http.ts';\nimport { isDownloadable, MODEL_FILENAMES, modelDir, modelPresent, readLanguages } from '../embed/store.ts';\nimport { featuresLine, presetsLines, stringifyJson } from '../output/output.ts';\nimport { docCount, getMeta, openStore } from '../store/index.ts';\nimport type { Store } from '../store/types.ts';\nimport { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, formatOf, parse, printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\n// status names what you cannot read off the config file: locations sense chose, values it\n// derived, state it stored. Config content is not echoed -- the config line says which file to\n// read, and duplicating its globs here would create two places that disagree after an edit.\n// The exception is the embed block's url and key, whose effect is remote and otherwise invisible.\n\n// Vectors are computed on the first semantic query, not at reconcile, so a tree can have a\n// semantic-on preset with nothing embedded yet -- reported here because a fast reconcile on\n// such a tree otherwise reads as \"the feature isn't on\".\nasync function vectorState(store: Store): Promise<{ embedded: number; pending: number } | null> {\n try {\n const stmt = await store.prepare('SELECT COUNT(vector) AS embedded, COUNT(*) - COUNT(vector) AS pending FROM embeddings');\n return (await stmt.get()) as { embedded: number; pending: number };\n } catch {\n return null;\n }\n}\n\nasync function parseErrorCount(store: Store): Promise<number> {\n const stmt = await store.prepare(`SELECT COUNT(*) AS n FROM frontmatter WHERE \"_parse_error\" IS NOT NULL`);\n return ((await stmt.get()) as { n: number }).n;\n}\n\n// A URL can carry credentials in its userinfo (https://user:pass@host/v1). status output gets\n// pasted into issues and transcripts, so it is always safe to paste.\nexport function redactUrl(url: string): string {\n try {\n const parsed = new URL(url);\n if (!parsed.username && !parsed.password) return url;\n parsed.username = '';\n parsed.password = '';\n return `${parsed.toString().replace(/\\/$/, '')} (credentials redacted)`;\n } catch {\n return url;\n }\n}\n\n// A stopped Ollama/LM Studio/Cohere endpoint prints identically to a running one otherwise; any\n// HTTP response counts as reachable (probeReachable), so this only distinguishes up from down.\nasync function embedReachable(e: { provider: string; url?: string }): Promise<boolean | null> {\n if (e.provider === 'static' || (e.provider === 'openai' && !e.url)) return null;\n const base = (e.url ?? 'https://api.cohere.com').replace(/\\/+$/, '');\n return probeReachable(e.provider === 'openai' ? `${base}/models` : base);\n}\n\nconst status: Command = async (ctx) => {\n const { values } = parse(ctx.argv, `usage: ${ctx.name} ${USAGE.status}`, { ...FORMAT, ...CONFIG });\n const format = formatOf(values);\n const cfg = ctx.resolveConfig(values.config as string | undefined);\n const { store, dbPath, warnings } = await openStore(cfg);\n printWarnings(warnings);\n\n const features = featureStates(cfg);\n const e = embedConfig(cfg);\n const hasModel = e ? modelPresent(cfg) : false;\n const reachable = e ? await embedReachable(e) : null;\n const vectors = e ? await vectorState(store) : null;\n const presets = await presetCoverage(store, cfg);\n const staticLanguages = e && e.provider === 'static' ? readLanguages(e.model) : undefined;\n const declaredLanguages = staticLanguages && staticLanguages.length > 0 ? staticLanguages : null;\n const detectedLanguages = (await languageDistribution(store)) ?? null;\n const heartbeat = await getMeta(store, 'watch_heartbeat');\n // Written by the store's open() on every open, so it is this cache's true version on either\n // store (sqlite 18, duckdb 2); a version mismatch already triggered a rebuild before this read.\n const cacheSchema = await getMeta(store, 'schema_version');\n // Derived at open() (F): 3x the largest reconcile this cache has ever held its write\n // transaction for, floored at 30s -- read back from the connection rather than\n // recomputed here, so this always reports what open() actually set. The pragma is\n // sqlite-engine-specific; other stores have no such setting and report null.\n const busyTimeoutMs = store.name === 'sqlite' ? ((await (await store.prepare('PRAGMA busy_timeout')).get()) as { timeout: number }).timeout : null;\n // The env var holds the token; only its name and whether it is set are ever reported.\n const keyEnv = e?.key ? { name: e.key, set: (process.env[e.key] ?? '') !== '' } : null;\n const result = {\n config: cfg.configPath,\n configVersion: SUPPORTED_CONFIG_VERSION,\n migratedFrom: cfg.migratedFrom ?? null,\n unknownConfigKeys: cfg.unknownKeys ?? null,\n tree: cfg.baseDir,\n cache: dirname(dbPath),\n db: dbPath,\n cacheSchema,\n docs: await docCount(store),\n unparseableFrontmatter: await parseErrorCount(store),\n features: features.on,\n featuresOff: features.off,\n embed: e ? { provider: e.provider, model: e.model, dir: e.provider === 'static' ? modelDir(e.model) : null, url: e.url ? redactUrl(e.url) : null, reachable, keyEnv, downloaded: hasModel, languages: declaredLanguages, detectedLanguages, ...(vectors ?? {}) } : null,\n presets,\n queries: Object.keys(cfg.queries ?? {}).length,\n watcherPid: await getMeta(store, 'watch_pid'),\n watcherHeartbeatSecondsAgo: heartbeat ? Math.round((Date.now() - Date.parse(heartbeat)) / 1000) : null,\n busyTimeoutMs,\n };\n\n if (format === 'json') {\n console.log(stringifyJson(result, 2));\n } else {\n const migrated = cfg.migratedFrom !== undefined ? `, migrated from v${cfg.migratedFrom} on this run` : '';\n console.log(`config: ${result.config} (v${SUPPORTED_CONFIG_VERSION}${migrated})`);\n // A load-time stderr warning has scrolled away by the time anyone looks here.\n if (cfg.unknownKeys) console.log(` unknown keys, ignored: ${cfg.unknownKeys.join(', ')}`);\n console.log(`tree: ${result.tree}`);\n console.log(`cache: ${result.cache} (schema ${result.cacheSchema}; delete this directory to reset)`);\n console.log(`docs: ${result.docs}${result.unparseableFrontmatter > 0 ? ` (${result.unparseableFrontmatter} with unparseable frontmatter: WHERE _parse_error IS NOT NULL)` : ''}`);\n console.log('');\n console.log(featuresLine(features));\n // One authoritative block, off states included: an absent model reads as a degraded search,\n // not as an empty corpus.\n if (!e) console.log('embed: off (no preset asks for vectors)');\n else {\n console.log(`embed: ${e.provider} ${e.model}`);\n 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`}`})`);\n if (declaredLanguages) console.log(` languages: ${declaredLanguages.join(', ')} (declared by the model card)`);\n // Cohere defaults to api.cohere.com with no url in the config; show it anyway so the\n // reachability probe below has something to name.\n if (e.url || reachable !== null) {\n const shown = e.url ? redactUrl(e.url) : 'https://api.cohere.com (default)';\n console.log(` url: ${shown}${reachable === null ? '' : reachable ? ' (reachable)' : ' (unreachable)'}`);\n }\n if (keyEnv) console.log(` key: env ${keyEnv.name} (${keyEnv.set ? 'set' : 'NOT SET'})`);\n if (!hasModel) console.log(' vectors: off until the model is present; search runs on words and links');\n else if (vectors) console.log(` vectors: ${vectors.embedded} embedded, ${vectors.pending} pending (embedded on the first semantic search)`);\n if (detectedLanguages) {\n const total = Object.values(detectedLanguages).reduce((a, b) => a + b, 0);\n const breakdown = Object.entries(detectedLanguages)\n .sort((a, b) => b[1] - a[1])\n .map(([code, n]) => `${code} ${Math.round((n / total) * 100)}%`)\n .join(', ');\n console.log(` detected: ${breakdown} (${total} chunks classified)`);\n }\n }\n console.log('');\n for (const line of presetsLines(presets)) console.log(line);\n console.log('');\n console.log(`queries: ${result.queries} saved (${ctx.name} --list)`);\n const pid = result.watcherPid ? `pid ${result.watcherPid}, ` : '';\n console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: none' : `watcher: ${pid}last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);\n if (result.busyTimeoutMs !== null) console.log(`sqlite: busy_timeout ${result.busyTimeoutMs}ms (derived: 3x the largest reconcile this cache has recorded, floored at 30000ms)`);\n }\n await store.close();\n};\nexport default status;\n"],"names":["dirname","presetCoverage","embedConfig","featureStates","SUPPORTED_CONFIG_VERSION","languageDistribution","probeReachable","isDownloadable","MODEL_FILENAMES","modelDir","modelPresent","readLanguages","featuresLine","presetsLines","stringifyJson","docCount","getMeta","openStore","USAGE","CONFIG","FORMAT","formatOf","parse","printWarnings","vectorState","store","stmt","prepare","get","parseErrorCount","n","redactUrl","url","parsed","URL","username","password","toString","replace","embedReachable","e","provider","base","status","ctx","process","cfg","values","argv","name","format","resolveConfig","config","dbPath","warnings","features","hasModel","reachable","vectors","presets","staticLanguages","model","undefined","declaredLanguages","length","detectedLanguages","heartbeat","cacheSchema","busyTimeoutMs","timeout","keyEnv","key","set","env","result","configPath","configVersion","migratedFrom","unknownConfigKeys","unknownKeys","tree","baseDir","cache","db","docs","unparseableFrontmatter","on","featuresOff","off","embed","dir","downloaded","languages","queries","Object","keys","watcherPid","watcherHeartbeatSecondsAgo","Math","round","Date","now","console","log","migrated","join","shown","embedded","pending","total","reduce","a","b","breakdown","entries","sort","map","code","line","pid","close"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/cli/status.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { presetCoverage } from '../commands/status.ts';\nimport { embedConfig, featureStates, SUPPORTED_CONFIG_VERSION } from '../config/index.ts';\nimport { languageDistribution } from '../embed/distribution.ts';\nimport { probeReachable } from '../embed/http.ts';\nimport { isDownloadable, MODEL_FILENAMES, modelDir, modelPresent, readLanguages } from '../embed/store.ts';\nimport { featuresLine, presetsLines, stringifyJson } from '../output/output.ts';\nimport { docCount, getMeta, openStore } from '../store/index.ts';\nimport type { Store } from '../store/types.ts';\nimport { USAGE } from './index.ts';\nimport { CONFIG, FORMAT, formatOf, parse, printWarnings } from './shared.ts';\nimport type { Command } from './types.ts';\n\n// status names what you cannot read off the config file: locations sense chose, values it\n// derived, state it stored. Config content is not echoed -- the config line says which file to\n// read, and duplicating its globs here would create two places that disagree after an edit.\n// The exception is the embed block's url and key, whose effect is remote and otherwise invisible.\n\n// Vectors are computed on the first semantic query, not at reconcile, so a tree can have a\n// semantic-on preset with nothing embedded yet -- reported here because a fast reconcile on\n// such a tree otherwise reads as \"the feature isn't on\".\nasync function vectorState(store: Store): Promise<{ embedded: number; pending: number } | null> {\n try {\n const stmt = await store.prepare('SELECT COUNT(vector) AS embedded, COUNT(*) - COUNT(vector) AS pending FROM embeddings');\n return (await stmt.get()) as { embedded: number; pending: number };\n } catch {\n return null;\n }\n}\n\nasync function parseErrorCount(store: Store): Promise<number> {\n const stmt = await store.prepare(`SELECT COUNT(*) AS n FROM frontmatter WHERE \"_parse_error\" IS NOT NULL`);\n return ((await stmt.get()) as { n: number }).n;\n}\n\n// A URL can carry credentials in its userinfo (https://user:pass@host/v1). status output gets\n// pasted into issues and transcripts, so it is always safe to paste.\nexport function redactUrl(url: string): string {\n try {\n const parsed = new URL(url);\n if (!parsed.username && !parsed.password) return url;\n parsed.username = '';\n parsed.password = '';\n return `${parsed.toString().replace(/\\/$/, '')} (credentials redacted)`;\n } catch {\n return url;\n }\n}\n\n// A stopped Ollama/LM Studio/Cohere endpoint prints identically to a running one otherwise; any\n// HTTP response counts as reachable (probeReachable), so this only distinguishes up from down.\nasync function embedReachable(e: { provider: string; url?: string }): Promise<boolean | null> {\n if (e.provider === 'static' || (e.provider === 'openai' && !e.url)) return null;\n const base = (e.url ?? 'https://api.cohere.com').replace(/\\/+$/, '');\n return probeReachable(e.provider === 'openai' ? `${base}/models` : base);\n}\n\nconst status: Command = async (ctx) => {\n const { values } = parse(ctx.argv, `usage: ${ctx.name} ${USAGE.status}`, { ...FORMAT, ...CONFIG });\n const format = formatOf(values);\n const cfg = ctx.resolveConfig(values.config as string | undefined);\n const { store, dbPath, warnings } = await openStore(cfg);\n printWarnings(warnings);\n\n const features = featureStates(cfg);\n const e = embedConfig(cfg);\n const hasModel = e ? modelPresent(cfg) : false;\n const reachable = e ? await embedReachable(e) : null;\n const vectors = e ? await vectorState(store) : null;\n const presets = await presetCoverage(store, cfg);\n const staticLanguages = e && e.provider === 'static' ? readLanguages(e.model) : undefined;\n const declaredLanguages = staticLanguages && staticLanguages.length > 0 ? staticLanguages : null;\n const detectedLanguages = (await languageDistribution(store)) ?? null;\n const heartbeat = await getMeta(store, 'watch_heartbeat');\n // Written by the store's open() on every open, so it is this cache's true version on either\n // store (sqlite 18, duckdb 2); a version mismatch already triggered a rebuild before this read.\n const cacheSchema = await getMeta(store, 'schema_version');\n // Each store owns what it reports and how it is worded (Store.engineStatus); this command\n // prints entries generically, without branching on any store's name.\n const engine = await store.engineStatus();\n // The env var holds the token; only its name and whether it is set are ever reported.\n const keyEnv = e?.key ? { name: e.key, set: (process.env[e.key] ?? '') !== '' } : null;\n const result = {\n config: cfg.configPath,\n configVersion: SUPPORTED_CONFIG_VERSION,\n migratedFrom: cfg.migratedFrom ?? null,\n unknownConfigKeys: cfg.unknownKeys ?? null,\n tree: cfg.baseDir,\n cache: dirname(dbPath),\n db: dbPath,\n cacheSchema,\n docs: await docCount(store),\n unparseableFrontmatter: await parseErrorCount(store),\n features: features.on,\n featuresOff: features.off,\n embed: e ? { provider: e.provider, model: e.model, dir: e.provider === 'static' ? modelDir(e.model) : null, url: e.url ? redactUrl(e.url) : null, reachable, keyEnv, downloaded: hasModel, languages: declaredLanguages, detectedLanguages, ...(vectors ?? {}) } : null,\n presets,\n queries: Object.keys(cfg.queries ?? {}).length,\n watcherPid: await getMeta(store, 'watch_pid'),\n watcherHeartbeatSecondsAgo: heartbeat ? Math.round((Date.now() - Date.parse(heartbeat)) / 1000) : null,\n engine,\n };\n\n if (format === 'json') {\n console.log(stringifyJson(result, 2));\n } else {\n const migrated = cfg.migratedFrom !== undefined ? `, migrated from v${cfg.migratedFrom} on this run` : '';\n console.log(`config: ${result.config} (v${SUPPORTED_CONFIG_VERSION}${migrated})`);\n // A load-time stderr warning has scrolled away by the time anyone looks here.\n if (cfg.unknownKeys) console.log(` unknown keys, ignored: ${cfg.unknownKeys.join(', ')}`);\n console.log(`tree: ${result.tree}`);\n console.log(`cache: ${result.cache} (schema ${result.cacheSchema}; delete this directory to reset)`);\n console.log(`docs: ${result.docs}${result.unparseableFrontmatter > 0 ? ` (${result.unparseableFrontmatter} with unparseable frontmatter: WHERE _parse_error IS NOT NULL)` : ''}`);\n console.log('');\n console.log(featuresLine(features));\n // One authoritative block, off states included: an absent model reads as a degraded search,\n // not as an empty corpus.\n if (!e) console.log('embed: off (no preset asks for vectors)');\n else {\n console.log(`embed: ${e.provider} ${e.model}`);\n 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`}`})`);\n if (declaredLanguages) console.log(` languages: ${declaredLanguages.join(', ')} (declared by the model card)`);\n // Cohere defaults to api.cohere.com with no url in the config; show it anyway so the\n // reachability probe below has something to name.\n if (e.url || reachable !== null) {\n const shown = e.url ? redactUrl(e.url) : 'https://api.cohere.com (default)';\n console.log(` url: ${shown}${reachable === null ? '' : reachable ? ' (reachable)' : ' (unreachable)'}`);\n }\n if (keyEnv) console.log(` key: env ${keyEnv.name} (${keyEnv.set ? 'set' : 'NOT SET'})`);\n if (!hasModel) console.log(' vectors: off until the model is present; search runs on words and links');\n else if (vectors) console.log(` vectors: ${vectors.embedded} embedded, ${vectors.pending} pending (embedded on the first semantic search)`);\n if (detectedLanguages) {\n const total = Object.values(detectedLanguages).reduce((a, b) => a + b, 0);\n const breakdown = Object.entries(detectedLanguages)\n .sort((a, b) => b[1] - a[1])\n .map(([code, n]) => `${code} ${Math.round((n / total) * 100)}%`)\n .join(', ');\n console.log(` detected: ${breakdown} (${total} chunks classified)`);\n }\n }\n console.log('');\n for (const line of presetsLines(presets)) console.log(line);\n console.log('');\n console.log(`queries: ${result.queries} saved (${ctx.name} --list)`);\n const pid = result.watcherPid ? `pid ${result.watcherPid}, ` : '';\n console.log(result.watcherHeartbeatSecondsAgo === null ? 'watcher: none' : `watcher: ${pid}last heartbeat ${result.watcherHeartbeatSecondsAgo}s ago`);\n for (const [key, value] of Object.entries(result.engine)) console.log(`${`${store.name}:`.padEnd(10)}${key} ${value}`);\n }\n await store.close();\n};\nexport default status;\n"],"names":["dirname","presetCoverage","embedConfig","featureStates","SUPPORTED_CONFIG_VERSION","languageDistribution","probeReachable","isDownloadable","MODEL_FILENAMES","modelDir","modelPresent","readLanguages","featuresLine","presetsLines","stringifyJson","docCount","getMeta","openStore","USAGE","CONFIG","FORMAT","formatOf","parse","printWarnings","vectorState","store","stmt","prepare","get","parseErrorCount","n","redactUrl","url","parsed","URL","username","password","toString","replace","embedReachable","e","provider","base","status","ctx","process","cfg","values","argv","name","format","resolveConfig","config","dbPath","warnings","features","hasModel","reachable","vectors","presets","staticLanguages","model","undefined","declaredLanguages","length","detectedLanguages","heartbeat","cacheSchema","engine","engineStatus","keyEnv","key","set","env","result","configPath","configVersion","migratedFrom","unknownConfigKeys","unknownKeys","tree","baseDir","cache","db","docs","unparseableFrontmatter","on","featuresOff","off","embed","dir","downloaded","languages","queries","Object","keys","watcherPid","watcherHeartbeatSecondsAgo","Math","round","Date","now","console","log","migrated","join","shown","embedded","pending","total","reduce","a","b","breakdown","entries","sort","map","code","line","pid","value","padEnd","close"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { featureEnabled, featureStates } from '../config/index.js';
2
2
  import { INTERNAL_COLUMNS, scopedPaths, setupMapScope } from './scope.js';
3
3
  import { presetCoverage } from './status.js';
4
- // A result row is capped at SQLITE_MAX_COLUMN (2000, default); two aggregate expressions
5
- // per field keeps a chunk's row safely under that regardless of how many fields the tree has.
4
+ // A result row is capped at SQLITE_MAX_COLUMN (2000, default); two aggregate expressions per
5
+ // field keeps a chunk's row width safely under that regardless of how many fields the tree has.
6
6
  const MAP_COLUMN_CHUNK = 300;
7
7
  // "YYYY-MM-DD HH:MM:SS" UTC, the exact shape sqlite's datetime(ms / 1000, 'unixepoch') prints;
8
8
  // formatted in JS so the query stays dialect-free.
@@ -23,24 +23,12 @@ export async function mapTree(store, cfg, overrides = {}) {
23
23
  const scopeAnd = 'AND f."path" IN (SELECT "path" FROM _map_scope)';
24
24
  const docs = await (await store.prepare(`SELECT COUNT(*) AS count, COALESCE(SUM("_size"), 0) AS bytes FROM frontmatter ${scopeWhere}`)).get();
25
25
  const columns = (await store.docs.columns()).filter((name)=>!INTERNAL_COLUMNS.has(name));
26
- // Observed types, not declared: SQLite types per value, so a field can be text in most notes
27
- // and numeric in a few. One aggregate scan per chunk of columns; FILTER matches COUNT's nulls.
26
+ // Observed types, not declared: a field can be text in most notes and numeric in a few, so
27
+ // every distinct type observed across the scope is reported, not just the first. Aggregated
28
+ // in SQL, one query per chunk of columns (native-not-emulated: each store's fieldStats()
29
+ // classifies through its own engine mechanism but returns the same vocabulary).
28
30
  const allFields = [];
29
- for (const group of chunk(columns, MAP_COLUMN_CHUNK)){
30
- const exprs = group.map((name, i)=>{
31
- const quoted = `"${name.split('"').join('""')}"`;
32
- return `COUNT(${quoted}) AS n${i}, GROUP_CONCAT(DISTINCT typeof(${quoted})) FILTER (WHERE ${quoted} IS NOT NULL) AS t${i}`;
33
- });
34
- const result = await (await store.prepare(`SELECT ${exprs.join(', ')} FROM frontmatter ${scopeWhere}`)).get();
35
- group.forEach((name, i)=>{
36
- var _result_;
37
- return allFields.push({
38
- field: name,
39
- coverage: result[`n${i}`],
40
- type: (_result_ = result[`t${i}`]) !== null && _result_ !== void 0 ? _result_ : ''
41
- });
42
- });
43
- }
31
+ for (const group of chunk(columns, MAP_COLUMN_CHUNK))allFields.push(...await store.docs.fieldStats(group, scopeWhere));
44
32
  allFields.sort((a, b)=>b.coverage - a.coverage);
45
33
  const fields = allFields.slice(0, 20);
46
34
  const hubs = featureEnabled(cfg, 'rank') ? await (await store.prepare(`SELECT f."path" AS path, round(f."_rank" * 100, 2) AS rank, content.title FROM frontmatter f JOIN content ON content.path = f."path" WHERE f."_rank" IS NOT NULL ${scopeAnd} ORDER BY f."_rank" DESC LIMIT 8`)).all() : [];
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/map.ts"],"sourcesContent":["import type { FeatureName, ResolvedConfig, SearchOverrides } from '../config/index.ts';\nimport { featureEnabled, featureStates } from '../config/index.ts';\nimport type { Row } from '../output/output.ts';\nimport type { Store } from '../store/types.ts';\nimport { INTERNAL_COLUMNS, scopedPaths, setupMapScope } from './scope.ts';\nimport type { PresetCoverage } from './status.ts';\nimport { presetCoverage } from './status.ts';\n\nexport interface TreeMap {\n docs: { count: number; bytes: number };\n fields: Row[]; // top 20 by coverage; fieldsTotal carries the real count\n fieldsTotal: number;\n features: { on: FeatureName[]; off: FeatureName[] };\n presets: PresetCoverage[];\n hubs: Row[];\n recent: Row[];\n recentCaveat: string | null;\n}\n\n// A result row is capped at SQLITE_MAX_COLUMN (2000, default); two aggregate expressions\n// per field keeps a chunk's row safely under that regardless of how many fields the tree has.\nconst MAP_COLUMN_CHUNK = 300;\n\n// \"YYYY-MM-DD HH:MM:SS\" UTC, the exact shape sqlite's datetime(ms / 1000, 'unixepoch') prints;\n// formatted in JS so the query stays dialect-free.\nfunction utcSecond(ms: number): string {\n return new Date(ms).toISOString().slice(0, 19).replace('T', ' ');\n}\n\nfunction chunk<T>(items: T[], size: number): T[][] {\n const out: T[][] = [];\n for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));\n return out;\n}\n\n// What is this scope: fixed-size output regardless of tree size. Coverage and features stay\n// global -- they describe the tree, not the current question.\nexport async function mapTree(store: Store, cfg: ResolvedConfig, overrides: SearchOverrides = {}): Promise<TreeMap> {\n return store.transaction(async () => {\n await setupMapScope(store, await scopedPaths(store, cfg, overrides));\n const scopeWhere = 'WHERE \"path\" IN (SELECT \"path\" FROM _map_scope)';\n const scopeAnd = 'AND f.\"path\" IN (SELECT \"path\" FROM _map_scope)';\n\n const docs = (await (await store.prepare(`SELECT COUNT(*) AS count, COALESCE(SUM(\"_size\"), 0) AS bytes FROM frontmatter ${scopeWhere}`)).get()) as { count: number; bytes: number };\n\n const columns = (await store.docs.columns()).filter((name) => !INTERNAL_COLUMNS.has(name));\n // Observed types, not declared: SQLite types per value, so a field can be text in most notes\n // and numeric in a few. One aggregate scan per chunk of columns; FILTER matches COUNT's nulls.\n const allFields: Row[] = [];\n for (const group of chunk(columns, MAP_COLUMN_CHUNK)) {\n const exprs = group.map((name, i) => {\n const quoted = `\"${name.split('\"').join('\"\"')}\"`;\n return `COUNT(${quoted}) AS n${i}, GROUP_CONCAT(DISTINCT typeof(${quoted})) FILTER (WHERE ${quoted} IS NOT NULL) AS t${i}`;\n });\n const result = (await (await store.prepare(`SELECT ${exprs.join(', ')} FROM frontmatter ${scopeWhere}`)).get()) as Record<string, number | string | null>;\n group.forEach((name, i) => allFields.push({ field: name, coverage: result[`n${i}`] as number, type: (result[`t${i}`] as string) ?? '' }));\n }\n allFields.sort((a, b) => (b.coverage as number) - (a.coverage as number));\n const fields = allFields.slice(0, 20);\n\n const hubs = featureEnabled(cfg, 'rank') ? ((await (await store.prepare(`SELECT f.\"path\" AS path, round(f.\"_rank\" * 100, 2) AS rank, content.title FROM frontmatter f JOIN content ON content.path = f.\"path\" WHERE f.\"_rank\" IS NOT NULL ${scopeAnd} ORDER BY f.\"_rank\" DESC LIMIT 8`)).all()) as Row[]) : [];\n\n const recent = ((await (await store.prepare(`SELECT \"path\", \"_mtime\" AS mtime FROM frontmatter ${scopeWhere} ORDER BY \"_mtime\" DESC LIMIT 5`)).all()) as Array<{ path: string; mtime: number }>).map((r) => ({ path: r.path, modified: utcSecond(r.mtime) }));\n\n // A fresh clone/copy stamps files with checkout time, not edit history; second granularity\n // matches the `recent` table above and is coarse enough to catch that without an exact-ms match.\n const topSecond = (await (await store.prepare(`SELECT COUNT(*) AS n FROM frontmatter ${scopeWhere} GROUP BY CAST(\"_mtime\" / 1000 AS INTEGER) ORDER BY n DESC LIMIT 1`)).get()) as { n: number } | undefined;\n const recentCaveat = topSecond && docs.count > 1 && topSecond.n > docs.count / 2 ? `${topSecond.n} of ${docs.count} files share one modified second, so recency likely reflects a checkout or copy, not edit history` : null;\n\n return { docs, fields, fieldsTotal: allFields.length, features: featureStates(cfg), presets: await presetCoverage(store, cfg), hubs, recent, recentCaveat };\n });\n}\n"],"names":["featureEnabled","featureStates","INTERNAL_COLUMNS","scopedPaths","setupMapScope","presetCoverage","MAP_COLUMN_CHUNK","utcSecond","ms","Date","toISOString","slice","replace","chunk","items","size","out","i","length","push","mapTree","store","cfg","overrides","transaction","scopeWhere","scopeAnd","docs","prepare","get","columns","filter","name","has","allFields","group","exprs","map","quoted","split","join","result","forEach","field","coverage","type","sort","a","b","fields","hubs","all","recent","r","path","modified","mtime","topSecond","recentCaveat","count","n","fieldsTotal","features","presets"],"mappings":"AACA,SAASA,cAAc,EAAEC,aAAa,QAAQ,qBAAqB;AAGnE,SAASC,gBAAgB,EAAEC,WAAW,EAAEC,aAAa,QAAQ,aAAa;AAE1E,SAASC,cAAc,QAAQ,cAAc;AAa7C,yFAAyF;AACzF,8FAA8F;AAC9F,MAAMC,mBAAmB;AAEzB,+FAA+F;AAC/F,mDAAmD;AACnD,SAASC,UAAUC,EAAU;IAC3B,OAAO,IAAIC,KAAKD,IAAIE,WAAW,GAAGC,KAAK,CAAC,GAAG,IAAIC,OAAO,CAAC,KAAK;AAC9D;AAEA,SAASC,MAASC,KAAU,EAAEC,IAAY;IACxC,MAAMC,MAAa,EAAE;IACrB,IAAK,IAAIC,IAAI,GAAGA,IAAIH,MAAMI,MAAM,EAAED,KAAKF,KAAMC,IAAIG,IAAI,CAACL,MAAMH,KAAK,CAACM,GAAGA,IAAIF;IACzE,OAAOC;AACT;AAEA,4FAA4F;AAC5F,8DAA8D;AAC9D,OAAO,eAAeI,QAAQC,KAAY,EAAEC,GAAmB,EAAEC,YAA6B,CAAC,CAAC;IAC9F,OAAOF,MAAMG,WAAW,CAAC;QACvB,MAAMpB,cAAciB,OAAO,MAAMlB,YAAYkB,OAAOC,KAAKC;QACzD,MAAME,aAAa;QACnB,MAAMC,WAAW;QAEjB,MAAMC,OAAQ,MAAM,AAAC,CAAA,MAAMN,MAAMO,OAAO,CAAC,CAAC,8EAA8E,EAAEH,YAAY,CAAA,EAAGI,GAAG;QAE5I,MAAMC,UAAU,AAAC,CAAA,MAAMT,MAAMM,IAAI,CAACG,OAAO,EAAC,EAAGC,MAAM,CAAC,CAACC,OAAS,CAAC9B,iBAAiB+B,GAAG,CAACD;QACpF,6FAA6F;QAC7F,+FAA+F;QAC/F,MAAME,YAAmB,EAAE;QAC3B,KAAK,MAAMC,SAAStB,MAAMiB,SAASxB,kBAAmB;YACpD,MAAM8B,QAAQD,MAAME,GAAG,CAAC,CAACL,MAAMf;gBAC7B,MAAMqB,SAAS,CAAC,CAAC,EAAEN,KAAKO,KAAK,CAAC,KAAKC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAChD,OAAO,CAAC,MAAM,EAAEF,OAAO,MAAM,EAAErB,EAAE,+BAA+B,EAAEqB,OAAO,iBAAiB,EAAEA,OAAO,kBAAkB,EAAErB,GAAG;YAC5H;YACA,MAAMwB,SAAU,MAAM,AAAC,CAAA,MAAMpB,MAAMO,OAAO,CAAC,CAAC,OAAO,EAAEQ,MAAMI,IAAI,CAAC,MAAM,kBAAkB,EAAEf,YAAY,CAAA,EAAGI,GAAG;YAC5GM,MAAMO,OAAO,CAAC,CAACV,MAAMf;oBAAgFwB;uBAA1EP,UAAUf,IAAI,CAAC;oBAAEwB,OAAOX;oBAAMY,UAAUH,MAAM,CAAC,CAAC,CAAC,EAAExB,GAAG,CAAC;oBAAY4B,IAAI,GAAGJ,WAAAA,MAAM,CAAC,CAAC,CAAC,EAAExB,GAAG,CAAC,cAAfwB,sBAAAA,WAA8B;gBAAG;;QACxI;QACAP,UAAUY,IAAI,CAAC,CAACC,GAAGC,IAAM,AAACA,EAAEJ,QAAQ,GAAeG,EAAEH,QAAQ;QAC7D,MAAMK,SAASf,UAAUvB,KAAK,CAAC,GAAG;QAElC,MAAMuC,OAAOlD,eAAesB,KAAK,UAAY,MAAM,AAAC,CAAA,MAAMD,MAAMO,OAAO,CAAC,CAAC,iKAAiK,EAAEF,SAAS,gCAAgC,CAAC,CAAA,EAAGyB,GAAG,KAAgB,EAAE;QAE9S,MAAMC,SAAS,AAAE,CAAA,MAAM,AAAC,CAAA,MAAM/B,MAAMO,OAAO,CAAC,CAAC,kDAAkD,EAAEH,WAAW,+BAA+B,CAAC,CAAA,EAAG0B,GAAG,EAAC,EAA8Cd,GAAG,CAAC,CAACgB,IAAO,CAAA;gBAAEC,MAAMD,EAAEC,IAAI;gBAAEC,UAAUhD,UAAU8C,EAAEG,KAAK;YAAE,CAAA;QAE1P,2FAA2F;QAC3F,iGAAiG;QACjG,MAAMC,YAAa,MAAM,AAAC,CAAA,MAAMpC,MAAMO,OAAO,CAAC,CAAC,sCAAsC,EAAEH,WAAW,kEAAkE,CAAC,CAAA,EAAGI,GAAG;QAC3K,MAAM6B,eAAeD,aAAa9B,KAAKgC,KAAK,GAAG,KAAKF,UAAUG,CAAC,GAAGjC,KAAKgC,KAAK,GAAG,IAAI,GAAGF,UAAUG,CAAC,CAAC,IAAI,EAAEjC,KAAKgC,KAAK,CAAC,iGAAiG,CAAC,GAAG;QAExN,OAAO;YAAEhC;YAAMsB;YAAQY,aAAa3B,UAAUhB,MAAM;YAAE4C,UAAU7D,cAAcqB;YAAMyC,SAAS,MAAM1D,eAAegB,OAAOC;YAAM4B;YAAME;YAAQM;QAAa;IAC5J;AACF"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/commands/map.ts"],"sourcesContent":["import type { FeatureName, ResolvedConfig, SearchOverrides } from '../config/index.ts';\nimport { featureEnabled, featureStates } from '../config/index.ts';\nimport type { Row } from '../output/output.ts';\nimport type { FieldStat, Store } from '../store/types.ts';\nimport { INTERNAL_COLUMNS, scopedPaths, setupMapScope } from './scope.ts';\nimport type { PresetCoverage } from './status.ts';\nimport { presetCoverage } from './status.ts';\n\nexport interface TreeMap {\n docs: { count: number; bytes: number };\n fields: Row[]; // top 20 by coverage; fieldsTotal carries the real count\n fieldsTotal: number;\n features: { on: FeatureName[]; off: FeatureName[] };\n presets: PresetCoverage[];\n hubs: Row[];\n recent: Row[];\n recentCaveat: string | null;\n}\n\n// A result row is capped at SQLITE_MAX_COLUMN (2000, default); two aggregate expressions per\n// field keeps a chunk's row width safely under that regardless of how many fields the tree has.\nconst MAP_COLUMN_CHUNK = 300;\n\n// \"YYYY-MM-DD HH:MM:SS\" UTC, the exact shape sqlite's datetime(ms / 1000, 'unixepoch') prints;\n// formatted in JS so the query stays dialect-free.\nfunction utcSecond(ms: number): string {\n return new Date(ms).toISOString().slice(0, 19).replace('T', ' ');\n}\n\nfunction chunk<T>(items: T[], size: number): T[][] {\n const out: T[][] = [];\n for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));\n return out;\n}\n\n// What is this scope: fixed-size output regardless of tree size. Coverage and features stay\n// global -- they describe the tree, not the current question.\nexport async function mapTree(store: Store, cfg: ResolvedConfig, overrides: SearchOverrides = {}): Promise<TreeMap> {\n return store.transaction(async () => {\n await setupMapScope(store, await scopedPaths(store, cfg, overrides));\n const scopeWhere = 'WHERE \"path\" IN (SELECT \"path\" FROM _map_scope)';\n const scopeAnd = 'AND f.\"path\" IN (SELECT \"path\" FROM _map_scope)';\n\n const docs = (await (await store.prepare(`SELECT COUNT(*) AS count, COALESCE(SUM(\"_size\"), 0) AS bytes FROM frontmatter ${scopeWhere}`)).get()) as { count: number; bytes: number };\n\n const columns = (await store.docs.columns()).filter((name) => !INTERNAL_COLUMNS.has(name));\n // Observed types, not declared: a field can be text in most notes and numeric in a few, so\n // every distinct type observed across the scope is reported, not just the first. Aggregated\n // in SQL, one query per chunk of columns (native-not-emulated: each store's fieldStats()\n // classifies through its own engine mechanism but returns the same vocabulary).\n const allFields: FieldStat[] = [];\n for (const group of chunk(columns, MAP_COLUMN_CHUNK)) allFields.push(...(await store.docs.fieldStats(group, scopeWhere)));\n allFields.sort((a, b) => b.coverage - a.coverage);\n const fields = allFields.slice(0, 20) as unknown as Row[];\n\n const hubs = featureEnabled(cfg, 'rank') ? ((await (await store.prepare(`SELECT f.\"path\" AS path, round(f.\"_rank\" * 100, 2) AS rank, content.title FROM frontmatter f JOIN content ON content.path = f.\"path\" WHERE f.\"_rank\" IS NOT NULL ${scopeAnd} ORDER BY f.\"_rank\" DESC LIMIT 8`)).all()) as Row[]) : [];\n\n const recent = ((await (await store.prepare(`SELECT \"path\", \"_mtime\" AS mtime FROM frontmatter ${scopeWhere} ORDER BY \"_mtime\" DESC LIMIT 5`)).all()) as Array<{ path: string; mtime: number }>).map((r) => ({ path: r.path, modified: utcSecond(r.mtime) }));\n\n // A fresh clone/copy stamps files with checkout time, not edit history; second granularity\n // matches the `recent` table above and is coarse enough to catch that without an exact-ms match.\n const topSecond = (await (await store.prepare(`SELECT COUNT(*) AS n FROM frontmatter ${scopeWhere} GROUP BY CAST(\"_mtime\" / 1000 AS INTEGER) ORDER BY n DESC LIMIT 1`)).get()) as { n: number } | undefined;\n const recentCaveat = topSecond && docs.count > 1 && topSecond.n > docs.count / 2 ? `${topSecond.n} of ${docs.count} files share one modified second, so recency likely reflects a checkout or copy, not edit history` : null;\n\n return { docs, fields, fieldsTotal: allFields.length, features: featureStates(cfg), presets: await presetCoverage(store, cfg), hubs, recent, recentCaveat };\n });\n}\n"],"names":["featureEnabled","featureStates","INTERNAL_COLUMNS","scopedPaths","setupMapScope","presetCoverage","MAP_COLUMN_CHUNK","utcSecond","ms","Date","toISOString","slice","replace","chunk","items","size","out","i","length","push","mapTree","store","cfg","overrides","transaction","scopeWhere","scopeAnd","docs","prepare","get","columns","filter","name","has","allFields","group","fieldStats","sort","a","b","coverage","fields","hubs","all","recent","map","r","path","modified","mtime","topSecond","recentCaveat","count","n","fieldsTotal","features","presets"],"mappings":"AACA,SAASA,cAAc,EAAEC,aAAa,QAAQ,qBAAqB;AAGnE,SAASC,gBAAgB,EAAEC,WAAW,EAAEC,aAAa,QAAQ,aAAa;AAE1E,SAASC,cAAc,QAAQ,cAAc;AAa7C,6FAA6F;AAC7F,gGAAgG;AAChG,MAAMC,mBAAmB;AAEzB,+FAA+F;AAC/F,mDAAmD;AACnD,SAASC,UAAUC,EAAU;IAC3B,OAAO,IAAIC,KAAKD,IAAIE,WAAW,GAAGC,KAAK,CAAC,GAAG,IAAIC,OAAO,CAAC,KAAK;AAC9D;AAEA,SAASC,MAASC,KAAU,EAAEC,IAAY;IACxC,MAAMC,MAAa,EAAE;IACrB,IAAK,IAAIC,IAAI,GAAGA,IAAIH,MAAMI,MAAM,EAAED,KAAKF,KAAMC,IAAIG,IAAI,CAACL,MAAMH,KAAK,CAACM,GAAGA,IAAIF;IACzE,OAAOC;AACT;AAEA,4FAA4F;AAC5F,8DAA8D;AAC9D,OAAO,eAAeI,QAAQC,KAAY,EAAEC,GAAmB,EAAEC,YAA6B,CAAC,CAAC;IAC9F,OAAOF,MAAMG,WAAW,CAAC;QACvB,MAAMpB,cAAciB,OAAO,MAAMlB,YAAYkB,OAAOC,KAAKC;QACzD,MAAME,aAAa;QACnB,MAAMC,WAAW;QAEjB,MAAMC,OAAQ,MAAM,AAAC,CAAA,MAAMN,MAAMO,OAAO,CAAC,CAAC,8EAA8E,EAAEH,YAAY,CAAA,EAAGI,GAAG;QAE5I,MAAMC,UAAU,AAAC,CAAA,MAAMT,MAAMM,IAAI,CAACG,OAAO,EAAC,EAAGC,MAAM,CAAC,CAACC,OAAS,CAAC9B,iBAAiB+B,GAAG,CAACD;QACpF,2FAA2F;QAC3F,4FAA4F;QAC5F,yFAAyF;QACzF,gFAAgF;QAChF,MAAME,YAAyB,EAAE;QACjC,KAAK,MAAMC,SAAStB,MAAMiB,SAASxB,kBAAmB4B,UAAUf,IAAI,IAAK,MAAME,MAAMM,IAAI,CAACS,UAAU,CAACD,OAAOV;QAC5GS,UAAUG,IAAI,CAAC,CAACC,GAAGC,IAAMA,EAAEC,QAAQ,GAAGF,EAAEE,QAAQ;QAChD,MAAMC,SAASP,UAAUvB,KAAK,CAAC,GAAG;QAElC,MAAM+B,OAAO1C,eAAesB,KAAK,UAAY,MAAM,AAAC,CAAA,MAAMD,MAAMO,OAAO,CAAC,CAAC,iKAAiK,EAAEF,SAAS,gCAAgC,CAAC,CAAA,EAAGiB,GAAG,KAAgB,EAAE;QAE9S,MAAMC,SAAS,AAAE,CAAA,MAAM,AAAC,CAAA,MAAMvB,MAAMO,OAAO,CAAC,CAAC,kDAAkD,EAAEH,WAAW,+BAA+B,CAAC,CAAA,EAAGkB,GAAG,EAAC,EAA8CE,GAAG,CAAC,CAACC,IAAO,CAAA;gBAAEC,MAAMD,EAAEC,IAAI;gBAAEC,UAAUzC,UAAUuC,EAAEG,KAAK;YAAE,CAAA;QAE1P,2FAA2F;QAC3F,iGAAiG;QACjG,MAAMC,YAAa,MAAM,AAAC,CAAA,MAAM7B,MAAMO,OAAO,CAAC,CAAC,sCAAsC,EAAEH,WAAW,kEAAkE,CAAC,CAAA,EAAGI,GAAG;QAC3K,MAAMsB,eAAeD,aAAavB,KAAKyB,KAAK,GAAG,KAAKF,UAAUG,CAAC,GAAG1B,KAAKyB,KAAK,GAAG,IAAI,GAAGF,UAAUG,CAAC,CAAC,IAAI,EAAE1B,KAAKyB,KAAK,CAAC,iGAAiG,CAAC,GAAG;QAExN,OAAO;YAAEzB;YAAMc;YAAQa,aAAapB,UAAUhB,MAAM;YAAEqC,UAAUtD,cAAcqB;YAAMkC,SAAS,MAAMnD,eAAegB,OAAOC;YAAMoB;YAAME;YAAQO;QAAa;IAC5J;AACF"}
@@ -1,8 +1,8 @@
1
1
  import type { Feature } from '../features/types.js';
2
2
  import type { SignalName, SignalWeights } from './signals.js';
3
- import { type Config, type FeatureName } from './types.js';
3
+ import { type Config, type FeatureName, type StoreName } from './types.js';
4
4
  export declare function presetNames(cfg: Config): string[];
5
- export declare function storeName(cfg: Config): 'sqlite' | 'duckdb';
5
+ export declare function storeName(cfg: Config): StoreName;
6
6
  export declare function embedEnabled(cfg: Config): boolean;
7
7
  export declare function presetSignals(cfg: Config, name: string): SignalWeights;
8
8
  export declare function presetHasSignal(cfg: Config, name: string, signal: SignalName): boolean;