sensemaking 0.26.0 → 0.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -4
- package/dist/cjs/chunk/extract.js.map +1 -1
- package/dist/cjs/chunk/group.js.map +1 -1
- package/dist/cjs/chunk/index.js.map +1 -1
- package/dist/cjs/chunk/parse.js.map +1 -1
- package/dist/cjs/chunk/parser.js.map +1 -1
- package/dist/cjs/chunk/tokens.js.map +1 -1
- package/dist/cjs/chunk/version.js.map +1 -1
- package/dist/cjs/cli/build.js.map +1 -1
- package/dist/cjs/cli/download.js.map +1 -1
- package/dist/cjs/cli/index.d.cts +2 -2
- package/dist/cjs/cli/index.d.ts +2 -2
- package/dist/cjs/cli/index.js +2 -2
- package/dist/cjs/cli/index.js.map +1 -1
- package/dist/cjs/cli/init.js.map +1 -1
- package/dist/cjs/cli/map.js.map +1 -1
- package/dist/cjs/cli/named.js.map +1 -1
- package/dist/cjs/cli/path.js.map +1 -1
- package/dist/cjs/cli/peek.js +43 -2
- package/dist/cjs/cli/peek.js.map +1 -1
- package/dist/cjs/cli/related.js.map +1 -1
- package/dist/cjs/cli/search.js +38 -6
- package/dist/cjs/cli/search.js.map +1 -1
- package/dist/cjs/cli/shared.js.map +1 -1
- package/dist/cjs/cli/sql.js.map +1 -1
- package/dist/cjs/cli/status.js.map +1 -1
- package/dist/cjs/cli/watch.js.map +1 -1
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/commands/index.d.cts +2 -2
- package/dist/cjs/commands/index.d.ts +2 -2
- package/dist/cjs/commands/index.js.map +1 -1
- package/dist/cjs/commands/map.js.map +1 -1
- package/dist/cjs/commands/path.js.map +1 -1
- package/dist/cjs/commands/peek.d.cts +9 -1
- package/dist/cjs/commands/peek.d.ts +9 -1
- package/dist/cjs/commands/peek.js +72 -29
- package/dist/cjs/commands/peek.js.map +1 -1
- package/dist/cjs/commands/related.js.map +1 -1
- package/dist/cjs/commands/scope.js.map +1 -1
- package/dist/cjs/commands/search.d.cts +6 -2
- package/dist/cjs/commands/search.d.ts +6 -2
- package/dist/cjs/commands/search.js +31 -4
- package/dist/cjs/commands/search.js.map +1 -1
- package/dist/cjs/commands/signals.d.cts +19 -5
- package/dist/cjs/commands/signals.d.ts +19 -5
- package/dist/cjs/commands/signals.js +64 -11
- package/dist/cjs/commands/signals.js.map +1 -1
- package/dist/cjs/commands/snapshot.js.map +1 -1
- package/dist/cjs/commands/status.js.map +1 -1
- package/dist/cjs/config/access.js.map +1 -1
- package/dist/cjs/config/index.js.map +1 -1
- package/dist/cjs/config/load.js +6 -0
- package/dist/cjs/config/load.js.map +1 -1
- package/dist/cjs/config/resolve.js.map +1 -1
- package/dist/cjs/config/signals.js.map +1 -1
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/config/validate.js.map +1 -1
- package/dist/cjs/embed/cohere.js.map +1 -1
- package/dist/cjs/embed/distribution.js.map +1 -1
- package/dist/cjs/embed/endpoint.js.map +1 -1
- package/dist/cjs/embed/handoff.js.map +1 -1
- package/dist/cjs/embed/http.js.map +1 -1
- package/dist/cjs/embed/identity.js.map +1 -1
- package/dist/cjs/embed/langfit.js.map +1 -1
- package/dist/cjs/embed/languages.js.map +1 -1
- package/dist/cjs/embed/openai.js.map +1 -1
- package/dist/cjs/embed/query.js.map +1 -1
- package/dist/cjs/embed/registry.js.map +1 -1
- package/dist/cjs/embed/static.js.map +1 -1
- package/dist/cjs/embed/store.js.map +1 -1
- package/dist/cjs/embed/types.js.map +1 -1
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/features/embed.js.map +1 -1
- package/dist/cjs/features/fences.js.map +1 -1
- package/dist/cjs/features/index.js.map +1 -1
- package/dist/cjs/features/links.js.map +1 -1
- package/dist/cjs/features/rank.js.map +1 -1
- package/dist/cjs/features/sections.js.map +1 -1
- package/dist/cjs/features/tags.js.map +1 -1
- package/dist/cjs/graph/graph.js.map +1 -1
- package/dist/cjs/graph/traverse.js.map +1 -1
- package/dist/cjs/index.d.cts +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/atomic-write.js.map +1 -1
- package/dist/cjs/lib/guarded-tick.js.map +1 -1
- package/dist/cjs/lib/serial-query.js.map +1 -1
- package/dist/cjs/lib/watch-notification.js.map +1 -1
- package/dist/cjs/lib/worker-file.js.map +1 -1
- package/dist/cjs/output/column-hint.js.map +1 -1
- package/dist/cjs/output/output.js.map +1 -1
- package/dist/cjs/output/progress.js.map +1 -1
- package/dist/cjs/output/search-error.js.map +1 -1
- package/dist/cjs/scan/frontmatter.js.map +1 -1
- package/dist/cjs/scan/index.js.map +1 -1
- package/dist/cjs/scan/list.js.map +1 -1
- package/dist/cjs/scan/pool.js.map +1 -1
- package/dist/cjs/scan/reparse.js.map +1 -1
- package/dist/cjs/scan/worker-error.js.map +1 -1
- package/dist/cjs/store/batch.js.map +1 -1
- package/dist/cjs/store/builder.js.map +1 -1
- package/dist/cjs/store/cache.js.map +1 -1
- package/dist/cjs/store/duckdb/batch.js.map +1 -1
- package/dist/cjs/store/duckdb/connection.js.map +1 -1
- package/dist/cjs/store/duckdb/fieldStats.js.map +1 -1
- package/dist/cjs/store/duckdb/lexical.d.cts +1 -6
- package/dist/cjs/store/duckdb/lexical.d.ts +1 -6
- package/dist/cjs/store/duckdb/lexical.js +28 -39
- package/dist/cjs/store/duckdb/lexical.js.map +1 -1
- package/dist/cjs/store/duckdb/native.d.cts +1 -2
- package/dist/cjs/store/duckdb/native.d.ts +1 -2
- package/dist/cjs/store/duckdb/native.js +1 -6
- package/dist/cjs/store/duckdb/native.js.map +1 -1
- package/dist/cjs/store/duckdb/open.js.map +1 -1
- package/dist/cjs/store/duckdb/ordered-bm25.d.cts +3 -16
- package/dist/cjs/store/duckdb/ordered-bm25.d.ts +3 -16
- package/dist/cjs/store/duckdb/ordered-bm25.js +27 -79
- package/dist/cjs/store/duckdb/ordered-bm25.js.map +1 -1
- package/dist/cjs/store/duckdb/reconcile.js.map +1 -1
- package/dist/cjs/store/duckdb/sql-functions.js.map +1 -1
- package/dist/cjs/store/duckdb/store.js.map +1 -1
- package/dist/cjs/store/duckdb/vectors.js.map +1 -1
- package/dist/cjs/store/embed-scope.js.map +1 -1
- package/dist/cjs/store/feature-scope.js.map +1 -1
- package/dist/cjs/store/index.js.map +1 -1
- package/dist/cjs/store/lock-wait.js.map +1 -1
- package/dist/cjs/store/native.js.map +1 -1
- package/dist/cjs/store/open.js.map +1 -1
- package/dist/cjs/store/preset-scope.js.map +1 -1
- package/dist/cjs/store/readiness.js.map +1 -1
- package/dist/cjs/store/reconcile.js.map +1 -1
- package/dist/cjs/store/shared.js.map +1 -1
- package/dist/cjs/store/signature.js.map +1 -1
- package/dist/cjs/store/sql-functions.js.map +1 -1
- package/dist/cjs/store/sqlite/connection.js.map +1 -1
- package/dist/cjs/store/sqlite/fieldStats.js.map +1 -1
- package/dist/cjs/store/sqlite/lexical.js.map +1 -1
- package/dist/cjs/store/sqlite/open.js.map +1 -1
- package/dist/cjs/store/sqlite/reconcile.js.map +1 -1
- package/dist/cjs/store/sqlite/sql-functions.js.map +1 -1
- package/dist/cjs/store/sqlite/store.js.map +1 -1
- package/dist/cjs/store/sqlite/vectors.js.map +1 -1
- package/dist/cjs/store/stages.js.map +1 -1
- package/dist/cjs/store/transaction.js.map +1 -1
- package/dist/cjs/store/turso/connection.js.map +1 -1
- package/dist/cjs/store/turso/fieldStats.js.map +1 -1
- package/dist/cjs/store/turso/lexical-text.js.map +1 -1
- package/dist/cjs/store/turso/lexical.js.map +1 -1
- package/dist/cjs/store/turso/native.js.map +1 -1
- package/dist/cjs/store/turso/open.js.map +1 -1
- package/dist/cjs/store/turso/reconcile.js.map +1 -1
- package/dist/cjs/store/turso/sql-functions.js.map +1 -1
- package/dist/cjs/store/turso/store.js.map +1 -1
- package/dist/cjs/store/turso/vectors.js.map +1 -1
- package/dist/cjs/store/types.js.map +1 -1
- package/dist/cjs/store/vectors.js.map +1 -1
- package/dist/cjs/text/segment.js.map +1 -1
- package/dist/cjs/text/strip.js.map +1 -1
- package/dist/cjs/watch-claim.js.map +1 -1
- package/dist/cjs/watch.js.map +1 -1
- package/dist/cjs/workers/parse.js.map +1 -1
- package/dist/cjs/workers/watch-heartbeat.js.map +1 -1
- package/dist/esm/chunk/extract.js.map +1 -1
- package/dist/esm/chunk/group.js.map +1 -1
- package/dist/esm/chunk/index.js.map +1 -1
- package/dist/esm/chunk/parse.js.map +1 -1
- package/dist/esm/chunk/parser.js.map +1 -1
- package/dist/esm/chunk/tokens.js.map +1 -1
- package/dist/esm/chunk/types.js.map +1 -1
- package/dist/esm/chunk/version.js.map +1 -1
- package/dist/esm/cli/build.js.map +1 -1
- package/dist/esm/cli/download.js.map +1 -1
- package/dist/esm/cli/index.d.ts +2 -2
- package/dist/esm/cli/index.js +2 -2
- package/dist/esm/cli/index.js.map +1 -1
- package/dist/esm/cli/init.js.map +1 -1
- package/dist/esm/cli/map.js.map +1 -1
- package/dist/esm/cli/named.js.map +1 -1
- package/dist/esm/cli/path.js.map +1 -1
- package/dist/esm/cli/peek.js +20 -2
- package/dist/esm/cli/peek.js.map +1 -1
- package/dist/esm/cli/related.js.map +1 -1
- package/dist/esm/cli/search.js +12 -2
- package/dist/esm/cli/search.js.map +1 -1
- package/dist/esm/cli/shared.js.map +1 -1
- package/dist/esm/cli/sql.js.map +1 -1
- package/dist/esm/cli/status.js.map +1 -1
- package/dist/esm/cli/types.js.map +1 -1
- package/dist/esm/cli/watch.js.map +1 -1
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/commands/index.d.ts +2 -2
- package/dist/esm/commands/index.js.map +1 -1
- package/dist/esm/commands/map.js.map +1 -1
- package/dist/esm/commands/path.js.map +1 -1
- package/dist/esm/commands/peek.d.ts +9 -1
- package/dist/esm/commands/peek.js +26 -12
- package/dist/esm/commands/peek.js.map +1 -1
- package/dist/esm/commands/related.js.map +1 -1
- package/dist/esm/commands/scope.js.map +1 -1
- package/dist/esm/commands/search.d.ts +6 -2
- package/dist/esm/commands/search.js +11 -3
- package/dist/esm/commands/search.js.map +1 -1
- package/dist/esm/commands/signals.d.ts +19 -5
- package/dist/esm/commands/signals.js +64 -14
- package/dist/esm/commands/signals.js.map +1 -1
- package/dist/esm/commands/snapshot.js.map +1 -1
- package/dist/esm/commands/status.js.map +1 -1
- package/dist/esm/config/access.js.map +1 -1
- package/dist/esm/config/index.js.map +1 -1
- package/dist/esm/config/load.js +6 -0
- package/dist/esm/config/load.js.map +1 -1
- package/dist/esm/config/resolve.js.map +1 -1
- package/dist/esm/config/signals.js.map +1 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/config/validate.js.map +1 -1
- package/dist/esm/embed/cohere.js.map +1 -1
- package/dist/esm/embed/distribution.js.map +1 -1
- package/dist/esm/embed/endpoint.js.map +1 -1
- package/dist/esm/embed/handoff.js.map +1 -1
- package/dist/esm/embed/http.js.map +1 -1
- package/dist/esm/embed/identity.js.map +1 -1
- package/dist/esm/embed/langfit.js.map +1 -1
- package/dist/esm/embed/languages.js.map +1 -1
- package/dist/esm/embed/openai.js.map +1 -1
- package/dist/esm/embed/query.js.map +1 -1
- package/dist/esm/embed/registry.js.map +1 -1
- package/dist/esm/embed/static.js.map +1 -1
- package/dist/esm/embed/store.js.map +1 -1
- package/dist/esm/embed/types.js.map +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/features/embed.js.map +1 -1
- package/dist/esm/features/fences.js.map +1 -1
- package/dist/esm/features/index.js.map +1 -1
- package/dist/esm/features/links.js.map +1 -1
- package/dist/esm/features/rank.js.map +1 -1
- package/dist/esm/features/sections.js.map +1 -1
- package/dist/esm/features/tags.js.map +1 -1
- package/dist/esm/features/types.js.map +1 -1
- package/dist/esm/graph/graph.js.map +1 -1
- package/dist/esm/graph/traverse.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/atomic-write.js.map +1 -1
- package/dist/esm/lib/guarded-tick.js.map +1 -1
- package/dist/esm/lib/serial-query.js.map +1 -1
- package/dist/esm/lib/watch-notification.js.map +1 -1
- package/dist/esm/lib/worker-file.js.map +1 -1
- package/dist/esm/output/column-hint.js.map +1 -1
- package/dist/esm/output/output.js.map +1 -1
- package/dist/esm/output/progress.js.map +1 -1
- package/dist/esm/output/search-error.js.map +1 -1
- package/dist/esm/scan/frontmatter.js.map +1 -1
- package/dist/esm/scan/index.js.map +1 -1
- package/dist/esm/scan/list.js.map +1 -1
- package/dist/esm/scan/pool.js.map +1 -1
- package/dist/esm/scan/reparse.js.map +1 -1
- package/dist/esm/scan/worker-error.js.map +1 -1
- package/dist/esm/store/batch.js.map +1 -1
- package/dist/esm/store/builder.js.map +1 -1
- package/dist/esm/store/cache.js.map +1 -1
- package/dist/esm/store/duckdb/batch.js.map +1 -1
- package/dist/esm/store/duckdb/connection.js.map +1 -1
- package/dist/esm/store/duckdb/fieldStats.js.map +1 -1
- package/dist/esm/store/duckdb/lexical.d.ts +1 -6
- package/dist/esm/store/duckdb/lexical.js +13 -17
- package/dist/esm/store/duckdb/lexical.js.map +1 -1
- package/dist/esm/store/duckdb/native.d.ts +1 -2
- package/dist/esm/store/duckdb/native.js +1 -3
- package/dist/esm/store/duckdb/native.js.map +1 -1
- package/dist/esm/store/duckdb/open.js.map +1 -1
- package/dist/esm/store/duckdb/ordered-bm25.d.ts +3 -16
- package/dist/esm/store/duckdb/ordered-bm25.js +18 -54
- package/dist/esm/store/duckdb/ordered-bm25.js.map +1 -1
- package/dist/esm/store/duckdb/reconcile.js.map +1 -1
- package/dist/esm/store/duckdb/sql-functions.js.map +1 -1
- package/dist/esm/store/duckdb/store.js.map +1 -1
- package/dist/esm/store/duckdb/vectors.js.map +1 -1
- package/dist/esm/store/embed-scope.js.map +1 -1
- package/dist/esm/store/feature-scope.js.map +1 -1
- package/dist/esm/store/index.js.map +1 -1
- package/dist/esm/store/lock-wait.js.map +1 -1
- package/dist/esm/store/native.js.map +1 -1
- package/dist/esm/store/open.js.map +1 -1
- package/dist/esm/store/preset-scope.js.map +1 -1
- package/dist/esm/store/readiness.js.map +1 -1
- package/dist/esm/store/reconcile.js.map +1 -1
- package/dist/esm/store/shared.js.map +1 -1
- package/dist/esm/store/signature.js.map +1 -1
- package/dist/esm/store/sql-functions.js.map +1 -1
- package/dist/esm/store/sqlite/connection.js.map +1 -1
- package/dist/esm/store/sqlite/fieldStats.js.map +1 -1
- package/dist/esm/store/sqlite/lexical.js.map +1 -1
- package/dist/esm/store/sqlite/open.js.map +1 -1
- package/dist/esm/store/sqlite/reconcile.js.map +1 -1
- package/dist/esm/store/sqlite/sql-functions.js.map +1 -1
- package/dist/esm/store/sqlite/store.js.map +1 -1
- package/dist/esm/store/sqlite/vectors.js.map +1 -1
- package/dist/esm/store/stages.js.map +1 -1
- package/dist/esm/store/transaction.js.map +1 -1
- package/dist/esm/store/turso/connection.js.map +1 -1
- package/dist/esm/store/turso/fieldStats.js.map +1 -1
- package/dist/esm/store/turso/lexical-text.js.map +1 -1
- package/dist/esm/store/turso/lexical.js.map +1 -1
- package/dist/esm/store/turso/native.js.map +1 -1
- package/dist/esm/store/turso/open.js.map +1 -1
- package/dist/esm/store/turso/reconcile.js.map +1 -1
- package/dist/esm/store/turso/sql-functions.js.map +1 -1
- package/dist/esm/store/turso/store.js.map +1 -1
- package/dist/esm/store/turso/vectors.js.map +1 -1
- package/dist/esm/store/types.js.map +1 -1
- package/dist/esm/store/vectors.js.map +1 -1
- package/dist/esm/text/segment.js.map +1 -1
- package/dist/esm/text/strip.js.map +1 -1
- package/dist/esm/watch-claim.js.map +1 -1
- package/dist/esm/watch.js.map +1 -1
- package/dist/esm/workers/parse.js.map +1 -1
- package/dist/esm/workers/watch-heartbeat.js.map +1 -1
- package/package.json +2 -2
- package/skills/sense/EXAMPLES.md +3 -3
- package/skills/sense/SKILL.md +7 -1
- package/skills/sense/references/search.md +17 -1
- package/skills/sense/references/sql.md +1 -1
- package/skills/sense/references/terminology.md +32 -0
- package/skills/sense-setup/references/store-benchmarks.md +5 -5
|
@@ -9,18 +9,16 @@ function _export(target, all) {
|
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
_export(exports, {
|
|
12
|
-
get
|
|
13
|
-
return
|
|
12
|
+
get FTS_STEMMER () {
|
|
13
|
+
return FTS_STEMMER;
|
|
14
14
|
},
|
|
15
|
-
get
|
|
16
|
-
return
|
|
15
|
+
get nativeQueryTerms () {
|
|
16
|
+
return nativeQueryTerms;
|
|
17
17
|
},
|
|
18
|
-
get
|
|
19
|
-
return
|
|
18
|
+
get orderedBm25Sql () {
|
|
19
|
+
return orderedBm25Sql;
|
|
20
20
|
}
|
|
21
21
|
});
|
|
22
|
-
var _nodecrypto = require("node:crypto");
|
|
23
|
-
var _errorsts = require("../../errors.js");
|
|
24
22
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
25
23
|
try {
|
|
26
24
|
var info = gen[key](arg);
|
|
@@ -146,93 +144,43 @@ function _ts_generator(thisArg, body) {
|
|
|
146
144
|
};
|
|
147
145
|
}
|
|
148
146
|
}
|
|
149
|
-
var
|
|
150
|
-
|
|
151
|
-
var SUPPORTED_CONTRACT_SHA256 = '4476d543e43e7f8c89751cac0659b64e09d906cd3fefb1bfcaf4d15d3b1d9e00';
|
|
152
|
-
var EXPECTED_PARAMETERS = [
|
|
153
|
-
'docname',
|
|
154
|
-
'query_string',
|
|
155
|
-
'fields',
|
|
156
|
-
'k',
|
|
157
|
-
'b',
|
|
158
|
-
'conjunctive'
|
|
159
|
-
];
|
|
160
|
-
var EXPECTED_DEFAULTS = {
|
|
161
|
-
fields: 'NULL',
|
|
162
|
-
k: '1.2',
|
|
163
|
-
b: '0.75',
|
|
164
|
-
conjunctive: 'false'
|
|
165
|
-
};
|
|
166
|
-
var EXPECTED_SIGNATURE = "docname, query_string, fields := ".concat(EXPECTED_DEFAULTS.fields, ", k := ").concat(EXPECTED_DEFAULTS.k, ", b := ").concat(EXPECTED_DEFAULTS.b, ", conjunctive := ").concat(EXPECTED_DEFAULTS.conjunctive);
|
|
167
|
-
var UNORDERED_SUM = 'sum(subscore)';
|
|
168
|
-
function unsupported(message) {
|
|
169
|
-
return new _errorsts.SenseError('STORE_CAPABILITY_MISSING', 'store "duckdb" cannot install its deterministic native BM25 adapter: '.concat(message, "; update the DuckDB adapter before using lexical search"));
|
|
170
|
-
}
|
|
171
|
-
function contractSha256(version, definition) {
|
|
172
|
-
return (0, _nodecrypto.createHash)('sha256').update("".concat(version, "\0").concat(EXPECTED_SIGNATURE, "\0").concat(definition)).digest('hex');
|
|
173
|
-
}
|
|
174
|
-
function validateNativeMacroContract(param) {
|
|
175
|
-
var version = param.version, macro = param.macro;
|
|
176
|
-
if (version !== SUPPORTED_DUCKDB_VERSION) throw unsupported("DuckDB ".concat(version, " is unsupported (validated version is ").concat(SUPPORTED_DUCKDB_VERSION, ")"));
|
|
177
|
-
if (macro.function_type !== 'macro') throw unsupported("match_bm25 is ".concat(macro.function_type, ", not a macro"));
|
|
178
|
-
if (JSON.stringify(macro.parameters) !== JSON.stringify(EXPECTED_PARAMETERS)) throw unsupported("match_bm25 parameters changed (".concat(JSON.stringify(macro.parameters), ")"));
|
|
179
|
-
if (!Array.isArray(macro.parameter_types) || macro.parameter_types.some(function(type) {
|
|
180
|
-
return type !== null;
|
|
181
|
-
})) throw unsupported('match_bm25 parameter types changed');
|
|
182
|
-
if (contractSha256(version, macro.macro_definition) !== SUPPORTED_CONTRACT_SHA256) throw unsupported('match_bm25 definition or reviewed parameter-default contract changed');
|
|
183
|
-
if (macro.macro_definition.split(UNORDERED_SUM).length !== 2) throw unsupported('match_bm25 does not contain exactly one validated unordered subscore sum');
|
|
184
|
-
return macro.macro_definition.replace(UNORDERED_SUM, 'sum(subscore ORDER BY subscore)');
|
|
185
|
-
}
|
|
186
|
-
function ensureOrderedBm25(conn, state) {
|
|
147
|
+
var FTS_STEMMER = 'porter';
|
|
148
|
+
function nativeQueryTerms(conn, query) {
|
|
187
149
|
return _async_to_generator(function() {
|
|
188
|
-
var
|
|
150
|
+
var stmt, rows;
|
|
189
151
|
return _ts_generator(this, function(_state) {
|
|
190
152
|
switch(_state.label){
|
|
191
153
|
case 0:
|
|
192
|
-
if (state.orderedMacroReady) return [
|
|
193
|
-
2
|
|
194
|
-
];
|
|
195
154
|
return [
|
|
196
155
|
4,
|
|
197
|
-
conn.prepare(
|
|
156
|
+
conn.prepare("\n WITH tokens AS (SELECT unnest(fts_main_content.tokenize(?)) AS raw_term)\n SELECT min(raw_term) AS term FROM tokens\n WHERE raw_term <> '' GROUP BY stem(raw_term, '".concat(FTS_STEMMER, "') ORDER BY term\n "))
|
|
198
157
|
];
|
|
199
158
|
case 1:
|
|
200
|
-
|
|
159
|
+
stmt = _state.sent();
|
|
201
160
|
return [
|
|
202
161
|
4,
|
|
203
|
-
|
|
162
|
+
stmt.all(query)
|
|
204
163
|
];
|
|
205
164
|
case 2:
|
|
206
|
-
|
|
165
|
+
rows = _state.sent();
|
|
207
166
|
return [
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
return [
|
|
214
|
-
4,
|
|
215
|
-
macroStatement.get()
|
|
216
|
-
];
|
|
217
|
-
case 4:
|
|
218
|
-
macro = _state.sent();
|
|
219
|
-
if (!macro) throw unsupported('fts_main_content.match_bm25 is missing');
|
|
220
|
-
orderedDefinition = validateNativeMacroContract({
|
|
221
|
-
version: versionRow.version,
|
|
222
|
-
macro: macro
|
|
223
|
-
});
|
|
224
|
-
return [
|
|
225
|
-
4,
|
|
226
|
-
conn.exec("CREATE OR REPLACE TEMP MACRO ".concat(ORDERED_BM25_MACRO, "(").concat(EXPECTED_SIGNATURE, ") AS ").concat(orderedDefinition))
|
|
227
|
-
];
|
|
228
|
-
case 5:
|
|
229
|
-
_state.sent();
|
|
230
|
-
state.orderedMacroReady = true;
|
|
231
|
-
return [
|
|
232
|
-
2
|
|
167
|
+
2,
|
|
168
|
+
rows.map(function(param) {
|
|
169
|
+
var term = param.term;
|
|
170
|
+
return term;
|
|
171
|
+
})
|
|
233
172
|
];
|
|
234
173
|
}
|
|
235
174
|
});
|
|
236
175
|
})();
|
|
237
176
|
}
|
|
177
|
+
function orderedBm25Sql(field, termCount) {
|
|
178
|
+
if (termCount === 0) return 'NULL';
|
|
179
|
+
var contributions = Array.from({
|
|
180
|
+
length: termCount
|
|
181
|
+
}, function() {
|
|
182
|
+
return 'SELECT fts_main_content.match_bm25(content."path", ?, fields := \''.concat(field, "', conjunctive := false) AS score");
|
|
183
|
+
});
|
|
184
|
+
return "(SELECT sum(score ORDER BY score) FROM (".concat(contributions.join(' UNION ALL '), "))");
|
|
185
|
+
}
|
|
238
186
|
/* 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; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/ordered-bm25.ts"],"sourcesContent":["import type { Connection } from '../types.ts';\n\nexport const FTS_STEMMER = 'porter';\n\n// Keep deduplication native, but return original tokens so native scoring stems once.\nexport async function nativeQueryTerms(conn: Connection, query: string): Promise<string[]> {\n const stmt = await conn.prepare(`\n WITH tokens AS (SELECT unnest(fts_main_content.tokenize(?)) AS raw_term)\n SELECT min(raw_term) AS term FROM tokens\n WHERE raw_term <> '' GROUP BY stem(raw_term, '${FTS_STEMMER}') ORDER BY term\n `);\n const rows = (await stmt.all(query)) as Array<{ term: string }>;\n return rows.map(({ term }) => term);\n}\n\n// Fixed parameters avoid a correlated document-by-term intermediate relation in DuckDB.\n// Only the number of terms shapes this authored SQL; query values are always bound.\nexport function orderedBm25Sql(field: 'title' | 'summary' | 'text', termCount: number): string {\n if (termCount === 0) return 'NULL';\n const contributions = Array.from({ length: termCount }, () => `SELECT fts_main_content.match_bm25(content.\"path\", ?, fields := '${field}', conjunctive := false) AS score`);\n return `(SELECT sum(score ORDER BY score) FROM (${contributions.join(' UNION ALL ')}))`;\n}\n"],"names":["FTS_STEMMER","nativeQueryTerms","orderedBm25Sql","conn","query","stmt","rows","prepare","all","map","term","field","termCount","contributions","Array","from","length","join"],"mappings":";;;;;;;;;;;QAEaA;eAAAA;;QAGSC;eAAAA;;QAYNC;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAfT,IAAMF,cAAc;AAGpB,SAAeC,iBAAiBE,IAAgB,EAAEC,KAAa;;YAC9DC,MAKAC;;;;oBALO;;wBAAMH,KAAKI,OAAO,CAAC,AAAC,mLAG6B,OAAZP,aAAY;;;oBAHxDK,OAAO;oBAKC;;wBAAMA,KAAKG,GAAG,CAACJ;;;oBAAvBE,OAAQ;oBACd;;wBAAOA,KAAKG,GAAG,CAAC;gCAAGC,aAAAA;mCAAWA;;;;;IAChC;;AAIO,SAASR,eAAeS,KAAmC,EAAEC,SAAiB;IACnF,IAAIA,cAAc,GAAG,OAAO;IAC5B,IAAMC,gBAAgBC,MAAMC,IAAI,CAAC;QAAEC,QAAQJ;IAAU,GAAG;eAAM,AAAC,qEAAyE,OAAND,OAAM;;IACxI,OAAO,AAAC,2CAA4E,OAAlCE,cAAcI,IAAI,CAAC,gBAAe;AACtF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/duckdb/reconcile.ts"],"sourcesContent":["import type { DuckDBConnection, DuckDBPreparedStatement, DuckDBValue } from '@duckdb/node-api';\nimport { SenseError } from '../../errors.ts';\nimport type { ReconcileDelta } from '../../features/types.ts';\nimport type { ParsedDoc } from '../../scan/index.ts';\nimport { appendRows, quoteIdent } from '../shared.ts';\nimport type { Connection, ReconcileDialect } from '../types.ts';\nimport type { DuckdbConnection } from './connection.ts';\nimport { markContentStale } from './lexical.ts';\nimport { duckdbApi } from './native.ts';\n\n// This store's dialect (types.ts's ReconcileDialect) for the shared orchestration in\n// store/reconcile.ts. `content` is a plain table, not FTS-virtual, so changed rows are maintained\n// here; DuckDB's ALTER TABLE needs a declared type, so every dynamic frontmatter\n// column is VARIANT (holds mapValue()'s mixed JS types for one key across files).\n\n// No rowid coupling needed (unlike sqlite's content, which links to frontmatter's rowid):\n// `path` is content's own primary key, so this is a plain per-doc row.\nconst CONTENT_COLUMNS = ['path', 'title', 'summary', 'text'];\nconst INSERT_CONTENT_SQL = `INSERT INTO content (${CONTENT_COLUMNS.map(quoteIdent).join(', ')}) VALUES (?, ?, ?, ?)`;\n// Bound the extra persisted text held for exact comparison, even during a full reparse.\nconst CONTENT_LOOKUP_CHUNK = 128;\n\ninterface ContentRow {\n path: string;\n title: string | null;\n summary: string | null;\n text: string | null;\n}\n\nfunction contentRow(doc: ParsedDoc): unknown[] {\n return [doc.relPath, doc.search.title, doc.search.summary, doc.search.text];\n}\n\n// No compile-time column cap in DuckDB (unlike SQLite's SQLITE_MAX_COLUMN); kept as a sanity fence anyway\n// so a runaway frontmatter generator fails with a clear message instead of an unbounded ALTER TABLE loop.\nconst MAX_FRONTMATTER_COLUMNS = 10_000;\nconst FRONTMATTER_UPDATE_CHUNK = 128;\n\nasync function withNativeStatement<T>(native: DuckDBConnection, sql: string, fn: (stmt: DuckDBPreparedStatement) => Promise<T>): Promise<T> {\n const stmt = await native.prepare(sql);\n const errors: unknown[] = [];\n let result!: T;\n try {\n result = await fn(stmt);\n } catch (err) {\n errors.push(err);\n }\n try {\n stmt.destroySync();\n } catch (err) {\n errors.push(err);\n }\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) throw new AggregateError(errors, 'frontmatter statement and cleanup failed');\n return result;\n}\n\n// Wide writes amplify native commit allocations even for one changed stamp.\n// Skip only known, exactly equal values; uncertain representations still write.\nasync function updateFrontmatter(conn: Connection, writableColumns: string[], rows: unknown[][]): Promise<void> {\n if (rows.length === 0) return;\n const native = (conn as DuckdbConnection).duckdb;\n const { DuckDBVariantValue, DuckDBTypeId } = await duckdbApi();\n const physical = await withNativeStatement(native, 'PRAGMA table_info(frontmatter)', async (stmt) => {\n const reader = await stmt.runAndReadAll();\n return reader.getRowObjectsJS() as Array<{ name: string; type: string }>;\n });\n const writable = new Map(writableColumns.map((name, i) => [name, i]));\n const pathIndex = writable.get('path');\n if (pathIndex === undefined) throw new Error('frontmatter update requires a writable path column');\n const columnTypes = new Map(physical.map((column) => [column.name, column.type]));\n const insertSql = `INSERT INTO frontmatter (${writableColumns.map(quoteIdent).join(', ')}) VALUES (${writableColumns.map(() => '?').join(', ')})`;\n const sameValue = (old: DuckDBValue, value: unknown, column: string): boolean => {\n if (value === null || value === undefined) return old === null;\n if (columnTypes.get(column) !== 'VARIANT') return Object.is(old, value);\n if (!(old instanceof DuckDBVariantValue)) return false;\n const typeId = typeof value === 'string' ? DuckDBTypeId.VARCHAR : typeof value === 'bigint' ? DuckDBTypeId.HUGEINT : typeof value === 'number' && !Number.isInteger(value) ? DuckDBTypeId.DOUBLE : undefined;\n return typeId !== undefined && old.type?.typeId === typeId && Object.is(old.value, value);\n };\n for (let i = 0; i < rows.length; i += FRONTMATTER_UPDATE_CHUNK) {\n const chunk = rows.slice(i, i + FRONTMATTER_UPDATE_CHUNK);\n const paths = chunk.map((row) => row[pathIndex] as string);\n const placeholders = paths.map(() => '?').join(', ');\n const selected = writableColumns.map(quoteIdent).join(', ');\n const existing = await withNativeStatement(native, `SELECT ${selected} FROM frontmatter WHERE \"path\" IN (${placeholders})`, async (stmt) => {\n stmt.bind(paths);\n const reader = await stmt.runAndReadAll();\n // Native wrappers distinguish numeric tags and SQL NULL from VARIANT null.\n return new Map(reader.getRowObjects().map((row) => [row.path as string, row]));\n });\n const plans = chunk.map((row) => {\n const old = existing.get(row[pathIndex] as string);\n const changed = old ? writableColumns.flatMap((column, index) => (sameValue(old[column], row[index], column) ? [] : [index])) : [];\n return { row, missing: old === undefined, changed, signature: changed.join(',') };\n });\n for (let position = 0; position < plans.length; ) {\n const plan = plans[position];\n if (!plan.missing && plan.changed.length === 0) {\n ++position;\n continue;\n }\n let end = position + 1;\n while (end < plans.length && plans[end].missing === plan.missing && plans[end].signature === plan.signature) ++end;\n if (plan.missing) {\n await appendRows(\n conn,\n 'frontmatter',\n writableColumns,\n insertSql,\n plans.slice(position, end).map((repair) => repair.row)\n );\n } else {\n const assignments = plan.changed.map((index) => `${quoteIdent(writableColumns[index])} = ?`).join(', ');\n await withNativeStatement(native, `UPDATE frontmatter SET ${assignments} WHERE \"path\" = ?`, async (stmt) => {\n for (let rowIndex = position; rowIndex < end; ++rowIndex) {\n const row = plans[rowIndex].row;\n stmt.bind([...plan.changed.map((index) => row[index] ?? null), row[pathIndex]] as DuckDBValue[]);\n await stmt.run();\n }\n });\n }\n position = end;\n }\n }\n}\n\nasync function reconcileContent(conn: Connection, touched: string[], docs: ParsedDoc[], delta: ReconcileDelta): Promise<void> {\n const added = new Set(delta.added);\n const reparsed = docs.filter((doc) => !added.has(doc.relPath));\n const changed = new Set(delta.added);\n const removed: string[] = [];\n for (let i = 0; i < reparsed.length; i += CONTENT_LOOKUP_CHUNK) {\n const chunk = reparsed.slice(i, i + CONTENT_LOOKUP_CHUNK);\n const stmt = await conn.prepare(`SELECT \"path\", title, summary, text FROM content WHERE \"path\" IN (${chunk.map(() => '?').join(', ')})`);\n const rows = (await stmt.all(...chunk.map((doc) => doc.relPath))) as ContentRow[];\n const existing = new Map(rows.map((row) => [row.path, row]));\n for (const doc of chunk) {\n const row = existing.get(doc.relPath);\n if (row && row.title === doc.search.title && row.summary === doc.search.summary && row.text === doc.search.text) continue;\n changed.add(doc.relPath);\n if (row) removed.push(doc.relPath);\n }\n }\n\n const docPaths = new Set(docs.map((doc) => doc.relPath));\n const vanished = touched.filter((path) => !docPaths.has(path));\n for (let i = 0; i < vanished.length; i += CONTENT_LOOKUP_CHUNK) {\n const chunk = vanished.slice(i, i + CONTENT_LOOKUP_CHUNK);\n const stmt = await conn.prepare(`SELECT \"path\" FROM content WHERE \"path\" IN (${chunk.map(() => '?').join(', ')})`);\n const rows = (await stmt.all(...chunk)) as Array<{ path: string }>;\n removed.push(...rows.map((row) => row.path));\n }\n\n if (removed.length > 0)\n await conn.runBatch(\n 'DELETE FROM content WHERE \"path\" = ?',\n removed.map((p) => [p])\n );\n // Keep document order and the existing insert/error semantics for added paths.\n const changedDocs = docs.filter((doc) => changed.has(doc.relPath));\n await appendRows(conn, 'content', CONTENT_COLUMNS, INSERT_CONTENT_SQL, changedDocs.map(contentRow));\n // Commit the stale mark with actual content changes. Identical rows leave prior staleness\n // untouched, and FTS preparation still owns missing-index recovery.\n if (removed.length > 0 || changedDocs.length > 0) await markContentStale(conn);\n}\n\n// DuckDB rejects more than one ALTER command per statement (\"Parser Error: Only one ALTER\n// command per statement is supported\", measured), so every name's clause joins into one string\n// and runs as a single exec() -- one column-add \"leg\" through the driver instead of `names.length`.\n// VARIANT is the only type that can hold the mixed bigint/number/string/null shapes mapValue()\n// produces for one key across files.\nasync function addColumns(conn: Connection, names: string[]): Promise<void> {\n if (names.length === 0) return;\n await conn.exec(names.map((name) => `ALTER TABLE frontmatter ADD COLUMN ${quoteIdent(name)} VARIANT`).join('; '));\n}\n\nexport const duckdbDialect: ReconcileDialect = {\n beginMode: () => 'BEGIN',\n checkColumnLimit(count) {\n if (count > MAX_FRONTMATTER_COLUMNS) {\n throw new SenseError('COLUMN_LIMIT', `frontmatter would need ${count} columns, crossing this store's sanity limit (${MAX_FRONTMATTER_COLUMNS}). Narrow the presets' include globs so fewer/other files are indexed, or fix whatever is generating unbounded frontmatter keys.`);\n }\n },\n addColumns,\n updateFrontmatter,\n reconcileContent,\n};\n"],"names":["duckdbDialect","CONTENT_COLUMNS","INSERT_CONTENT_SQL","map","quoteIdent","join","CONTENT_LOOKUP_CHUNK","contentRow","doc","relPath","search","title","summary","text","MAX_FRONTMATTER_COLUMNS","FRONTMATTER_UPDATE_CHUNK","withNativeStatement","native","sql","fn","stmt","errors","result","err","prepare","push","destroySync","length","AggregateError","updateFrontmatter","conn","writableColumns","rows","DuckDBVariantValue","DuckDBTypeId","physical","writable","pathIndex","columnTypes","insertSql","sameValue","i","chunk","paths","placeholders","selected","existing","plans","position","plan","end","assignments","missing","changed","signature","appendRows","slice","repair","row","index","rowIndex","bind","run","reader","runAndReadAll","Map","getRowObjects","path","old","get","flatMap","column","undefined","duckdb","duckdbApi","getRowObjectsJS","name","Error","type","value","Object","is","typeId","VARCHAR","HUGEINT","Number","isInteger","DOUBLE","reconcileContent","touched","docs","delta","added","reparsed","removed","docPaths","vanished","changedDocs","Set","filter","has","all","add","runBatch","p","markContentStale","addColumns","names","exec","beginMode","checkColumnLimit","count","SenseError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/reconcile.ts"],"sourcesContent":["import type { DuckDBConnection, DuckDBPreparedStatement, DuckDBValue } from '@duckdb/node-api';\nimport { SenseError } from '../../errors.ts';\nimport type { ReconcileDelta } from '../../features/types.ts';\nimport type { ParsedDoc } from '../../scan/index.ts';\nimport { appendRows, quoteIdent } from '../shared.ts';\nimport type { Connection, ReconcileDialect } from '../types.ts';\nimport type { DuckdbConnection } from './connection.ts';\nimport { markContentStale } from './lexical.ts';\nimport { duckdbApi } from './native.ts';\n\n// This store's dialect (types.ts's ReconcileDialect) for the shared orchestration in\n// store/reconcile.ts. `content` is a plain table, not FTS-virtual, so changed rows are maintained\n// here; DuckDB's ALTER TABLE needs a declared type, so every dynamic frontmatter\n// column is VARIANT (holds mapValue()'s mixed JS types for one key across files).\n\n// No rowid coupling needed (unlike sqlite's content, which links to frontmatter's rowid):\n// `path` is content's own primary key, so this is a plain per-doc row.\nconst CONTENT_COLUMNS = ['path', 'title', 'summary', 'text'];\nconst INSERT_CONTENT_SQL = `INSERT INTO content (${CONTENT_COLUMNS.map(quoteIdent).join(', ')}) VALUES (?, ?, ?, ?)`;\n// Bound the extra persisted text held for exact comparison, even during a full reparse.\nconst CONTENT_LOOKUP_CHUNK = 128;\n\ninterface ContentRow {\n path: string;\n title: string | null;\n summary: string | null;\n text: string | null;\n}\n\nfunction contentRow(doc: ParsedDoc): unknown[] {\n return [doc.relPath, doc.search.title, doc.search.summary, doc.search.text];\n}\n\n// No compile-time column cap in DuckDB (unlike SQLite's SQLITE_MAX_COLUMN); kept as a sanity fence anyway\n// so a runaway frontmatter generator fails with a clear message instead of an unbounded ALTER TABLE loop.\nconst MAX_FRONTMATTER_COLUMNS = 10_000;\nconst FRONTMATTER_UPDATE_CHUNK = 128;\n\nasync function withNativeStatement<T>(native: DuckDBConnection, sql: string, fn: (stmt: DuckDBPreparedStatement) => Promise<T>): Promise<T> {\n const stmt = await native.prepare(sql);\n const errors: unknown[] = [];\n let result!: T;\n try {\n result = await fn(stmt);\n } catch (err) {\n errors.push(err);\n }\n try {\n stmt.destroySync();\n } catch (err) {\n errors.push(err);\n }\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) throw new AggregateError(errors, 'frontmatter statement and cleanup failed');\n return result;\n}\n\n// Wide writes amplify native commit allocations even for one changed stamp.\n// Skip only known, exactly equal values; uncertain representations still write.\nasync function updateFrontmatter(conn: Connection, writableColumns: string[], rows: unknown[][]): Promise<void> {\n if (rows.length === 0) return;\n const native = (conn as DuckdbConnection).duckdb;\n const { DuckDBVariantValue, DuckDBTypeId } = await duckdbApi();\n const physical = await withNativeStatement(native, 'PRAGMA table_info(frontmatter)', async (stmt) => {\n const reader = await stmt.runAndReadAll();\n return reader.getRowObjectsJS() as Array<{ name: string; type: string }>;\n });\n const writable = new Map(writableColumns.map((name, i) => [name, i]));\n const pathIndex = writable.get('path');\n if (pathIndex === undefined) throw new Error('frontmatter update requires a writable path column');\n const columnTypes = new Map(physical.map((column) => [column.name, column.type]));\n const insertSql = `INSERT INTO frontmatter (${writableColumns.map(quoteIdent).join(', ')}) VALUES (${writableColumns.map(() => '?').join(', ')})`;\n const sameValue = (old: DuckDBValue, value: unknown, column: string): boolean => {\n if (value === null || value === undefined) return old === null;\n if (columnTypes.get(column) !== 'VARIANT') return Object.is(old, value);\n if (!(old instanceof DuckDBVariantValue)) return false;\n const typeId = typeof value === 'string' ? DuckDBTypeId.VARCHAR : typeof value === 'bigint' ? DuckDBTypeId.HUGEINT : typeof value === 'number' && !Number.isInteger(value) ? DuckDBTypeId.DOUBLE : undefined;\n return typeId !== undefined && old.type?.typeId === typeId && Object.is(old.value, value);\n };\n for (let i = 0; i < rows.length; i += FRONTMATTER_UPDATE_CHUNK) {\n const chunk = rows.slice(i, i + FRONTMATTER_UPDATE_CHUNK);\n const paths = chunk.map((row) => row[pathIndex] as string);\n const placeholders = paths.map(() => '?').join(', ');\n const selected = writableColumns.map(quoteIdent).join(', ');\n const existing = await withNativeStatement(native, `SELECT ${selected} FROM frontmatter WHERE \"path\" IN (${placeholders})`, async (stmt) => {\n stmt.bind(paths);\n const reader = await stmt.runAndReadAll();\n // Native wrappers distinguish numeric tags and SQL NULL from VARIANT null.\n return new Map(reader.getRowObjects().map((row) => [row.path as string, row]));\n });\n const plans = chunk.map((row) => {\n const old = existing.get(row[pathIndex] as string);\n const changed = old ? writableColumns.flatMap((column, index) => (sameValue(old[column], row[index], column) ? [] : [index])) : [];\n return { row, missing: old === undefined, changed, signature: changed.join(',') };\n });\n for (let position = 0; position < plans.length; ) {\n const plan = plans[position];\n if (!plan.missing && plan.changed.length === 0) {\n ++position;\n continue;\n }\n let end = position + 1;\n while (end < plans.length && plans[end].missing === plan.missing && plans[end].signature === plan.signature) ++end;\n if (plan.missing) {\n await appendRows(\n conn,\n 'frontmatter',\n writableColumns,\n insertSql,\n plans.slice(position, end).map((repair) => repair.row)\n );\n } else {\n const assignments = plan.changed.map((index) => `${quoteIdent(writableColumns[index])} = ?`).join(', ');\n await withNativeStatement(native, `UPDATE frontmatter SET ${assignments} WHERE \"path\" = ?`, async (stmt) => {\n for (let rowIndex = position; rowIndex < end; ++rowIndex) {\n const row = plans[rowIndex].row;\n stmt.bind([...plan.changed.map((index) => row[index] ?? null), row[pathIndex]] as DuckDBValue[]);\n await stmt.run();\n }\n });\n }\n position = end;\n }\n }\n}\n\nasync function reconcileContent(conn: Connection, touched: string[], docs: ParsedDoc[], delta: ReconcileDelta): Promise<void> {\n const added = new Set(delta.added);\n const reparsed = docs.filter((doc) => !added.has(doc.relPath));\n const changed = new Set(delta.added);\n const removed: string[] = [];\n for (let i = 0; i < reparsed.length; i += CONTENT_LOOKUP_CHUNK) {\n const chunk = reparsed.slice(i, i + CONTENT_LOOKUP_CHUNK);\n const stmt = await conn.prepare(`SELECT \"path\", title, summary, text FROM content WHERE \"path\" IN (${chunk.map(() => '?').join(', ')})`);\n const rows = (await stmt.all(...chunk.map((doc) => doc.relPath))) as ContentRow[];\n const existing = new Map(rows.map((row) => [row.path, row]));\n for (const doc of chunk) {\n const row = existing.get(doc.relPath);\n if (row && row.title === doc.search.title && row.summary === doc.search.summary && row.text === doc.search.text) continue;\n changed.add(doc.relPath);\n if (row) removed.push(doc.relPath);\n }\n }\n\n const docPaths = new Set(docs.map((doc) => doc.relPath));\n const vanished = touched.filter((path) => !docPaths.has(path));\n for (let i = 0; i < vanished.length; i += CONTENT_LOOKUP_CHUNK) {\n const chunk = vanished.slice(i, i + CONTENT_LOOKUP_CHUNK);\n const stmt = await conn.prepare(`SELECT \"path\" FROM content WHERE \"path\" IN (${chunk.map(() => '?').join(', ')})`);\n const rows = (await stmt.all(...chunk)) as Array<{ path: string }>;\n removed.push(...rows.map((row) => row.path));\n }\n\n if (removed.length > 0)\n await conn.runBatch(\n 'DELETE FROM content WHERE \"path\" = ?',\n removed.map((p) => [p])\n );\n // Keep document order and the existing insert/error semantics for added paths.\n const changedDocs = docs.filter((doc) => changed.has(doc.relPath));\n await appendRows(conn, 'content', CONTENT_COLUMNS, INSERT_CONTENT_SQL, changedDocs.map(contentRow));\n // Commit the stale mark with actual content changes. Identical rows leave prior staleness\n // untouched, and FTS preparation still owns missing-index recovery.\n if (removed.length > 0 || changedDocs.length > 0) await markContentStale(conn);\n}\n\n// DuckDB rejects more than one ALTER command per statement (\"Parser Error: Only one ALTER\n// command per statement is supported\", measured), so every name's clause joins into one string\n// and runs as a single exec() -- one column-add \"leg\" through the driver instead of `names.length`.\n// VARIANT is the only type that can hold the mixed bigint/number/string/null shapes mapValue()\n// produces for one key across files.\nasync function addColumns(conn: Connection, names: string[]): Promise<void> {\n if (names.length === 0) return;\n await conn.exec(names.map((name) => `ALTER TABLE frontmatter ADD COLUMN ${quoteIdent(name)} VARIANT`).join('; '));\n}\n\nexport const duckdbDialect: ReconcileDialect = {\n beginMode: () => 'BEGIN',\n checkColumnLimit(count) {\n if (count > MAX_FRONTMATTER_COLUMNS) {\n throw new SenseError('COLUMN_LIMIT', `frontmatter would need ${count} columns, crossing this store's sanity limit (${MAX_FRONTMATTER_COLUMNS}). Narrow the presets' include globs so fewer/other files are indexed, or fix whatever is generating unbounded frontmatter keys.`);\n }\n },\n addColumns,\n updateFrontmatter,\n reconcileContent,\n};\n"],"names":["duckdbDialect","CONTENT_COLUMNS","INSERT_CONTENT_SQL","map","quoteIdent","join","CONTENT_LOOKUP_CHUNK","contentRow","doc","relPath","search","title","summary","text","MAX_FRONTMATTER_COLUMNS","FRONTMATTER_UPDATE_CHUNK","withNativeStatement","native","sql","fn","stmt","errors","result","err","prepare","push","destroySync","length","AggregateError","updateFrontmatter","conn","writableColumns","rows","DuckDBVariantValue","DuckDBTypeId","physical","writable","pathIndex","columnTypes","insertSql","sameValue","i","chunk","paths","placeholders","selected","existing","plans","position","plan","end","assignments","missing","changed","signature","appendRows","slice","repair","row","index","rowIndex","bind","run","reader","runAndReadAll","Map","getRowObjects","path","old","get","flatMap","column","undefined","duckdb","duckdbApi","getRowObjectsJS","name","Error","type","value","Object","is","typeId","VARCHAR","HUGEINT","Number","isInteger","DOUBLE","reconcileContent","touched","docs","delta","added","reparsed","removed","docPaths","vanished","changedDocs","Set","filter","has","all","add","runBatch","p","markContentStale","addColumns","names","exec","beginMode","checkColumnLimit","count","SenseError"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/sql-functions.ts"],"sourcesContent":["import type { DuckDBConnection } from '@duckdb/node-api';\nimport { segmentMatch } from '../../text/segment.ts';\nimport { basenameImpl, hasImpl } from '../sql-functions.ts';\nimport { duckdbApi } from './native.ts';\n\n// Dynamic, not a top-level import: sqlite trees must never attempt to resolve this optional peer dependency (open.ts's connect()).\n// Goes through native.ts's shared duckdbApi(), not its own bare import, since a second independent lookup would hit Node's stale pre-install resolution miss.\nexport async function registerFunctions(conn: DuckDBConnection): Promise<void> {\n const { DuckDBIntegerType, DuckDBScalarFunction, DuckDBVarCharType } = await duckdbApi();\n conn.registerScalarFunction(\n DuckDBScalarFunction.create({\n name: 'has',\n parameterTypes: [DuckDBVarCharType.instance, DuckDBVarCharType.instance],\n returnType: DuckDBIntegerType.instance,\n mainFunction(_info, inputChunk, outputVector) {\n const fieldVec = inputChunk.getColumnVector(0);\n const valueVec = inputChunk.getColumnVector(1);\n for (let i = 0; i < inputChunk.rowCount; i++) outputVector.setItem(i, hasImpl(fieldVec.getItem(i), valueVec.getItem(i)));\n outputVector.flush();\n },\n })\n );\n conn.registerScalarFunction(\n DuckDBScalarFunction.create({\n name: 'basename',\n parameterTypes: [DuckDBVarCharType.instance],\n varArgsType: DuckDBVarCharType.instance,\n returnType: DuckDBVarCharType.instance,\n mainFunction(_info, inputChunk, outputVector) {\n const pathVec = inputChunk.getColumnVector(0);\n const suffixVec = inputChunk.columnCount > 1 ? inputChunk.getColumnVector(1) : null;\n for (let i = 0; i < inputChunk.rowCount; i++) outputVector.setItem(i, basenameImpl(pathVec.getItem(i), suffixVec ? suffixVec.getItem(i) : undefined));\n outputVector.flush();\n },\n })\n );\n // segment() rewrites unspaced-script runs into the grapheme phrase FTS5's `_seg` sidecars need (text/segment.ts); this store's own\n // lexical index uses contains() instead and never calls this, but hand-written raw SQL naming it gets the real implementation, not a silent passthrough (PRINCIPLES: no-silent-modes).\n conn.registerScalarFunction(\n DuckDBScalarFunction.create({\n name: 'segment',\n parameterTypes: [DuckDBVarCharType.instance],\n returnType: DuckDBVarCharType.instance,\n mainFunction(_info, inputChunk, outputVector) {\n const textVec = inputChunk.getColumnVector(0);\n for (let i = 0; i < inputChunk.rowCount; i++) outputVector.setItem(i, segmentMatch(String(textVec.getItem(i) ?? '')));\n outputVector.flush();\n },\n })\n );\n}\n"],"names":["registerFunctions","conn","DuckDBIntegerType","DuckDBScalarFunction","DuckDBVarCharType","duckdbApi","registerScalarFunction","create","name","parameterTypes","instance","returnType","mainFunction","_info","inputChunk","outputVector","fieldVec","getColumnVector","valueVec","i","rowCount","setItem","hasImpl","getItem","flush","varArgsType","pathVec","suffixVec","columnCount","basenameImpl","undefined","textVec","segmentMatch","String"],"mappings":";;;;+BAOsBA;;;eAAAA;;;yBANO;8BACS;wBACZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAInB,SAAeA,kBAAkBC,IAAsB;;YACW,MAA/DC,mBAAmBC,sBAAsBC;;;;oBAAsB;;wBAAMC,IAAAA,mBAAS;;;oBAAf,OAAA,eAA/DH,oBAA+D,KAA/DA,mBAAmBC,uBAA4C,KAA5CA,sBAAsBC,oBAAsB,KAAtBA;oBACjDH,KAAKK,sBAAsB,CACzBH,qBAAqBI,MAAM,CAAC;wBAC1BC,MAAM;wBACNC,cAAc;4BAAGL,kBAAkBM,QAAQ;4BAAEN,kBAAkBM,QAAQ;;wBACvEC,YAAYT,kBAAkBQ,QAAQ;wBACtCE,cAAAA,SAAAA,aAAaC,KAAK,EAAEC,UAAU,EAAEC,YAAY;4BAC1C,IAAMC,WAAWF,WAAWG,eAAe,CAAC;4BAC5C,IAAMC,WAAWJ,WAAWG,eAAe,CAAC;4BAC5C,IAAK,IAAIE,IAAI,GAAGA,IAAIL,WAAWM,QAAQ,EAAED,IAAKJ,aAAaM,OAAO,CAACF,GAAGG,IAAAA,uBAAO,EAACN,SAASO,OAAO,CAACJ,IAAID,SAASK,OAAO,CAACJ;4BACpHJ,aAAaS,KAAK;wBACpB;oBACF;oBAEFvB,KAAKK,sBAAsB,CACzBH,qBAAqBI,MAAM,CAAC;wBAC1BC,MAAM;wBACNC,cAAc;4BAAGL,kBAAkBM,QAAQ;;wBAC3Ce,aAAarB,kBAAkBM,QAAQ;wBACvCC,YAAYP,kBAAkBM,QAAQ;wBACtCE,cAAAA,SAAAA,aAAaC,KAAK,EAAEC,UAAU,EAAEC,YAAY;4BAC1C,IAAMW,UAAUZ,WAAWG,eAAe,CAAC;4BAC3C,IAAMU,YAAYb,WAAWc,WAAW,GAAG,IAAId,WAAWG,eAAe,CAAC,KAAK;4BAC/E,IAAK,IAAIE,IAAI,GAAGA,IAAIL,WAAWM,QAAQ,EAAED,IAAKJ,aAAaM,OAAO,CAACF,GAAGU,IAAAA,4BAAY,EAACH,QAAQH,OAAO,CAACJ,IAAIQ,YAAYA,UAAUJ,OAAO,CAACJ,KAAKW;4BAC1If,aAAaS,KAAK;wBACpB;oBACF;oBAEF,mIAAmI;oBACnI,uLAAuL;oBACvLvB,KAAKK,sBAAsB,CACzBH,qBAAqBI,MAAM,CAAC;wBAC1BC,MAAM;wBACNC,cAAc;4BAAGL,kBAAkBM,QAAQ;;wBAC3CC,YAAYP,kBAAkBM,QAAQ;wBACtCE,cAAAA,SAAAA,aAAaC,KAAK,EAAEC,UAAU,EAAEC,YAAY;gCAEgDgB;4BAD1F,IAAMA,UAAUjB,WAAWG,eAAe,CAAC;4BAC3C,IAAK,IAAIE,IAAI,GAAGA,IAAIL,WAAWM,QAAQ,EAAED,IAAKJ,aAAaM,OAAO,CAACF,GAAGa,IAAAA,uBAAY,EAACC,QAAOF,mBAAAA,QAAQR,OAAO,CAACJ,gBAAhBY,8BAAAA,mBAAsB;4BAChHhB,aAAaS,KAAK;wBACpB;oBACF;;;;;;IAEJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/store.ts"],"sourcesContent":["import type { DuckDBConnection, DuckDBInstance } from '@duckdb/node-api';\nimport { STORE_DIMS } from '../../embed/types.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 { storeRowToJs } from './connection.ts';\nimport { fieldStats } from './fieldStats.ts';\nimport { createLexicalIndex } from './lexical.ts';\nimport { scanCandidates, scanSimilar, writeVectorBatch } from './vectors.ts';\n\n// Portable surface, links/sections/tags/rank, raw sql passthrough, lexical (fts BM25 + contains(), lexical.ts), and vectors (native\n// FLOAT[N] + array_cosine_similarity, vectors.ts) are implemented. segment() registers as a UDF (sql-functions.ts).\nexport const CAPABILITIES: ReadonlySet<Capability> = new Set(['vectors', 'segment']);\n\n// Shares one Connection instance (conn) with the builder's own reconcile call so transaction depth (transaction.ts) is tracked against the same object everywhere.\n// The instance is the native handle that owns the WAL: close() must close it, not just disconnect, or DuckDB never checkpoints and the next open reads a mismatched WAL.\nexport function createStore(instance: DuckDBInstance, duckdb: DuckDBConnection, conn: Connection): Store {\n const lex = createLexicalIndex(conn);\n return {\n name: 'duckdb',\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 docs: {\n async columns() {\n return [...(await getColumns(conn))];\n },\n fieldStats: (columns, scopeWhere) => fieldStats(conn, columns, scopeWhere),\n },\n lexical: {\n query: lex.query,\n },\n // The column's fixed DDL width (STORE_DIMS) is what every scan binds against, not the interface's per-call storeDims --\n // see vectors.ts's padded() for why a shorter vector remains correct against a wider column.\n vectors: {\n pending: () => pendingRows(conn),\n writeVectors: (rows) => writeVectorBatch(duckdb, conn, STORE_DIMS, rows),\n candidates: (qv, _storeDims, fetch, allowed) => scanCandidates(duckdb, qv, STORE_DIMS, fetch, allowed),\n similar: (path, opts) => scanSimilar(duckdb, conn, STORE_DIMS, path, opts),\n hasVector: (path) => hasVectorRow(conn, path),\n },\n // No comparable setting to report yet.\n async engineStatus() {\n return {};\n },\n raw: {\n async prepare(sql: string) {\n const prepared = await duckdb.prepare(sql);\n return {\n columns: () => {\n const out: Array<{ name: string }> = [];\n for (let i = 0; i < prepared.columnCount; i++) out.push({ name: prepared.columnName(i) });\n return out;\n },\n // Real incremental streaming: DuckDB reads its own result in row-group chunks, so\n // each readUntil only fetches what isn't already in hand.\n iterate: async function* (...params: unknown[]) {\n if (params.length > 0) prepared.bind(params as Parameters<typeof prepared.bind>[0]);\n const reader = await prepared.streamAndRead();\n let yielded = 0;\n do {\n await reader.readUntil(reader.currentRowCount + 2048);\n const rows = reader.getRowObjectsJS() as Array<Record<string, unknown>>;\n for (; yielded < rows.length; yielded++) yield storeRowToJs(rows[yielded]);\n } while (!reader.done);\n },\n };\n },\n },\n async close() {\n // Order matters: the connection must be gone before the instance closes the WAL.\n duckdb.disconnectSync();\n instance.closeSync();\n },\n };\n}\n"],"names":["CAPABILITIES","createStore","Set","instance","duckdb","conn","lex","createLexicalIndex","name","capabilities","exec","sql","prepare","runBatch","paramRows","transaction","fn","withTransaction","docs","columns","getColumns","fieldStats","scopeWhere","lexical","query","vectors","pending","pendingRows","writeVectors","rows","writeVectorBatch","STORE_DIMS","candidates","qv","_storeDims","fetch","allowed","scanCandidates","similar","path","opts","scanSimilar","hasVector","hasVectorRow","engineStatus","raw","prepared","out","i","columnCount","push","columnName","iterate","params","reader","yielded","length","bind","streamAndRead","readUntil","currentRowCount","getRowObjectsJS","storeRowToJs","done","close","disconnectSync","closeSync"],"mappings":";;;;;;;;;;;QAaaA;eAAAA;;QAIGC;eAAAA;;;uBAhBW;wBACA;6BACK;yBAEU;4BACb;4BACF;yBACQ;0BAC2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIvD,IAAMD,eAAwC,IAAIE,IAAI;IAAC;IAAW;CAAU;AAI5E,SAASD,YAAYE,QAAwB,EAAEC,MAAwB,EAAEC,IAAgB;IAC9F,IAAMC,MAAMC,IAAAA,6BAAkB,EAACF;IAC/B,OAAO;QACLG,MAAM;QACNC,cAAcT;QACRU,MAAN,SAAMA,KAAKC,GAAW;;;;;4BACpB;;gCAAMN,KAAKK,IAAI,CAACC;;;4BAAhB;;;;;;YACF;;QACMC,SAAN,SAAMA,QAAQD,GAAW;;;oBACvB;;wBAAON,KAAKO,OAAO,CAACD;;;YACtB;;QACME,UAAN,SAAMA,SAASF,GAAW,EAAEG,SAAsB;;;;;4BAChD;;gCAAMT,KAAKQ,QAAQ,CAACF,KAAKG;;;4BAAzB;;;;;;YACF;;QACMC,aAAN,SAAMA,YAAeC,EAAoB;;;oBACvC;;wBAAOC,IAAAA,8BAAe,EAACZ,MAAMW;;;YAC/B;;QACAE,MAAM;YACEC,SAAN,SAAMA;;;;;gCACQ;;oCAAMC,IAAAA,oBAAU,EAACf;;;gCAA7B;;oCAAQ;wCAAI;;;;;gBACd;;YACAgB,YAAY,SAAZA,WAAaF,SAASG;uBAAeD,IAAAA,wBAAU,EAAChB,MAAMc,SAASG;;QACjE;QACAC,SAAS;YACPC,OAAOlB,IAAIkB,KAAK;QAClB;QACA,wHAAwH;QACxH,6FAA6F;QAC7FC,SAAS;YACPC,SAAS,SAATA;uBAAeC,IAAAA,sBAAW,EAACtB;;YAC3BuB,cAAc,SAAdA,aAAeC;uBAASC,IAAAA,4BAAgB,EAAC1B,QAAQC,MAAM0B,mBAAU,EAAEF;;YACnEG,YAAY,SAAZA,WAAaC,IAAIC,YAAYC,OAAOC;uBAAYC,IAAAA,0BAAc,EAACjC,QAAQ6B,IAAIF,mBAAU,EAAEI,OAAOC;;YAC9FE,SAAS,SAATA,QAAUC,MAAMC;uBAASC,IAAAA,uBAAW,EAACrC,QAAQC,MAAM0B,mBAAU,EAAEQ,MAAMC;;YACrEE,WAAW,SAAXA,UAAYH;uBAASI,IAAAA,uBAAY,EAACtC,MAAMkC;;QAC1C;QAEMK,cADN,uCAAuC;QACvC,SAAMA;;;oBACJ;;wBAAO,CAAC;;;YACV;;QACAC,KAAK;YACGjC,SAAN,SAAMA,QAAQD,GAAW;;wBACjBmC;;;;gCAAW;;oCAAM1C,OAAOQ,OAAO,CAACD;;;gCAAhCmC,WAAW;gCACjB;;oCAAO;wCACL3B,SAAS,SAATA;4CACE,IAAM4B,MAA+B,EAAE;4CACvC,IAAK,IAAIC,IAAI,GAAGA,IAAIF,SAASG,WAAW,EAAED,IAAKD,IAAIG,IAAI,CAAC;gDAAE1C,MAAMsC,SAASK,UAAU,CAACH;4CAAG;4CACvF,OAAOD;wCACT;wCACA,kFAAkF;wCAClF,0DAA0D;wCAC1DK,SAAS,SAATA;4CAA0B,IAAA,IAAA,OAAA,UAAA,QAAA,AAAGC,SAAH,UAAA,OAAA,OAAA,GAAA,OAAA,MAAA;gDAAGA,OAAH,QAAA,SAAA,CAAA,KAAoB;;;oDAEtCC,QACFC,SAGI1B;;;;4DALR,IAAIwB,OAAOG,MAAM,GAAG,GAAGV,SAASW,IAAI,CAACJ;4DACtB;;gEAAA,uBAAMP,SAASY,aAAa;;;4DAArCJ,SAAS;4DACXC,UAAU;;;4DAEZ;;gEAAA,uBAAMD,OAAOK,SAAS,CAACL,OAAOM,eAAe,GAAG;;;4DAAhD;4DACM/B,OAAOyB,OAAOO,eAAe;;;iEAC5BN,CAAAA,UAAU1B,KAAK2B,MAAM,AAAD;;;;4DAAc;;gEAAMM,IAAAA,0BAAY,EAACjC,IAAI,CAAC0B,QAAQ;;;4DAAhC;;;4DAAXA;;;;;;gEACvB,CAACD,OAAOS,IAAI,EAAZ;;;;;;;;;;;4CACX;;oCACF;;;;gBACF;;QACF;QACMC,OAAN,SAAMA;;;oBACJ,iFAAiF;oBACjF5D,OAAO6D,cAAc;oBACrB9D,SAAS+D,SAAS;;;;;YACpB;;IACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/duckdb/vectors.ts"],"sourcesContent":["import type { DuckDBConnection, DuckDBType, DuckDBValue } from '@duckdb/node-api';\nimport { withTransaction } from '../transaction.ts';\nimport type { Connection, VectorCandidate, VectorSimilar, VectorWriteRow } from '../types.ts';\nimport { asCosine, sampleEvenly } from '../vectors.ts';\nimport { duckdbApi } from './native.ts';\n\n// This store keeps vectors as native FLOAT[dims] arrays (dims fixed at DDL time by open.ts's ensureSchema, from embed/types.ts's STORE_DIMS) and\n// scans them with array_cosine_similarity, pushing top-k into SQL instead of pulling every row into JS; sqlite's int8+scale BLOB scan is its own representation. Every function here takes `dims` as a parameter rather than importing STORE_DIMS directly, so it stays testable at any width.\n\n// A value import of '@duckdb/node-api' must never sit at module top level, or a sqlite-only tree would resolve this optional dependency\n// just by importing store/index.ts; native.ts's shared duckdbApi() keeps that lazy and reuses whatever open.ts already resolved.\n\n// A bind position whose type is left to auto-inference (safe for plain strings/numbers; only\n// the vector ARRAY positions below need an explicit type -- see writeVectorBatch's comment).\nconst untyped = undefined as unknown as DuckDBType;\nconst VECTOR_WRITE_STAGE = '_sense_vector_write_stage';\n\n// Created once per native connection outside write transactions; its lifetime follows that connection.\nexport async function createVectorWriteStage(duckdb: DuckDBConnection, dims: number): Promise<void> {\n await duckdb.run(`CREATE TEMP TABLE ${VECTOR_WRITE_STAGE} (\"path\" TEXT, chunk INTEGER, vector FLOAT[${dims}])`);\n}\n\n// The DDL-fixed array width can exceed a vector's actual length (a hypothetical model sliced under the column's width);\n// zero-padding leaves cosine scores unchanged since the added dimensions contribute nothing to either vector's dot product or norm.\nfunction padded(values: ArrayLike<number>, dims: number): number[] {\n const out = new Array<number>(dims).fill(0);\n for (let d = 0; d < Math.min(values.length, dims); d++) out[d] = values[d];\n return out;\n}\n\nfunction inClause(column: string, count: number): string {\n return `${column} IN (${Array.from({ length: count }, () => '?').join(', ')})`;\n}\n\n// Rows arrive int8-quantized with a per-vector scale (the wire format embed/query.ts produces for every store, see toStore);\n// dequantizing into a plain float array is this store's own representation choice, so both stores are handed the same vectors and diverge only here.\nfunction dequantize(row: VectorWriteRow, dims: number): number[] {\n const q = new Int8Array(row.vector.buffer, row.vector.byteOffset, row.vector.byteLength);\n return padded(\n Array.from(q, (v) => v * row.scale),\n dims\n );\n}\n\n// The native appender needs an explicit FLOAT array type: inference from an integer first component\n// silently truncates fractional components. The fixed UPDATE keeps each provider batch keyed by path and chunk.\nexport async function writeVectorBatch(duckdb: DuckDBConnection, conn: Connection, dims: number, rows: VectorWriteRow[]): Promise<void> {\n if (rows.length === 0) return;\n const { ARRAY, FLOAT } = await duckdbApi();\n const vectorType = ARRAY(FLOAT, dims);\n\n await withTransaction(conn, async () => {\n await duckdb.run(`DELETE FROM ${VECTOR_WRITE_STAGE}`);\n const appender = await duckdb.createAppender(VECTOR_WRITE_STAGE);\n try {\n for (const row of rows) {\n appender.appendVarchar(row.path);\n appender.appendInteger(row.chunk);\n appender.appendArray(dequantize(row, dims), vectorType);\n appender.endRow();\n }\n appender.flushSync();\n } finally {\n appender.closeSync();\n }\n await duckdb.run(`UPDATE embeddings SET vector = staged.vector FROM ${VECTOR_WRITE_STAGE} AS staged WHERE embeddings.\"path\" = staged.\"path\" AND embeddings.chunk = staged.chunk`);\n });\n}\n\n// Best chunk per file by cosine, with the earliest chunk winning exact score ties.\n// An empty `allowed` set matches sqlite's scan (every row filtered out) without touching the table.\nexport async function scanCandidates(duckdb: DuckDBConnection, qv: Float32Array, dims: number, fetch: number, allowed?: Set<string>): Promise<VectorCandidate[]> {\n if (allowed && allowed.size === 0) return [];\n const { arrayValue, ARRAY, DOUBLE } = await duckdbApi();\n const allowedList = allowed ? [...allowed] : [];\n const query = padded(qv, dims);\n const queryNorm = Math.sqrt(query.reduce((sum, value) => sum + value * value, 0));\n const score = queryNorm === 0 ? '0.0' : 'CASE WHEN array_inner_product(vector, vector) = 0 THEN 0.0 ELSE array_cosine_similarity(vector, ?) END';\n const sql = `SELECT \"path\", start_line, end_line, score\n FROM (\n SELECT \"path\", start_line, end_line, score,\n row_number() OVER (PARTITION BY \"path\" ORDER BY score DESC, chunk ASC) AS selected\n FROM (\n SELECT \"path\", chunk, start_line, end_line, ${score} AS score\n FROM embeddings\n WHERE vector IS NOT NULL ${allowed ? `AND ${inClause('\"path\"', allowedList.length)}` : ''}\n ) sub\n ) ranked\n WHERE selected = 1\n ORDER BY score DESC, \"path\" ASC\n LIMIT ?`;\n const stmt = await duckdb.prepare(sql);\n try {\n const values: DuckDBValue[] = [...(queryNorm === 0 ? [] : [arrayValue(query)]), ...allowedList, fetch];\n const types: DuckDBType[] = [...(queryNorm === 0 ? [] : [ARRAY(DOUBLE, dims)]), ...allowedList.map(() => untyped), untyped];\n stmt.bind(values, types);\n const reader = await stmt.runAndReadAll();\n const rows = reader.getRowObjectsJS() as Array<{ path: string; start_line: number; end_line: number; score: number }>;\n return rows.map((r) => ({ path: r.path, lines: `L${r.start_line}-${r.end_line}`, similarity: asCosine(r.score) }));\n } finally {\n stmt.destroySync();\n }\n}\n\n// Note-to-note similarity is the max cosine over (target chunk, other chunk) pairs, pushed into one native scan: the sampled target vectors become\n// a small VALUES list, cross-joined against every stored vector and reduced with max()/GROUP BY, so the O(target x stored) cost (12.7s at 201 chunks/note in JS) runs vectorized instead of scalar.\nexport async function scanSimilar(duckdb: DuckDBConnection, conn: Connection, dims: number, path: string, opts: { exclude: Set<string>; allowed?: Set<string>; k: number }): Promise<VectorSimilar[]> {\n if (opts.allowed && opts.allowed.size === 0) return [];\n const targetStmt = await conn.prepare('SELECT vector FROM embeddings WHERE \"path\" = ? AND vector IS NOT NULL ORDER BY chunk');\n const targetRows = (await targetStmt.all(path)) as Array<{ vector: number[] }>;\n if (targetRows.length === 0) return [];\n const targets = sampleEvenly(targetRows).map((row) => row.vector);\n\n const { arrayValue, ARRAY, DOUBLE } = await duckdbApi();\n const excludeList = [...opts.exclude];\n const allowedList = opts.allowed ? [...opts.allowed] : [];\n const sql = `WITH targets(tv) AS (VALUES ${targets.map(() => '(?)').join(', ')}), grouped AS (\n SELECT e.\"path\" AS path, max(CASE WHEN array_inner_product(e.vector, e.vector) = 0 OR array_inner_product(t.tv, t.tv) = 0 THEN 0.0 ELSE array_cosine_similarity(e.vector, t.tv) END) AS score\n FROM embeddings e, targets t\n WHERE e.vector IS NOT NULL AND e.\"path\" != ?\n ${excludeList.length > 0 ? `AND NOT ${inClause('e.\"path\"', excludeList.length)}` : ''}\n ${opts.allowed ? `AND ${inClause('e.\"path\"', allowedList.length)}` : ''}\n GROUP BY e.\"path\"\n )\n SELECT path, score FROM grouped\n ORDER BY score DESC, path ASC\n LIMIT ?`;\n const stmt = await duckdb.prepare(sql);\n try {\n const values: DuckDBValue[] = [...targets.map((t) => arrayValue(padded(t, dims))), path, ...excludeList, ...allowedList, opts.k];\n const types: DuckDBType[] = [...targets.map(() => ARRAY(DOUBLE, dims)), untyped, ...excludeList.map(() => untyped), ...allowedList.map(() => untyped), untyped];\n stmt.bind(values, types);\n const reader = await stmt.runAndReadAll();\n const rows = reader.getRowObjectsJS() as Array<{ path: string; score: number }>;\n return rows.map((r) => ({ path: r.path, similarity: asCosine(r.score) }));\n } finally {\n stmt.destroySync();\n }\n}\n"],"names":["createVectorWriteStage","scanCandidates","scanSimilar","writeVectorBatch","untyped","undefined","VECTOR_WRITE_STAGE","duckdb","dims","run","padded","values","out","Array","fill","d","Math","min","length","inClause","column","count","from","join","dequantize","row","q","Int8Array","vector","buffer","byteOffset","byteLength","v","scale","conn","rows","ARRAY","FLOAT","vectorType","duckdbApi","withTransaction","appender","createAppender","appendVarchar","path","appendInteger","chunk","appendArray","endRow","flushSync","closeSync","qv","fetch","allowed","arrayValue","DOUBLE","allowedList","query","queryNorm","score","sql","stmt","types","reader","size","sqrt","reduce","sum","value","prepare","map","bind","runAndReadAll","getRowObjectsJS","r","lines","start_line","end_line","similarity","asCosine","destroySync","opts","targetStmt","targetRows","targets","excludeList","all","sampleEvenly","exclude","t","k"],"mappings":";;;;;;;;;;;QAkBsBA;eAAAA;;QAqDAC;eAAAA;;QAmCAC;eAAAA;;QA5DAC;eAAAA;;;6BA7CU;yBAEO;wBACb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE1B,iJAAiJ;AACjJ,+RAA+R;AAE/R,wIAAwI;AACxI,iIAAiI;AAEjI,6FAA6F;AAC7F,6FAA6F;AAC7F,IAAMC,UAAUC;AAChB,IAAMC,qBAAqB;AAGpB,SAAeN,uBAAuBO,MAAwB,EAAEC,IAAY;;;;;oBACjF;;wBAAMD,OAAOE,GAAG,CAAC,AAAC,qBAAoFD,OAAhEF,oBAAmB,+CAAkD,OAALE,MAAK;;;oBAA3G;;;;;;IACF;;AAEA,wHAAwH;AACxH,oIAAoI;AACpI,SAASE,OAAOC,MAAyB,EAAEH,IAAY;IACrD,IAAMI,MAAM,IAAIC,MAAcL,MAAMM,IAAI,CAAC;IACzC,IAAK,IAAIC,IAAI,GAAGA,IAAIC,KAAKC,GAAG,CAACN,OAAOO,MAAM,EAAEV,OAAOO,IAAKH,GAAG,CAACG,EAAE,GAAGJ,MAAM,CAACI,EAAE;IAC1E,OAAOH;AACT;AAEA,SAASO,SAASC,MAAc,EAAEC,KAAa;IAC7C,OAAO,AAAC,GAAgBR,OAAdO,QAAO,SAA2D,OAApDP,MAAMS,IAAI,CAAC;QAAEJ,QAAQG;IAAM,GAAG;eAAM;OAAKE,IAAI,CAAC,OAAM;AAC9E;AAEA,6HAA6H;AAC7H,qJAAqJ;AACrJ,SAASC,WAAWC,GAAmB,EAAEjB,IAAY;IACnD,IAAMkB,IAAI,IAAIC,UAAUF,IAAIG,MAAM,CAACC,MAAM,EAAEJ,IAAIG,MAAM,CAACE,UAAU,EAAEL,IAAIG,MAAM,CAACG,UAAU;IACvF,OAAOrB,OACLG,MAAMS,IAAI,CAACI,GAAG,SAACM;eAAMA,IAAIP,IAAIQ,KAAK;QAClCzB;AAEJ;AAIO,SAAeL,iBAAiBI,MAAwB,EAAE2B,IAAgB,EAAE1B,IAAY,EAAE2B,IAAsB;;YAE5F,MAAjBC,OAAOC,OACTC;;;;oBAFN,IAAIH,KAAKjB,MAAM,KAAK,GAAG;;;oBACE;;wBAAMqB,IAAAA,mBAAS;;;oBAAf,OAAA,eAAjBH,QAAiB,KAAjBA,OAAOC,QAAU,KAAVA;oBACTC,aAAaF,MAAMC,OAAO7B;oBAEhC;;wBAAMgC,IAAAA,8BAAe,EAACN,MAAM;;oCAEpBO,UAEC,2BAAA,mBAAA,gBAAA,WAAA,OAAMhB;;;;4CAHb;;gDAAMlB,OAAOE,GAAG,CAAC,AAAC,eAAiC,OAAnBH;;;4CAAhC;4CACiB;;gDAAMC,OAAOmC,cAAc,CAACpC;;;4CAAvCmC,WAAW;4CACjB,IAAI;gDACG,kCAAA,2BAAA;;oDAAL,IAAK,YAAaN,2BAAb,6BAAA,QAAA,yBAAA,iCAAmB;wDAAbV,MAAN;wDACHgB,SAASE,aAAa,CAAClB,IAAImB,IAAI;wDAC/BH,SAASI,aAAa,CAACpB,IAAIqB,KAAK;wDAChCL,SAASM,WAAW,CAACvB,WAAWC,KAAKjB,OAAO8B;wDAC5CG,SAASO,MAAM;oDACjB;;oDALK;oDAAA;;;6DAAA,6BAAA;4DAAA;;;4DAAA;kEAAA;;;;gDAMLP,SAASQ,SAAS;4CACpB,SAAU;gDACRR,SAASS,SAAS;4CACpB;4CACA;;gDAAM3C,OAAOE,GAAG,CAAC,AAAC,qDAAuE,OAAnBH,oBAAmB;;;4CAAzF;;;;;;4BACF;;;;oBAfA;;;;;;IAgBF;;AAIO,SAAeL,eAAeM,MAAwB,EAAE4C,EAAgB,EAAE3C,IAAY,EAAE4C,KAAa,EAAEC,OAAqB;;YAE3F,MAA9BC,YAAYlB,OAAOmB,QACrBC,aACAC,OACAC,WACAC,OACAC,KAaAC,MAEElD,QACAmD,OAEAC,QACA5B;;;;oBAzBR,IAAIkB,WAAWA,QAAQW,IAAI,KAAK,GAAG;;;;oBACG;;wBAAMzB,IAAAA,mBAAS;;;oBAAf,OAAA,eAA9Be,aAA8B,KAA9BA,YAAYlB,QAAkB,KAAlBA,OAAOmB,SAAW,KAAXA;oBACrBC,cAAcH,UAAW,qBAAGA;oBAC5BI,QAAQ/C,OAAOyC,IAAI3C;oBACnBkD,YAAY1C,KAAKiD,IAAI,CAACR,MAAMS,MAAM,CAAC,SAACC,KAAKC;+BAAUD,MAAMC,QAAQA;uBAAO;oBACxET,QAAQD,cAAc,IAAI,QAAQ;oBAClCE,MAAM,AAAC,4QAOoBP,OAFmBM,OAAM,yEAEsC,OAA/DN,UAAU,AAAC,OAA6C,OAAvClC,SAAS,UAAUqC,YAAYtC,MAAM,KAAM,IAAG;oBAMnF;;wBAAMX,OAAO8D,OAAO,CAACT;;;oBAA5BC,OAAO;;;;;;;;;oBAELlD,SAAwB,AAAC,qBAAI+C,cAAc;wBAAUJ,WAAWG;8BAAU,qBAAGD;wBAAaJ;;oBAC1FU,QAAsB,AAAC,qBAAIJ,cAAc;wBAAUtB,MAAMmB,QAAQ/C;8BAAS,qBAAGgD,YAAYc,GAAG,CAAC;+BAAMlE;;wBAAUA;;oBACnHyD,KAAKU,IAAI,CAAC5D,QAAQmD;oBACH;;wBAAMD,KAAKW,aAAa;;;oBAAjCT,SAAS;oBACT5B,OAAO4B,OAAOU,eAAe;oBACnC;;wBAAOtC,KAAKmC,GAAG,CAAC,SAACI;mCAAO;gCAAE9B,MAAM8B,EAAE9B,IAAI;gCAAE+B,OAAO,AAAC,IAAmBD,OAAhBA,EAAEE,UAAU,EAAC,KAAc,OAAXF,EAAEG,QAAQ;gCAAIC,YAAYC,IAAAA,mBAAQ,EAACL,EAAEf,KAAK;4BAAE;;;;oBAE/GE,KAAKmB,WAAW;;;;;;;;;;IAEpB;;AAIO,SAAe9E,YAAYK,MAAwB,EAAE2B,IAAgB,EAAE1B,IAAY,EAAEoC,IAAY,EAAEqC,IAAgE;;YAElKC,YACAC,YAEAC,SAEgC,MAA9B9B,YAAYlB,OAAOmB,QACrB8B,aACA7B,aACAI,KAWAC,MAEElD,QACAmD,OAEAC,QACA5B;;;;oBA1BR,IAAI8C,KAAK5B,OAAO,IAAI4B,KAAK5B,OAAO,CAACW,IAAI,KAAK,GAAG;;;;oBAC1B;;wBAAM9B,KAAKmC,OAAO,CAAC;;;oBAAhCa,aAAa;oBACC;;wBAAMA,WAAWI,GAAG,CAAC1C;;;oBAAnCuC,aAAc;oBACpB,IAAIA,WAAWjE,MAAM,KAAK,GAAG;;;;oBACvBkE,UAAUG,IAAAA,uBAAY,EAACJ,YAAYb,GAAG,CAAC,SAAC7C;+BAAQA,IAAIG,MAAM;;oBAE1B;;wBAAMW,IAAAA,mBAAS;;;oBAAf,OAAA,eAA9Be,aAA8B,KAA9BA,YAAYlB,QAAkB,KAAlBA,OAAOmB,SAAW,KAAXA;oBACrB8B,cAAe,qBAAGJ,KAAKO,OAAO;oBAC9BhC,cAAcyB,KAAK5B,OAAO,GAAI,qBAAG4B,KAAK5B,OAAO;oBAC7CO,MAAM,AAAC,+BAIPyB,OAJqCD,QAAQd,GAAG,CAAC;+BAAM;uBAAO/C,IAAI,CAAC,OAAM,kTAKzE0D,OADAI,YAAYnE,MAAM,GAAG,IAAI,AAAC,WAAmD,OAAzCC,SAAS,YAAYkE,YAAYnE,MAAM,KAAM,IAAG,YACd,OAAtE+D,KAAK5B,OAAO,GAAG,AAAC,OAA+C,OAAzClC,SAAS,YAAYqC,YAAYtC,MAAM,KAAM,IAAG;oBAM/D;;wBAAMX,OAAO8D,OAAO,CAACT;;;oBAA5BC,OAAO;;;;;;;;;oBAELlD,SAAwB,AAAC,qBAAGyE,QAAQd,GAAG,CAAC,SAACmB;+BAAMnC,WAAW5C,OAAO+E,GAAGjF;;wBAASoC;uBAAM,qBAAGyC,cAAa,qBAAG7B;wBAAayB,KAAKS,CAAC;;oBACzH5B,QAAsB,AAAC,qBAAGsB,QAAQd,GAAG,CAAC;+BAAMlC,MAAMmB,QAAQ/C;;wBAAQJ;uBAAS,qBAAGiF,YAAYf,GAAG,CAAC;+BAAMlE;yBAAU,qBAAGoD,YAAYc,GAAG,CAAC;+BAAMlE;;wBAAUA;;oBACvJyD,KAAKU,IAAI,CAAC5D,QAAQmD;oBACH;;wBAAMD,KAAKW,aAAa;;;oBAAjCT,SAAS;oBACT5B,OAAO4B,OAAOU,eAAe;oBACnC;;wBAAOtC,KAAKmC,GAAG,CAAC,SAACI;mCAAO;gCAAE9B,MAAM8B,EAAE9B,IAAI;gCAAEkC,YAAYC,IAAAA,mBAAQ,EAACL,EAAEf,KAAK;4BAAE;;;;oBAEtEE,KAAKmB,WAAW;;;;;;;;;;IAEpB"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/duckdb/vectors.ts"],"sourcesContent":["import type { DuckDBConnection, DuckDBType, DuckDBValue } from '@duckdb/node-api';\nimport { withTransaction } from '../transaction.ts';\nimport type { Connection, VectorCandidate, VectorSimilar, VectorWriteRow } from '../types.ts';\nimport { asCosine, sampleEvenly } from '../vectors.ts';\nimport { duckdbApi } from './native.ts';\n\n// This store keeps vectors as native FLOAT[dims] arrays (dims fixed at DDL time by open.ts's ensureSchema, from embed/types.ts's STORE_DIMS) and\n// scans them with array_cosine_similarity, pushing top-k into SQL instead of pulling every row into JS; sqlite's int8+scale BLOB scan is its own representation. Every function here takes `dims` as a parameter rather than importing STORE_DIMS directly, so it stays testable at any width.\n\n// A value import of '@duckdb/node-api' must never sit at module top level, or a sqlite-only tree would resolve this optional dependency\n// just by importing store/index.ts; native.ts's shared duckdbApi() keeps that lazy and reuses whatever open.ts already resolved.\n\n// A bind position whose type is left to auto-inference (safe for plain strings/numbers; only\n// the vector ARRAY positions below need an explicit type -- see writeVectorBatch's comment).\nconst untyped = undefined as unknown as DuckDBType;\nconst VECTOR_WRITE_STAGE = '_sense_vector_write_stage';\n\n// Created once per native connection outside write transactions; its lifetime follows that connection.\nexport async function createVectorWriteStage(duckdb: DuckDBConnection, dims: number): Promise<void> {\n await duckdb.run(`CREATE TEMP TABLE ${VECTOR_WRITE_STAGE} (\"path\" TEXT, chunk INTEGER, vector FLOAT[${dims}])`);\n}\n\n// The DDL-fixed array width can exceed a vector's actual length (a hypothetical model sliced under the column's width);\n// zero-padding leaves cosine scores unchanged since the added dimensions contribute nothing to either vector's dot product or norm.\nfunction padded(values: ArrayLike<number>, dims: number): number[] {\n const out = new Array<number>(dims).fill(0);\n for (let d = 0; d < Math.min(values.length, dims); d++) out[d] = values[d];\n return out;\n}\n\nfunction inClause(column: string, count: number): string {\n return `${column} IN (${Array.from({ length: count }, () => '?').join(', ')})`;\n}\n\n// Rows arrive int8-quantized with a per-vector scale (the wire format embed/query.ts produces for every store, see toStore);\n// dequantizing into a plain float array is this store's own representation choice, so both stores are handed the same vectors and diverge only here.\nfunction dequantize(row: VectorWriteRow, dims: number): number[] {\n const q = new Int8Array(row.vector.buffer, row.vector.byteOffset, row.vector.byteLength);\n return padded(\n Array.from(q, (v) => v * row.scale),\n dims\n );\n}\n\n// The native appender needs an explicit FLOAT array type: inference from an integer first component\n// silently truncates fractional components. The fixed UPDATE keeps each provider batch keyed by path and chunk.\nexport async function writeVectorBatch(duckdb: DuckDBConnection, conn: Connection, dims: number, rows: VectorWriteRow[]): Promise<void> {\n if (rows.length === 0) return;\n const { ARRAY, FLOAT } = await duckdbApi();\n const vectorType = ARRAY(FLOAT, dims);\n\n await withTransaction(conn, async () => {\n await duckdb.run(`DELETE FROM ${VECTOR_WRITE_STAGE}`);\n const appender = await duckdb.createAppender(VECTOR_WRITE_STAGE);\n try {\n for (const row of rows) {\n appender.appendVarchar(row.path);\n appender.appendInteger(row.chunk);\n appender.appendArray(dequantize(row, dims), vectorType);\n appender.endRow();\n }\n appender.flushSync();\n } finally {\n appender.closeSync();\n }\n await duckdb.run(`UPDATE embeddings SET vector = staged.vector FROM ${VECTOR_WRITE_STAGE} AS staged WHERE embeddings.\"path\" = staged.\"path\" AND embeddings.chunk = staged.chunk`);\n });\n}\n\n// Best chunk per file by cosine, with the earliest chunk winning exact score ties.\n// An empty `allowed` set matches sqlite's scan (every row filtered out) without touching the table.\nexport async function scanCandidates(duckdb: DuckDBConnection, qv: Float32Array, dims: number, fetch: number, allowed?: Set<string>): Promise<VectorCandidate[]> {\n if (allowed && allowed.size === 0) return [];\n const { arrayValue, ARRAY, DOUBLE } = await duckdbApi();\n const allowedList = allowed ? [...allowed] : [];\n const query = padded(qv, dims);\n const queryNorm = Math.sqrt(query.reduce((sum, value) => sum + value * value, 0));\n const score = queryNorm === 0 ? '0.0' : 'CASE WHEN array_inner_product(vector, vector) = 0 THEN 0.0 ELSE array_cosine_similarity(vector, ?) END';\n const sql = `SELECT \"path\", start_line, end_line, score\n FROM (\n SELECT \"path\", start_line, end_line, score,\n row_number() OVER (PARTITION BY \"path\" ORDER BY score DESC, chunk ASC) AS selected\n FROM (\n SELECT \"path\", chunk, start_line, end_line, ${score} AS score\n FROM embeddings\n WHERE vector IS NOT NULL ${allowed ? `AND ${inClause('\"path\"', allowedList.length)}` : ''}\n ) sub\n ) ranked\n WHERE selected = 1\n ORDER BY score DESC, \"path\" ASC\n LIMIT ?`;\n const stmt = await duckdb.prepare(sql);\n try {\n const values: DuckDBValue[] = [...(queryNorm === 0 ? [] : [arrayValue(query)]), ...allowedList, fetch];\n const types: DuckDBType[] = [...(queryNorm === 0 ? [] : [ARRAY(DOUBLE, dims)]), ...allowedList.map(() => untyped), untyped];\n stmt.bind(values, types);\n const reader = await stmt.runAndReadAll();\n const rows = reader.getRowObjectsJS() as Array<{ path: string; start_line: number; end_line: number; score: number }>;\n return rows.map((r) => ({ path: r.path, lines: `L${r.start_line}-${r.end_line}`, similarity: asCosine(r.score) }));\n } finally {\n stmt.destroySync();\n }\n}\n\n// Note-to-note similarity is the max cosine over (target chunk, other chunk) pairs, pushed into one native scan: the sampled target vectors become\n// a small VALUES list, cross-joined against every stored vector and reduced with max()/GROUP BY, so the O(target x stored) cost (12.7s at 201 chunks/note in JS) runs vectorized instead of scalar.\nexport async function scanSimilar(duckdb: DuckDBConnection, conn: Connection, dims: number, path: string, opts: { exclude: Set<string>; allowed?: Set<string>; k: number }): Promise<VectorSimilar[]> {\n if (opts.allowed && opts.allowed.size === 0) return [];\n const targetStmt = await conn.prepare('SELECT vector FROM embeddings WHERE \"path\" = ? AND vector IS NOT NULL ORDER BY chunk');\n const targetRows = (await targetStmt.all(path)) as Array<{ vector: number[] }>;\n if (targetRows.length === 0) return [];\n const targets = sampleEvenly(targetRows).map((row) => row.vector);\n\n const { arrayValue, ARRAY, DOUBLE } = await duckdbApi();\n const excludeList = [...opts.exclude];\n const allowedList = opts.allowed ? [...opts.allowed] : [];\n const sql = `WITH targets(tv) AS (VALUES ${targets.map(() => '(?)').join(', ')}), grouped AS (\n SELECT e.\"path\" AS path, max(CASE WHEN array_inner_product(e.vector, e.vector) = 0 OR array_inner_product(t.tv, t.tv) = 0 THEN 0.0 ELSE array_cosine_similarity(e.vector, t.tv) END) AS score\n FROM embeddings e, targets t\n WHERE e.vector IS NOT NULL AND e.\"path\" != ?\n ${excludeList.length > 0 ? `AND NOT ${inClause('e.\"path\"', excludeList.length)}` : ''}\n ${opts.allowed ? `AND ${inClause('e.\"path\"', allowedList.length)}` : ''}\n GROUP BY e.\"path\"\n )\n SELECT path, score FROM grouped\n ORDER BY score DESC, path ASC\n LIMIT ?`;\n const stmt = await duckdb.prepare(sql);\n try {\n const values: DuckDBValue[] = [...targets.map((t) => arrayValue(padded(t, dims))), path, ...excludeList, ...allowedList, opts.k];\n const types: DuckDBType[] = [...targets.map(() => ARRAY(DOUBLE, dims)), untyped, ...excludeList.map(() => untyped), ...allowedList.map(() => untyped), untyped];\n stmt.bind(values, types);\n const reader = await stmt.runAndReadAll();\n const rows = reader.getRowObjectsJS() as Array<{ path: string; score: number }>;\n return rows.map((r) => ({ path: r.path, similarity: asCosine(r.score) }));\n } finally {\n stmt.destroySync();\n }\n}\n"],"names":["createVectorWriteStage","scanCandidates","scanSimilar","writeVectorBatch","untyped","undefined","VECTOR_WRITE_STAGE","duckdb","dims","run","padded","values","out","Array","fill","d","Math","min","length","inClause","column","count","from","join","dequantize","row","q","Int8Array","vector","buffer","byteOffset","byteLength","v","scale","conn","rows","ARRAY","FLOAT","vectorType","duckdbApi","withTransaction","appender","createAppender","appendVarchar","path","appendInteger","chunk","appendArray","endRow","flushSync","closeSync","qv","fetch","allowed","arrayValue","DOUBLE","allowedList","query","queryNorm","score","sql","stmt","types","reader","size","sqrt","reduce","sum","value","prepare","map","bind","runAndReadAll","getRowObjectsJS","r","lines","start_line","end_line","similarity","asCosine","destroySync","opts","targetStmt","targetRows","targets","excludeList","all","sampleEvenly","exclude","t","k"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/embed-scope.ts"],"sourcesContent":["// Decomposition of the `embed:` featureSignature segment (config/access.ts's featureSignature,\n// features/embed.ts's signature()), for open()'s narrow embed-invalidation routing.\n\nexport type EmbedChangeKind = 'model' | 'chunk';\n\ninterface EmbedSegment {\n provider: string;\n model: string;\n endpoint?: string;\n chunkVersion: string;\n}\n\n// One embed segment's provider/model/endpoint/chunkVersion, ignoring any trailing `@identity`.\n// The endpoint-less HTTP shape remains readable so upgrading invalidates vectors, not core data.\nfunction parseEmbedSegment(sig: string): EmbedSegment | null {\n const part = sig.split('|').find((p) => p.startsWith('embed:'));\n if (part === undefined || part === 'embed:off') return null;\n const at = part.indexOf('@');\n const body = at === -1 ? part : part.slice(0, at);\n const withEndpoint = /^embed:(openai|cohere):(.+):endpoint=([0-9a-f]{64}):(chunk:v\\d+(?::\\d+)?)$/.exec(body);\n if (withEndpoint) {\n const [, provider, model, endpoint, chunkVersion] = withEndpoint;\n return { provider, model, endpoint, chunkVersion };\n }\n const legacy = /^embed:(static|openai|cohere):(.+):(chunk:v\\d+(?::\\d+)?)$/.exec(body);\n if (!legacy) return null;\n const [, provider, model, chunkVersion] = legacy;\n return { provider, model, chunkVersion };\n}\n\n// 'chunk' when chunkTokens or the chunk version moved (boundaries changed, embeddings rebuild);\n// 'model' when only the provider or model moved (rows unchanged, values stale); null otherwise.\nexport function classifyEmbedChange(before: string, after: string): EmbedChangeKind | null {\n const b = parseEmbedSegment(before);\n const a = parseEmbedSegment(after);\n if (b === null || a === null) return null;\n if (b.chunkVersion !== a.chunkVersion) return 'chunk';\n if (b.provider !== a.provider || b.model !== a.model || b.endpoint !== a.endpoint) return 'model';\n return null;\n}\n"],"names":["classifyEmbedChange","parseEmbedSegment","sig","part","split","find","p","startsWith","undefined","at","indexOf","body","slice","withEndpoint","exec","provider","model","endpoint","chunkVersion","legacy","before","after","b","a"],"mappings":"AAAA,+FAA+F;AAC/F,oFAAoF;;;;;+BA+BpEA;;;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AApBhB,+FAA+F;AAC/F,iGAAiG;AACjG,SAASC,kBAAkBC,GAAW;IACpC,IAAMC,OAAOD,IAAIE,KAAK,CAAC,KAAKC,IAAI,CAAC,SAACC;eAAMA,EAAEC,UAAU,CAAC;;IACrD,IAAIJ,SAASK,aAAaL,SAAS,aAAa,OAAO;IACvD,IAAMM,KAAKN,KAAKO,OAAO,CAAC;IACxB,IAAMC,OAAOF,OAAO,CAAC,IAAIN,OAAOA,KAAKS,KAAK,CAAC,GAAGH;IAC9C,IAAMI,eAAe,6EAA6EC,IAAI,CAACH;IACvG,IAAIE,cAAc;QAChB,IAAoDA,iCAAAA,kBAA3CE,WAA2CF,kBAAjCG,QAAiCH,kBAA1BI,WAA0BJ,kBAAhBK,eAAgBL;QACpD,OAAO;YAAEE,UAAAA;YAAUC,OAAAA;YAAOC,UAAAA;YAAUC,cAAAA;QAAa;IACnD;IACA,IAAMC,SAAS,4DAA4DL,IAAI,CAACH;IAChF,IAAI,CAACQ,QAAQ,OAAO;IACpB,IAA0CA,2BAAAA,YAAjCJ,YAAiCI,YAAvBH,SAAuBG,YAAhBD,gBAAgBC;IAC1C,OAAO;QAAEJ,UAAAA;QAAUC,OAAAA;QAAOE,cAAAA;IAAa;AACzC;AAIO,SAASlB,oBAAoBoB,MAAc,EAAEC,KAAa;IAC/D,IAAMC,IAAIrB,kBAAkBmB;IAC5B,IAAMG,IAAItB,kBAAkBoB;IAC5B,IAAIC,MAAM,QAAQC,MAAM,MAAM,OAAO;IACrC,IAAID,EAAEJ,YAAY,KAAKK,EAAEL,YAAY,EAAE,OAAO;IAC9C,IAAII,EAAEP,QAAQ,KAAKQ,EAAER,QAAQ,IAAIO,EAAEN,KAAK,KAAKO,EAAEP,KAAK,IAAIM,EAAEL,QAAQ,KAAKM,EAAEN,QAAQ,EAAE,OAAO;IAC1F,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/feature-scope.ts"],"sourcesContent":["import type { FeatureName } from '../config/index.ts';\n\n// Decomposition of the `feature:<name>:<on|off>` featureSignature segments (config/access.ts's\n// featureSignature), for open()'s narrow feature-toggle invalidation routing.\n\n// Every narrow-supported feature but rank owns one dedicated table, dropped and (turning on)\n// fully re-derived. rank has no table -- it writes PageRank into frontmatter's own `_rank`\n// column -- so builder.ts handles it, and the links/rank pair, as special cases outside this map.\nexport const NARROW_FEATURE_TABLE: Readonly<Record<string, string>> = { tags: 'tags', sections: 'sections', links: 'links' };\n\n// links feeds rank's afterReconcile pass, so a links toggle always co-changes the `feature:rank`\n// segment too (featureEnabled's dependency); both are narrow-supported and builder.ts applies\n// them together. A changed set naming any other feature falls through to the existing full clear.\nconst NARROW_FEATURE_NAMES: ReadonlySet<string> = new Set([...Object.keys(NARROW_FEATURE_TABLE), 'rank']);\n\nexport interface FeatureToggle {\n name: FeatureName;\n // true: was off, now on (must fully re-derive). false: was on, now off (drop its rows).\n turnedOn: boolean;\n}\n\n// Every changed key is a `feature:<name>` segment for a narrow-supported feature.\nexport function isFeatureOnlyChange(changedKeys: ReadonlySet<string>): boolean {\n return changedKeys.size > 0 && [...changedKeys].every((key) => key.startsWith('feature:') && NARROW_FEATURE_NAMES.has(key.slice('feature:'.length)));\n}\n\n// One feature segment's old on/off, read back out of a stored `feature:<name>:on|off` segment.\n// Anything not in that exact shape returns null so the caller falls back to a full rebuild.\nfunction parseOnOff(sig: string, name: string): boolean | null {\n const part = sig.split('|').find((p) => p.startsWith(`feature:${name}:`));\n if (part === undefined) return null;\n const fields = part.split(':');\n if (fields.length !== 3 || (fields[2] !== 'on' && fields[2] !== 'off')) return null;\n return fields[2] === 'on';\n}\n\n// Old-vs-new on/off for every changed feature key, or null when a segment can't be parsed back\n// out of `before` or `after`, or when it parses to the same state on both sides (should never\n// happen for a genuinely changed key) -- either way the caller takes the full rebuild.\nexport function classifyFeatureToggles(before: string, after: string, changedKeys: ReadonlySet<string>): FeatureToggle[] | null {\n const toggles: FeatureToggle[] = [];\n for (const key of changedKeys) {\n const name = key.slice('feature:'.length) as FeatureName;\n const wasOn = parseOnOff(before, name);\n const isOn = parseOnOff(after, name);\n if (wasOn === null || isOn === null || wasOn === isOn) return null;\n toggles.push({ name, turnedOn: isOn });\n }\n return toggles;\n}\n"],"names":["NARROW_FEATURE_TABLE","classifyFeatureToggles","isFeatureOnlyChange","tags","sections","links","NARROW_FEATURE_NAMES","Set","Object","keys","changedKeys","size","every","key","startsWith","has","slice","length","parseOnOff","sig","name","part","split","find","p","undefined","fields","before","after","toggles","wasOn","isOn","push","turnedOn"],"mappings":";;;;;;;;;;;QAQaA;eAAAA;;QA+BGC;eAAAA;;QAjBAC;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAdT,IAAMF,uBAAyD;IAAEG,MAAM;IAAQC,UAAU;IAAYC,OAAO;AAAQ;AAE3H,iGAAiG;AACjG,8FAA8F;AAC9F,kGAAkG;AAClG,IAAMC,uBAA4C,IAAIC,IAAI,AAAC,qBAAGC,OAAOC,IAAI,CAACT,8BAAhB;IAAuC;CAAO;AASjG,SAASE,oBAAoBQ,WAAgC;IAClE,OAAOA,YAAYC,IAAI,GAAG,KAAK,AAAC,qBAAGD,aAAaE,KAAK,CAAC,SAACC;eAAQA,IAAIC,UAAU,CAAC,eAAeR,qBAAqBS,GAAG,CAACF,IAAIG,KAAK,CAAC,WAAWC,MAAM;;AACnJ;AAEA,+FAA+F;AAC/F,4FAA4F;AAC5F,SAASC,WAAWC,GAAW,EAAEC,IAAY;IAC3C,IAAMC,OAAOF,IAAIG,KAAK,CAAC,KAAKC,IAAI,CAAC,SAACC;eAAMA,EAAEV,UAAU,CAAC,AAAC,WAAe,OAALM,MAAK;;IACrE,IAAIC,SAASI,WAAW,OAAO;IAC/B,IAAMC,SAASL,KAAKC,KAAK,CAAC;IAC1B,IAAII,OAAOT,MAAM,KAAK,KAAMS,MAAM,CAAC,EAAE,KAAK,QAAQA,MAAM,CAAC,EAAE,KAAK,OAAQ,OAAO;IAC/E,OAAOA,MAAM,CAAC,EAAE,KAAK;AACvB;AAKO,SAASzB,uBAAuB0B,MAAc,EAAEC,KAAa,EAAElB,WAAgC;IACpG,IAAMmB,UAA2B,EAAE;QAC9B,kCAAA,2BAAA;;QAAL,QAAK,YAAanB,gCAAb,SAAA,6BAAA,QAAA,yBAAA,iCAA0B;YAA1B,IAAMG,MAAN;YACH,IAAMO,OAAOP,IAAIG,KAAK,CAAC,WAAWC,MAAM;YACxC,IAAMa,QAAQZ,WAAWS,QAAQP;YACjC,IAAMW,OAAOb,WAAWU,OAAOR;YAC/B,IAAIU,UAAU,QAAQC,SAAS,QAAQD,UAAUC,MAAM,OAAO;YAC9DF,QAAQG,IAAI,CAAC;gBAAEZ,MAAAA;gBAAMa,UAAUF;YAAK;QACtC;;QANK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAOL,OAAOF;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/index.ts"],"sourcesContent":["// Rows -> a backing store: registry + the public open/build boundary. Parsing lives in scan.ts;\n// everything beyond frontmatter + content lives in src/features/.\n\nimport type { ResolvedConfig, StoreName } from '../config/index.ts';\nimport { anyPresetEmbeds, storeName } from '../config/index.ts';\nimport { SenseError } from '../errors.ts';\nimport { clearCache } from './cache.ts';\nimport { DB_FILENAME as DUCKDB_FILENAME, openDuckdb } from './duckdb/open.ts';\nimport { CAPABILITIES as DUCKDB_CAPABILITIES } from './duckdb/store.ts';\nimport type { BuildRequirement, InternalOpenOptions, OpenOptions, OpenResult } from './open.ts';\nimport { openSqlite, DB_FILENAME as SQLITE_FILENAME } from './sqlite/open.ts';\nimport { CAPABILITIES as SQLITE_CAPABILITIES } from './sqlite/store.ts';\nimport type { Stages } from './stages.ts';\nimport { openTurso, DB_FILENAME as TURSO_FILENAME } from './turso/open.ts';\nimport { CAPABILITIES as TURSO_CAPABILITIES } from './turso/store.ts';\nimport type { Capability } from './types.ts';\n\ninterface StoreEntry {\n capabilities: ReadonlySet<Capability>;\n filename: string;\n open: (cfg: ResolvedConfig, options?: InternalOpenOptions) => Promise<OpenResult>;\n}\n\nconst REGISTRY: Record<StoreName, StoreEntry> = {\n sqlite: { capabilities: SQLITE_CAPABILITIES, filename: SQLITE_FILENAME, open: openSqlite },\n duckdb: { capabilities: DUCKDB_CAPABILITIES, filename: DUCKDB_FILENAME, open: openDuckdb },\n turso: { capabilities: TURSO_CAPABILITIES, filename: TURSO_FILENAME, open: openTurso },\n};\n\nfunction entryFor(name: StoreName): StoreEntry {\n const entry = REGISTRY[name];\n if (!entry) throw new SenseError('STORE_UNKNOWN', `unknown backing store \"${name}\"; available: ${Object.keys(REGISTRY).join(', ')}`);\n return entry;\n}\n\nfunction requirementsFor(cfg: ResolvedConfig): Set<BuildRequirement> {\n const requirements = new Set<BuildRequirement>(['core', 'lexical']);\n if (anyPresetEmbeds(cfg)) requirements.add('vectors');\n return requirements;\n}\n\nfunction validateRequirements(cfg: ResolvedConfig, entry: StoreEntry, requirements: ReadonlySet<BuildRequirement>): void {\n if (requirements.has('vectors') && anyPresetEmbeds(cfg) && !entry.capabilities.has('vectors')) {\n const name = storeName(cfg);\n throw new SenseError('STORE_CAPABILITY_MISSING', `store \"${name}\" does not implement \"vectors\" in this build, but this config's \"embed\" block is in use by at least one preset; remove or narrow it, or set \"store\" to a store that supports vectors (sqlite)`);\n }\n}\n\nexport async function openStoreFor(cfg: ResolvedConfig, options: InternalOpenOptions): Promise<OpenResult> {\n options.signal?.throwIfAborted();\n const entry = entryFor(storeName(cfg));\n validateRequirements(cfg, entry, options.requirements ?? new Set<BuildRequirement>(['core']));\n return entry.open(cfg, options);\n}\n\n/** Opens a store through the root `open` API, preparing capabilities unless `build` is `false`. */\nexport async function openStore(cfg: ResolvedConfig, options: OpenOptions = {}): Promise<OpenResult> {\n const buildEnabled = options.build !== false;\n return openStoreFor(cfg, {\n build: buildEnabled,\n requirements: buildEnabled ? requirementsFor(cfg) : new Set<BuildRequirement>(['core']),\n signal: options.signal,\n });\n}\n\nexport async function lexicalReadiness(cfg: ResolvedConfig): Promise<{ ready: boolean; error: string | null }> {\n let opened: OpenResult;\n try {\n opened = await openStoreFor(cfg, { build: false, requirements: new Set<BuildRequirement>(['core', 'lexical']) });\n } catch (err) {\n if (err instanceof SenseError && err.code === 'INDEX_NOT_READY') return { ready: false, error: err.message };\n throw err;\n }\n try {\n return { ready: true, error: null };\n } finally {\n await opened.store.close();\n }\n}\n\n/** Options for the root `build(config, options)` API. */\nexport interface BuildOptions {\n /** Recreates the derived cache before building. */\n force?: boolean;\n /** Cancels supported provider I/O and stops between phases after active native work finishes. */\n signal?: AbortSignal;\n}\n\nexport interface BuildResult {\n cfg: ResolvedConfig;\n dbPath: string;\n parsed: number;\n warnings: string[];\n stages: Stages;\n}\n\n/** Builds every configured capability, waiting for active native work and cleanup before settling. */\nexport async function buildIndex(cfg: ResolvedConfig, options: BuildOptions = {}): Promise<BuildResult> {\n options.signal?.throwIfAborted();\n if (options.force) clearCache(cfg);\n const opened = await openStoreFor(cfg, { build: true, requirements: requirementsFor(cfg), signal: options.signal });\n try {\n const { store: _store, ...result } = opened;\n return result;\n } finally {\n await opened.store.close();\n }\n}\n\nexport function storeFilename(cfg: ResolvedConfig): string {\n return entryFor(storeName(cfg)).filename;\n}\n\nexport type { OpenOptions, OpenResult } from './open.ts';\nexport { docCount } from './open.ts';\nexport { getMeta, setMeta } from './shared.ts';\nexport { DB_FILENAME, SCHEMA_VERSION } from './sqlite/open.ts';\nexport type { Stages } from './stages.ts';\nexport type { Capability, Connection, DocumentStore, LexicalHit, LexicalIndex, LexicalQueryOptions, RawStatement, RunResult, SqlSession, Statement, Store, VectorCandidate, VectorSimilar, VectorStore, VectorWriteRow } from './types.ts';\nexport { CAPABILITY_NAMES } from './types.ts';\nexport { clearCache };\n"],"names":["CAPABILITY_NAMES","DB_FILENAME","SCHEMA_VERSION","buildIndex","clearCache","docCount","getMeta","lexicalReadiness","openStore","openStoreFor","setMeta","storeFilename","REGISTRY","sqlite","capabilities","SQLITE_CAPABILITIES","filename","SQLITE_FILENAME","open","openSqlite","duckdb","DUCKDB_CAPABILITIES","DUCKDB_FILENAME","openDuckdb","turso","TURSO_CAPABILITIES","TURSO_FILENAME","openTurso","entryFor","name","entry","SenseError","Object","keys","join","requirementsFor","cfg","requirements","Set","anyPresetEmbeds","add","validateRequirements","has","storeName","options","signal","throwIfAborted","buildEnabled","build","opened","err","code","ready","error","message","store","close","_store","result","force"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/store/lock-wait.ts"],"sourcesContent":["import { readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { STATE_DIR } from '../config/index.ts';\n\n// duckdb/turso lock the cache file exclusively, so a waiter can't connect and read reconcile_max_ms\n// from meta; this sidecar is plain fs, readable while locked. Same derivation as busy_timeout (open.ts).\nconst SIDECAR_FILENAME = 'lock-wait.json';\nconst FLOOR_MS = 5_000;\nconst CEILING_MS = 600_000;\n\nfunction sidecarPath(configDir: string): string {\n return join(configDir, STATE_DIR, SIDECAR_FILENAME);\n}\n\nfunction readRecordedMs(configDir: string): number | undefined {\n try {\n const raw = JSON.parse(readFileSync(sidecarPath(configDir), 'utf8'));\n const value = raw.reconcile_max_ms;\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;\n } catch {\n return undefined;\n }\n}\n\n// Called after every reconcile's write transaction, every store alike, so a fresh cache records\n// its first write even when the measured duration is zero.\nexport function recordLockWaitMs(configDir: string, ms: number): void {\n const recordedMs = readRecordedMs(configDir);\n if (recordedMs !== undefined && ms <= recordedMs) return;\n try {\n writeFileSync(sidecarPath(configDir), JSON.stringify({ reconcile_max_ms: ms }));\n } catch {\n // Best-effort: a write failure here only narrows the next waiter's budget back to the floor.\n }\n}\n\n// 3x the largest reconcile this cache has recorded, floored and capped -- a waiter outlasts a\n// real reconcile and still fails behind a hung one.\nexport function lockWaitBudgetMs(configDir: string): number {\n return Math.min(Math.max(FLOOR_MS, 3 * (readRecordedMs(configDir) ?? 0)), CEILING_MS);\n}\n"],"names":["lockWaitBudgetMs","recordLockWaitMs","SIDECAR_FILENAME","FLOOR_MS","CEILING_MS","sidecarPath","configDir","join","STATE_DIR","readRecordedMs","raw","JSON","parse","readFileSync","value","reconcile_max_ms","Number","isFinite","undefined","ms","recordedMs","writeFileSync","stringify","Math","min","max"],"mappings":";;;;;;;;;;;QAsCgBA;eAAAA;;QAZAC;eAAAA;;;sBA1B4B;wBACvB;uBACK;AAE1B,oGAAoG;AACpG,yGAAyG;AACzG,IAAMC,mBAAmB;AACzB,IAAMC,WAAW;AACjB,IAAMC,aAAa;AAEnB,SAASC,YAAYC,SAAiB;IACpC,OAAOC,IAAAA,cAAI,EAACD,WAAWE,kBAAS,EAAEN;AACpC;AAEA,SAASO,eAAeH,SAAiB;IACvC,IAAI;QACF,IAAMI,MAAMC,KAAKC,KAAK,CAACC,IAAAA,oBAAY,EAACR,YAAYC,YAAY;QAC5D,IAAMQ,QAAQJ,IAAIK,gBAAgB;QAClC,OAAO,OAAOD,UAAU,YAAYE,OAAOC,QAAQ,CAACH,UAAUA,SAAS,IAAIA,QAAQI;IACrF,EAAE,eAAM;QACN,OAAOA;IACT;AACF;AAIO,SAASjB,iBAAiBK,SAAiB,EAAEa,EAAU;IAC5D,IAAMC,aAAaX,eAAeH;IAClC,IAAIc,eAAeF,aAAaC,MAAMC,YAAY;IAClD,IAAI;QACFC,IAAAA,qBAAa,EAAChB,YAAYC,YAAYK,KAAKW,SAAS,CAAC;YAAEP,kBAAkBI;QAAG;IAC9E,EAAE,eAAM;IACN,6FAA6F;IAC/F;AACF;AAIO,SAASnB,iBAAiBM,SAAiB;QACRG;IAAxC,OAAOc,KAAKC,GAAG,CAACD,KAAKE,GAAG,CAACtB,UAAU,MAAKM,kBAAAA,eAAeH,wBAAfG,6BAAAA,kBAA6B,KAAKL;AAC5E"}
|