sensemaking 0.25.1 → 0.26.0
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 +13 -9
- package/dist/cjs/cli/index.d.cts +1 -1
- package/dist/cjs/cli/index.d.ts +1 -1
- package/dist/cjs/cli/index.js +1 -1
- package/dist/cjs/cli/index.js.map +1 -1
- package/dist/cjs/cli/path.js +5 -29
- package/dist/cjs/cli/path.js.map +1 -1
- package/dist/cjs/cli/related.js +4 -3
- package/dist/cjs/cli/related.js.map +1 -1
- package/dist/cjs/commands/index.d.cts +6 -3
- package/dist/cjs/commands/index.d.ts +6 -3
- package/dist/cjs/commands/index.js +4 -0
- package/dist/cjs/commands/index.js.map +1 -1
- package/dist/cjs/commands/map.d.cts +14 -5
- package/dist/cjs/commands/map.d.ts +14 -5
- package/dist/cjs/commands/map.js +42 -35
- package/dist/cjs/commands/map.js.map +1 -1
- package/dist/cjs/commands/path.d.cts +14 -0
- package/dist/cjs/commands/path.d.ts +14 -0
- package/dist/cjs/commands/path.js +209 -0
- package/dist/cjs/commands/path.js.map +1 -0
- package/dist/cjs/commands/peek.d.cts +16 -1
- package/dist/cjs/commands/peek.d.ts +16 -1
- package/dist/cjs/commands/peek.js +71 -33
- package/dist/cjs/commands/peek.js.map +1 -1
- package/dist/cjs/commands/related.d.cts +16 -3
- package/dist/cjs/commands/related.d.ts +16 -3
- package/dist/cjs/commands/related.js +131 -98
- package/dist/cjs/commands/related.js.map +1 -1
- package/dist/cjs/commands/scope.d.cts +1 -0
- package/dist/cjs/commands/scope.d.ts +1 -0
- package/dist/cjs/commands/scope.js +149 -0
- package/dist/cjs/commands/scope.js.map +1 -1
- package/dist/cjs/commands/search.d.cts +26 -3
- package/dist/cjs/commands/search.d.ts +26 -3
- package/dist/cjs/commands/search.js +211 -71
- package/dist/cjs/commands/search.js.map +1 -1
- package/dist/cjs/commands/signals.d.cts +4 -3
- package/dist/cjs/commands/signals.d.ts +4 -3
- package/dist/cjs/commands/signals.js +13 -4
- package/dist/cjs/commands/signals.js.map +1 -1
- package/dist/cjs/commands/snapshot.d.cts +3 -0
- package/dist/cjs/commands/snapshot.d.ts +3 -0
- package/dist/cjs/commands/snapshot.js +180 -0
- package/dist/cjs/commands/snapshot.js.map +1 -0
- package/dist/cjs/embed/cohere.js +41 -16
- package/dist/cjs/embed/cohere.js.map +1 -1
- package/dist/cjs/embed/endpoint.d.cts +2 -0
- package/dist/cjs/embed/endpoint.d.ts +2 -0
- package/dist/cjs/embed/endpoint.js +30 -0
- package/dist/cjs/embed/endpoint.js.map +1 -0
- package/dist/cjs/embed/handoff.d.cts +7 -2
- package/dist/cjs/embed/handoff.d.ts +7 -2
- package/dist/cjs/embed/handoff.js +10 -0
- package/dist/cjs/embed/handoff.js.map +1 -1
- package/dist/cjs/embed/http.d.cts +18 -1
- package/dist/cjs/embed/http.d.ts +18 -1
- package/dist/cjs/embed/http.js +239 -40
- package/dist/cjs/embed/http.js.map +1 -1
- package/dist/cjs/embed/openai.js +39 -17
- package/dist/cjs/embed/openai.js.map +1 -1
- package/dist/cjs/embed/query.d.cts +9 -3
- package/dist/cjs/embed/query.d.ts +9 -3
- package/dist/cjs/embed/query.js +257 -90
- package/dist/cjs/embed/query.js.map +1 -1
- package/dist/cjs/embed/registry.d.cts +2 -2
- package/dist/cjs/embed/registry.d.ts +2 -2
- package/dist/cjs/embed/registry.js +36 -4
- package/dist/cjs/embed/registry.js.map +1 -1
- package/dist/cjs/embed/static.js +6 -2
- package/dist/cjs/embed/static.js.map +1 -1
- package/dist/cjs/embed/store.js +42 -77
- package/dist/cjs/embed/store.js.map +1 -1
- package/dist/cjs/embed/types.d.cts +5 -2
- package/dist/cjs/embed/types.d.ts +5 -2
- package/dist/cjs/embed/types.js.map +1 -1
- package/dist/cjs/features/embed.js +290 -43
- package/dist/cjs/features/embed.js.map +1 -1
- package/dist/cjs/graph/traverse.d.cts +2 -2
- package/dist/cjs/graph/traverse.d.ts +2 -2
- package/dist/cjs/graph/traverse.js +15 -5
- package/dist/cjs/graph/traverse.js.map +1 -1
- package/dist/cjs/index.d.cts +2 -2
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +6 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/output/output.d.cts +4 -36
- package/dist/cjs/output/output.d.ts +4 -36
- package/dist/cjs/output/output.js +1 -2
- package/dist/cjs/output/output.js.map +1 -1
- package/dist/cjs/scan/pool.d.cts +2 -1
- package/dist/cjs/scan/pool.d.ts +2 -1
- package/dist/cjs/scan/pool.js +116 -27
- package/dist/cjs/scan/pool.js.map +1 -1
- package/dist/cjs/scan/reparse.d.cts +1 -0
- package/dist/cjs/scan/reparse.d.ts +1 -0
- package/dist/cjs/scan/reparse.js +75 -21
- package/dist/cjs/scan/reparse.js.map +1 -1
- package/dist/cjs/store/builder.d.cts +11 -21
- package/dist/cjs/store/builder.d.ts +11 -21
- package/dist/cjs/store/builder.js +1077 -438
- package/dist/cjs/store/builder.js.map +1 -1
- package/dist/cjs/store/duckdb/connection.js +16 -2
- package/dist/cjs/store/duckdb/connection.js.map +1 -1
- package/dist/cjs/store/duckdb/open.d.cts +1 -1
- package/dist/cjs/store/duckdb/open.d.ts +1 -1
- package/dist/cjs/store/duckdb/open.js +73 -65
- package/dist/cjs/store/duckdb/open.js.map +1 -1
- package/dist/cjs/store/duckdb/reconcile.js +533 -15
- package/dist/cjs/store/duckdb/reconcile.js.map +1 -1
- package/dist/cjs/store/embed-scope.js +19 -9
- package/dist/cjs/store/embed-scope.js.map +1 -1
- package/dist/cjs/store/index.d.cts +6 -0
- package/dist/cjs/store/index.d.ts +6 -0
- package/dist/cjs/store/index.js +8 -4
- package/dist/cjs/store/index.js.map +1 -1
- package/dist/cjs/store/open.d.cts +6 -1
- package/dist/cjs/store/open.d.ts +6 -1
- package/dist/cjs/store/open.js +230 -307
- package/dist/cjs/store/open.js.map +1 -1
- package/dist/cjs/store/readiness.d.cts +5 -0
- package/dist/cjs/store/readiness.d.ts +5 -0
- package/dist/cjs/store/readiness.js +39 -0
- package/dist/cjs/store/readiness.js.map +1 -0
- package/dist/cjs/store/reconcile.d.cts +26 -1
- package/dist/cjs/store/reconcile.d.ts +26 -1
- package/dist/cjs/store/reconcile.js +670 -576
- package/dist/cjs/store/reconcile.js.map +1 -1
- package/dist/cjs/store/signature.d.cts +1 -0
- package/dist/cjs/store/signature.d.ts +1 -0
- package/dist/cjs/store/signature.js +9 -0
- package/dist/cjs/store/signature.js.map +1 -1
- package/dist/cjs/store/sqlite/open.d.cts +1 -1
- package/dist/cjs/store/sqlite/open.d.ts +1 -1
- package/dist/cjs/store/sqlite/open.js +84 -90
- 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/store.js +63 -60
- package/dist/cjs/store/sqlite/store.js.map +1 -1
- package/dist/cjs/store/sqlite/vectors.d.cts +2 -2
- package/dist/cjs/store/sqlite/vectors.d.ts +2 -2
- package/dist/cjs/store/sqlite/vectors.js +8 -4
- package/dist/cjs/store/sqlite/vectors.js.map +1 -1
- package/dist/cjs/store/stages.js.map +1 -1
- package/dist/cjs/store/turso/connection.d.cts +1 -0
- package/dist/cjs/store/turso/connection.d.ts +1 -0
- package/dist/cjs/store/turso/connection.js +319 -94
- package/dist/cjs/store/turso/connection.js.map +1 -1
- package/dist/cjs/store/turso/open.d.cts +1 -1
- package/dist/cjs/store/turso/open.d.ts +1 -1
- package/dist/cjs/store/turso/open.js +70 -74
- package/dist/cjs/store/turso/open.js.map +1 -1
- package/dist/cjs/store/turso/store.js +25 -23
- package/dist/cjs/store/turso/store.js.map +1 -1
- package/dist/cjs/store/turso/vectors.d.cts +2 -2
- package/dist/cjs/store/turso/vectors.d.ts +2 -2
- package/dist/cjs/store/turso/vectors.js +26 -16
- package/dist/cjs/store/turso/vectors.js.map +1 -1
- package/dist/cjs/store/types.d.cts +4 -1
- package/dist/cjs/store/types.d.ts +4 -1
- package/dist/cjs/store/types.js.map +1 -1
- package/dist/cjs/store/vectors.d.cts +14 -1
- package/dist/cjs/store/vectors.d.ts +14 -1
- package/dist/cjs/store/vectors.js +61 -0
- package/dist/cjs/store/vectors.js.map +1 -1
- package/dist/cjs/watch.d.cts +6 -0
- package/dist/cjs/watch.d.ts +6 -0
- package/dist/cjs/watch.js +42 -10
- package/dist/cjs/watch.js.map +1 -1
- package/dist/cjs/workers/parse.d.cts +4 -3
- package/dist/cjs/workers/parse.d.ts +4 -3
- package/dist/cjs/workers/parse.js +19 -17
- package/dist/cjs/workers/parse.js.map +1 -1
- package/dist/esm/cli/index.d.ts +1 -1
- package/dist/esm/cli/index.js +1 -1
- package/dist/esm/cli/index.js.map +1 -1
- package/dist/esm/cli/path.js +4 -10
- package/dist/esm/cli/path.js.map +1 -1
- package/dist/esm/cli/related.js +5 -3
- package/dist/esm/cli/related.js.map +1 -1
- package/dist/esm/commands/index.d.ts +6 -3
- package/dist/esm/commands/index.js +1 -0
- package/dist/esm/commands/index.js.map +1 -1
- package/dist/esm/commands/map.d.ts +14 -5
- package/dist/esm/commands/map.js +2 -0
- package/dist/esm/commands/map.js.map +1 -1
- package/dist/esm/commands/path.d.ts +14 -0
- package/dist/esm/commands/path.js +33 -0
- package/dist/esm/commands/path.js.map +1 -0
- package/dist/esm/commands/peek.d.ts +16 -1
- package/dist/esm/commands/peek.js +35 -9
- package/dist/esm/commands/peek.js.map +1 -1
- package/dist/esm/commands/related.d.ts +16 -3
- package/dist/esm/commands/related.js +45 -28
- package/dist/esm/commands/related.js.map +1 -1
- package/dist/esm/commands/scope.d.ts +1 -0
- package/dist/esm/commands/scope.js +58 -0
- package/dist/esm/commands/scope.js.map +1 -1
- package/dist/esm/commands/search.d.ts +26 -3
- package/dist/esm/commands/search.js +85 -18
- package/dist/esm/commands/search.js.map +1 -1
- package/dist/esm/commands/signals.d.ts +4 -3
- package/dist/esm/commands/signals.js +11 -4
- package/dist/esm/commands/signals.js.map +1 -1
- package/dist/esm/commands/snapshot.d.ts +3 -0
- package/dist/esm/commands/snapshot.js +25 -0
- package/dist/esm/commands/snapshot.js.map +1 -0
- package/dist/esm/embed/cohere.js +35 -10
- package/dist/esm/embed/cohere.js.map +1 -1
- package/dist/esm/embed/endpoint.d.ts +2 -0
- package/dist/esm/embed/endpoint.js +11 -0
- package/dist/esm/embed/endpoint.js.map +1 -0
- package/dist/esm/embed/handoff.d.ts +7 -2
- package/dist/esm/embed/handoff.js +7 -0
- package/dist/esm/embed/handoff.js.map +1 -1
- package/dist/esm/embed/http.d.ts +18 -1
- package/dist/esm/embed/http.js +137 -17
- package/dist/esm/embed/http.js.map +1 -1
- package/dist/esm/embed/openai.js +34 -12
- package/dist/esm/embed/openai.js.map +1 -1
- package/dist/esm/embed/query.d.ts +9 -3
- package/dist/esm/embed/query.js +98 -26
- package/dist/esm/embed/query.js.map +1 -1
- package/dist/esm/embed/registry.d.ts +2 -2
- package/dist/esm/embed/registry.js +34 -5
- package/dist/esm/embed/registry.js.map +1 -1
- package/dist/esm/embed/static.js +10 -2
- package/dist/esm/embed/static.js.map +1 -1
- package/dist/esm/embed/store.js +30 -21
- package/dist/esm/embed/store.js.map +1 -1
- package/dist/esm/embed/types.d.ts +5 -2
- package/dist/esm/embed/types.js.map +1 -1
- package/dist/esm/features/embed.js +82 -21
- package/dist/esm/features/embed.js.map +1 -1
- package/dist/esm/graph/traverse.d.ts +2 -2
- package/dist/esm/graph/traverse.js +4 -2
- package/dist/esm/graph/traverse.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/output/output.d.ts +4 -36
- package/dist/esm/output/output.js +1 -2
- package/dist/esm/output/output.js.map +1 -1
- package/dist/esm/scan/pool.d.ts +2 -1
- package/dist/esm/scan/pool.js +80 -23
- package/dist/esm/scan/pool.js.map +1 -1
- package/dist/esm/scan/reparse.d.ts +1 -0
- package/dist/esm/scan/reparse.js +40 -12
- package/dist/esm/scan/reparse.js.map +1 -1
- package/dist/esm/store/builder.d.ts +11 -21
- package/dist/esm/store/builder.js +337 -133
- package/dist/esm/store/builder.js.map +1 -1
- package/dist/esm/store/duckdb/connection.js +9 -1
- package/dist/esm/store/duckdb/connection.js.map +1 -1
- package/dist/esm/store/duckdb/open.d.ts +1 -1
- package/dist/esm/store/duckdb/open.js +13 -9
- package/dist/esm/store/duckdb/open.js.map +1 -1
- package/dist/esm/store/duckdb/reconcile.js +145 -10
- package/dist/esm/store/duckdb/reconcile.js.map +1 -1
- package/dist/esm/store/embed-scope.js +16 -6
- package/dist/esm/store/embed-scope.js.map +1 -1
- package/dist/esm/store/index.d.ts +6 -0
- package/dist/esm/store/index.js +10 -4
- package/dist/esm/store/index.js.map +1 -1
- package/dist/esm/store/open.d.ts +6 -1
- package/dist/esm/store/open.js +77 -87
- package/dist/esm/store/open.js.map +1 -1
- package/dist/esm/store/readiness.d.ts +5 -0
- package/dist/esm/store/readiness.js +11 -0
- package/dist/esm/store/readiness.js.map +1 -0
- package/dist/esm/store/reconcile.d.ts +26 -1
- package/dist/esm/store/reconcile.js +142 -120
- package/dist/esm/store/reconcile.js.map +1 -1
- package/dist/esm/store/signature.d.ts +1 -0
- package/dist/esm/store/signature.js +8 -0
- package/dist/esm/store/signature.js.map +1 -1
- package/dist/esm/store/sqlite/open.d.ts +1 -1
- package/dist/esm/store/sqlite/open.js +12 -12
- package/dist/esm/store/sqlite/open.js.map +1 -1
- package/dist/esm/store/sqlite/reconcile.js +2 -2
- package/dist/esm/store/sqlite/reconcile.js.map +1 -1
- package/dist/esm/store/sqlite/store.js +21 -18
- package/dist/esm/store/sqlite/store.js.map +1 -1
- package/dist/esm/store/sqlite/vectors.d.ts +2 -2
- package/dist/esm/store/sqlite/vectors.js +7 -5
- package/dist/esm/store/sqlite/vectors.js.map +1 -1
- package/dist/esm/store/stages.js.map +1 -1
- package/dist/esm/store/turso/connection.d.ts +1 -0
- package/dist/esm/store/turso/connection.js +97 -28
- package/dist/esm/store/turso/connection.js.map +1 -1
- package/dist/esm/store/turso/open.d.ts +1 -1
- package/dist/esm/store/turso/open.js +9 -8
- package/dist/esm/store/turso/open.js.map +1 -1
- package/dist/esm/store/turso/store.js +16 -14
- package/dist/esm/store/turso/store.js.map +1 -1
- package/dist/esm/store/turso/vectors.d.ts +2 -2
- package/dist/esm/store/turso/vectors.js +27 -17
- package/dist/esm/store/turso/vectors.js.map +1 -1
- package/dist/esm/store/types.d.ts +4 -1
- package/dist/esm/store/types.js.map +1 -1
- package/dist/esm/store/vectors.d.ts +14 -1
- package/dist/esm/store/vectors.js +55 -0
- package/dist/esm/store/vectors.js.map +1 -1
- package/dist/esm/watch.d.ts +6 -0
- package/dist/esm/watch.js +40 -14
- package/dist/esm/watch.js.map +1 -1
- package/dist/esm/workers/parse.d.ts +4 -3
- package/dist/esm/workers/parse.js +19 -17
- package/dist/esm/workers/parse.js.map +1 -1
- package/package.json +1 -1
- package/skills/sense/SKILL.md +4 -2
- package/skills/sense/references/stores/duckdb.md +1 -1
- package/skills/sense-setup/SKILL.md +2 -2
- package/skills/sense-setup/references/embeddings.md +1 -1
- package/skills/sense-setup/references/store-benchmarks.md +5 -5
- package/skills/sense-setup/references/stores/duckdb.md +1 -1
|
@@ -1,178 +1,382 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { channel } from 'node:diagnostics_channel';
|
|
2
|
+
import { featureEnabled, featureSignature } from '../config/index.js';
|
|
3
|
+
import { SenseError } from '../errors.js';
|
|
2
4
|
import { embed } from '../features/embed.js';
|
|
3
5
|
import { FEATURES } from '../features/index.js';
|
|
4
6
|
import { rank } from '../features/rank.js';
|
|
5
7
|
import { listFiles } from '../scan/index.js';
|
|
6
8
|
import { ParsePool } from '../scan/pool.js';
|
|
7
9
|
import { reparseFiles } from '../scan/reparse.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
10
|
+
import { classifyEmbedChange } from './embed-scope.js';
|
|
11
|
+
import { classifyFeatureToggles, isFeatureOnlyChange, NARROW_FEATURE_TABLE } from './feature-scope.js';
|
|
12
|
+
import { forcedPresetPaths, isPresetOnlyChange } from './preset-scope.js';
|
|
13
|
+
import { CORE_GENERATION_META_KEY, CORE_READY_META_KEY, FEATURE_SIGNATURE_META_KEY } from './readiness.js';
|
|
14
|
+
import { createReconcileTiming, prepareReconcile, readReconcileSnapshot } from './reconcile.js';
|
|
15
|
+
import { setMeta } from './shared.js';
|
|
16
|
+
import { changedSignatureKeys, embedIdentityAdopted, signatureDiff } from './signature.js';
|
|
11
17
|
import { withTransaction } from './transaction.js';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
let StaleBuildPlan = class StaleBuildPlan extends Error {
|
|
19
|
+
};
|
|
20
|
+
const buildPlan = channel('sensemaking.store.build-plan');
|
|
21
|
+
const SCHEMA_VERSION_META_KEY = 'schema_version';
|
|
22
|
+
async function readCoreBaseline(conn) {
|
|
23
|
+
var _values_get, _values_get1, _values_get2, _values_get3;
|
|
24
|
+
const keys = [
|
|
25
|
+
SCHEMA_VERSION_META_KEY,
|
|
26
|
+
FEATURE_SIGNATURE_META_KEY,
|
|
27
|
+
CORE_READY_META_KEY,
|
|
28
|
+
CORE_GENERATION_META_KEY
|
|
29
|
+
];
|
|
30
|
+
const stmt = await conn.prepare(`SELECT key, value FROM meta WHERE key IN (${keys.map(()=>'?').join(', ')})`);
|
|
31
|
+
const values = new Map((await stmt.all(...keys)).map((row)=>[
|
|
32
|
+
row.key,
|
|
33
|
+
row.value
|
|
34
|
+
]));
|
|
16
35
|
return {
|
|
17
|
-
|
|
36
|
+
schemaVersion: (_values_get = values.get(SCHEMA_VERSION_META_KEY)) !== null && _values_get !== void 0 ? _values_get : null,
|
|
37
|
+
features: (_values_get1 = values.get(FEATURE_SIGNATURE_META_KEY)) !== null && _values_get1 !== void 0 ? _values_get1 : null,
|
|
38
|
+
ready: (_values_get2 = values.get(CORE_READY_META_KEY)) !== null && _values_get2 !== void 0 ? _values_get2 : null,
|
|
39
|
+
generation: (_values_get3 = values.get(CORE_GENERATION_META_KEY)) !== null && _values_get3 !== void 0 ? _values_get3 : null
|
|
18
40
|
};
|
|
19
41
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
function sameBaseline(a, b) {
|
|
43
|
+
return a.schemaVersion === b.schemaVersion && a.features === b.features && a.ready === b.ready && a.generation === b.generation;
|
|
44
|
+
}
|
|
45
|
+
function nextGeneration(value) {
|
|
46
|
+
const current = value === null ? 0 : Number(value);
|
|
47
|
+
if (!Number.isSafeInteger(current) || current < 0 || current === Number.MAX_SAFE_INTEGER) throw new SenseError('INDEX_NOT_READY', `the durable core generation is invalid (${value !== null && value !== void 0 ? value : 'missing'}); run sense build --force to recreate the derived index`);
|
|
48
|
+
return String(current + 1);
|
|
49
|
+
}
|
|
50
|
+
async function readPlanningSnapshot(conn, timing) {
|
|
51
|
+
return withTransaction(conn, async ()=>{
|
|
52
|
+
const baseline = await readCoreBaseline(conn);
|
|
53
|
+
const reconcile = await readReconcileSnapshot(conn, timing);
|
|
54
|
+
const tablesStmt = await conn.prepare("SELECT name FROM sqlite_master WHERE type = 'table'");
|
|
55
|
+
const tables = new Set((await tablesStmt.all()).map((row)=>row.name));
|
|
56
|
+
return {
|
|
57
|
+
baseline,
|
|
58
|
+
reconcile,
|
|
59
|
+
tables
|
|
60
|
+
};
|
|
35
61
|
});
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
62
|
+
}
|
|
63
|
+
function activeSchemaMissing(snapshot, cfg) {
|
|
64
|
+
for (const feature of FEATURES){
|
|
65
|
+
if (!featureEnabled(cfg, feature.name)) continue;
|
|
66
|
+
if (feature.name === 'rank') {
|
|
67
|
+
if (!snapshot.reconcile.seenColumns.has('_rank')) return true;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const table = feature.name === 'embed' ? 'embeddings' : NARROW_FEATURE_TABLE[feature.name];
|
|
71
|
+
if (table && !snapshot.tables.has(table)) return true;
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
function classifyBuild(snapshot, cfg, paths, wanted) {
|
|
76
|
+
const before = snapshot.baseline.features;
|
|
77
|
+
const recover = snapshot.baseline.ready === '0';
|
|
78
|
+
const messages = [];
|
|
79
|
+
if (recover) messages.push('sense: recovering an incomplete index generation in place');
|
|
80
|
+
if (!recover && before !== null && before === wanted && activeSchemaMissing(snapshot, cfg)) {
|
|
81
|
+
messages.push('sense: recovering missing feature schema in place');
|
|
82
|
+
return {
|
|
83
|
+
embedKind: null,
|
|
84
|
+
featureToggles: [],
|
|
85
|
+
fullRebuild: true,
|
|
86
|
+
messages
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (recover || before === null || before === wanted) return {
|
|
90
|
+
embedKind: null,
|
|
91
|
+
featureToggles: [],
|
|
92
|
+
fullRebuild: recover,
|
|
93
|
+
messages
|
|
42
94
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
95
|
+
const changedKeys = changedSignatureKeys(before, wanted);
|
|
96
|
+
if (changedKeys.size === 1 && changedKeys.has('embed') && embedIdentityAdopted(before, wanted)) {
|
|
97
|
+
messages.push("sense: recorded the embedding model's resolved identity; vectors are unaffected");
|
|
98
|
+
return {
|
|
99
|
+
embedKind: null,
|
|
100
|
+
featureToggles: [],
|
|
101
|
+
fullRebuild: false,
|
|
102
|
+
messages
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const embedKind = changedKeys.size === 1 && changedKeys.has('embed') ? classifyEmbedChange(before, wanted) : null;
|
|
106
|
+
if (embedKind !== null) {
|
|
107
|
+
messages.push(embedKind === 'model' ? 'sense: config change (embed settings) invalidates only the stale vectors' : 'sense: config change (embed settings) rebuilds only the embeddings it affects');
|
|
108
|
+
return {
|
|
109
|
+
embedKind,
|
|
110
|
+
featureToggles: [],
|
|
111
|
+
fullRebuild: false,
|
|
112
|
+
messages
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const presetForced = isPresetOnlyChange(changedKeys) ? forcedPresetPaths(cfg, paths.rootDir, before, changedKeys) : null;
|
|
116
|
+
if (presetForced !== null) {
|
|
117
|
+
messages.push(`sense: config change (${signatureDiff(before, wanted)}) reparses only the files it affects`);
|
|
118
|
+
return {
|
|
119
|
+
embedKind: null,
|
|
120
|
+
featureToggles: [],
|
|
121
|
+
forcedPaths: presetForced,
|
|
122
|
+
fullRebuild: false,
|
|
123
|
+
messages
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const toggles = isFeatureOnlyChange(changedKeys) ? classifyFeatureToggles(before, wanted, changedKeys) : null;
|
|
127
|
+
if (toggles !== null) {
|
|
128
|
+
messages.push(`sense: config change (${signatureDiff(before, wanted)}) reparses only the feature it affects`);
|
|
129
|
+
return {
|
|
130
|
+
embedKind: null,
|
|
131
|
+
featureToggles: toggles,
|
|
132
|
+
fullRebuild: false,
|
|
133
|
+
messages
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
messages.push(`sense: config change (${signatureDiff(before, wanted)}) rebuilds the index`);
|
|
51
137
|
return {
|
|
52
|
-
|
|
138
|
+
embedKind: null,
|
|
139
|
+
featureToggles: [],
|
|
140
|
+
fullRebuild: true,
|
|
141
|
+
messages
|
|
53
142
|
};
|
|
54
143
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// added, edited, or deleted got no remove/store for it), so this never diffs against them --
|
|
58
|
-
// dropping every row and reparsing the whole tree is the only safe path back to consistent state.
|
|
59
|
-
async function invalidateFeatureTable(conn, cfg, baseDir, dialect, pool, toggle) {
|
|
60
|
-
const table = NARROW_FEATURE_TABLE[toggle.name];
|
|
61
|
-
const feature = FEATURES.find((f)=>f.name === toggle.name);
|
|
62
|
-
if (!feature) throw new Error(`invalidateFeatureTable: no registered feature named "${toggle.name}"`);
|
|
63
|
-
if (!toggle.turnedOn) {
|
|
64
|
-
await withTransaction(conn, ()=>conn.exec(`DELETE FROM ${table}`), dialect.beginMode());
|
|
144
|
+
async function prepareEmbedInvalidation(kind, snapshot, cfg, paths, pool) {
|
|
145
|
+
if (kind === 'model') {
|
|
65
146
|
return {
|
|
66
|
-
|
|
147
|
+
mutated: true,
|
|
148
|
+
parsed: 0,
|
|
149
|
+
apply: (conn)=>conn.exec('UPDATE embeddings SET vector = NULL, scale = NULL')
|
|
67
150
|
};
|
|
68
151
|
}
|
|
69
|
-
const
|
|
152
|
+
const existing = new Set(snapshot.reconcile.existingRows.map((row)=>row.path));
|
|
153
|
+
const files = listFiles(cfg, paths.rootDir).filter((file)=>file.embed && existing.has(file.relPath));
|
|
70
154
|
const { docs } = await reparseFiles(files, [
|
|
71
|
-
|
|
155
|
+
embed
|
|
72
156
|
], cfg, new Set(), undefined, {
|
|
73
157
|
pool
|
|
74
158
|
});
|
|
75
|
-
const
|
|
76
|
-
path: d.relPath,
|
|
77
|
-
extracted: d.extracted[feature.name]
|
|
78
|
-
}));
|
|
79
|
-
const paths = docs.map((d)=>d.relPath);
|
|
80
|
-
// Every path counts as added, not just touched: nothing stale to diff against. Links resolves
|
|
81
|
-
// dst inside store() itself when added.length equals files.length (a cold build).
|
|
159
|
+
const pathsChanged = docs.map((doc)=>doc.relPath);
|
|
82
160
|
const delta = {
|
|
83
161
|
files,
|
|
84
|
-
reparsed:
|
|
85
|
-
added:
|
|
162
|
+
reparsed: pathsChanged,
|
|
163
|
+
added: [],
|
|
86
164
|
vanished: []
|
|
87
165
|
};
|
|
88
|
-
await withTransaction(conn, async ()=>{
|
|
89
|
-
var _feature_store, _feature_afterReconcile;
|
|
90
|
-
await conn.exec(`DELETE FROM ${table}`);
|
|
91
|
-
await ((_feature_store = feature.store) === null || _feature_store === void 0 ? void 0 : _feature_store.call(feature, conn, docsForFeature, delta));
|
|
92
|
-
await ((_feature_afterReconcile = feature.afterReconcile) === null || _feature_afterReconcile === void 0 ? void 0 : _feature_afterReconcile.call(feature, conn, delta));
|
|
93
|
-
}, dialect.beginMode());
|
|
94
166
|
return {
|
|
95
|
-
|
|
167
|
+
mutated: true,
|
|
168
|
+
parsed: docs.length,
|
|
169
|
+
async apply (conn) {
|
|
170
|
+
var _embed_store;
|
|
171
|
+
// Chunk changes can also change the model. Clear every affected row even when
|
|
172
|
+
// its text identity happens to match under the new configuration.
|
|
173
|
+
if (pathsChanged.length > 0) await conn.runBatch('DELETE FROM embeddings WHERE "path" = ?', pathsChanged.map((path)=>[
|
|
174
|
+
path
|
|
175
|
+
]));
|
|
176
|
+
await ((_embed_store = embed.store) === null || _embed_store === void 0 ? void 0 : _embed_store.call(embed, conn, docs.map((doc)=>({
|
|
177
|
+
path: doc.relPath,
|
|
178
|
+
extracted: doc.extracted.embed
|
|
179
|
+
})), delta));
|
|
180
|
+
}
|
|
96
181
|
};
|
|
97
182
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
await withTransaction(conn, ()=>conn.exec('UPDATE frontmatter SET "_rank" = NULL'), dialect.beginMode());
|
|
104
|
-
}
|
|
105
|
-
// Whole-tree and reparse-free: PageRank is computed from the links table, not from files, so
|
|
106
|
-
// turning rank back on needs no reparseFiles pass at all.
|
|
107
|
-
async function rerunRank(conn, dialect) {
|
|
108
|
-
const delta = {
|
|
109
|
-
files: [],
|
|
110
|
-
reparsed: [],
|
|
111
|
-
added: [],
|
|
112
|
-
vanished: []
|
|
183
|
+
async function prepareFeatureInvalidation(toggles, snapshot, cfg, paths, pool) {
|
|
184
|
+
if (toggles.length === 0) return {
|
|
185
|
+
mutated: false,
|
|
186
|
+
parsed: 0,
|
|
187
|
+
apply: async ()=>{}
|
|
113
188
|
};
|
|
114
|
-
|
|
115
|
-
var _rank_afterReconcile;
|
|
116
|
-
await ((_rank_afterReconcile = rank.afterReconcile) === null || _rank_afterReconcile === void 0 ? void 0 : _rank_afterReconcile.call(rank, conn, delta));
|
|
117
|
-
}, dialect.beginMode());
|
|
118
|
-
}
|
|
119
|
-
async function invalidateFeatureToggles(conn, cfg, baseDir, dialect, pool, toggles) {
|
|
120
|
-
const byName = new Map(toggles.map((toggle)=>[
|
|
121
|
-
toggle.name,
|
|
122
|
-
toggle
|
|
123
|
-
]));
|
|
189
|
+
const prepared = new Map();
|
|
124
190
|
let parsed = 0;
|
|
125
|
-
// links first, if present: rank's rerun below (whether from its own toggle or the co-change
|
|
126
|
-
// rankToggle carries) must read the links table after it is back in its new state.
|
|
127
|
-
const linksToggle = byName.get('links');
|
|
128
|
-
if (linksToggle) {
|
|
129
|
-
parsed += (await invalidateFeatureTable(conn, cfg, baseDir, dialect, pool, linksToggle)).parsed;
|
|
130
|
-
// Unconditional, per rank's dependency on links: nulling is a no-op (guarded) when rank was
|
|
131
|
-
// never enabled for this tree, so this is safe even when no feature:rank segment changed.
|
|
132
|
-
if (!linksToggle.turnedOn) await nullRank(conn, dialect);
|
|
133
|
-
}
|
|
134
|
-
// rank's effective on/off (featureEnabled's links dependency) only appears as a changed
|
|
135
|
-
// `feature:rank` segment when it actually flips -- whether that's rank's own config or a
|
|
136
|
-
// links toggle taking it along -- so honoring it here is complete on its own.
|
|
137
|
-
const rankToggle = byName.get('rank');
|
|
138
|
-
if (rankToggle) {
|
|
139
|
-
if (rankToggle.turnedOn) await rerunRank(conn, dialect);
|
|
140
|
-
else await nullRank(conn, dialect);
|
|
141
|
-
}
|
|
142
191
|
for (const toggle of toggles){
|
|
143
|
-
if (toggle.
|
|
144
|
-
|
|
192
|
+
if (!toggle.turnedOn || toggle.name === 'rank') continue;
|
|
193
|
+
const feature = FEATURES.find((candidate)=>candidate.name === toggle.name);
|
|
194
|
+
if (!feature) throw new Error(`prepareFeatureInvalidation: no registered feature named "${toggle.name}"`);
|
|
195
|
+
const files = listFiles(cfg, paths.rootDir);
|
|
196
|
+
const { docs } = await reparseFiles(files, [
|
|
197
|
+
feature
|
|
198
|
+
], cfg, new Set(), undefined, {
|
|
199
|
+
pool
|
|
200
|
+
});
|
|
201
|
+
parsed += docs.length;
|
|
202
|
+
prepared.set(toggle.name, {
|
|
203
|
+
feature,
|
|
204
|
+
docs,
|
|
205
|
+
files
|
|
206
|
+
});
|
|
145
207
|
}
|
|
208
|
+
const applyTable = async (conn, toggle)=>{
|
|
209
|
+
var _plan_feature_store, _plan_feature, _plan_feature_afterReconcile, _plan_feature1;
|
|
210
|
+
const table = NARROW_FEATURE_TABLE[toggle.name];
|
|
211
|
+
if (!table) return;
|
|
212
|
+
if (!toggle.turnedOn) {
|
|
213
|
+
if (snapshot.tables.has(table)) await conn.exec(`DELETE FROM ${table}`);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const plan = prepared.get(toggle.name);
|
|
217
|
+
if (!plan) throw new Error(`prepareFeatureInvalidation: missing prepared feature "${toggle.name}"`);
|
|
218
|
+
const pathsChanged = plan.docs.map((doc)=>doc.relPath);
|
|
219
|
+
const delta = {
|
|
220
|
+
files: plan.files,
|
|
221
|
+
reparsed: pathsChanged,
|
|
222
|
+
added: pathsChanged,
|
|
223
|
+
vanished: []
|
|
224
|
+
};
|
|
225
|
+
await conn.exec(`DELETE FROM ${table}`);
|
|
226
|
+
await ((_plan_feature_store = (_plan_feature = plan.feature).store) === null || _plan_feature_store === void 0 ? void 0 : _plan_feature_store.call(_plan_feature, conn, plan.docs.map((doc)=>({
|
|
227
|
+
path: doc.relPath,
|
|
228
|
+
extracted: doc.extracted[plan.feature.name]
|
|
229
|
+
})), delta));
|
|
230
|
+
await ((_plan_feature_afterReconcile = (_plan_feature1 = plan.feature).afterReconcile) === null || _plan_feature_afterReconcile === void 0 ? void 0 : _plan_feature_afterReconcile.call(_plan_feature1, conn, delta));
|
|
231
|
+
};
|
|
232
|
+
const nullRank = async (conn)=>{
|
|
233
|
+
if (snapshot.reconcile.seenColumns.has('_rank')) await conn.exec('UPDATE frontmatter SET "_rank" = NULL');
|
|
234
|
+
};
|
|
146
235
|
return {
|
|
147
|
-
|
|
236
|
+
mutated: true,
|
|
237
|
+
parsed,
|
|
238
|
+
async apply (conn) {
|
|
239
|
+
const byName = new Map(toggles.map((toggle)=>[
|
|
240
|
+
toggle.name,
|
|
241
|
+
toggle
|
|
242
|
+
]));
|
|
243
|
+
const linksToggle = byName.get('links');
|
|
244
|
+
if (linksToggle) {
|
|
245
|
+
await applyTable(conn, linksToggle);
|
|
246
|
+
if (!linksToggle.turnedOn) await nullRank(conn);
|
|
247
|
+
}
|
|
248
|
+
const rankToggle = byName.get('rank');
|
|
249
|
+
if (rankToggle) {
|
|
250
|
+
var _rank_afterReconcile;
|
|
251
|
+
if (rankToggle.turnedOn) await ((_rank_afterReconcile = rank.afterReconcile) === null || _rank_afterReconcile === void 0 ? void 0 : _rank_afterReconcile.call(rank, conn, {
|
|
252
|
+
files: [],
|
|
253
|
+
reparsed: [],
|
|
254
|
+
added: [],
|
|
255
|
+
vanished: []
|
|
256
|
+
}));
|
|
257
|
+
else await nullRank(conn);
|
|
258
|
+
}
|
|
259
|
+
for (const toggle of toggles){
|
|
260
|
+
if (toggle.name !== 'links' && toggle.name !== 'rank') await applyTable(conn, toggle);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
148
263
|
};
|
|
149
264
|
}
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
for (const feature of
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const toggles = disabled.filter((feature)=>feature.name !== 'embed').map((feature)=>({
|
|
265
|
+
function recoveryToggles(cfg, snapshot) {
|
|
266
|
+
const toggles = [];
|
|
267
|
+
for (const feature of FEATURES){
|
|
268
|
+
const table = NARROW_FEATURE_TABLE[feature.name];
|
|
269
|
+
if (table && !featureEnabled(cfg, feature.name) && snapshot.tables.has(table)) toggles.push({
|
|
156
270
|
name: feature.name,
|
|
157
271
|
turnedOn: false
|
|
158
|
-
})
|
|
159
|
-
await invalidateFeatureToggles(conn, cfg, paths.rootDir, dialect, pool, toggles);
|
|
160
|
-
if (disabled.some((feature)=>feature.name === 'embed')) {
|
|
161
|
-
const embeddingsTable = await conn.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'embeddings'");
|
|
162
|
-
if ((await embeddingsTable.all()).length > 0) await withTransaction(conn, ()=>conn.exec('DELETE FROM embeddings'), dialect.beginMode());
|
|
272
|
+
});
|
|
163
273
|
}
|
|
164
|
-
|
|
165
|
-
|
|
274
|
+
return toggles;
|
|
275
|
+
}
|
|
276
|
+
async function prepareInvalidation(classification, snapshot, cfg, paths, pool) {
|
|
277
|
+
const plans = [];
|
|
278
|
+
if (classification.embedKind) plans.push(await prepareEmbedInvalidation(classification.embedKind, snapshot, cfg, paths, pool));
|
|
279
|
+
if (classification.featureToggles.length > 0) plans.push(await prepareFeatureInvalidation(classification.featureToggles, snapshot, cfg, paths, pool));
|
|
280
|
+
if (classification.fullRebuild) {
|
|
281
|
+
plans.push(await prepareFeatureInvalidation(recoveryToggles(cfg, snapshot), snapshot, cfg, paths, pool));
|
|
282
|
+
// Full rebuild and recovery must not reuse vectors from the prior generation.
|
|
283
|
+
if (snapshot.tables.has('embeddings')) {
|
|
284
|
+
plans.push({
|
|
285
|
+
mutated: true,
|
|
286
|
+
parsed: 0,
|
|
287
|
+
apply: (conn)=>conn.exec('DELETE FROM embeddings')
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
if (!featureEnabled(cfg, 'rank') && snapshot.reconcile.seenColumns.has('_rank')) {
|
|
291
|
+
plans.push({
|
|
292
|
+
mutated: true,
|
|
293
|
+
parsed: 0,
|
|
294
|
+
apply: (conn)=>conn.exec('UPDATE frontmatter SET "_rank" = NULL')
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
mutated: plans.some((plan)=>plan.mutated),
|
|
300
|
+
parsed: plans.reduce((sum, plan)=>sum + plan.parsed, 0),
|
|
301
|
+
async apply (conn) {
|
|
302
|
+
for (const plan of plans)await plan.apply(conn);
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
function forcedPaths(classification, snapshot) {
|
|
307
|
+
if (!classification.fullRebuild) return classification.forcedPaths;
|
|
308
|
+
// New paths are reparsed by definition. Forcing every previously indexed path makes every
|
|
309
|
+
// survivor a reparse without a second filesystem scan outside prepareReconcile's one listing.
|
|
310
|
+
return new Set(snapshot.reconcile.existingRows.map((row)=>row.path));
|
|
311
|
+
}
|
|
312
|
+
async function publishAttempt(conn, liveCfg, dialect, pool, ensureFeatureSchema, timing, attempt) {
|
|
313
|
+
var _cfg_rootDir, _cfg_configDir;
|
|
314
|
+
const cfg = structuredClone(liveCfg);
|
|
315
|
+
const configIdentity = JSON.stringify(cfg);
|
|
316
|
+
const paths = {
|
|
317
|
+
rootDir: (_cfg_rootDir = cfg.rootDir) !== null && _cfg_rootDir !== void 0 ? _cfg_rootDir : cfg.baseDir,
|
|
318
|
+
configDir: (_cfg_configDir = cfg.configDir) !== null && _cfg_configDir !== void 0 ? _cfg_configDir : cfg.baseDir
|
|
319
|
+
};
|
|
320
|
+
const wanted = featureSignature(cfg, FEATURES);
|
|
321
|
+
const snapshot = await readPlanningSnapshot(conn, timing);
|
|
322
|
+
const classification = classifyBuild(snapshot, cfg, paths, wanted);
|
|
323
|
+
const invalidation = await prepareInvalidation(classification, snapshot, cfg, paths, pool);
|
|
324
|
+
const reconcile = await prepareReconcile(snapshot.reconcile, cfg, paths, dialect, timing, pool, forcedPaths(classification, snapshot));
|
|
325
|
+
const mutated = classification.fullRebuild || invalidation.mutated || reconcile.mutated || snapshot.baseline.features !== wanted || snapshot.baseline.ready !== '1';
|
|
326
|
+
if (buildPlan.hasSubscribers) buildPlan.publish({
|
|
327
|
+
attempt,
|
|
328
|
+
baseline: snapshot.baseline,
|
|
329
|
+
wantedSignature: wanted
|
|
330
|
+
});
|
|
331
|
+
const txStart = Date.now();
|
|
332
|
+
let txMs;
|
|
333
|
+
try {
|
|
334
|
+
await withTransaction(conn, async ()=>{
|
|
335
|
+
const current = await readCoreBaseline(conn);
|
|
336
|
+
const currentWanted = featureSignature(liveCfg, FEATURES);
|
|
337
|
+
if (!sameBaseline(current, snapshot.baseline) || JSON.stringify(liveCfg) !== configIdentity || currentWanted !== wanted) {
|
|
338
|
+
throw new StaleBuildPlan('core generation or configuration changed while this build was planning');
|
|
339
|
+
}
|
|
340
|
+
if (!mutated) return;
|
|
341
|
+
await ensureFeatureSchema(cfg);
|
|
342
|
+
await invalidation.apply(conn);
|
|
343
|
+
await reconcile.apply(conn);
|
|
344
|
+
const publishedWanted = featureSignature(liveCfg, FEATURES);
|
|
345
|
+
if (JSON.stringify(liveCfg) !== configIdentity || publishedWanted !== wanted) throw new StaleBuildPlan('configuration changed while this build was publishing');
|
|
346
|
+
await setMeta(conn, FEATURE_SIGNATURE_META_KEY, wanted);
|
|
347
|
+
await setMeta(conn, CORE_READY_META_KEY, '1');
|
|
348
|
+
await setMeta(conn, CORE_GENERATION_META_KEY, nextGeneration(snapshot.baseline.generation));
|
|
349
|
+
}, dialect.beginMode());
|
|
350
|
+
} finally{
|
|
351
|
+
txMs = Date.now() - txStart;
|
|
352
|
+
timing.txMs += txMs;
|
|
353
|
+
}
|
|
354
|
+
if (reconcile.mutated) await reconcile.record(conn, txMs);
|
|
355
|
+
return {
|
|
356
|
+
parsed: invalidation.parsed + reconcile.parsed,
|
|
357
|
+
warnings: reconcile.warnings,
|
|
358
|
+
stages: reconcile.finish(timing.txMs),
|
|
359
|
+
messages: classification.messages
|
|
360
|
+
};
|
|
166
361
|
}
|
|
167
|
-
|
|
168
|
-
// needs it, and reused by every later call on this instance.
|
|
169
|
-
export function createBuilder(conn, cfg, paths, dialect) {
|
|
362
|
+
export function createBuilder(conn, cfg, dialect, ensureFeatureSchema) {
|
|
170
363
|
const pool = new ParsePool();
|
|
171
364
|
return {
|
|
172
|
-
build
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
365
|
+
async build () {
|
|
366
|
+
// One clock and recorder span both bounded attempts. Baseline/catalog reads and feature
|
|
367
|
+
// invalidation preparation are included in totalMs but remain intentionally unlabelled;
|
|
368
|
+
// existing/list/parse and publication stages accumulate under their established labels.
|
|
369
|
+
const timing = createReconcileTiming(cfg);
|
|
370
|
+
for(let attempt = 0; attempt < 2; attempt++){
|
|
371
|
+
try {
|
|
372
|
+
return await publishAttempt(conn, cfg, dialect, pool, ensureFeatureSchema, timing, attempt);
|
|
373
|
+
} catch (err) {
|
|
374
|
+
if (!(err instanceof StaleBuildPlan)) throw err;
|
|
375
|
+
if (attempt === 1) throw new SenseError('STORE_BUSY', 'the index changed during both bounded publication attempts; wait for the competing build to finish and retry');
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
throw new Error('unreachable build attempt state');
|
|
379
|
+
},
|
|
176
380
|
close: ()=>pool.close(),
|
|
177
381
|
get poolsCreated () {
|
|
178
382
|
return pool.poolsCreated;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/builder.ts"],"sourcesContent":["import { type Config, featureEnabled } from '../config/index.ts';\nimport { embed } from '../features/embed.ts';\nimport { FEATURES } from '../features/index.ts';\nimport { rank } from '../features/rank.ts';\nimport type { ReconcileDelta } from '../features/types.ts';\nimport { listFiles } from '../scan/index.ts';\nimport { ParsePool } from '../scan/pool.ts';\nimport { reparseFiles } from '../scan/reparse.ts';\nimport type { EmbedChangeKind } from './embed-scope.ts';\nimport type { FeatureToggle } from './feature-scope.ts';\nimport { NARROW_FEATURE_TABLE } from './feature-scope.ts';\nimport { type ReconcilePaths, reconcile } from './reconcile.ts';\nimport { getColumns } from './shared.ts';\nimport type { Stages } from './stages.ts';\nimport { withTransaction } from './transaction.ts';\nimport type { Connection, ReconcileDialect } from './types.ts';\n\n// Owns bringing a store's index current: the write half `Store` (types.ts) deliberately does not\n// carry. A one-shot open calls build() once; a watcher calls it repeatedly on the same instance.\nexport interface Builder {\n // forcedPaths (open.ts's preset-only narrow rebuild) applies to this call alone, not future ones.\n build(forcedPaths?: ReadonlySet<string>): Promise<{ parsed: number; warnings: string[]; stages: Stages }>;\n // Repairs an incomplete generation in place, including state owned by disabled features.\n recover(): Promise<{ parsed: number; warnings: string[]; stages: Stages }>;\n // Narrow embed invalidation (open.ts, embed-scope.ts's classifyEmbedChange): 'model' nulls every\n // vector/scale in place; 'chunk' rebuilds every embedding row. Neither touches another table.\n invalidate(kind: EmbedChangeKind): Promise<{ parsed: number }>;\n // Narrow feature-toggle invalidation (open.ts, feature-scope.ts's classifyFeatureToggles): a\n // toggle drops (or, turning back on, fully re-derives) that feature's own table; rank instead\n // nulls or recomputes its `_rank` column, since rows written while a feature was off are\n // untrustworthy (reconcile.ts's activeFeatures skips a disabled feature's hooks entirely).\n invalidateFeatures(toggles: FeatureToggle[]): Promise<{ parsed: number }>;\n // Releases the parse worker pool, if this lifetime ever created one; never the connection.\n close(): Promise<void>;\n // Pools this lifetime has constructed, so reuse is observable rather than inferred.\n readonly poolsCreated: number;\n}\n\n// 'model': the provider or model name moved but chunk boundaries did not, so only the vector\n// values are stale. No reparse, and no table but embeddings is touched.\nasync function nullEmbedVectors(conn: Connection, dialect: ReconcileDialect): Promise<{ parsed: number }> {\n await withTransaction(conn, () => conn.exec('UPDATE embeddings SET vector = NULL, scale = NULL'), dialect.beginMode());\n return { parsed: 0 };\n}\n\n// 'chunk': chunkTokens or the chunk version moved, so chunk boundaries genuinely changed. Rebuilds\n// every embedding row through the embed feature's own remove/store, touching no other table.\nasync function rebuildEmbeddings(conn: Connection, cfg: Config, baseDir: string, dialect: ReconcileDialect, pool: ParsePool): Promise<{ parsed: number }> {\n const existingStmt = await conn.prepare('SELECT \"path\" FROM frontmatter');\n const existingPaths = new Set((await existingStmt.all()).map((r) => (r as { path: string }).path));\n // A file added since the last build has no row yet; leaving it for build() to insert avoids a\n // primary-key collision between this INSERT and build()'s own insert for the same new file.\n const files = listFiles(cfg, baseDir).filter((f) => f.embed && existingPaths.has(f.relPath));\n if (files.length === 0) return { parsed: 0 };\n\n const { docs } = await reparseFiles(files, [embed], cfg, new Set(), undefined, { pool });\n const paths = docs.map((d) => d.relPath);\n const delta: ReconcileDelta = { files, reparsed: paths, added: [], vanished: [] };\n await withTransaction(\n conn,\n async () => {\n await embed.remove?.(conn, paths, delta);\n await embed.store?.(\n conn,\n docs.map((d) => ({ path: d.relPath, extracted: d.extracted.embed })),\n delta\n );\n },\n dialect.beginMode()\n );\n return { parsed: docs.length };\n}\n\n// One feature's own table, dropped and (turning on) fully re-derived across every indexed file.\n// Rows left over from before this feature was disabled are untrustworthy by construction (files\n// added, edited, or deleted got no remove/store for it), so this never diffs against them --\n// dropping every row and reparsing the whole tree is the only safe path back to consistent state.\nasync function invalidateFeatureTable(conn: Connection, cfg: Config, baseDir: string, dialect: ReconcileDialect, pool: ParsePool, toggle: FeatureToggle): Promise<{ parsed: number }> {\n const table = NARROW_FEATURE_TABLE[toggle.name];\n const feature = FEATURES.find((f) => f.name === toggle.name);\n if (!feature) throw new Error(`invalidateFeatureTable: no registered feature named \"${toggle.name}\"`);\n\n if (!toggle.turnedOn) {\n await withTransaction(conn, () => conn.exec(`DELETE FROM ${table}`), dialect.beginMode());\n return { parsed: 0 };\n }\n\n const files = listFiles(cfg, baseDir);\n const { docs } = await reparseFiles(files, [feature], cfg, new Set(), undefined, { pool });\n const docsForFeature = docs.map((d) => ({ path: d.relPath, extracted: d.extracted[feature.name] }));\n const paths = docs.map((d) => d.relPath);\n // Every path counts as added, not just touched: nothing stale to diff against. Links resolves\n // dst inside store() itself when added.length equals files.length (a cold build).\n const delta: ReconcileDelta = { files, reparsed: paths, added: paths, vanished: [] };\n await withTransaction(\n conn,\n async () => {\n await conn.exec(`DELETE FROM ${table}`);\n await feature.store?.(conn, docsForFeature, delta);\n await feature.afterReconcile?.(conn, delta);\n },\n dialect.beginMode()\n );\n return { parsed: docs.length };\n}\n\n// rank has no table of its own: frontmatter._rank is the only state it owns. Guarded on column\n// presence, since links can toggle off while rank has never been enabled for this tree.\nasync function nullRank(conn: Connection, dialect: ReconcileDialect): Promise<void> {\n const columns = await getColumns(conn);\n if (!columns.has('_rank')) return;\n await withTransaction(conn, () => conn.exec('UPDATE frontmatter SET \"_rank\" = NULL'), dialect.beginMode());\n}\n\n// Whole-tree and reparse-free: PageRank is computed from the links table, not from files, so\n// turning rank back on needs no reparseFiles pass at all.\nasync function rerunRank(conn: Connection, dialect: ReconcileDialect): Promise<void> {\n const delta: ReconcileDelta = { files: [], reparsed: [], added: [], vanished: [] };\n await withTransaction(\n conn,\n async () => {\n await rank.afterReconcile?.(conn, delta);\n },\n dialect.beginMode()\n );\n}\n\nasync function invalidateFeatureToggles(conn: Connection, cfg: Config, baseDir: string, dialect: ReconcileDialect, pool: ParsePool, toggles: FeatureToggle[]): Promise<{ parsed: number }> {\n const byName = new Map(toggles.map((toggle) => [toggle.name, toggle]));\n let parsed = 0;\n\n // links first, if present: rank's rerun below (whether from its own toggle or the co-change\n // rankToggle carries) must read the links table after it is back in its new state.\n const linksToggle = byName.get('links');\n if (linksToggle) {\n parsed += (await invalidateFeatureTable(conn, cfg, baseDir, dialect, pool, linksToggle)).parsed;\n // Unconditional, per rank's dependency on links: nulling is a no-op (guarded) when rank was\n // never enabled for this tree, so this is safe even when no feature:rank segment changed.\n if (!linksToggle.turnedOn) await nullRank(conn, dialect);\n }\n\n // rank's effective on/off (featureEnabled's links dependency) only appears as a changed\n // `feature:rank` segment when it actually flips -- whether that's rank's own config or a\n // links toggle taking it along -- so honoring it here is complete on its own.\n const rankToggle = byName.get('rank');\n if (rankToggle) {\n if (rankToggle.turnedOn) await rerunRank(conn, dialect);\n else await nullRank(conn, dialect);\n }\n\n for (const toggle of toggles) {\n if (toggle.name === 'links' || toggle.name === 'rank') continue;\n parsed += (await invalidateFeatureTable(conn, cfg, baseDir, dialect, pool, toggle)).parsed;\n }\n return { parsed };\n}\n\nasync function recoverIncomplete(conn: Connection, cfg: Config, paths: ReconcilePaths, dialect: ReconcileDialect, pool: ParsePool): Promise<{ parsed: number; warnings: string[]; stages: Stages }> {\n const disabled = FEATURES.filter((feature) => !featureEnabled(cfg, feature.name));\n for (const feature of disabled) {\n if (feature.name !== 'embed') await feature.schema(conn);\n }\n\n const toggles: FeatureToggle[] = disabled.filter((feature) => feature.name !== 'embed').map((feature) => ({ name: feature.name, turnedOn: false }));\n await invalidateFeatureToggles(conn, cfg, paths.rootDir, dialect, pool, toggles);\n if (disabled.some((feature) => feature.name === 'embed')) {\n const embeddingsTable = await conn.prepare(\"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'embeddings'\");\n if ((await embeddingsTable.all()).length > 0) await withTransaction(conn, () => conn.exec('DELETE FROM embeddings'), dialect.beginMode());\n }\n\n const forcedPaths = new Set(listFiles(cfg, paths.rootDir).map((file) => file.relPath));\n return reconcile(conn, cfg, paths, dialect, pool, forcedPaths);\n}\n\n// The pool is created at most once, lazily, on whichever build() or invalidate() call first\n// needs it, and reused by every later call on this instance.\nexport function createBuilder(conn: Connection, cfg: Config, paths: ReconcilePaths, dialect: ReconcileDialect): Builder {\n const pool = new ParsePool();\n return {\n build: (forcedPaths) => reconcile(conn, cfg, paths, dialect, pool, forcedPaths),\n recover: () => recoverIncomplete(conn, cfg, paths, dialect, pool),\n invalidate: (kind) => (kind === 'model' ? nullEmbedVectors(conn, dialect) : rebuildEmbeddings(conn, cfg, paths.rootDir, dialect, pool)),\n invalidateFeatures: (toggles) => invalidateFeatureToggles(conn, cfg, paths.rootDir, dialect, pool, toggles),\n close: () => pool.close(),\n get poolsCreated() {\n return pool.poolsCreated;\n },\n };\n}\n"],"names":["featureEnabled","embed","FEATURES","rank","listFiles","ParsePool","reparseFiles","NARROW_FEATURE_TABLE","reconcile","getColumns","withTransaction","nullEmbedVectors","conn","dialect","exec","beginMode","parsed","rebuildEmbeddings","cfg","baseDir","pool","existingStmt","prepare","existingPaths","Set","all","map","r","path","files","filter","f","has","relPath","length","docs","undefined","paths","d","delta","reparsed","added","vanished","remove","store","extracted","invalidateFeatureTable","toggle","table","name","feature","find","Error","turnedOn","docsForFeature","afterReconcile","nullRank","columns","rerunRank","invalidateFeatureToggles","toggles","byName","Map","linksToggle","get","rankToggle","recoverIncomplete","disabled","schema","rootDir","some","embeddingsTable","forcedPaths","file","createBuilder","build","recover","invalidate","kind","invalidateFeatures","close","poolsCreated"],"mappings":"AAAA,SAAsBA,cAAc,QAAQ,qBAAqB;AACjE,SAASC,KAAK,QAAQ,uBAAuB;AAC7C,SAASC,QAAQ,QAAQ,uBAAuB;AAChD,SAASC,IAAI,QAAQ,sBAAsB;AAE3C,SAASC,SAAS,QAAQ,mBAAmB;AAC7C,SAASC,SAAS,QAAQ,kBAAkB;AAC5C,SAASC,YAAY,QAAQ,qBAAqB;AAGlD,SAASC,oBAAoB,QAAQ,qBAAqB;AAC1D,SAA8BC,SAAS,QAAQ,iBAAiB;AAChE,SAASC,UAAU,QAAQ,cAAc;AAEzC,SAASC,eAAe,QAAQ,mBAAmB;AAwBnD,6FAA6F;AAC7F,wEAAwE;AACxE,eAAeC,iBAAiBC,IAAgB,EAAEC,OAAyB;IACzE,MAAMH,gBAAgBE,MAAM,IAAMA,KAAKE,IAAI,CAAC,sDAAsDD,QAAQE,SAAS;IACnH,OAAO;QAAEC,QAAQ;IAAE;AACrB;AAEA,mGAAmG;AACnG,6FAA6F;AAC7F,eAAeC,kBAAkBL,IAAgB,EAAEM,GAAW,EAAEC,OAAe,EAAEN,OAAyB,EAAEO,IAAe;IACzH,MAAMC,eAAe,MAAMT,KAAKU,OAAO,CAAC;IACxC,MAAMC,gBAAgB,IAAIC,IAAI,AAAC,CAAA,MAAMH,aAAaI,GAAG,EAAC,EAAGC,GAAG,CAAC,CAACC,IAAM,AAACA,EAAuBC,IAAI;IAChG,8FAA8F;IAC9F,4FAA4F;IAC5F,MAAMC,QAAQzB,UAAUc,KAAKC,SAASW,MAAM,CAAC,CAACC,IAAMA,EAAE9B,KAAK,IAAIsB,cAAcS,GAAG,CAACD,EAAEE,OAAO;IAC1F,IAAIJ,MAAMK,MAAM,KAAK,GAAG,OAAO;QAAElB,QAAQ;IAAE;IAE3C,MAAM,EAAEmB,IAAI,EAAE,GAAG,MAAM7B,aAAauB,OAAO;QAAC5B;KAAM,EAAEiB,KAAK,IAAIM,OAAOY,WAAW;QAAEhB;IAAK;IACtF,MAAMiB,QAAQF,KAAKT,GAAG,CAAC,CAACY,IAAMA,EAAEL,OAAO;IACvC,MAAMM,QAAwB;QAAEV;QAAOW,UAAUH;QAAOI,OAAO,EAAE;QAAEC,UAAU,EAAE;IAAC;IAChF,MAAMhC,gBACJE,MACA;YACQX,eACAA;QADN,QAAMA,gBAAAA,MAAM0C,MAAM,cAAZ1C,oCAAAA,mBAAAA,OAAeW,MAAMyB,OAAOE;QAClC,QAAMtC,eAAAA,MAAM2C,KAAK,cAAX3C,mCAAAA,kBAAAA,OACJW,MACAuB,KAAKT,GAAG,CAAC,CAACY,IAAO,CAAA;gBAAEV,MAAMU,EAAEL,OAAO;gBAAEY,WAAWP,EAAEO,SAAS,CAAC5C,KAAK;YAAC,CAAA,IACjEsC;IAEJ,GACA1B,QAAQE,SAAS;IAEnB,OAAO;QAAEC,QAAQmB,KAAKD,MAAM;IAAC;AAC/B;AAEA,gGAAgG;AAChG,gGAAgG;AAChG,6FAA6F;AAC7F,kGAAkG;AAClG,eAAeY,uBAAuBlC,IAAgB,EAAEM,GAAW,EAAEC,OAAe,EAAEN,OAAyB,EAAEO,IAAe,EAAE2B,MAAqB;IACrJ,MAAMC,QAAQzC,oBAAoB,CAACwC,OAAOE,IAAI,CAAC;IAC/C,MAAMC,UAAUhD,SAASiD,IAAI,CAAC,CAACpB,IAAMA,EAAEkB,IAAI,KAAKF,OAAOE,IAAI;IAC3D,IAAI,CAACC,SAAS,MAAM,IAAIE,MAAM,CAAC,qDAAqD,EAAEL,OAAOE,IAAI,CAAC,CAAC,CAAC;IAEpG,IAAI,CAACF,OAAOM,QAAQ,EAAE;QACpB,MAAM3C,gBAAgBE,MAAM,IAAMA,KAAKE,IAAI,CAAC,CAAC,YAAY,EAAEkC,OAAO,GAAGnC,QAAQE,SAAS;QACtF,OAAO;YAAEC,QAAQ;QAAE;IACrB;IAEA,MAAMa,QAAQzB,UAAUc,KAAKC;IAC7B,MAAM,EAAEgB,IAAI,EAAE,GAAG,MAAM7B,aAAauB,OAAO;QAACqB;KAAQ,EAAEhC,KAAK,IAAIM,OAAOY,WAAW;QAAEhB;IAAK;IACxF,MAAMkC,iBAAiBnB,KAAKT,GAAG,CAAC,CAACY,IAAO,CAAA;YAAEV,MAAMU,EAAEL,OAAO;YAAEY,WAAWP,EAAEO,SAAS,CAACK,QAAQD,IAAI,CAAC;QAAC,CAAA;IAChG,MAAMZ,QAAQF,KAAKT,GAAG,CAAC,CAACY,IAAMA,EAAEL,OAAO;IACvC,8FAA8F;IAC9F,kFAAkF;IAClF,MAAMM,QAAwB;QAAEV;QAAOW,UAAUH;QAAOI,OAAOJ;QAAOK,UAAU,EAAE;IAAC;IACnF,MAAMhC,gBACJE,MACA;YAEQsC,gBACAA;QAFN,MAAMtC,KAAKE,IAAI,CAAC,CAAC,YAAY,EAAEkC,OAAO;QACtC,QAAME,iBAAAA,QAAQN,KAAK,cAAbM,qCAAAA,oBAAAA,SAAgBtC,MAAM0C,gBAAgBf;QAC5C,QAAMW,0BAAAA,QAAQK,cAAc,cAAtBL,8CAAAA,6BAAAA,SAAyBtC,MAAM2B;IACvC,GACA1B,QAAQE,SAAS;IAEnB,OAAO;QAAEC,QAAQmB,KAAKD,MAAM;IAAC;AAC/B;AAEA,+FAA+F;AAC/F,wFAAwF;AACxF,eAAesB,SAAS5C,IAAgB,EAAEC,OAAyB;IACjE,MAAM4C,UAAU,MAAMhD,WAAWG;IACjC,IAAI,CAAC6C,QAAQzB,GAAG,CAAC,UAAU;IAC3B,MAAMtB,gBAAgBE,MAAM,IAAMA,KAAKE,IAAI,CAAC,0CAA0CD,QAAQE,SAAS;AACzG;AAEA,6FAA6F;AAC7F,0DAA0D;AAC1D,eAAe2C,UAAU9C,IAAgB,EAAEC,OAAyB;IAClE,MAAM0B,QAAwB;QAAEV,OAAO,EAAE;QAAEW,UAAU,EAAE;QAAEC,OAAO,EAAE;QAAEC,UAAU,EAAE;IAAC;IACjF,MAAMhC,gBACJE,MACA;YACQT;QAAN,QAAMA,uBAAAA,KAAKoD,cAAc,cAAnBpD,2CAAAA,0BAAAA,MAAsBS,MAAM2B;IACpC,GACA1B,QAAQE,SAAS;AAErB;AAEA,eAAe4C,yBAAyB/C,IAAgB,EAAEM,GAAW,EAAEC,OAAe,EAAEN,OAAyB,EAAEO,IAAe,EAAEwC,OAAwB;IAC1J,MAAMC,SAAS,IAAIC,IAAIF,QAAQlC,GAAG,CAAC,CAACqB,SAAW;YAACA,OAAOE,IAAI;YAAEF;SAAO;IACpE,IAAI/B,SAAS;IAEb,4FAA4F;IAC5F,mFAAmF;IACnF,MAAM+C,cAAcF,OAAOG,GAAG,CAAC;IAC/B,IAAID,aAAa;QACf/C,UAAU,AAAC,CAAA,MAAM8B,uBAAuBlC,MAAMM,KAAKC,SAASN,SAASO,MAAM2C,YAAW,EAAG/C,MAAM;QAC/F,4FAA4F;QAC5F,0FAA0F;QAC1F,IAAI,CAAC+C,YAAYV,QAAQ,EAAE,MAAMG,SAAS5C,MAAMC;IAClD;IAEA,wFAAwF;IACxF,yFAAyF;IACzF,8EAA8E;IAC9E,MAAMoD,aAAaJ,OAAOG,GAAG,CAAC;IAC9B,IAAIC,YAAY;QACd,IAAIA,WAAWZ,QAAQ,EAAE,MAAMK,UAAU9C,MAAMC;aAC1C,MAAM2C,SAAS5C,MAAMC;IAC5B;IAEA,KAAK,MAAMkC,UAAUa,QAAS;QAC5B,IAAIb,OAAOE,IAAI,KAAK,WAAWF,OAAOE,IAAI,KAAK,QAAQ;QACvDjC,UAAU,AAAC,CAAA,MAAM8B,uBAAuBlC,MAAMM,KAAKC,SAASN,SAASO,MAAM2B,OAAM,EAAG/B,MAAM;IAC5F;IACA,OAAO;QAAEA;IAAO;AAClB;AAEA,eAAekD,kBAAkBtD,IAAgB,EAAEM,GAAW,EAAEmB,KAAqB,EAAExB,OAAyB,EAAEO,IAAe;IAC/H,MAAM+C,WAAWjE,SAAS4B,MAAM,CAAC,CAACoB,UAAY,CAAClD,eAAekB,KAAKgC,QAAQD,IAAI;IAC/E,KAAK,MAAMC,WAAWiB,SAAU;QAC9B,IAAIjB,QAAQD,IAAI,KAAK,SAAS,MAAMC,QAAQkB,MAAM,CAACxD;IACrD;IAEA,MAAMgD,UAA2BO,SAASrC,MAAM,CAAC,CAACoB,UAAYA,QAAQD,IAAI,KAAK,SAASvB,GAAG,CAAC,CAACwB,UAAa,CAAA;YAAED,MAAMC,QAAQD,IAAI;YAAEI,UAAU;QAAM,CAAA;IAChJ,MAAMM,yBAAyB/C,MAAMM,KAAKmB,MAAMgC,OAAO,EAAExD,SAASO,MAAMwC;IACxE,IAAIO,SAASG,IAAI,CAAC,CAACpB,UAAYA,QAAQD,IAAI,KAAK,UAAU;QACxD,MAAMsB,kBAAkB,MAAM3D,KAAKU,OAAO,CAAC;QAC3C,IAAI,AAAC,CAAA,MAAMiD,gBAAgB9C,GAAG,EAAC,EAAGS,MAAM,GAAG,GAAG,MAAMxB,gBAAgBE,MAAM,IAAMA,KAAKE,IAAI,CAAC,2BAA2BD,QAAQE,SAAS;IACxI;IAEA,MAAMyD,cAAc,IAAIhD,IAAIpB,UAAUc,KAAKmB,MAAMgC,OAAO,EAAE3C,GAAG,CAAC,CAAC+C,OAASA,KAAKxC,OAAO;IACpF,OAAOzB,UAAUI,MAAMM,KAAKmB,OAAOxB,SAASO,MAAMoD;AACpD;AAEA,4FAA4F;AAC5F,6DAA6D;AAC7D,OAAO,SAASE,cAAc9D,IAAgB,EAAEM,GAAW,EAAEmB,KAAqB,EAAExB,OAAyB;IAC3G,MAAMO,OAAO,IAAIf;IACjB,OAAO;QACLsE,OAAO,CAACH,cAAgBhE,UAAUI,MAAMM,KAAKmB,OAAOxB,SAASO,MAAMoD;QACnEI,SAAS,IAAMV,kBAAkBtD,MAAMM,KAAKmB,OAAOxB,SAASO;QAC5DyD,YAAY,CAACC,OAAUA,SAAS,UAAUnE,iBAAiBC,MAAMC,WAAWI,kBAAkBL,MAAMM,KAAKmB,MAAMgC,OAAO,EAAExD,SAASO;QACjI2D,oBAAoB,CAACnB,UAAYD,yBAAyB/C,MAAMM,KAAKmB,MAAMgC,OAAO,EAAExD,SAASO,MAAMwC;QACnGoB,OAAO,IAAM5D,KAAK4D,KAAK;QACvB,IAAIC;YACF,OAAO7D,KAAK6D,YAAY;QAC1B;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/builder.ts"],"sourcesContent":["import { channel } from 'node:diagnostics_channel';\nimport { type Config, featureEnabled, featureSignature, type ResolvedConfig } from '../config/index.ts';\nimport { SenseError } from '../errors.ts';\nimport { embed } from '../features/embed.ts';\nimport { FEATURES } from '../features/index.ts';\nimport { rank } from '../features/rank.ts';\nimport type { ReconcileDelta } from '../features/types.ts';\nimport { listFiles } from '../scan/index.ts';\nimport { ParsePool } from '../scan/pool.ts';\nimport { reparseFiles } from '../scan/reparse.ts';\nimport { classifyEmbedChange } from './embed-scope.ts';\nimport { classifyFeatureToggles, type FeatureToggle, isFeatureOnlyChange, NARROW_FEATURE_TABLE } from './feature-scope.ts';\nimport { forcedPresetPaths, isPresetOnlyChange } from './preset-scope.ts';\nimport { CORE_GENERATION_META_KEY, CORE_READY_META_KEY, FEATURE_SIGNATURE_META_KEY } from './readiness.ts';\nimport { createReconcileTiming, prepareReconcile, type ReconcilePaths, type ReconcileSnapshot, type ReconcileTiming, readReconcileSnapshot } from './reconcile.ts';\nimport { setMeta } from './shared.ts';\nimport { changedSignatureKeys, embedIdentityAdopted, signatureDiff } from './signature.ts';\nimport type { Stages } from './stages.ts';\nimport { withTransaction } from './transaction.ts';\nimport type { Connection, ReconcileDialect } from './types.ts';\n\ninterface BuildResult {\n parsed: number;\n warnings: string[];\n stages: Stages;\n messages: string[];\n}\n\nexport interface Builder {\n build(): Promise<BuildResult>;\n close(): Promise<void>;\n readonly poolsCreated: number;\n}\n\ninterface CoreBaseline {\n schemaVersion: string | null;\n features: string | null;\n ready: string | null;\n generation: string | null;\n}\n\ninterface PlanningSnapshot {\n baseline: CoreBaseline;\n reconcile: ReconcileSnapshot;\n tables: Set<string>;\n}\n\ninterface PreparedInvalidation {\n mutated: boolean;\n parsed: number;\n apply(conn: Connection): Promise<void>;\n}\n\ninterface BuildClassification {\n embedKind: ReturnType<typeof classifyEmbedChange>;\n featureToggles: FeatureToggle[];\n forcedPaths?: ReadonlySet<string>;\n fullRebuild: boolean;\n messages: string[];\n}\n\ntype EnsureFeatureSchema = (cfg: ResolvedConfig) => Promise<void>;\n\nclass StaleBuildPlan extends Error {}\n\nconst buildPlan = channel('sensemaking.store.build-plan');\nconst SCHEMA_VERSION_META_KEY = 'schema_version';\n\nasync function readCoreBaseline(conn: Connection): Promise<CoreBaseline> {\n const keys = [SCHEMA_VERSION_META_KEY, FEATURE_SIGNATURE_META_KEY, CORE_READY_META_KEY, CORE_GENERATION_META_KEY];\n const stmt = await conn.prepare(`SELECT key, value FROM meta WHERE key IN (${keys.map(() => '?').join(', ')})`);\n const values = new Map(((await stmt.all(...keys)) as Array<{ key: string; value: string }>).map((row) => [row.key, row.value]));\n return {\n schemaVersion: values.get(SCHEMA_VERSION_META_KEY) ?? null,\n features: values.get(FEATURE_SIGNATURE_META_KEY) ?? null,\n ready: values.get(CORE_READY_META_KEY) ?? null,\n generation: values.get(CORE_GENERATION_META_KEY) ?? null,\n };\n}\n\nfunction sameBaseline(a: CoreBaseline, b: CoreBaseline): boolean {\n return a.schemaVersion === b.schemaVersion && a.features === b.features && a.ready === b.ready && a.generation === b.generation;\n}\n\nfunction nextGeneration(value: string | null): string {\n const current = value === null ? 0 : Number(value);\n if (!Number.isSafeInteger(current) || current < 0 || current === Number.MAX_SAFE_INTEGER) throw new SenseError('INDEX_NOT_READY', `the durable core generation is invalid (${value ?? 'missing'}); run sense build --force to recreate the derived index`);\n return String(current + 1);\n}\n\nasync function readPlanningSnapshot(conn: Connection, timing: ReconcileTiming): Promise<PlanningSnapshot> {\n return withTransaction(conn, async () => {\n const baseline = await readCoreBaseline(conn);\n const reconcile = await readReconcileSnapshot(conn, timing);\n const tablesStmt = await conn.prepare(\"SELECT name FROM sqlite_master WHERE type = 'table'\");\n const tables = new Set(((await tablesStmt.all()) as Array<{ name: string }>).map((row) => row.name));\n return { baseline, reconcile, tables };\n });\n}\n\nfunction activeSchemaMissing(snapshot: PlanningSnapshot, cfg: Config): boolean {\n for (const feature of FEATURES) {\n if (!featureEnabled(cfg, feature.name)) continue;\n if (feature.name === 'rank') {\n if (!snapshot.reconcile.seenColumns.has('_rank')) return true;\n continue;\n }\n const table = feature.name === 'embed' ? 'embeddings' : NARROW_FEATURE_TABLE[feature.name];\n if (table && !snapshot.tables.has(table)) return true;\n }\n return false;\n}\n\nfunction classifyBuild(snapshot: PlanningSnapshot, cfg: Config, paths: ReconcilePaths, wanted: string): BuildClassification {\n const before = snapshot.baseline.features;\n const recover = snapshot.baseline.ready === '0';\n const messages: string[] = [];\n if (recover) messages.push('sense: recovering an incomplete index generation in place');\n if (!recover && before !== null && before === wanted && activeSchemaMissing(snapshot, cfg)) {\n messages.push('sense: recovering missing feature schema in place');\n return { embedKind: null, featureToggles: [], fullRebuild: true, messages };\n }\n if (recover || before === null || before === wanted) return { embedKind: null, featureToggles: [], fullRebuild: recover, messages };\n\n const changedKeys = changedSignatureKeys(before, wanted);\n if (changedKeys.size === 1 && changedKeys.has('embed') && embedIdentityAdopted(before, wanted)) {\n messages.push(\"sense: recorded the embedding model's resolved identity; vectors are unaffected\");\n return { embedKind: null, featureToggles: [], fullRebuild: false, messages };\n }\n\n const embedKind = changedKeys.size === 1 && changedKeys.has('embed') ? classifyEmbedChange(before, wanted) : null;\n if (embedKind !== null) {\n messages.push(embedKind === 'model' ? 'sense: config change (embed settings) invalidates only the stale vectors' : 'sense: config change (embed settings) rebuilds only the embeddings it affects');\n return { embedKind, featureToggles: [], fullRebuild: false, messages };\n }\n\n const presetForced = isPresetOnlyChange(changedKeys) ? forcedPresetPaths(cfg, paths.rootDir, before, changedKeys) : null;\n if (presetForced !== null) {\n messages.push(`sense: config change (${signatureDiff(before, wanted)}) reparses only the files it affects`);\n return { embedKind: null, featureToggles: [], forcedPaths: presetForced, fullRebuild: false, messages };\n }\n\n const toggles = isFeatureOnlyChange(changedKeys) ? classifyFeatureToggles(before, wanted, changedKeys) : null;\n if (toggles !== null) {\n messages.push(`sense: config change (${signatureDiff(before, wanted)}) reparses only the feature it affects`);\n return { embedKind: null, featureToggles: toggles, fullRebuild: false, messages };\n }\n\n messages.push(`sense: config change (${signatureDiff(before, wanted)}) rebuilds the index`);\n return { embedKind: null, featureToggles: [], fullRebuild: true, messages };\n}\n\nasync function prepareEmbedInvalidation(kind: NonNullable<BuildClassification['embedKind']>, snapshot: PlanningSnapshot, cfg: Config, paths: ReconcilePaths, pool: ParsePool): Promise<PreparedInvalidation> {\n if (kind === 'model') {\n return { mutated: true, parsed: 0, apply: (conn) => conn.exec('UPDATE embeddings SET vector = NULL, scale = NULL') };\n }\n\n const existing = new Set(snapshot.reconcile.existingRows.map((row) => row.path));\n const files = listFiles(cfg, paths.rootDir).filter((file) => file.embed && existing.has(file.relPath));\n const { docs } = await reparseFiles(files, [embed], cfg, new Set(), undefined, { pool });\n const pathsChanged = docs.map((doc) => doc.relPath);\n const delta: ReconcileDelta = { files, reparsed: pathsChanged, added: [], vanished: [] };\n return {\n mutated: true,\n parsed: docs.length,\n async apply(conn) {\n // Chunk changes can also change the model. Clear every affected row even when\n // its text identity happens to match under the new configuration.\n if (pathsChanged.length > 0)\n await conn.runBatch(\n 'DELETE FROM embeddings WHERE \"path\" = ?',\n pathsChanged.map((path) => [path])\n );\n await embed.store?.(\n conn,\n docs.map((doc) => ({ path: doc.relPath, extracted: doc.extracted.embed })),\n delta\n );\n },\n };\n}\n\nasync function prepareFeatureInvalidation(toggles: FeatureToggle[], snapshot: PlanningSnapshot, cfg: Config, paths: ReconcilePaths, pool: ParsePool): Promise<PreparedInvalidation> {\n if (toggles.length === 0) return { mutated: false, parsed: 0, apply: async () => {} };\n const prepared = new Map<string, { feature: (typeof FEATURES)[number]; docs: Awaited<ReturnType<typeof reparseFiles>>['docs']; files: ReturnType<typeof listFiles> }>();\n let parsed = 0;\n for (const toggle of toggles) {\n if (!toggle.turnedOn || toggle.name === 'rank') continue;\n const feature = FEATURES.find((candidate) => candidate.name === toggle.name);\n if (!feature) throw new Error(`prepareFeatureInvalidation: no registered feature named \"${toggle.name}\"`);\n const files = listFiles(cfg, paths.rootDir);\n const { docs } = await reparseFiles(files, [feature], cfg, new Set(), undefined, { pool });\n parsed += docs.length;\n prepared.set(toggle.name, { feature, docs, files });\n }\n\n const applyTable = async (conn: Connection, toggle: FeatureToggle): Promise<void> => {\n const table = NARROW_FEATURE_TABLE[toggle.name];\n if (!table) return;\n if (!toggle.turnedOn) {\n if (snapshot.tables.has(table)) await conn.exec(`DELETE FROM ${table}`);\n return;\n }\n const plan = prepared.get(toggle.name);\n if (!plan) throw new Error(`prepareFeatureInvalidation: missing prepared feature \"${toggle.name}\"`);\n const pathsChanged = plan.docs.map((doc) => doc.relPath);\n const delta: ReconcileDelta = { files: plan.files, reparsed: pathsChanged, added: pathsChanged, vanished: [] };\n await conn.exec(`DELETE FROM ${table}`);\n await plan.feature.store?.(\n conn,\n plan.docs.map((doc) => ({ path: doc.relPath, extracted: doc.extracted[plan.feature.name] })),\n delta\n );\n await plan.feature.afterReconcile?.(conn, delta);\n };\n\n const nullRank = async (conn: Connection): Promise<void> => {\n if (snapshot.reconcile.seenColumns.has('_rank')) await conn.exec('UPDATE frontmatter SET \"_rank\" = NULL');\n };\n\n return {\n mutated: true,\n parsed,\n async apply(conn) {\n const byName = new Map(toggles.map((toggle) => [toggle.name, toggle]));\n const linksToggle = byName.get('links');\n if (linksToggle) {\n await applyTable(conn, linksToggle);\n if (!linksToggle.turnedOn) await nullRank(conn);\n }\n const rankToggle = byName.get('rank');\n if (rankToggle) {\n if (rankToggle.turnedOn) await rank.afterReconcile?.(conn, { files: [], reparsed: [], added: [], vanished: [] });\n else await nullRank(conn);\n }\n for (const toggle of toggles) {\n if (toggle.name !== 'links' && toggle.name !== 'rank') await applyTable(conn, toggle);\n }\n },\n };\n}\n\nfunction recoveryToggles(cfg: Config, snapshot: PlanningSnapshot): FeatureToggle[] {\n const toggles: FeatureToggle[] = [];\n for (const feature of FEATURES) {\n const table = NARROW_FEATURE_TABLE[feature.name];\n if (table && !featureEnabled(cfg, feature.name) && snapshot.tables.has(table)) toggles.push({ name: feature.name, turnedOn: false });\n }\n return toggles;\n}\n\nasync function prepareInvalidation(classification: BuildClassification, snapshot: PlanningSnapshot, cfg: Config, paths: ReconcilePaths, pool: ParsePool): Promise<PreparedInvalidation> {\n const plans: PreparedInvalidation[] = [];\n if (classification.embedKind) plans.push(await prepareEmbedInvalidation(classification.embedKind, snapshot, cfg, paths, pool));\n if (classification.featureToggles.length > 0) plans.push(await prepareFeatureInvalidation(classification.featureToggles, snapshot, cfg, paths, pool));\n if (classification.fullRebuild) {\n plans.push(await prepareFeatureInvalidation(recoveryToggles(cfg, snapshot), snapshot, cfg, paths, pool));\n // Full rebuild and recovery must not reuse vectors from the prior generation.\n if (snapshot.tables.has('embeddings')) {\n plans.push({ mutated: true, parsed: 0, apply: (conn) => conn.exec('DELETE FROM embeddings') });\n }\n if (!featureEnabled(cfg, 'rank') && snapshot.reconcile.seenColumns.has('_rank')) {\n plans.push({ mutated: true, parsed: 0, apply: (conn) => conn.exec('UPDATE frontmatter SET \"_rank\" = NULL') });\n }\n }\n return {\n mutated: plans.some((plan) => plan.mutated),\n parsed: plans.reduce((sum, plan) => sum + plan.parsed, 0),\n async apply(conn) {\n for (const plan of plans) await plan.apply(conn);\n },\n };\n}\n\nfunction forcedPaths(classification: BuildClassification, snapshot: PlanningSnapshot): ReadonlySet<string> | undefined {\n if (!classification.fullRebuild) return classification.forcedPaths;\n // New paths are reparsed by definition. Forcing every previously indexed path makes every\n // survivor a reparse without a second filesystem scan outside prepareReconcile's one listing.\n return new Set(snapshot.reconcile.existingRows.map((row) => row.path));\n}\n\nasync function publishAttempt(conn: Connection, liveCfg: ResolvedConfig, dialect: ReconcileDialect, pool: ParsePool, ensureFeatureSchema: EnsureFeatureSchema, timing: ReconcileTiming, attempt: number): Promise<BuildResult> {\n const cfg = structuredClone(liveCfg);\n const configIdentity = JSON.stringify(cfg);\n const paths: ReconcilePaths = { rootDir: cfg.rootDir ?? cfg.baseDir, configDir: cfg.configDir ?? cfg.baseDir };\n const wanted = featureSignature(cfg, FEATURES);\n const snapshot = await readPlanningSnapshot(conn, timing);\n const classification = classifyBuild(snapshot, cfg, paths, wanted);\n const invalidation = await prepareInvalidation(classification, snapshot, cfg, paths, pool);\n const reconcile = await prepareReconcile(snapshot.reconcile, cfg, paths, dialect, timing, pool, forcedPaths(classification, snapshot));\n const mutated = classification.fullRebuild || invalidation.mutated || reconcile.mutated || snapshot.baseline.features !== wanted || snapshot.baseline.ready !== '1';\n\n if (buildPlan.hasSubscribers) buildPlan.publish({ attempt, baseline: snapshot.baseline, wantedSignature: wanted });\n const txStart = Date.now();\n let txMs: number;\n try {\n await withTransaction(\n conn,\n async () => {\n const current = await readCoreBaseline(conn);\n const currentWanted = featureSignature(liveCfg, FEATURES);\n if (!sameBaseline(current, snapshot.baseline) || JSON.stringify(liveCfg) !== configIdentity || currentWanted !== wanted) {\n throw new StaleBuildPlan('core generation or configuration changed while this build was planning');\n }\n if (!mutated) return;\n await ensureFeatureSchema(cfg);\n await invalidation.apply(conn);\n await reconcile.apply(conn);\n const publishedWanted = featureSignature(liveCfg, FEATURES);\n if (JSON.stringify(liveCfg) !== configIdentity || publishedWanted !== wanted) throw new StaleBuildPlan('configuration changed while this build was publishing');\n await setMeta(conn, FEATURE_SIGNATURE_META_KEY, wanted);\n await setMeta(conn, CORE_READY_META_KEY, '1');\n await setMeta(conn, CORE_GENERATION_META_KEY, nextGeneration(snapshot.baseline.generation));\n },\n dialect.beginMode()\n );\n } finally {\n txMs = Date.now() - txStart;\n timing.txMs += txMs;\n }\n if (reconcile.mutated) await reconcile.record(conn, txMs);\n return {\n parsed: invalidation.parsed + reconcile.parsed,\n warnings: reconcile.warnings,\n stages: reconcile.finish(timing.txMs),\n messages: classification.messages,\n };\n}\n\nexport function createBuilder(conn: Connection, cfg: ResolvedConfig, dialect: ReconcileDialect, ensureFeatureSchema: EnsureFeatureSchema): Builder {\n const pool = new ParsePool();\n return {\n async build() {\n // One clock and recorder span both bounded attempts. Baseline/catalog reads and feature\n // invalidation preparation are included in totalMs but remain intentionally unlabelled;\n // existing/list/parse and publication stages accumulate under their established labels.\n const timing = createReconcileTiming(cfg);\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n return await publishAttempt(conn, cfg, dialect, pool, ensureFeatureSchema, timing, attempt);\n } catch (err) {\n if (!(err instanceof StaleBuildPlan)) throw err;\n if (attempt === 1) throw new SenseError('STORE_BUSY', 'the index changed during both bounded publication attempts; wait for the competing build to finish and retry');\n }\n }\n throw new Error('unreachable build attempt state');\n },\n close: () => pool.close(),\n get poolsCreated() {\n return pool.poolsCreated;\n },\n };\n}\n"],"names":["channel","featureEnabled","featureSignature","SenseError","embed","FEATURES","rank","listFiles","ParsePool","reparseFiles","classifyEmbedChange","classifyFeatureToggles","isFeatureOnlyChange","NARROW_FEATURE_TABLE","forcedPresetPaths","isPresetOnlyChange","CORE_GENERATION_META_KEY","CORE_READY_META_KEY","FEATURE_SIGNATURE_META_KEY","createReconcileTiming","prepareReconcile","readReconcileSnapshot","setMeta","changedSignatureKeys","embedIdentityAdopted","signatureDiff","withTransaction","StaleBuildPlan","Error","buildPlan","SCHEMA_VERSION_META_KEY","readCoreBaseline","conn","values","keys","stmt","prepare","map","join","Map","all","row","key","value","schemaVersion","get","features","ready","generation","sameBaseline","a","b","nextGeneration","current","Number","isSafeInteger","MAX_SAFE_INTEGER","String","readPlanningSnapshot","timing","baseline","reconcile","tablesStmt","tables","Set","name","activeSchemaMissing","snapshot","cfg","feature","seenColumns","has","table","classifyBuild","paths","wanted","before","recover","messages","push","embedKind","featureToggles","fullRebuild","changedKeys","size","presetForced","rootDir","forcedPaths","toggles","prepareEmbedInvalidation","kind","pool","mutated","parsed","apply","exec","existing","existingRows","path","files","filter","file","relPath","docs","undefined","pathsChanged","doc","delta","reparsed","added","vanished","length","runBatch","store","extracted","prepareFeatureInvalidation","prepared","toggle","turnedOn","find","candidate","set","applyTable","plan","afterReconcile","nullRank","byName","linksToggle","rankToggle","recoveryToggles","prepareInvalidation","classification","plans","some","reduce","sum","publishAttempt","liveCfg","dialect","ensureFeatureSchema","attempt","structuredClone","configIdentity","JSON","stringify","baseDir","configDir","invalidation","hasSubscribers","publish","wantedSignature","txStart","Date","now","txMs","currentWanted","publishedWanted","beginMode","record","warnings","stages","finish","createBuilder","build","err","close","poolsCreated"],"mappings":"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"}
|