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.
- package/dist/cjs/cli/status.js +32 -31
- package/dist/cjs/cli/status.js.map +1 -1
- package/dist/cjs/commands/map.js +50 -67
- package/dist/cjs/commands/map.js.map +1 -1
- package/dist/cjs/config/access.d.cts +2 -2
- package/dist/cjs/config/access.d.ts +2 -2
- package/dist/cjs/config/access.js.map +1 -1
- package/dist/cjs/config/index.d.cts +1 -1
- package/dist/cjs/config/index.d.ts +1 -1
- package/dist/cjs/config/index.js.map +1 -1
- package/dist/cjs/config/load.js +3 -2
- package/dist/cjs/config/load.js.map +1 -1
- package/dist/cjs/config/types.d.cts +2 -1
- package/dist/cjs/config/types.d.ts +2 -1
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/config/validate.js +3 -0
- package/dist/cjs/config/validate.js.map +1 -1
- package/dist/cjs/embed/identity.js +3 -2
- package/dist/cjs/embed/identity.js.map +1 -1
- package/dist/cjs/embed/store.js +3 -3
- package/dist/cjs/embed/store.js.map +1 -1
- package/dist/cjs/index.d.cts +2 -2
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/atomic-write.d.cts +1 -0
- package/dist/cjs/lib/atomic-write.d.ts +1 -0
- package/dist/cjs/lib/atomic-write.js +26 -0
- package/dist/cjs/lib/atomic-write.js.map +1 -0
- package/dist/cjs/store/duckdb/batch.js +3 -2
- package/dist/cjs/store/duckdb/batch.js.map +1 -1
- package/dist/cjs/store/duckdb/connection.js +12 -0
- package/dist/cjs/store/duckdb/connection.js.map +1 -1
- package/dist/cjs/store/duckdb/fieldStats.d.cts +2 -0
- package/dist/cjs/store/duckdb/fieldStats.d.ts +2 -0
- package/dist/cjs/store/duckdb/fieldStats.js +219 -0
- package/dist/cjs/store/duckdb/fieldStats.js.map +1 -0
- package/dist/cjs/store/duckdb/lexical.js +3 -2
- package/dist/cjs/store/duckdb/lexical.js.map +1 -1
- package/dist/cjs/store/duckdb/native.d.cts +0 -1
- package/dist/cjs/store/duckdb/native.d.ts +0 -1
- package/dist/cjs/store/duckdb/native.js +7 -336
- package/dist/cjs/store/duckdb/native.js.map +1 -1
- package/dist/cjs/store/duckdb/sql-functions.js +1 -1
- package/dist/cjs/store/duckdb/sql-functions.js.map +1 -1
- package/dist/cjs/store/duckdb/store.js +16 -1
- package/dist/cjs/store/duckdb/store.js.map +1 -1
- package/dist/cjs/store/duckdb/vectors.js +5 -17
- package/dist/cjs/store/duckdb/vectors.js.map +1 -1
- package/dist/cjs/store/index.js +6 -0
- package/dist/cjs/store/index.js.map +1 -1
- package/dist/cjs/store/native.d.cts +7 -0
- package/dist/cjs/store/native.d.ts +7 -0
- package/dist/cjs/store/native.js +350 -0
- package/dist/cjs/store/native.js.map +1 -0
- package/dist/cjs/store/sqlite/fieldStats.d.cts +2 -0
- package/dist/cjs/store/sqlite/fieldStats.d.ts +2 -0
- package/dist/cjs/store/sqlite/fieldStats.js +201 -0
- package/dist/cjs/store/sqlite/fieldStats.js.map +1 -0
- package/dist/cjs/store/sqlite/open.js +82 -29
- package/dist/cjs/store/sqlite/open.js.map +1 -1
- package/dist/cjs/store/sqlite/store.js +32 -4
- package/dist/cjs/store/sqlite/store.js.map +1 -1
- package/dist/cjs/store/sqlite/vectors.d.cts +0 -5
- package/dist/cjs/store/sqlite/vectors.d.ts +0 -5
- package/dist/cjs/store/sqlite/vectors.js +5 -71
- package/dist/cjs/store/sqlite/vectors.js.map +1 -1
- package/dist/cjs/store/turso/connection.d.cts +3 -0
- package/dist/cjs/store/turso/connection.d.ts +3 -0
- package/dist/cjs/store/turso/connection.js +529 -0
- package/dist/cjs/store/turso/connection.js.map +1 -0
- package/dist/cjs/store/turso/fieldStats.d.cts +2 -0
- package/dist/cjs/store/turso/fieldStats.d.ts +2 -0
- package/dist/cjs/store/turso/fieldStats.js +201 -0
- package/dist/cjs/store/turso/fieldStats.js.map +1 -0
- package/dist/cjs/store/turso/native.d.cts +2 -0
- package/dist/cjs/store/turso/native.d.ts +2 -0
- package/dist/cjs/store/turso/native.js +31 -0
- package/dist/cjs/store/turso/native.js.map +1 -0
- package/dist/cjs/store/turso/open.d.cts +12 -0
- package/dist/cjs/store/turso/open.d.ts +12 -0
- package/dist/cjs/store/turso/open.js +500 -0
- package/dist/cjs/store/turso/open.js.map +1 -0
- package/dist/cjs/store/turso/reconcile.d.cts +6 -0
- package/dist/cjs/store/turso/reconcile.d.ts +6 -0
- package/dist/cjs/store/turso/reconcile.js +793 -0
- package/dist/cjs/store/turso/reconcile.js.map +1 -0
- package/dist/cjs/store/turso/store.d.cts +5 -0
- package/dist/cjs/store/turso/store.d.ts +5 -0
- package/dist/cjs/store/turso/store.js +609 -0
- package/dist/cjs/store/turso/store.js.map +1 -0
- package/dist/cjs/store/types.d.cts +9 -1
- package/dist/cjs/store/types.d.ts +9 -1
- package/dist/cjs/store/types.js +0 -7
- package/dist/cjs/store/types.js.map +1 -1
- package/dist/cjs/store/vectors.d.cts +9 -0
- package/dist/cjs/store/vectors.d.ts +9 -0
- package/dist/cjs/store/vectors.js +215 -0
- package/dist/cjs/store/vectors.js.map +1 -0
- package/dist/esm/cli/status.js +5 -7
- package/dist/esm/cli/status.js.map +1 -1
- package/dist/esm/commands/map.js +7 -19
- package/dist/esm/commands/map.js.map +1 -1
- package/dist/esm/config/access.d.ts +2 -2
- package/dist/esm/config/access.js.map +1 -1
- package/dist/esm/config/index.d.ts +1 -1
- package/dist/esm/config/index.js.map +1 -1
- package/dist/esm/config/load.js +4 -3
- package/dist/esm/config/load.js.map +1 -1
- package/dist/esm/config/types.d.ts +2 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/config/validate.js +3 -0
- package/dist/esm/config/validate.js.map +1 -1
- package/dist/esm/embed/identity.js +4 -3
- package/dist/esm/embed/identity.js.map +1 -1
- package/dist/esm/embed/store.js +3 -3
- package/dist/esm/embed/store.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/atomic-write.d.ts +1 -0
- package/dist/esm/lib/atomic-write.js +17 -0
- package/dist/esm/lib/atomic-write.js.map +1 -0
- package/dist/esm/store/duckdb/batch.js +3 -2
- package/dist/esm/store/duckdb/batch.js.map +1 -1
- package/dist/esm/store/duckdb/connection.js +12 -0
- package/dist/esm/store/duckdb/connection.js.map +1 -1
- package/dist/esm/store/duckdb/fieldStats.d.ts +2 -0
- package/dist/esm/store/duckdb/fieldStats.js +39 -0
- package/dist/esm/store/duckdb/fieldStats.js.map +1 -0
- package/dist/esm/store/duckdb/lexical.js +3 -2
- package/dist/esm/store/duckdb/lexical.js.map +1 -1
- package/dist/esm/store/duckdb/native.d.ts +0 -1
- package/dist/esm/store/duckdb/native.js +7 -84
- package/dist/esm/store/duckdb/native.js.map +1 -1
- package/dist/esm/store/duckdb/sql-functions.js +1 -1
- package/dist/esm/store/duckdb/sql-functions.js.map +1 -1
- package/dist/esm/store/duckdb/store.js +8 -5
- package/dist/esm/store/duckdb/store.js.map +1 -1
- package/dist/esm/store/duckdb/vectors.js +2 -12
- package/dist/esm/store/duckdb/vectors.js.map +1 -1
- package/dist/esm/store/index.js +6 -0
- package/dist/esm/store/index.js.map +1 -1
- package/dist/esm/store/native.d.ts +7 -0
- package/dist/esm/store/native.js +83 -0
- package/dist/esm/store/native.js.map +1 -0
- package/dist/esm/store/sqlite/fieldStats.d.ts +2 -0
- package/dist/esm/store/sqlite/fieldStats.js +25 -0
- package/dist/esm/store/sqlite/fieldStats.js.map +1 -0
- package/dist/esm/store/sqlite/open.js +21 -8
- package/dist/esm/store/sqlite/open.js.map +1 -1
- package/dist/esm/store/sqlite/store.js +14 -1
- package/dist/esm/store/sqlite/store.js.map +1 -1
- package/dist/esm/store/sqlite/vectors.d.ts +0 -5
- package/dist/esm/store/sqlite/vectors.js +2 -22
- package/dist/esm/store/sqlite/vectors.js.map +1 -1
- package/dist/esm/store/turso/connection.d.ts +3 -0
- package/dist/esm/store/turso/connection.js +52 -0
- package/dist/esm/store/turso/connection.js.map +1 -0
- package/dist/esm/store/turso/fieldStats.d.ts +2 -0
- package/dist/esm/store/turso/fieldStats.js +24 -0
- package/dist/esm/store/turso/fieldStats.js.map +1 -0
- package/dist/esm/store/turso/native.d.ts +2 -0
- package/dist/esm/store/turso/native.js +19 -0
- package/dist/esm/store/turso/native.js.map +1 -0
- package/dist/esm/store/turso/open.d.ts +12 -0
- package/dist/esm/store/turso/open.js +113 -0
- package/dist/esm/store/turso/open.js.map +1 -0
- package/dist/esm/store/turso/reconcile.d.ts +6 -0
- package/dist/esm/store/turso/reconcile.js +158 -0
- package/dist/esm/store/turso/reconcile.js.map +1 -0
- package/dist/esm/store/turso/store.d.ts +5 -0
- package/dist/esm/store/turso/store.js +93 -0
- package/dist/esm/store/turso/store.js.map +1 -0
- package/dist/esm/store/types.d.ts +9 -1
- package/dist/esm/store/types.js +0 -7
- package/dist/esm/store/types.js.map +1 -1
- package/dist/esm/store/vectors.d.ts +9 -0
- package/dist/esm/store/vectors.js +26 -0
- package/dist/esm/store/vectors.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { SenseError } from '../../errors.js';
|
|
2
|
+
import { getColumns } from '../shared.js';
|
|
3
|
+
import { withTransaction } from '../transaction.js';
|
|
4
|
+
import { hasVectorRow, pendingRows } from '../vectors.js';
|
|
5
|
+
import { fieldStats } from './fieldStats.js';
|
|
6
|
+
import { reconcile } from './reconcile.js';
|
|
7
|
+
// Phase 1: the portable surface only -- frontmatter, links, sections, tags, rank, raw SQL,
|
|
8
|
+
// reconcile, transactions. Neither lexical (Tantivy FTS) nor vectors (native vector_distance_cos
|
|
9
|
+
// scans) is claimed yet -- phase 2 and phase 3 of the plan add them -- so lexical.query() and the
|
|
10
|
+
// vector-math methods throw the named capability error rather than answer differently.
|
|
11
|
+
// pending()/hasVector() are plain IS NULL/IS NOT NULL checks with no engine-specific math, so
|
|
12
|
+
// they're wired through the same store-agnostic helpers duckdb's store.ts reuses: harmless ahead
|
|
13
|
+
// of phase 3 (unreachable in practice, since openStore() already rejects a turso tree whose
|
|
14
|
+
// config uses vectors) and correct with no further change once vectors land.
|
|
15
|
+
export const CAPABILITIES = new Set();
|
|
16
|
+
function missing(name) {
|
|
17
|
+
throw new SenseError('STORE_CAPABILITY_MISSING', `store "turso" does not implement "${name}" in this build; set "store" to "sqlite" or "duckdb" in this tree's config`);
|
|
18
|
+
}
|
|
19
|
+
// Shares one Connection instance (conn) with open()'s own reconcile call so transaction depth
|
|
20
|
+
// (see transaction.ts) is tracked against the same object everywhere.
|
|
21
|
+
export function createStore(db, conn, cfg, baseDir) {
|
|
22
|
+
return {
|
|
23
|
+
name: 'turso',
|
|
24
|
+
capabilities: CAPABILITIES,
|
|
25
|
+
async exec (sql) {
|
|
26
|
+
await conn.exec(sql);
|
|
27
|
+
},
|
|
28
|
+
async prepare (sql) {
|
|
29
|
+
return conn.prepare(sql);
|
|
30
|
+
},
|
|
31
|
+
async runBatch (sql, paramRows) {
|
|
32
|
+
await conn.runBatch(sql, paramRows);
|
|
33
|
+
},
|
|
34
|
+
async transaction (fn) {
|
|
35
|
+
return withTransaction(conn, fn);
|
|
36
|
+
},
|
|
37
|
+
async reconcile () {
|
|
38
|
+
return reconcile(conn, cfg, baseDir);
|
|
39
|
+
},
|
|
40
|
+
docs: {
|
|
41
|
+
async columns () {
|
|
42
|
+
return [
|
|
43
|
+
...await getColumns(conn)
|
|
44
|
+
];
|
|
45
|
+
},
|
|
46
|
+
fieldStats: (columns, scopeWhere)=>fieldStats(conn, columns, scopeWhere)
|
|
47
|
+
},
|
|
48
|
+
lexical: {
|
|
49
|
+
async query () {
|
|
50
|
+
return missing('lexical');
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
vectors: {
|
|
54
|
+
pending: ()=>pendingRows(conn),
|
|
55
|
+
async writeVectors () {
|
|
56
|
+
return missing('vectors');
|
|
57
|
+
},
|
|
58
|
+
async candidates () {
|
|
59
|
+
return missing('vectors');
|
|
60
|
+
},
|
|
61
|
+
async similar () {
|
|
62
|
+
return missing('vectors');
|
|
63
|
+
},
|
|
64
|
+
hasVector: (path)=>hasVectorRow(conn, path)
|
|
65
|
+
},
|
|
66
|
+
async engineStatus () {
|
|
67
|
+
// Read back rather than recomputed: this is what open() actually set (3x the largest
|
|
68
|
+
// recorded reconcile, floored at 30s, capped at 10min), not a value re-derived here.
|
|
69
|
+
// Turso's raw PRAGMA busy_timeout names its result column "busy_timeout" (spike-verified),
|
|
70
|
+
// not "timeout" like real SQLite's own quirky column name for this one pragma.
|
|
71
|
+
const row = await (await db.prepare('PRAGMA busy_timeout')).get();
|
|
72
|
+
return {
|
|
73
|
+
busy_timeout: `${row.busy_timeout}ms (derived: 3x the largest reconcile this cache has recorded, floored at 30000ms)`
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
raw: {
|
|
77
|
+
async prepare (sql) {
|
|
78
|
+
const stmt = await db.prepare(sql);
|
|
79
|
+
stmt.safeIntegers(true); // int64 past 2^53 arrives as BigInt instead of losing precision
|
|
80
|
+
return {
|
|
81
|
+
columns: ()=>stmt.columns(),
|
|
82
|
+
// sense sql streams through the client's own async generator.
|
|
83
|
+
iterate: async function*(...params) {
|
|
84
|
+
yield* stmt.iterate(...params);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
async close () {
|
|
90
|
+
await db.close();
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/turso/store.ts"],"sourcesContent":["import type { Database } from '@tursodatabase/database';\nimport type { Config } from '../../config/index.ts';\nimport { SenseError } from '../../errors.ts';\nimport { getColumns } from '../shared.ts';\nimport { withTransaction } from '../transaction.ts';\nimport type { Capability, Connection, Statement, Store } from '../types.ts';\nimport { hasVectorRow, pendingRows } from '../vectors.ts';\nimport { fieldStats } from './fieldStats.ts';\nimport { reconcile } from './reconcile.ts';\n\n// Phase 1: the portable surface only -- frontmatter, links, sections, tags, rank, raw SQL,\n// reconcile, transactions. Neither lexical (Tantivy FTS) nor vectors (native vector_distance_cos\n// scans) is claimed yet -- phase 2 and phase 3 of the plan add them -- so lexical.query() and the\n// vector-math methods throw the named capability error rather than answer differently.\n// pending()/hasVector() are plain IS NULL/IS NOT NULL checks with no engine-specific math, so\n// they're wired through the same store-agnostic helpers duckdb's store.ts reuses: harmless ahead\n// of phase 3 (unreachable in practice, since openStore() already rejects a turso tree whose\n// config uses vectors) and correct with no further change once vectors land.\nexport const CAPABILITIES: ReadonlySet<Capability> = new Set();\n\nfunction missing(name: 'lexical' | 'vectors'): never {\n throw new SenseError('STORE_CAPABILITY_MISSING', `store \"turso\" does not implement \"${name}\" in this build; set \"store\" to \"sqlite\" or \"duckdb\" in this tree's config`);\n}\n\n// Shares one Connection instance (conn) with open()'s own reconcile call so transaction depth\n// (see transaction.ts) is tracked against the same object everywhere.\nexport function createStore(db: Database, conn: Connection, cfg: Config, baseDir: string): Store {\n return {\n name: 'turso',\n capabilities: CAPABILITIES,\n async exec(sql: string): Promise<void> {\n await conn.exec(sql);\n },\n async prepare(sql: string): Promise<Statement> {\n return conn.prepare(sql);\n },\n async runBatch(sql: string, paramRows: unknown[][]): Promise<void> {\n await conn.runBatch(sql, paramRows);\n },\n async transaction<T>(fn: () => Promise<T>): Promise<T> {\n return withTransaction(conn, fn);\n },\n async reconcile() {\n return reconcile(conn, cfg, baseDir);\n },\n docs: {\n async columns() {\n return [...(await getColumns(conn))];\n },\n fieldStats: (columns, scopeWhere) => fieldStats(conn, columns, scopeWhere),\n },\n lexical: {\n async query() {\n return missing('lexical');\n },\n },\n vectors: {\n pending: () => pendingRows(conn),\n async writeVectors() {\n return missing('vectors');\n },\n async candidates() {\n return missing('vectors');\n },\n async similar() {\n return missing('vectors');\n },\n hasVector: (path) => hasVectorRow(conn, path),\n },\n async engineStatus() {\n // Read back rather than recomputed: this is what open() actually set (3x the largest\n // recorded reconcile, floored at 30s, capped at 10min), not a value re-derived here.\n // Turso's raw PRAGMA busy_timeout names its result column \"busy_timeout\" (spike-verified),\n // not \"timeout\" like real SQLite's own quirky column name for this one pragma.\n const row = (await (await db.prepare('PRAGMA busy_timeout')).get()) as { busy_timeout: number };\n return { busy_timeout: `${row.busy_timeout}ms (derived: 3x the largest reconcile this cache has recorded, floored at 30000ms)` };\n },\n raw: {\n async prepare(sql: string) {\n const stmt = await db.prepare(sql);\n stmt.safeIntegers(true); // int64 past 2^53 arrives as BigInt instead of losing precision\n return {\n columns: () => stmt.columns(),\n // sense sql streams through the client's own async generator.\n iterate: async function* (...params: unknown[]) {\n yield* stmt.iterate(...params);\n },\n };\n },\n },\n async close() {\n await db.close();\n },\n };\n}\n"],"names":["SenseError","getColumns","withTransaction","hasVectorRow","pendingRows","fieldStats","reconcile","CAPABILITIES","Set","missing","name","createStore","db","conn","cfg","baseDir","capabilities","exec","sql","prepare","runBatch","paramRows","transaction","fn","docs","columns","scopeWhere","lexical","query","vectors","pending","writeVectors","candidates","similar","hasVector","path","engineStatus","row","get","busy_timeout","raw","stmt","safeIntegers","iterate","params","close"],"mappings":"AAEA,SAASA,UAAU,QAAQ,kBAAkB;AAC7C,SAASC,UAAU,QAAQ,eAAe;AAC1C,SAASC,eAAe,QAAQ,oBAAoB;AAEpD,SAASC,YAAY,EAAEC,WAAW,QAAQ,gBAAgB;AAC1D,SAASC,UAAU,QAAQ,kBAAkB;AAC7C,SAASC,SAAS,QAAQ,iBAAiB;AAE3C,2FAA2F;AAC3F,iGAAiG;AACjG,kGAAkG;AAClG,uFAAuF;AACvF,8FAA8F;AAC9F,iGAAiG;AACjG,4FAA4F;AAC5F,6EAA6E;AAC7E,OAAO,MAAMC,eAAwC,IAAIC,MAAM;AAE/D,SAASC,QAAQC,IAA2B;IAC1C,MAAM,IAAIV,WAAW,4BAA4B,CAAC,kCAAkC,EAAEU,KAAK,0EAA0E,CAAC;AACxK;AAEA,8FAA8F;AAC9F,sEAAsE;AACtE,OAAO,SAASC,YAAYC,EAAY,EAAEC,IAAgB,EAAEC,GAAW,EAAEC,OAAe;IACtF,OAAO;QACLL,MAAM;QACNM,cAAcT;QACd,MAAMU,MAAKC,GAAW;YACpB,MAAML,KAAKI,IAAI,CAACC;QAClB;QACA,MAAMC,SAAQD,GAAW;YACvB,OAAOL,KAAKM,OAAO,CAACD;QACtB;QACA,MAAME,UAASF,GAAW,EAAEG,SAAsB;YAChD,MAAMR,KAAKO,QAAQ,CAACF,KAAKG;QAC3B;QACA,MAAMC,aAAeC,EAAoB;YACvC,OAAOrB,gBAAgBW,MAAMU;QAC/B;QACA,MAAMjB;YACJ,OAAOA,UAAUO,MAAMC,KAAKC;QAC9B;QACAS,MAAM;YACJ,MAAMC;gBACJ,OAAO;uBAAK,MAAMxB,WAAWY;iBAAO;YACtC;YACAR,YAAY,CAACoB,SAASC,aAAerB,WAAWQ,MAAMY,SAASC;QACjE;QACAC,SAAS;YACP,MAAMC;gBACJ,OAAOnB,QAAQ;YACjB;QACF;QACAoB,SAAS;YACPC,SAAS,IAAM1B,YAAYS;YAC3B,MAAMkB;gBACJ,OAAOtB,QAAQ;YACjB;YACA,MAAMuB;gBACJ,OAAOvB,QAAQ;YACjB;YACA,MAAMwB;gBACJ,OAAOxB,QAAQ;YACjB;YACAyB,WAAW,CAACC,OAAShC,aAAaU,MAAMsB;QAC1C;QACA,MAAMC;YACJ,qFAAqF;YACrF,qFAAqF;YACrF,2FAA2F;YAC3F,+EAA+E;YAC/E,MAAMC,MAAO,MAAM,AAAC,CAAA,MAAMzB,GAAGO,OAAO,CAAC,sBAAqB,EAAGmB,GAAG;YAChE,OAAO;gBAAEC,cAAc,GAAGF,IAAIE,YAAY,CAAC,kFAAkF,CAAC;YAAC;QACjI;QACAC,KAAK;YACH,MAAMrB,SAAQD,GAAW;gBACvB,MAAMuB,OAAO,MAAM7B,GAAGO,OAAO,CAACD;gBAC9BuB,KAAKC,YAAY,CAAC,OAAO,gEAAgE;gBACzF,OAAO;oBACLjB,SAAS,IAAMgB,KAAKhB,OAAO;oBAC3B,8DAA8D;oBAC9DkB,SAAS,gBAAiB,GAAGC,MAAiB;wBAC5C,OAAOH,KAAKE,OAAO,IAAIC;oBACzB;gBACF;YACF;QACF;QACA,MAAMC;YACJ,MAAMjC,GAAGiC,KAAK;QAChB;IACF;AACF"}
|
|
@@ -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:
|
|
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
|
}
|
package/dist/esm/store/types.js
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
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
|
export { };
|
|
@@ -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:
|
|
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;AAoH7D,WAyBC"}
|
|
@@ -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,26 @@
|
|
|
1
|
+
// Seed chunks that participate in a `related` scan. Cost is target_chunks x stored_chunks, so a
|
|
2
|
+
// heading-dense seed multiplies a full-corpus scan (12.7s at 201 chunks/note unsampled).
|
|
3
|
+
export const TARGET_CHUNK_CAP = 16;
|
|
4
|
+
// Evenly samples down to at most `cap` rows, so late sections of a long note still get a vote
|
|
5
|
+
// instead of being cut off by a fixed prefix.
|
|
6
|
+
export function sampleEvenly(rows, cap = TARGET_CHUNK_CAP) {
|
|
7
|
+
const step = Math.max(1, Math.ceil(rows.length / cap));
|
|
8
|
+
return rows.filter((_, i)=>i % step === 0);
|
|
9
|
+
}
|
|
10
|
+
// Dequantised int8 dot products (sqlite) land a little either side of a true cosine, so an
|
|
11
|
+
// identical pair can print 1.001; array_cosine_similarity (duckdb) has no such error but is
|
|
12
|
+
// rounded the same way, so both stores print the same bounded number.
|
|
13
|
+
export function asCosine(score) {
|
|
14
|
+
return Math.round(Math.min(1, Math.max(-1, score)) * 1000) / 1000;
|
|
15
|
+
}
|
|
16
|
+
export async function pendingRows(conn) {
|
|
17
|
+
const stmt = await conn.prepare('SELECT "path", chunk FROM embeddings WHERE vector IS NULL ORDER BY "path", chunk');
|
|
18
|
+
return await stmt.all();
|
|
19
|
+
}
|
|
20
|
+
// Whether a note has any chunk with a vector. Distinguishes "nothing is near this note" from
|
|
21
|
+
// "this note has no text", which look the same in an empty result.
|
|
22
|
+
export async function hasVectorRow(conn, path) {
|
|
23
|
+
const stmt = await conn.prepare('SELECT 1 AS ok FROM embeddings WHERE "path" = ? AND vector IS NOT NULL LIMIT 1');
|
|
24
|
+
const row = await stmt.get(path);
|
|
25
|
+
return row !== undefined;
|
|
26
|
+
}
|
|
@@ -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","sampleEvenly","rows","cap","step","Math","max","ceil","length","filter","_","i","asCosine","score","round","min","pendingRows","conn","stmt","prepare","all","hasVectorRow","path","row","get","undefined"],"mappings":"AAEA,gGAAgG;AAChG,yFAAyF;AACzF,OAAO,MAAMA,mBAAmB,GAAG;AAEnC,8FAA8F;AAC9F,8CAA8C;AAC9C,OAAO,SAASC,aAAgBC,IAAS,EAAEC,MAAcH,gBAAgB;IACvE,MAAMI,OAAOC,KAAKC,GAAG,CAAC,GAAGD,KAAKE,IAAI,CAACL,KAAKM,MAAM,GAAGL;IACjD,OAAOD,KAAKO,MAAM,CAAC,CAACC,GAAGC,IAAMA,IAAIP,SAAS;AAC5C;AAEA,2FAA2F;AAC3F,4FAA4F;AAC5F,sEAAsE;AACtE,OAAO,SAASQ,SAASC,KAAa;IACpC,OAAOR,KAAKS,KAAK,CAACT,KAAKU,GAAG,CAAC,GAAGV,KAAKC,GAAG,CAAC,CAAC,GAAGO,UAAU,QAAQ;AAC/D;AAEA,OAAO,eAAeG,YAAYC,IAAgB;IAChD,MAAMC,OAAO,MAAMD,KAAKE,OAAO,CAAC;IAChC,OAAQ,MAAMD,KAAKE,GAAG;AACxB;AAEA,6FAA6F;AAC7F,mEAAmE;AACnE,OAAO,eAAeC,aAAaJ,IAAgB,EAAEK,IAAY;IAC/D,MAAMJ,OAAO,MAAMD,KAAKE,OAAO,CAAC;IAChC,MAAMI,MAAO,MAAML,KAAKM,GAAG,CAACF;IAC5B,OAAOC,QAAQE;AACjB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sensemaking",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.3",
|
|
4
4
|
"description": "Query and search your markdown notes with context-aware progressive disclosure: SQL over frontmatter, links, and text, plus semantic search and link-graph ranking. No server, no build step",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
|
@@ -97,6 +97,7 @@
|
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|
|
99
99
|
"@duckdb/node-api": "*",
|
|
100
|
+
"@tursodatabase/database": "*",
|
|
100
101
|
"@types/mdast": "^4.0.4",
|
|
101
102
|
"@types/mocha": "*",
|
|
102
103
|
"@types/node": "*",
|