sensemaking 0.25.1 → 0.27.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 +48 -12
- package/dist/cjs/cli/index.d.cts +3 -3
- package/dist/cjs/cli/index.d.ts +3 -3
- package/dist/cjs/cli/index.js +3 -3
- 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/peek.js +43 -2
- package/dist/cjs/cli/peek.js.map +1 -1
- package/dist/cjs/cli/related.js +4 -3
- 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/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 +25 -2
- package/dist/cjs/commands/peek.d.ts +25 -2
- package/dist/cjs/commands/peek.js +131 -50
- 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 +30 -3
- package/dist/cjs/commands/search.d.ts +30 -3
- package/dist/cjs/commands/search.js +240 -73
- package/dist/cjs/commands/search.js.map +1 -1
- package/dist/cjs/commands/signals.d.cts +22 -7
- package/dist/cjs/commands/signals.d.ts +22 -7
- package/dist/cjs/commands/signals.js +77 -15
- 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/config/load.js +6 -0
- package/dist/cjs/config/load.js.map +1 -1
- 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 +3 -3
- package/dist/esm/cli/index.js +3 -3
- 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/peek.js +20 -2
- package/dist/esm/cli/peek.js.map +1 -1
- package/dist/esm/cli/related.js +5 -3
- 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/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 +25 -2
- package/dist/esm/commands/peek.js +59 -19
- 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 +30 -3
- package/dist/esm/commands/search.js +95 -20
- package/dist/esm/commands/search.js.map +1 -1
- package/dist/esm/commands/signals.d.ts +22 -7
- package/dist/esm/commands/signals.js +74 -17
- 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/config/load.js +6 -0
- package/dist/esm/config/load.js.map +1 -1
- 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/EXAMPLES.md +3 -3
- package/skills/sense/SKILL.md +11 -3
- package/skills/sense/references/search.md +17 -1
- package/skills/sense/references/sql.md +1 -1
- package/skills/sense/references/stores/duckdb.md +1 -1
- package/skills/sense/references/terminology.md +32 -0
- 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
|
@@ -27,6 +27,7 @@ export interface ReconcileDialect {
|
|
|
27
27
|
beginMode(): string;
|
|
28
28
|
checkColumnLimit(count: number): void;
|
|
29
29
|
addColumns(conn: Connection, names: string[]): Promise<void>;
|
|
30
|
+
updateFrontmatter?(conn: Connection, writableColumns: string[], rows: unknown[][]): Promise<void>;
|
|
30
31
|
reconcileContent(conn: Connection, touched: string[], docs: ParsedDoc[], delta: ReconcileDelta, cfg: Config): Promise<void>;
|
|
31
32
|
recordDuration?(conn: Connection, ms: number): Promise<void>;
|
|
32
33
|
}
|
|
@@ -45,7 +46,9 @@ export interface OpenDialect<Handle> {
|
|
|
45
46
|
observational?: boolean;
|
|
46
47
|
}): Promise<void>;
|
|
47
48
|
isLocked?(err: Error): boolean;
|
|
48
|
-
|
|
49
|
+
ensureCoreSchema(handle: Handle, conn: Connection): Promise<void>;
|
|
50
|
+
ensureFeatureSchema(handle: Handle, conn: Connection, cfg: Config): Promise<void>;
|
|
51
|
+
prepareConnection?(handle: Handle, conn: Connection, cfg: Config): Promise<void>;
|
|
49
52
|
setDerivedBusyTimeout?(handle: Handle, conn: Connection, ms: number): Promise<void>;
|
|
50
53
|
prepareLexical?(conn: Connection): Promise<void>;
|
|
51
54
|
assertLexicalReady?(conn: Connection): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/types.ts"],"sourcesContent":["// The backing-store interface: a minimal portable statement surface (exec/prepare), plus\n// dedicated interfaces exactly where engines diverge (lexical index, vector scan, raw sql).\n\nimport type { Config, ResolvedConfig, StoreName } from '../config/index.ts';\nimport type { ReconcileDelta } from '../features/types.ts';\nimport type { ParsedDoc } from '../scan/index.ts';\n\n// 'vectors': the store's VectorStore is functionally implemented, not present-but-inert; checked\n// at open (index.ts) before a config with an \"embed\" block is allowed onto a store lacking it.\n// 'segment': the engine can run segment() (Intl.Segmenter grapheme clustering) as a SQL function;\n// turso's client cannot register it and has no rewrite for it, unlike has()/basename(), which now\n// work everywhere. An array, not a bare union, so a runtime check reads the same list the type does.\nexport const CAPABILITY_NAMES = ['vectors', 'segment'] as const;\nexport type Capability = (typeof CAPABILITY_NAMES)[number];\n\nexport interface RunResult {\n changes: number | bigint;\n lastInsertRowid: number | bigint;\n}\n\n// A prepared statement's async surface: every supported engine crosses a real async boundary\n// for a query (DuckDB has no synchronous client), so run/get/all return Promises.\nexport interface Statement {\n run(...params: unknown[]): Promise<RunResult>;\n get(...params: unknown[]): Promise<unknown>;\n all(...params: unknown[]): Promise<unknown[]>;\n iterate(...params: unknown[]): AsyncIterable<unknown>;\n columns(): Array<{ name: string }>;\n setReadBigInts(enabled: boolean): void;\n}\n\n// Connection surface feature-owned SQL runs against inside a store's hot loops (schema,\n// reconcile), portable so a feature never imports an engine-specific client type.\nexport interface Connection {\n exec(sql: string): Promise<void>;\n prepare(sql: string): Promise<Statement>;\n runBatch(sql: string, paramRows: unknown[][]): Promise<void>;\n // Bulk-inserts rows that cannot conflict, through a path that binds no per-value parameters.\n // Optional: a store that has nothing faster than its own INSERT omits it and callers fall back\n // (appendRows in shared.ts). `columns` names the values each row carries; a table column the\n // caller does not write takes its default.\n appendRows?(table: string, columns: string[], rows: unknown[][]): Promise<void>;\n}\n\n// One reconcile algorithm (src/store/reconcile.ts), parameterised per engine. reconcileContent is\n// the load-bearing member: it lands every content-table change and owns its own multi-step\n// strategy (sqlite FTS5 incremental, duckdb combined delete/insert, turso incremental-or-rebuild).\nexport interface ReconcileDialect {\n // BEGIN mode for the whole reconcile: sqlite/turso 'BEGIN IMMEDIATE', duckdb 'BEGIN'.\n beginMode(): string;\n // Throws SenseError('COLUMN_LIMIT', ...) past this store's own column ceiling and reasoning.\n checkColumnLimit(count: number): void;\n // Adds `names` to frontmatter, already filtered to columns this connection doesn't have yet.\n // sqlite/turso loop (their ADD COLUMN is metadata-only); duckdb issues one statement per call.\n addColumns(conn: Connection, names: string[]): Promise<void>;\n // Deletes content rows for `touched`, inserts rows for `docs`; `delta` carries the tree state a\n // strategy may need. Must not open its own transaction, and must not return before its own\n // multi-step strategy (e.g. turso's DROP/rebuild) completes.\n reconcileContent(conn: Connection, touched: string[], docs: ParsedDoc[], delta: ReconcileDelta, cfg: Config): Promise<void>;\n // Records this reconcile's write-transaction duration. sqlite/turso use it for open()'s derived\n // busy_timeout; duckdb has no such PRAGMA and omits it.\n recordDuration?(conn: Connection, ms: number): Promise<void>;\n}\n\n// One open algorithm (src/store/open.ts), parameterised per engine. `Handle` is whatever this\n// store needs to close the connection and construct its Store (sqlite: {db}; duckdb:\n// {instance, duckdb}; turso: db) -- opaque to the shared orchestration, threaded through unchanged.\nexport interface OpenDialect<Handle> {\n // Cache filename under STATE_DIR, e.g. 'cache.db'.\n filename: string;\n // Cache shape version, independent of the config's own `version`; bumping it rebuilds an existing tree.\n schemaVersion: string;\n reconcileDialect: ReconcileDialect;\n // Opens the physical connection and applies pragmas due before any SQL runs (sqlite: busy_timeout\n // + WAL; turso: connect-time timeout; duckdb: none).\n connect(dbPath: string, cfg: ResolvedConfig, options: { existingOnly: boolean; observational: boolean }): Promise<{ handle: Handle; conn: Connection }>;\n // Releases the handle, for both the rebuild-and-reopen branch and error cleanup on this attempt.\n close(handle: Handle, options?: { observational?: boolean }): Promise<void>;\n // True when connect() failed because another process holds the cache file, which the orchestration\n // retries. Each engine words it differently, so the match is the dialect's own (`native-not-emulated`).\n // Absent for sqlite, whose file lock is shared and whose concurrent-open failure is a different defect.\n // Matching on message text is forced, not chosen: measured 2026-09-02, duckdb throws a plain Error\n // whose only own properties are stack and message, and turso sets code to the constant\n // 'GenericFailure' on every failure alike with rawCode undefined. Neither exposes anything a\n // predicate could switch on, so each dialect pins its engine's wordings and unit-tests them.\n isLocked?(err: Error): boolean;\n // Schema DDL beyond frontmatter/preset_files/meta (content table, feature hooks); sole owner of\n // whether it wraps itself in a write transaction (sqlite: yes, guards a cold-open ALTER race; duckdb/turso: no).\n ensureSchema(handle: Handle, conn: Connection, cfg: Config): Promise<void>;\n // Installs the derived busy_timeout PRAGMA right before reconcile (sqlite/turso); absent for\n // duckdb, which has no such PRAGMA.\n setDerivedBusyTimeout?(handle: Handle, conn: Connection, ms: number): Promise<void>;\n // Persistent lexical preparation belongs to build, while no-build calls only the readiness\n // check. SQLite and Turso maintain lexical state during reconcile and omit both hooks.\n prepareLexical?(conn: Connection): Promise<void>;\n assertLexicalReady?(conn: Connection): Promise<void>;\n createStore(handle: Handle, conn: Connection, cfg: ResolvedConfig, options: { observational: boolean }): Store;\n}\n\nexport interface FieldStat {\n field: string;\n coverage: number;\n type: string;\n}\n\nexport interface DocumentStore {\n // Frontmatter column names (including internal ones; callers filter).\n columns(): Promise<string[]>;\n // Per-column coverage (non-null count) and observed type set, aggregated in one SQL query,\n // never one row per note. `scopeWhere` is a caller-built WHERE fragment, per LexicalQueryOptions.\n fieldStats(columns: string[], scopeWhere: string): Promise<FieldStat[]>;\n}\n\n// A ranked match, nothing more. Snippets are cut from the document above the store\n// (commands/search.ts), identically for every engine, so no store carries them.\nexport interface LexicalHit {\n path: string;\n}\n\nexport interface LexicalQueryOptions {\n whereJoin: string;\n whereCond: string;\n scopeCond: string;\n limit: number;\n}\n\nexport interface LexicalIndex {\n // Ranked word-match query with snippet, scoped by the caller-built SQL fragments (the same\n // fragments narrowByWhere/materializeScope produce elsewhere).\n query(terms: string, opts: LexicalQueryOptions): Promise<LexicalHit[]>;\n}\n\nexport interface VectorCandidate {\n path: string;\n lines: string;\n similarity: number;\n}\n\nexport interface VectorSimilar {\n path: string;\n similarity: number;\n}\n\nexport interface VectorWriteRow {\n path: string;\n chunk: number;\n scale: number;\n vector: Buffer;\n}\n\nexport interface VectorStore {\n // Rows whose vector is NULL: never embedded, or added since.\n pending(): Promise<Array<{ path: string; chunk: number }>>;\n // One batch write per call (never per row) so a provider's embedding batch stays inside a\n // single store method.\n writeVectors(rows: VectorWriteRow[]): Promise<void>;\n candidates(queryVector: Float32Array, storeDims: number, fetch: number, allowed?: Set<string>): Promise<VectorCandidate[]>;\n similar(path: string, opts: { exclude: Set<string>; allowed?: Set<string>; k: number }): Promise<VectorSimilar[]>;\n hasVector(path: string): Promise<boolean>;\n}\n\n// The `sense sql` passthrough: string in, streamed rows out. Each store registers the same\n// sense-supplied functions and applies its own read-bigints/error-translation behavior.\nexport interface RawStatement {\n columns(): Array<{ name: string }>;\n iterate(...params: unknown[]): AsyncIterable<unknown>;\n}\n\nexport interface SqlSession {\n prepare(sql: string): Promise<RawStatement>;\n}\n\nexport interface Store {\n readonly name: StoreName;\n readonly capabilities: ReadonlySet<Capability>;\n exec(sql: string): Promise<void>;\n prepare(sql: string): Promise<Statement>;\n // One crossing, N rows: every external write loop (search's candidate insert, graph ring's\n // temp-table writes) goes through this instead of looping over `run()`. Same contract as Connection.runBatch.\n runBatch(sql: string, paramRows: unknown[][]): Promise<void>;\n // Pins one snapshot across multi-statement reads; `map` and `peek` use it. A network-bound\n // write (search's embedding top-up) must stay outside it. Nesting joins the enclosing transaction.\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n docs: DocumentStore;\n lexical: LexicalIndex;\n vectors: VectorStore;\n raw: SqlSession;\n // Engine-level facts for `sense status` (e.g. a derived busy_timeout PRAGMA reading); each\n // store owns what it reports and how it is worded. Empty when there is nothing to report.\n engineStatus(): Promise<Record<string, string>>;\n close(): Promise<void>;\n}\n"],"names":["CAPABILITY_NAMES"],"mappings":"AAAA,yFAAyF;AACzF,4FAA4F;;;;;+BAW/EA;;;eAAAA;;;AAAN,IAAMA,mBAAmB;IAAC;IAAW;CAAU"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/types.ts"],"sourcesContent":["// The backing-store interface: a minimal portable statement surface (exec/prepare), plus\n// dedicated interfaces exactly where engines diverge (lexical index, vector scan, raw sql).\n\nimport type { Config, ResolvedConfig, StoreName } from '../config/index.ts';\nimport type { ReconcileDelta } from '../features/types.ts';\nimport type { ParsedDoc } from '../scan/index.ts';\n\n// 'vectors': the store's VectorStore is functionally implemented, not present-but-inert; checked\n// at open (index.ts) before a config with an \"embed\" block is allowed onto a store lacking it.\n// 'segment': the engine can run segment() (Intl.Segmenter grapheme clustering) as a SQL function;\n// turso's client cannot register it and has no rewrite for it, unlike has()/basename(), which now\n// work everywhere. An array, not a bare union, so a runtime check reads the same list the type does.\nexport const CAPABILITY_NAMES = ['vectors', 'segment'] as const;\nexport type Capability = (typeof CAPABILITY_NAMES)[number];\n\nexport interface RunResult {\n changes: number | bigint;\n lastInsertRowid: number | bigint;\n}\n\n// A prepared statement's async surface: every supported engine crosses a real async boundary\n// for a query (DuckDB has no synchronous client), so run/get/all return Promises.\nexport interface Statement {\n run(...params: unknown[]): Promise<RunResult>;\n get(...params: unknown[]): Promise<unknown>;\n all(...params: unknown[]): Promise<unknown[]>;\n iterate(...params: unknown[]): AsyncIterable<unknown>;\n columns(): Array<{ name: string }>;\n setReadBigInts(enabled: boolean): void;\n}\n\n// Connection surface feature-owned SQL runs against inside a store's hot loops (schema,\n// reconcile), portable so a feature never imports an engine-specific client type.\nexport interface Connection {\n exec(sql: string): Promise<void>;\n prepare(sql: string): Promise<Statement>;\n runBatch(sql: string, paramRows: unknown[][]): Promise<void>;\n // Bulk-inserts rows that cannot conflict, through a path that binds no per-value parameters.\n // Optional: a store that has nothing faster than its own INSERT omits it and callers fall back\n // (appendRows in shared.ts). `columns` names the values each row carries; a table column the\n // caller does not write takes its default.\n appendRows?(table: string, columns: string[], rows: unknown[][]): Promise<void>;\n}\n\n// One reconcile algorithm (src/store/reconcile.ts), parameterised per engine. reconcileContent is\n// the load-bearing member: it lands every content-table change and owns its own multi-step\n// strategy (sqlite FTS5 incremental, duckdb combined delete/insert, turso incremental-or-rebuild).\nexport interface ReconcileDialect {\n // BEGIN mode for the whole reconcile: sqlite/turso 'BEGIN IMMEDIATE', duckdb 'BEGIN'.\n beginMode(): string;\n // Throws SenseError('COLUMN_LIMIT', ...) past this store's own column ceiling and reasoning.\n checkColumnLimit(count: number): void;\n // Adds `names` to frontmatter, already filtered to columns this connection doesn't have yet.\n // sqlite/turso loop (their ADD COLUMN is metadata-only); duckdb issues one statement per call.\n addColumns(conn: Connection, names: string[]): Promise<void>;\n // Replaces this engine's existing-row frontmatter upsert, inside the caller's\n // publication transaction. Preserve non-writable columns and repair missing rows.\n updateFrontmatter?(conn: Connection, writableColumns: string[], rows: unknown[][]): Promise<void>;\n // Reconciles searchable content for `touched` paths and parsed `docs`; `delta` carries the tree\n // state a strategy may need. Must not open its own transaction, and must not return before its own\n // multi-step strategy (e.g. turso's DROP/rebuild) completes.\n reconcileContent(conn: Connection, touched: string[], docs: ParsedDoc[], delta: ReconcileDelta, cfg: Config): Promise<void>;\n // Records this reconcile's write-transaction duration. sqlite/turso use it for open()'s derived\n // busy_timeout; duckdb has no such PRAGMA and omits it.\n recordDuration?(conn: Connection, ms: number): Promise<void>;\n}\n\n// One open algorithm (src/store/open.ts), parameterised per engine. `Handle` is whatever this\n// store needs to close the connection and construct its Store (sqlite: {db}; duckdb:\n// {instance, duckdb}; turso: db) -- opaque to the shared orchestration, threaded through unchanged.\nexport interface OpenDialect<Handle> {\n // Cache filename under STATE_DIR, e.g. 'cache.db'.\n filename: string;\n // Cache shape version, independent of the config's own `version`; bumping it rebuilds an existing tree.\n schemaVersion: string;\n reconcileDialect: ReconcileDialect;\n // Opens the physical connection and applies pragmas due before any SQL runs (sqlite: busy_timeout\n // + WAL; turso: connect-time timeout; duckdb: none).\n connect(dbPath: string, cfg: ResolvedConfig, options: { existingOnly: boolean; observational: boolean }): Promise<{ handle: Handle; conn: Connection }>;\n // Releases the handle, for both the rebuild-and-reopen branch and error cleanup on this attempt.\n close(handle: Handle, options?: { observational?: boolean }): Promise<void>;\n // True when connect() failed because another process holds the cache file, which the orchestration\n // retries. Each engine words it differently, so the match is the dialect's own (`native-not-emulated`).\n // Absent for sqlite, whose file lock is shared and whose concurrent-open failure is a different defect.\n // Matching on message text is forced, not chosen: measured 2026-09-02, duckdb throws a plain Error\n // whose only own properties are stack and message, and turso sets code to the constant\n // 'GenericFailure' on every failure alike with rawCode undefined. Neither exposes anything a\n // predicate could switch on, so each dialect pins its engine's wordings and unit-tests them.\n isLocked?(err: Error): boolean;\n // Minimal, configuration-independent schema needed before the builder can capture a planning\n // snapshot. This bootstrap may commit independently because no feature generation is published.\n ensureCoreSchema(handle: Handle, conn: Connection): Promise<void>;\n // Configuration-dependent persistent DDL. The builder invokes this only inside its fenced write\n // transaction, so a failed feature enable cannot leave catalog changes under the old signature.\n ensureFeatureSchema(handle: Handle, conn: Connection, cfg: Config): Promise<void>;\n // Connection-local preparation with no durable cache effect (DuckDB's TEMP vector stage).\n prepareConnection?(handle: Handle, conn: Connection, cfg: Config): Promise<void>;\n // Installs the derived busy_timeout PRAGMA right before reconcile (sqlite/turso); absent for\n // duckdb, which has no such PRAGMA.\n setDerivedBusyTimeout?(handle: Handle, conn: Connection, ms: number): Promise<void>;\n // Persistent lexical preparation belongs to build, while no-build calls only the readiness\n // check. SQLite and Turso maintain lexical state during reconcile and omit both hooks.\n prepareLexical?(conn: Connection): Promise<void>;\n assertLexicalReady?(conn: Connection): Promise<void>;\n createStore(handle: Handle, conn: Connection, cfg: ResolvedConfig, options: { observational: boolean }): Store;\n}\n\nexport interface FieldStat {\n field: string;\n coverage: number;\n type: string;\n}\n\nexport interface DocumentStore {\n // Frontmatter column names (including internal ones; callers filter).\n columns(): Promise<string[]>;\n // Per-column coverage (non-null count) and observed type set, aggregated in one SQL query,\n // never one row per note. `scopeWhere` is a caller-built WHERE fragment, per LexicalQueryOptions.\n fieldStats(columns: string[], scopeWhere: string): Promise<FieldStat[]>;\n}\n\n// A ranked match, nothing more. Snippets are cut from the document above the store\n// (commands/search.ts), identically for every engine, so no store carries them.\nexport interface LexicalHit {\n path: string;\n}\n\nexport interface LexicalQueryOptions {\n whereJoin: string;\n whereCond: string;\n scopeCond: string;\n limit: number;\n}\n\nexport interface LexicalIndex {\n // Ranked word-match query with snippet, scoped by the caller-built SQL fragments (the same\n // fragments narrowByWhere/materializeScope produce elsewhere).\n query(terms: string, opts: LexicalQueryOptions): Promise<LexicalHit[]>;\n}\n\nexport interface VectorCandidate {\n path: string;\n lines: string;\n similarity: number;\n}\n\nexport interface VectorSimilar {\n path: string;\n similarity: number;\n}\n\nexport interface VectorWriteRow {\n path: string;\n chunk: number;\n scale: number;\n vector: Buffer;\n}\n\nexport interface VectorStore {\n // Rows whose vector is NULL: never embedded, or added since.\n pending(): Promise<Array<{ path: string; chunk: number }>>;\n // One batch write per call (never per row) so a provider's embedding batch stays inside a\n // single store method.\n writeVectors(rows: VectorWriteRow[]): Promise<void>;\n candidates(queryVector: Float32Array, storeDims: number, fetch: number, allowed?: Set<string>): Promise<VectorCandidate[]>;\n similar(path: string, opts: { exclude: Set<string>; allowed?: Set<string>; k: number }): Promise<VectorSimilar[]>;\n hasVector(path: string): Promise<boolean>;\n}\n\n// The `sense sql` passthrough: string in, streamed rows out. Each store registers the same\n// sense-supplied functions and applies its own read-bigints/error-translation behavior.\nexport interface RawStatement {\n columns(): Array<{ name: string }>;\n iterate(...params: unknown[]): AsyncIterable<unknown>;\n}\n\nexport interface SqlSession {\n prepare(sql: string): Promise<RawStatement>;\n}\n\nexport interface Store {\n readonly name: StoreName;\n readonly capabilities: ReadonlySet<Capability>;\n exec(sql: string): Promise<void>;\n prepare(sql: string): Promise<Statement>;\n // One crossing, N rows: every external write loop (search's candidate insert, graph ring's\n // temp-table writes) goes through this instead of looping over `run()`. Same contract as Connection.runBatch.\n runBatch(sql: string, paramRows: unknown[][]): Promise<void>;\n // Pins one snapshot across multi-statement reads; `map` and `peek` use it. A network-bound\n // write (search's embedding top-up) must stay outside it. Nesting joins the enclosing transaction.\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n docs: DocumentStore;\n lexical: LexicalIndex;\n vectors: VectorStore;\n raw: SqlSession;\n // Engine-level facts for `sense status` (e.g. a derived busy_timeout PRAGMA reading); each\n // store owns what it reports and how it is worded. Empty when there is nothing to report.\n engineStatus(): Promise<Record<string, string>>;\n close(): Promise<void>;\n}\n"],"names":["CAPABILITY_NAMES"],"mappings":"AAAA,yFAAyF;AACzF,4FAA4F;;;;;+BAW/EA;;;eAAAA;;;AAAN,IAAMA,mBAAmB;IAAC;IAAW;CAAU"}
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
import type { Connection } from './types.js';
|
|
1
|
+
import type { Connection, VectorStore } from './types.js';
|
|
2
|
+
export declare const NATIVE_VECTOR_SCOPE_TABLE = "_vector_scope";
|
|
3
|
+
interface NativeVectorScopeOwner {
|
|
4
|
+
bind(vectors: VectorStore): void;
|
|
5
|
+
activeFor(allowed: Set<string> | undefined): boolean;
|
|
6
|
+
}
|
|
7
|
+
interface NativeVectorScopeReservation {
|
|
8
|
+
activate(): void;
|
|
9
|
+
deactivate(): void;
|
|
10
|
+
invalidate(): void;
|
|
11
|
+
}
|
|
12
|
+
export declare function createNativeVectorScopeOwner(): NativeVectorScopeOwner;
|
|
13
|
+
export declare function reserveNativeVectorScope(vectors: VectorStore, allowed: Set<string>): NativeVectorScopeReservation | null;
|
|
2
14
|
export declare const TARGET_CHUNK_CAP = 16;
|
|
3
15
|
export declare function sampleEvenly<T>(rows: T[], cap?: number): T[];
|
|
4
16
|
export declare function asCosine(score: number): number;
|
|
@@ -14,3 +26,4 @@ export declare function pendingRows(conn: Connection): Promise<Array<{
|
|
|
14
26
|
chunk: number;
|
|
15
27
|
}>>;
|
|
16
28
|
export declare function hasVectorRow(conn: Connection, path: string): Promise<boolean>;
|
|
29
|
+
export {};
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
import type { Connection } from './types.js';
|
|
1
|
+
import type { Connection, VectorStore } from './types.js';
|
|
2
|
+
export declare const NATIVE_VECTOR_SCOPE_TABLE = "_vector_scope";
|
|
3
|
+
interface NativeVectorScopeOwner {
|
|
4
|
+
bind(vectors: VectorStore): void;
|
|
5
|
+
activeFor(allowed: Set<string> | undefined): boolean;
|
|
6
|
+
}
|
|
7
|
+
interface NativeVectorScopeReservation {
|
|
8
|
+
activate(): void;
|
|
9
|
+
deactivate(): void;
|
|
10
|
+
invalidate(): void;
|
|
11
|
+
}
|
|
12
|
+
export declare function createNativeVectorScopeOwner(): NativeVectorScopeOwner;
|
|
13
|
+
export declare function reserveNativeVectorScope(vectors: VectorStore, allowed: Set<string>): NativeVectorScopeReservation | null;
|
|
2
14
|
export declare const TARGET_CHUNK_CAP = 16;
|
|
3
15
|
export declare function sampleEvenly<T>(rows: T[], cap?: number): T[];
|
|
4
16
|
export declare function asCosine(score: number): number;
|
|
@@ -14,3 +26,4 @@ export declare function pendingRows(conn: Connection): Promise<Array<{
|
|
|
14
26
|
chunk: number;
|
|
15
27
|
}>>;
|
|
16
28
|
export declare function hasVectorRow(conn: Connection, path: string): Promise<boolean>;
|
|
29
|
+
export {};
|
|
@@ -9,6 +9,9 @@ function _export(target, all) {
|
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
_export(exports, {
|
|
12
|
+
get NATIVE_VECTOR_SCOPE_TABLE () {
|
|
13
|
+
return NATIVE_VECTOR_SCOPE_TABLE;
|
|
14
|
+
},
|
|
12
15
|
get TARGET_CHUNK_CAP () {
|
|
13
16
|
return TARGET_CHUNK_CAP;
|
|
14
17
|
},
|
|
@@ -18,12 +21,18 @@ _export(exports, {
|
|
|
18
21
|
get compareVectorScores () {
|
|
19
22
|
return compareVectorScores;
|
|
20
23
|
},
|
|
24
|
+
get createNativeVectorScopeOwner () {
|
|
25
|
+
return createNativeVectorScopeOwner;
|
|
26
|
+
},
|
|
21
27
|
get hasVectorRow () {
|
|
22
28
|
return hasVectorRow;
|
|
23
29
|
},
|
|
24
30
|
get pendingRows () {
|
|
25
31
|
return pendingRows;
|
|
26
32
|
},
|
|
33
|
+
get reserveNativeVectorScope () {
|
|
34
|
+
return reserveNativeVectorScope;
|
|
35
|
+
},
|
|
27
36
|
get sampleEvenly () {
|
|
28
37
|
return sampleEvenly;
|
|
29
38
|
}
|
|
@@ -153,6 +162,58 @@ function _ts_generator(thisArg, body) {
|
|
|
153
162
|
};
|
|
154
163
|
}
|
|
155
164
|
}
|
|
165
|
+
var NATIVE_VECTOR_SCOPE_TABLE = '_vector_scope';
|
|
166
|
+
var nativeVectorScopeOwners = new WeakMap();
|
|
167
|
+
function createNativeVectorScopeOwner() {
|
|
168
|
+
var owner = {};
|
|
169
|
+
return {
|
|
170
|
+
bind: function bind(vectors) {
|
|
171
|
+
if (owner.vectors) throw new Error('native vector scope owner is already bound');
|
|
172
|
+
if (nativeVectorScopeOwners.has(vectors)) throw new Error('VectorStore is already bound to a native vector scope owner');
|
|
173
|
+
owner.vectors = vectors;
|
|
174
|
+
nativeVectorScopeOwners.set(vectors, owner);
|
|
175
|
+
},
|
|
176
|
+
activeFor: function activeFor(allowed) {
|
|
177
|
+
var _owner_scope;
|
|
178
|
+
return allowed !== undefined && ((_owner_scope = owner.scope) === null || _owner_scope === void 0 ? void 0 : _owner_scope.phase) === 'active' && owner.scope.allowed === allowed;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function reserveNativeVectorScope(vectors, allowed) {
|
|
183
|
+
var owner = nativeVectorScopeOwners.get(vectors);
|
|
184
|
+
if (!owner) return null;
|
|
185
|
+
if (owner.scope) throw new Error('native vector scope operation is already active for this Store');
|
|
186
|
+
var token = {};
|
|
187
|
+
owner.scope = {
|
|
188
|
+
token: token,
|
|
189
|
+
allowed: allowed,
|
|
190
|
+
phase: 'materializing'
|
|
191
|
+
};
|
|
192
|
+
var valid = true;
|
|
193
|
+
var current = function current() {
|
|
194
|
+
var _owner_scope;
|
|
195
|
+
if (!valid || ((_owner_scope = owner.scope) === null || _owner_scope === void 0 ? void 0 : _owner_scope.token) !== token) throw new Error('native vector scope reservation is no longer valid');
|
|
196
|
+
return owner.scope;
|
|
197
|
+
};
|
|
198
|
+
return {
|
|
199
|
+
activate: function activate() {
|
|
200
|
+
var scope = current();
|
|
201
|
+
if (scope.phase !== 'materializing') throw new Error("native vector scope cannot activate from ".concat(scope.phase));
|
|
202
|
+
scope.phase = 'active';
|
|
203
|
+
},
|
|
204
|
+
deactivate: function deactivate() {
|
|
205
|
+
var scope = current();
|
|
206
|
+
if (scope.phase === 'cleaning') throw new Error('native vector scope cleanup already started');
|
|
207
|
+
scope.phase = 'cleaning';
|
|
208
|
+
},
|
|
209
|
+
invalidate: function invalidate() {
|
|
210
|
+
var _owner_scope;
|
|
211
|
+
if (!valid) return;
|
|
212
|
+
if (((_owner_scope = owner.scope) === null || _owner_scope === void 0 ? void 0 : _owner_scope.token) === token) owner.scope = undefined;
|
|
213
|
+
valid = false;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
156
217
|
var TARGET_CHUNK_CAP = 16;
|
|
157
218
|
function sampleEvenly(rows) {
|
|
158
219
|
var cap = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : TARGET_CHUNK_CAP;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/vectors.ts"],"sourcesContent":["import type { Connection } from './types.ts';\n\n// Seed chunks that participate in a `related` scan. Cost is target_chunks x stored_chunks, so a\n// heading-dense seed multiplies a full-corpus scan (12.7s at 201 chunks/note unsampled).\nexport const TARGET_CHUNK_CAP = 16;\n\n// Evenly samples down to at most `cap` rows, so late sections of a long note still get a vote\n// instead of being cut off by a fixed prefix.\nexport function sampleEvenly<T>(rows: T[], cap: number = TARGET_CHUNK_CAP): T[] {\n const step = Math.max(1, Math.ceil(rows.length / cap));\n return rows.filter((_, i) => i % step === 0);\n}\n\n// Every store computes a real cosine; clamp float error at the ends and round for the public score.\nexport function asCosine(score: number): number {\n return Math.round(Math.min(1, Math.max(-1, score)) * 1000) / 1000;\n}\n\n// Rank by the computed cosine before rounding for display. Bytewise path order resolves only an\n// exact score tie, so two distinguishable similarities never cross a caller's result boundary.\nexport function compareVectorScores(a: { path: string; score: number }, b: { path: string; score: number }): number {\n const byScore = b.score - a.score;\n if (byScore !== 0) return byScore;\n return Buffer.compare(Buffer.from(a.path), Buffer.from(b.path));\n}\n\nexport async function pendingRows(conn: Connection): Promise<Array<{ path: string; chunk: number }>> {\n const stmt = await conn.prepare('SELECT \"path\", chunk FROM embeddings WHERE vector IS NULL ORDER BY \"path\", chunk');\n return (await stmt.all()) as Array<{ path: string; chunk: number }>;\n}\n\n// Whether a note has any chunk with a vector. Distinguishes \"nothing is near this note\" from\n// \"this note has no text\", which look the same in an empty result.\nexport async function hasVectorRow(conn: Connection, path: string): Promise<boolean> {\n const stmt = await conn.prepare('SELECT 1 AS ok FROM embeddings WHERE \"path\" = ? AND vector IS NOT NULL LIMIT 1');\n const row = (await stmt.get(path)) as { ok: number } | undefined;\n return row !== undefined;\n}\n"],"names":["TARGET_CHUNK_CAP","asCosine","compareVectorScores","hasVectorRow","pendingRows","sampleEvenly","rows","cap","step","Math","max","ceil","length","filter","_","i","score","round","min","a","b","byScore","Buffer","compare","from","path","conn","stmt","prepare","all","row"
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/vectors.ts"],"sourcesContent":["import type { Connection, VectorStore } from './types.ts';\n\nexport const NATIVE_VECTOR_SCOPE_TABLE = '_vector_scope';\n\ntype NativeVectorScopePhase = 'materializing' | 'active' | 'cleaning';\n\ninterface NativeVectorScopeState {\n token: object;\n allowed: Set<string>;\n phase: NativeVectorScopePhase;\n}\n\ninterface NativeVectorScopeOwnerState {\n vectors?: VectorStore;\n scope?: NativeVectorScopeState;\n}\n\ninterface NativeVectorScopeOwner {\n bind(vectors: VectorStore): void;\n activeFor(allowed: Set<string> | undefined): boolean;\n}\n\ninterface NativeVectorScopeReservation {\n activate(): void;\n deactivate(): void;\n invalidate(): void;\n}\n\nconst nativeVectorScopeOwners = new WeakMap<VectorStore, NativeVectorScopeOwnerState>();\n\n// One owner is constructed beside one native store connection, then bound to that connection's\n// VectorStore wrapper. The adapter asks its own owner for a private boolean; no Set or reservation\n// can activate another Store, even when a caller reuses the same Set object across both.\nexport function createNativeVectorScopeOwner(): NativeVectorScopeOwner {\n const owner: NativeVectorScopeOwnerState = {};\n return {\n bind(vectors) {\n if (owner.vectors) throw new Error('native vector scope owner is already bound');\n if (nativeVectorScopeOwners.has(vectors)) throw new Error('VectorStore is already bound to a native vector scope owner');\n owner.vectors = vectors;\n nativeVectorScopeOwners.set(vectors, owner);\n },\n activeFor(allowed) {\n return allowed !== undefined && owner.scope?.phase === 'active' && owner.scope.allowed === allowed;\n },\n };\n}\n\nexport function reserveNativeVectorScope(vectors: VectorStore, allowed: Set<string>): NativeVectorScopeReservation | null {\n const owner = nativeVectorScopeOwners.get(vectors);\n if (!owner) return null;\n if (owner.scope) throw new Error('native vector scope operation is already active for this Store');\n\n const token = {};\n owner.scope = { token, allowed, phase: 'materializing' };\n let valid = true;\n\n const current = (): NativeVectorScopeState => {\n if (!valid || owner.scope?.token !== token) throw new Error('native vector scope reservation is no longer valid');\n return owner.scope;\n };\n\n return {\n activate() {\n const scope = current();\n if (scope.phase !== 'materializing') throw new Error(`native vector scope cannot activate from ${scope.phase}`);\n scope.phase = 'active';\n },\n deactivate() {\n const scope = current();\n if (scope.phase === 'cleaning') throw new Error('native vector scope cleanup already started');\n scope.phase = 'cleaning';\n },\n invalidate() {\n if (!valid) return;\n if (owner.scope?.token === token) owner.scope = undefined;\n valid = false;\n },\n };\n}\n\n// Seed chunks that participate in a `related` scan. Cost is target_chunks x stored_chunks, so a\n// heading-dense seed multiplies a full-corpus scan (12.7s at 201 chunks/note unsampled).\nexport const TARGET_CHUNK_CAP = 16;\n\n// Evenly samples down to at most `cap` rows, so late sections of a long note still get a vote\n// instead of being cut off by a fixed prefix.\nexport function sampleEvenly<T>(rows: T[], cap: number = TARGET_CHUNK_CAP): T[] {\n const step = Math.max(1, Math.ceil(rows.length / cap));\n return rows.filter((_, i) => i % step === 0);\n}\n\n// Every store computes a real cosine; clamp float error at the ends and round for the public score.\nexport function asCosine(score: number): number {\n return Math.round(Math.min(1, Math.max(-1, score)) * 1000) / 1000;\n}\n\n// Rank by the computed cosine before rounding for display. Bytewise path order resolves only an\n// exact score tie, so two distinguishable similarities never cross a caller's result boundary.\nexport function compareVectorScores(a: { path: string; score: number }, b: { path: string; score: number }): number {\n const byScore = b.score - a.score;\n if (byScore !== 0) return byScore;\n return Buffer.compare(Buffer.from(a.path), Buffer.from(b.path));\n}\n\nexport async function pendingRows(conn: Connection): Promise<Array<{ path: string; chunk: number }>> {\n const stmt = await conn.prepare('SELECT \"path\", chunk FROM embeddings WHERE vector IS NULL ORDER BY \"path\", chunk');\n return (await stmt.all()) as Array<{ path: string; chunk: number }>;\n}\n\n// Whether a note has any chunk with a vector. Distinguishes \"nothing is near this note\" from\n// \"this note has no text\", which look the same in an empty result.\nexport async function hasVectorRow(conn: Connection, path: string): Promise<boolean> {\n const stmt = await conn.prepare('SELECT 1 AS ok FROM embeddings WHERE \"path\" = ? AND vector IS NOT NULL LIMIT 1');\n const row = (await stmt.get(path)) as { ok: number } | undefined;\n return row !== undefined;\n}\n"],"names":["NATIVE_VECTOR_SCOPE_TABLE","TARGET_CHUNK_CAP","asCosine","compareVectorScores","createNativeVectorScopeOwner","hasVectorRow","pendingRows","reserveNativeVectorScope","sampleEvenly","nativeVectorScopeOwners","WeakMap","owner","bind","vectors","Error","has","set","activeFor","allowed","undefined","scope","phase","get","token","valid","current","activate","deactivate","invalidate","rows","cap","step","Math","max","ceil","length","filter","_","i","score","round","min","a","b","byScore","Buffer","compare","from","path","conn","stmt","prepare","all","row"],"mappings":"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"}
|
package/dist/cjs/watch.d.cts
CHANGED
|
@@ -12,11 +12,17 @@ export type WatchEvent = {
|
|
|
12
12
|
type: 'reconcile-error';
|
|
13
13
|
message: string;
|
|
14
14
|
};
|
|
15
|
+
/** Options for the root {@link runWatch} API. */
|
|
15
16
|
export interface WatchOptions {
|
|
16
17
|
force?: boolean;
|
|
17
18
|
onEvent?: (event: WatchEvent) => void;
|
|
19
|
+
/** Caller abort cancels provider work, skips final preparation, and resolves after cleanup. */
|
|
18
20
|
signal?: AbortSignal;
|
|
19
21
|
debounceMs?: number;
|
|
20
22
|
heartbeatIntervalMs?: number;
|
|
21
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Runs in the foreground. Caller abort waits for active native work and cleanup; SIGINT/SIGTERM
|
|
26
|
+
* also run one final freshness pass. Cleanup failures reject either shutdown path.
|
|
27
|
+
*/
|
|
22
28
|
export declare function runWatch(cfg: ResolvedConfig, opts?: WatchOptions): Promise<void>;
|
package/dist/cjs/watch.d.ts
CHANGED
|
@@ -12,11 +12,17 @@ export type WatchEvent = {
|
|
|
12
12
|
type: 'reconcile-error';
|
|
13
13
|
message: string;
|
|
14
14
|
};
|
|
15
|
+
/** Options for the root {@link runWatch} API. */
|
|
15
16
|
export interface WatchOptions {
|
|
16
17
|
force?: boolean;
|
|
17
18
|
onEvent?: (event: WatchEvent) => void;
|
|
19
|
+
/** Caller abort cancels provider work, skips final preparation, and resolves after cleanup. */
|
|
18
20
|
signal?: AbortSignal;
|
|
19
21
|
debounceMs?: number;
|
|
20
22
|
heartbeatIntervalMs?: number;
|
|
21
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Runs in the foreground. Caller abort waits for active native work and cleanup; SIGINT/SIGTERM
|
|
26
|
+
* also run one final freshness pass. Cleanup failures reject either shutdown path.
|
|
27
|
+
*/
|
|
22
28
|
export declare function runWatch(cfg: ResolvedConfig, opts?: WatchOptions): Promise<void>;
|
package/dist/cjs/watch.js
CHANGED
|
@@ -174,14 +174,23 @@ function _ts_generator(thisArg, body) {
|
|
|
174
174
|
// Watch prepares the index for snapshot queries; filesystem events request debounced builds
|
|
175
175
|
// and periodic reconciliation recovers missed notifications.
|
|
176
176
|
var DEBOUNCE_MS = 200;
|
|
177
|
+
function isCallerAbort(signal, reason) {
|
|
178
|
+
return (signal === null || signal === void 0 ? void 0 : signal.aborted) === true && Object.is(reason, signal.reason);
|
|
179
|
+
}
|
|
180
|
+
function errorMessage(reason) {
|
|
181
|
+
return _instanceof(reason, Error) ? reason.message : String(reason);
|
|
182
|
+
}
|
|
177
183
|
function runWatch(_0) {
|
|
178
184
|
return _async_to_generator(function(cfg) {
|
|
179
|
-
var opts, _opts_onEvent, _opts_debounceMs, _opts_heartbeatIntervalMs, _cfg_rootDir, _cfg_configDir, _opts_force, onEvent, debounceMs, reconcileIntervalMs, claimIntervalMs, rootDir, configDir, claimFailure, requestShutdown, claim, claimCloseStarted, closeClaim, watcher, startup, startupNotification, scheduleReconcile, stopping,
|
|
185
|
+
var opts, _opts_onEvent, _opts_debounceMs, _opts_heartbeatIntervalMs, _cfg_rootDir, _cfg_configDir, _opts_force, _opts_signal, onEvent, debounceMs, reconcileIntervalMs, claimIntervalMs, rootDir, configDir, claimFailure, requestShutdown, claim, claimCloseStarted, closeClaim, watcher, startup, startupNotification, scheduleReconcile, stopping, callerCanceled, _opts_signal1, _opts_signal2, _opts_signal3, startupEvents, _ref, initialStore, dbPath, initialWarnings, initialParsed, initialTotal, _tmp, _opts_signal4, _opts_signal5, _ref1, store, parsed, warnings, _, _tmp1, running, queuedAlways, tick, startCycle, requestCycle, debounceTimer, reconcileTimer, err, canceledByCaller, closeError;
|
|
180
186
|
var _arguments = arguments;
|
|
181
187
|
return _ts_generator(this, function(_state) {
|
|
182
188
|
switch(_state.label){
|
|
183
189
|
case 0:
|
|
184
190
|
opts = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
|
|
191
|
+
if ((_opts_signal = opts.signal) === null || _opts_signal === void 0 ? void 0 : _opts_signal.aborted) return [
|
|
192
|
+
2
|
|
193
|
+
];
|
|
185
194
|
onEvent = (_opts_onEvent = opts.onEvent) !== null && _opts_onEvent !== void 0 ? _opts_onEvent : function() {};
|
|
186
195
|
debounceMs = (_opts_debounceMs = opts.debounceMs) !== null && _opts_debounceMs !== void 0 ? _opts_debounceMs : DEBOUNCE_MS;
|
|
187
196
|
reconcileIntervalMs = (_opts_heartbeatIntervalMs = opts.heartbeatIntervalMs) !== null && _opts_heartbeatIntervalMs !== void 0 ? _opts_heartbeatIntervalMs : _watchclaimts.WATCH_HEARTBEAT_INTERVAL_MS;
|
|
@@ -208,6 +217,7 @@ function runWatch(_0) {
|
|
|
208
217
|
startup = true;
|
|
209
218
|
startupNotification = false;
|
|
210
219
|
stopping = false;
|
|
220
|
+
callerCanceled = false;
|
|
211
221
|
_state.label = 2;
|
|
212
222
|
case 2:
|
|
213
223
|
_state.trys.push([
|
|
@@ -216,6 +226,7 @@ function runWatch(_0) {
|
|
|
216
226
|
27,
|
|
217
227
|
28
|
|
218
228
|
]);
|
|
229
|
+
(_opts_signal1 = opts.signal) === null || _opts_signal1 === void 0 ? void 0 : _opts_signal1.throwIfAborted();
|
|
219
230
|
// Subscribe before the first build. Native watchers have no ready barrier, so startup also
|
|
220
231
|
// performs an unconditional catch-up pass after the initial build.
|
|
221
232
|
watcher = (0, _nodefs.watch)(rootDir, {
|
|
@@ -232,7 +243,9 @@ function runWatch(_0) {
|
|
|
232
243
|
startupEvents = [];
|
|
233
244
|
return [
|
|
234
245
|
4,
|
|
235
|
-
(0, _indexts.openStore)(cfg
|
|
246
|
+
(0, _indexts.openStore)(cfg, {
|
|
247
|
+
signal: opts.signal
|
|
248
|
+
})
|
|
236
249
|
];
|
|
237
250
|
case 3:
|
|
238
251
|
_ref = _state.sent(), initialStore = _ref.store, dbPath = _ref.dbPath, initialWarnings = _ref.warnings, initialParsed = _ref.parsed;
|
|
@@ -280,6 +293,7 @@ function runWatch(_0) {
|
|
|
280
293
|
7
|
|
281
294
|
];
|
|
282
295
|
case 10:
|
|
296
|
+
(_opts_signal2 = opts.signal) === null || _opts_signal2 === void 0 ? void 0 : _opts_signal2.throwIfAborted();
|
|
283
297
|
if (claimFailure) throw claimFailure;
|
|
284
298
|
startupEvents.push({
|
|
285
299
|
parsed: initialParsed,
|
|
@@ -289,9 +303,12 @@ function runWatch(_0) {
|
|
|
289
303
|
_state.label = 11;
|
|
290
304
|
case 11:
|
|
291
305
|
startupNotification = false;
|
|
306
|
+
(_opts_signal4 = opts.signal) === null || _opts_signal4 === void 0 ? void 0 : _opts_signal4.throwIfAborted();
|
|
292
307
|
return [
|
|
293
308
|
4,
|
|
294
|
-
(0, _indexts.openStore)(cfg
|
|
309
|
+
(0, _indexts.openStore)(cfg, {
|
|
310
|
+
signal: opts.signal
|
|
311
|
+
})
|
|
295
312
|
];
|
|
296
313
|
case 12:
|
|
297
314
|
_ref1 = _state.sent(), store = _ref1.store, parsed = _ref1.parsed, warnings = _ref1.warnings;
|
|
@@ -336,10 +353,11 @@ function runWatch(_0) {
|
|
|
336
353
|
7
|
|
337
354
|
];
|
|
338
355
|
case 18:
|
|
356
|
+
(_opts_signal5 = opts.signal) === null || _opts_signal5 === void 0 ? void 0 : _opts_signal5.throwIfAborted();
|
|
339
357
|
if (claimFailure) throw claimFailure;
|
|
340
358
|
_state.label = 19;
|
|
341
359
|
case 19:
|
|
342
|
-
if (startupNotification && !((
|
|
360
|
+
if (startupNotification && !((_opts_signal3 = opts.signal) === null || _opts_signal3 === void 0 ? void 0 : _opts_signal3.aborted)) return [
|
|
343
361
|
3,
|
|
344
362
|
11
|
|
345
363
|
];
|
|
@@ -364,7 +382,9 @@ function runWatch(_0) {
|
|
|
364
382
|
]);
|
|
365
383
|
return [
|
|
366
384
|
4,
|
|
367
|
-
(0, _indexts.openStore)(cfg
|
|
385
|
+
(0, _indexts.openStore)(cfg, {
|
|
386
|
+
signal: opts.signal
|
|
387
|
+
})
|
|
368
388
|
];
|
|
369
389
|
case 1:
|
|
370
390
|
_ref = _state.sent(), store = _ref.store, parsed = _ref.parsed, warnings = _ref.warnings;
|
|
@@ -415,9 +435,12 @@ function runWatch(_0) {
|
|
|
415
435
|
];
|
|
416
436
|
case 8:
|
|
417
437
|
err = _state.sent();
|
|
438
|
+
if (isCallerAbort(opts.signal, err)) return [
|
|
439
|
+
2
|
|
440
|
+
];
|
|
418
441
|
onEvent({
|
|
419
442
|
type: 'reconcile-error',
|
|
420
|
-
message: err
|
|
443
|
+
message: errorMessage(err)
|
|
421
444
|
});
|
|
422
445
|
return [
|
|
423
446
|
3,
|
|
@@ -477,7 +500,9 @@ function runWatch(_0) {
|
|
|
477
500
|
var _opts_signal;
|
|
478
501
|
var shutdownReason = null;
|
|
479
502
|
var shutdown = function shutdown(reason) {
|
|
503
|
+
var canceledByCaller = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
|
|
480
504
|
shutdownReason !== null && shutdownReason !== void 0 ? shutdownReason : shutdownReason = reason !== null && reason !== void 0 ? reason : null;
|
|
505
|
+
callerCanceled || (callerCanceled = canceledByCaller);
|
|
481
506
|
if (stopping) return;
|
|
482
507
|
stopping = true;
|
|
483
508
|
var shutdownTask = function() {
|
|
@@ -488,7 +513,7 @@ function runWatch(_0) {
|
|
|
488
513
|
case 0:
|
|
489
514
|
process.off('SIGINT', stopNormally);
|
|
490
515
|
process.off('SIGTERM', stopNormally);
|
|
491
|
-
(_opts_signal = opts.signal) === null || _opts_signal === void 0 ? void 0 : _opts_signal.removeEventListener('abort',
|
|
516
|
+
(_opts_signal = opts.signal) === null || _opts_signal === void 0 ? void 0 : _opts_signal.removeEventListener('abort', stopForCaller);
|
|
492
517
|
clearInterval(reconcileTimer);
|
|
493
518
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
494
519
|
watcher === null || watcher === void 0 ? void 0 : watcher.close();
|
|
@@ -506,7 +531,7 @@ function runWatch(_0) {
|
|
|
506
531
|
,
|
|
507
532
|
7
|
|
508
533
|
]);
|
|
509
|
-
if (
|
|
534
|
+
if (!(!shutdownReason && !callerCanceled)) return [
|
|
510
535
|
3,
|
|
511
536
|
5
|
|
512
537
|
];
|
|
@@ -574,14 +599,17 @@ function runWatch(_0) {
|
|
|
574
599
|
var stopNormally = function stopNormally() {
|
|
575
600
|
return shutdown();
|
|
576
601
|
};
|
|
602
|
+
var stopForCaller = function stopForCaller() {
|
|
603
|
+
return shutdown(undefined, true);
|
|
604
|
+
};
|
|
577
605
|
requestShutdown = shutdown;
|
|
578
606
|
process.once('SIGINT', stopNormally);
|
|
579
607
|
process.once('SIGTERM', stopNormally);
|
|
580
608
|
if (claimFailure) shutdown(claimFailure);
|
|
581
|
-
else if ((_opts_signal = opts.signal) === null || _opts_signal === void 0 ? void 0 : _opts_signal.aborted)
|
|
609
|
+
else if ((_opts_signal = opts.signal) === null || _opts_signal === void 0 ? void 0 : _opts_signal.aborted) stopForCaller();
|
|
582
610
|
else {
|
|
583
611
|
var _opts_signal1;
|
|
584
|
-
(_opts_signal1 = opts.signal) === null || _opts_signal1 === void 0 ? void 0 : _opts_signal1.addEventListener('abort',
|
|
612
|
+
(_opts_signal1 = opts.signal) === null || _opts_signal1 === void 0 ? void 0 : _opts_signal1.addEventListener('abort', stopForCaller, {
|
|
585
613
|
once: true
|
|
586
614
|
});
|
|
587
615
|
try {
|
|
@@ -628,6 +656,7 @@ function runWatch(_0) {
|
|
|
628
656
|
];
|
|
629
657
|
case 22:
|
|
630
658
|
err = _state.sent();
|
|
659
|
+
canceledByCaller = isCallerAbort(opts.signal, err);
|
|
631
660
|
watcher === null || watcher === void 0 ? void 0 : watcher.close();
|
|
632
661
|
if (claimCloseStarted) throw err;
|
|
633
662
|
_state.label = 23;
|
|
@@ -655,6 +684,9 @@ function runWatch(_0) {
|
|
|
655
684
|
closeError
|
|
656
685
|
], 'watch setup and claim cleanup both failed');
|
|
657
686
|
case 26:
|
|
687
|
+
if (canceledByCaller) return [
|
|
688
|
+
2
|
|
689
|
+
];
|
|
658
690
|
throw err;
|
|
659
691
|
case 27:
|
|
660
692
|
requestShutdown = undefined;
|
package/dist/cjs/watch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/watch.ts"],"sourcesContent":["import { watch as fsWatch } from 'node:fs';\nimport type { ResolvedConfig } from './config/index.ts';\nimport { SenseError } from './errors.ts';\nimport { guardedTick } from './lib/guarded-tick.ts';\nimport { shouldReconcileWatchNotification } from './lib/watch-notification.ts';\nimport { docCount, openStore } from './store/index.ts';\nimport { startWatchClaim, WATCH_HEARTBEAT_INTERVAL_MS } from './watch-claim.ts';\n\n// Watch prepares the index for snapshot queries; filesystem events request debounced builds\n// and periodic reconciliation recovers missed notifications.\nconst DEBOUNCE_MS = 200;\n\nexport type WatchEvent = { type: 'started'; rootDir: string; dbPath: string } | { type: 'reconciled'; parsed: number; total: number; warnings: string[] } | { type: 'reconcile-error'; message: string };\n\nexport interface WatchOptions {\n force?: boolean;\n onEvent?: (event: WatchEvent) => void;\n // Aborting runs the same shutdown path as SIGINT/SIGTERM.\n signal?: AbortSignal;\n debounceMs?: number;\n heartbeatIntervalMs?: number;\n}\n\n// Runs in the foreground until SIGINT/SIGTERM/signal abort. DuckDB and Turso hand the cache file to\n// one process at a time, so every reconcile cycle opens and closes instead of holding an idle lock.\nexport async function runWatch(cfg: ResolvedConfig, opts: WatchOptions = {}): Promise<void> {\n const onEvent = opts.onEvent ?? (() => {});\n const debounceMs = opts.debounceMs ?? DEBOUNCE_MS;\n const reconcileIntervalMs = opts.heartbeatIntervalMs ?? WATCH_HEARTBEAT_INTERVAL_MS;\n if (!Number.isFinite(reconcileIntervalMs) || reconcileIntervalMs <= 0) throw new SenseError('CONFIG_INVALID', 'watch heartbeatIntervalMs must be a finite positive number');\n // Reconciliation may be parked for a caller, but live ownership must renew before fixed expiry.\n const claimIntervalMs = Math.min(reconcileIntervalMs, WATCH_HEARTBEAT_INTERVAL_MS);\n const rootDir = cfg.rootDir ?? cfg.baseDir;\n const configDir = cfg.configDir ?? rootDir;\n let claimFailure: Error | null = null;\n let requestShutdown: ((reason: Error) => void) | undefined;\n const claim = await startWatchClaim(configDir, opts.force ?? false, claimIntervalMs, (err) => {\n claimFailure ??= err;\n requestShutdown?.(err);\n });\n let claimCloseStarted = false;\n const closeClaim = (): Promise<void> => {\n claimCloseStarted = true;\n return claim.close();\n };\n let watcher: ReturnType<typeof fsWatch> | undefined;\n let startup = true;\n let startupNotification = false;\n let scheduleReconcile: (() => void) | undefined;\n let stopping = false;\n try {\n // Subscribe before the first build. Native watchers have no ready barrier, so startup also\n // performs an unconditional catch-up pass after the initial build.\n watcher = fsWatch(rootDir, { recursive: true }, (_event, filename) => {\n if (!shouldReconcileWatchNotification(filename)) return;\n if (startup) startupNotification = true;\n else scheduleReconcile?.();\n });\n watcher.on('error', (err) => {\n claimFailure ??= err;\n requestShutdown?.(err);\n });\n\n const startupEvents: Array<{ parsed: number; total: number; warnings: string[] }> = [];\n const { store: initialStore, dbPath, warnings: initialWarnings, parsed: initialParsed } = await openStore(cfg);\n let initialTotal = 0;\n try {\n // total is read before close: an event fires only once nothing is held open again.\n initialTotal = initialWarnings.length > 0 || initialParsed > 0 ? await docCount(initialStore) : 0;\n } finally {\n await initialStore.close();\n }\n if (claimFailure) throw claimFailure;\n\n startupEvents.push({ parsed: initialParsed, total: initialTotal, warnings: initialWarnings });\n // Always reopen once after subscribing, then drain notifications observed while startup was\n // in progress. Each pass closes before the next one starts, so no stores overlap.\n do {\n startupNotification = false;\n const { store, parsed, warnings } = await openStore(cfg);\n try {\n if (parsed > 0 || warnings.length > 0) startupEvents.push({ parsed, total: await docCount(store), warnings });\n } finally {\n await store.close();\n }\n if (claimFailure) throw claimFailure;\n } while (startupNotification && !opts.signal?.aborted);\n startup = false;\n\n // At most one open+reconcile+close cycle runs at a time; a trigger that arrives mid-cycle is\n // coalesced into a single rerun instead of opening a second, overlapping connection.\n let running: Promise<void> | null = null;\n let queuedAlways: boolean | null = null;\n\n const tick = async (alwaysEmit: boolean): Promise<void> => {\n try {\n const { store, parsed, warnings } = await openStore(cfg);\n try {\n if (alwaysEmit || parsed > 0 || warnings.length > 0) {\n onEvent({ type: 'reconciled', parsed, total: await docCount(store), warnings });\n }\n } finally {\n await store.close();\n }\n } catch (err) {\n onEvent({ type: 'reconcile-error', message: (err as Error).message });\n }\n };\n\n const startCycle = (alwaysEmit: boolean) => {\n running = tick(alwaysEmit).then(() => {\n running = null;\n if (queuedAlways !== null && !stopping) {\n const again = queuedAlways;\n queuedAlways = null;\n startCycle(again);\n }\n });\n };\n\n const requestCycle = (alwaysEmit: boolean) => {\n if (stopping) return;\n if (running) {\n queuedAlways = queuedAlways || alwaysEmit;\n return;\n }\n startCycle(alwaysEmit);\n };\n\n let debounceTimer: NodeJS.Timeout | null = null;\n // Ignore our own state files, or cache and claim writes would retrigger reconciliation forever.\n // An unresolvable filename reconciles because parsing nothing costs less than missing a real edit.\n scheduleReconcile = () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n requestCycle(true);\n }, debounceMs);\n };\n const reconcileTimer = setInterval(\n guardedTick(\n async () => requestCycle(false),\n () => stopping\n ),\n reconcileIntervalMs\n );\n\n return await new Promise<void>((resolveShutdown, rejectShutdown) => {\n let shutdownReason: Error | null = null;\n const shutdown = (reason?: Error) => {\n shutdownReason ??= reason ?? null;\n if (stopping) return;\n stopping = true;\n const shutdownTask = (async () => {\n process.off('SIGINT', stopNormally);\n process.off('SIGTERM', stopNormally);\n opts.signal?.removeEventListener('abort', stopNormally);\n clearInterval(reconcileTimer);\n if (debounceTimer) clearTimeout(debounceTimer);\n watcher?.close();\n await running;\n let finalError: unknown;\n try {\n // A normal stop performs one final freshness pass. Ownership loss drains existing work\n // but starts nothing new because the replacement watcher now owns that responsibility.\n if (!shutdownReason) {\n const { store: finalStore } = await openStore(cfg);\n await finalStore.close();\n }\n } catch (err) {\n finalError = err;\n }\n try {\n await closeClaim();\n } catch (err) {\n if (finalError) throw new AggregateError([finalError, err], 'watch shutdown and claim cleanup both failed');\n throw err;\n }\n if (finalError) throw finalError;\n if (shutdownReason) throw shutdownReason;\n })();\n shutdownTask.then(resolveShutdown, rejectShutdown);\n };\n const stopNormally = () => shutdown();\n requestShutdown = shutdown;\n process.once('SIGINT', stopNormally);\n process.once('SIGTERM', stopNormally);\n if (claimFailure) shutdown(claimFailure);\n else if (opts.signal?.aborted) shutdown();\n else {\n opts.signal?.addEventListener('abort', stopNormally, { once: true });\n try {\n onEvent({ type: 'started', rootDir, dbPath });\n if (!stopping) {\n for (const event of startupEvents) {\n if (stopping) break;\n if (event.warnings.length > 0 || event.parsed > 0) onEvent({ type: 'reconciled', ...event });\n }\n }\n } catch (err) {\n shutdown(err instanceof Error ? err : new Error(String(err)));\n }\n }\n });\n } catch (err) {\n watcher?.close();\n if (claimCloseStarted) throw err;\n try {\n await closeClaim();\n } catch (closeError) {\n throw new AggregateError([err, closeError], 'watch setup and claim cleanup both failed');\n }\n throw err;\n } finally {\n requestShutdown = undefined;\n }\n}\n"],"names":["runWatch","DEBOUNCE_MS","cfg","opts","onEvent","debounceMs","reconcileIntervalMs","claimIntervalMs","rootDir","configDir","claimFailure","requestShutdown","claim","claimCloseStarted","closeClaim","watcher","startup","startupNotification","scheduleReconcile","stopping","startupEvents","initialStore","dbPath","initialWarnings","initialParsed","initialTotal","store","parsed","warnings","running","queuedAlways","tick","startCycle","requestCycle","debounceTimer","reconcileTimer","err","closeError","heartbeatIntervalMs","WATCH_HEARTBEAT_INTERVAL_MS","Number","isFinite","SenseError","Math","min","baseDir","startWatchClaim","force","close","fsWatch","recursive","_event","filename","shouldReconcileWatchNotification","on","openStore","length","docCount","push","total","signal","aborted","alwaysEmit","type","message","then","again","clearTimeout","setTimeout","setInterval","guardedTick","Promise","resolveShutdown","rejectShutdown","shutdownReason","shutdown","reason","shutdownTask","finalError","finalStore","process","off","stopNormally","removeEventListener","clearInterval","AggregateError","once","addEventListener","event","Error","String","undefined"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/watch.ts"],"sourcesContent":["import { watch as fsWatch } from 'node:fs';\nimport type { ResolvedConfig } from './config/index.ts';\nimport { SenseError } from './errors.ts';\nimport { guardedTick } from './lib/guarded-tick.ts';\nimport { shouldReconcileWatchNotification } from './lib/watch-notification.ts';\nimport { docCount, openStore } from './store/index.ts';\nimport { startWatchClaim, WATCH_HEARTBEAT_INTERVAL_MS } from './watch-claim.ts';\n\n// Watch prepares the index for snapshot queries; filesystem events request debounced builds\n// and periodic reconciliation recovers missed notifications.\nconst DEBOUNCE_MS = 200;\n\nexport type WatchEvent = { type: 'started'; rootDir: string; dbPath: string } | { type: 'reconciled'; parsed: number; total: number; warnings: string[] } | { type: 'reconcile-error'; message: string };\n\n/** Options for the root {@link runWatch} API. */\nexport interface WatchOptions {\n force?: boolean;\n onEvent?: (event: WatchEvent) => void;\n /** Caller abort cancels provider work, skips final preparation, and resolves after cleanup. */\n signal?: AbortSignal;\n debounceMs?: number;\n heartbeatIntervalMs?: number;\n}\n\nfunction isCallerAbort(signal: AbortSignal | undefined, reason: unknown): boolean {\n return signal?.aborted === true && Object.is(reason, signal.reason);\n}\n\nfunction errorMessage(reason: unknown): string {\n return reason instanceof Error ? reason.message : String(reason);\n}\n\n/**\n * Runs in the foreground. Caller abort waits for active native work and cleanup; SIGINT/SIGTERM\n * also run one final freshness pass. Cleanup failures reject either shutdown path.\n */\nexport async function runWatch(cfg: ResolvedConfig, opts: WatchOptions = {}): Promise<void> {\n if (opts.signal?.aborted) return;\n const onEvent = opts.onEvent ?? (() => {});\n const debounceMs = opts.debounceMs ?? DEBOUNCE_MS;\n const reconcileIntervalMs = opts.heartbeatIntervalMs ?? WATCH_HEARTBEAT_INTERVAL_MS;\n if (!Number.isFinite(reconcileIntervalMs) || reconcileIntervalMs <= 0) throw new SenseError('CONFIG_INVALID', 'watch heartbeatIntervalMs must be a finite positive number');\n // Reconciliation may be parked for a caller, but live ownership must renew before fixed expiry.\n const claimIntervalMs = Math.min(reconcileIntervalMs, WATCH_HEARTBEAT_INTERVAL_MS);\n const rootDir = cfg.rootDir ?? cfg.baseDir;\n const configDir = cfg.configDir ?? rootDir;\n let claimFailure: Error | null = null;\n let requestShutdown: ((reason: Error) => void) | undefined;\n const claim = await startWatchClaim(configDir, opts.force ?? false, claimIntervalMs, (err) => {\n claimFailure ??= err;\n requestShutdown?.(err);\n });\n let claimCloseStarted = false;\n const closeClaim = (): Promise<void> => {\n claimCloseStarted = true;\n return claim.close();\n };\n let watcher: ReturnType<typeof fsWatch> | undefined;\n let startup = true;\n let startupNotification = false;\n let scheduleReconcile: (() => void) | undefined;\n let stopping = false;\n let callerCanceled = false;\n try {\n opts.signal?.throwIfAborted();\n // Subscribe before the first build. Native watchers have no ready barrier, so startup also\n // performs an unconditional catch-up pass after the initial build.\n watcher = fsWatch(rootDir, { recursive: true }, (_event, filename) => {\n if (!shouldReconcileWatchNotification(filename)) return;\n if (startup) startupNotification = true;\n else scheduleReconcile?.();\n });\n watcher.on('error', (err) => {\n claimFailure ??= err;\n requestShutdown?.(err);\n });\n\n const startupEvents: Array<{ parsed: number; total: number; warnings: string[] }> = [];\n const { store: initialStore, dbPath, warnings: initialWarnings, parsed: initialParsed } = await openStore(cfg, { signal: opts.signal });\n let initialTotal = 0;\n try {\n // total is read before close: an event fires only once nothing is held open again.\n initialTotal = initialWarnings.length > 0 || initialParsed > 0 ? await docCount(initialStore) : 0;\n } finally {\n await initialStore.close();\n }\n opts.signal?.throwIfAborted();\n if (claimFailure) throw claimFailure;\n\n startupEvents.push({ parsed: initialParsed, total: initialTotal, warnings: initialWarnings });\n // Always reopen once after subscribing, then drain notifications observed while startup was\n // in progress. Each pass closes before the next one starts, so no stores overlap.\n do {\n startupNotification = false;\n opts.signal?.throwIfAborted();\n const { store, parsed, warnings } = await openStore(cfg, { signal: opts.signal });\n try {\n if (parsed > 0 || warnings.length > 0) startupEvents.push({ parsed, total: await docCount(store), warnings });\n } finally {\n await store.close();\n }\n opts.signal?.throwIfAborted();\n if (claimFailure) throw claimFailure;\n } while (startupNotification && !opts.signal?.aborted);\n startup = false;\n\n // At most one open+reconcile+close cycle runs at a time; a trigger that arrives mid-cycle is\n // coalesced into a single rerun instead of opening a second, overlapping connection.\n let running: Promise<void> | null = null;\n let queuedAlways: boolean | null = null;\n\n const tick = async (alwaysEmit: boolean): Promise<void> => {\n try {\n const { store, parsed, warnings } = await openStore(cfg, { signal: opts.signal });\n try {\n if (alwaysEmit || parsed > 0 || warnings.length > 0) {\n onEvent({ type: 'reconciled', parsed, total: await docCount(store), warnings });\n }\n } finally {\n await store.close();\n }\n } catch (err) {\n if (isCallerAbort(opts.signal, err)) return;\n onEvent({ type: 'reconcile-error', message: errorMessage(err) });\n }\n };\n\n const startCycle = (alwaysEmit: boolean) => {\n running = tick(alwaysEmit).then(() => {\n running = null;\n if (queuedAlways !== null && !stopping) {\n const again = queuedAlways;\n queuedAlways = null;\n startCycle(again);\n }\n });\n };\n\n const requestCycle = (alwaysEmit: boolean) => {\n if (stopping) return;\n if (running) {\n queuedAlways = queuedAlways || alwaysEmit;\n return;\n }\n startCycle(alwaysEmit);\n };\n\n let debounceTimer: NodeJS.Timeout | null = null;\n // Ignore our own state files, or cache and claim writes would retrigger reconciliation forever.\n // An unresolvable filename reconciles because parsing nothing costs less than missing a real edit.\n scheduleReconcile = () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n requestCycle(true);\n }, debounceMs);\n };\n const reconcileTimer = setInterval(\n guardedTick(\n async () => requestCycle(false),\n () => stopping\n ),\n reconcileIntervalMs\n );\n\n return await new Promise<void>((resolveShutdown, rejectShutdown) => {\n let shutdownReason: Error | null = null;\n const shutdown = (reason?: Error, canceledByCaller = false) => {\n shutdownReason ??= reason ?? null;\n callerCanceled ||= canceledByCaller;\n if (stopping) return;\n stopping = true;\n const shutdownTask = (async () => {\n process.off('SIGINT', stopNormally);\n process.off('SIGTERM', stopNormally);\n opts.signal?.removeEventListener('abort', stopForCaller);\n clearInterval(reconcileTimer);\n if (debounceTimer) clearTimeout(debounceTimer);\n watcher?.close();\n await running;\n let finalError: unknown;\n try {\n // A normal stop performs one final freshness pass. Ownership loss drains existing work\n // but starts nothing new because the replacement watcher now owns that responsibility.\n if (!shutdownReason && !callerCanceled) {\n const { store: finalStore } = await openStore(cfg);\n await finalStore.close();\n }\n } catch (err) {\n finalError = err;\n }\n try {\n await closeClaim();\n } catch (err) {\n if (finalError) throw new AggregateError([finalError, err], 'watch shutdown and claim cleanup both failed');\n throw err;\n }\n if (finalError) throw finalError;\n if (shutdownReason) throw shutdownReason;\n })();\n shutdownTask.then(resolveShutdown, rejectShutdown);\n };\n const stopNormally = () => shutdown();\n const stopForCaller = () => shutdown(undefined, true);\n requestShutdown = shutdown;\n process.once('SIGINT', stopNormally);\n process.once('SIGTERM', stopNormally);\n if (claimFailure) shutdown(claimFailure);\n else if (opts.signal?.aborted) stopForCaller();\n else {\n opts.signal?.addEventListener('abort', stopForCaller, { once: true });\n try {\n onEvent({ type: 'started', rootDir, dbPath });\n if (!stopping) {\n for (const event of startupEvents) {\n if (stopping) break;\n if (event.warnings.length > 0 || event.parsed > 0) onEvent({ type: 'reconciled', ...event });\n }\n }\n } catch (err) {\n shutdown(err instanceof Error ? err : new Error(String(err)));\n }\n }\n });\n } catch (err) {\n const canceledByCaller = isCallerAbort(opts.signal, err);\n watcher?.close();\n if (claimCloseStarted) throw err;\n try {\n await closeClaim();\n } catch (closeError) {\n throw new AggregateError([err, closeError], 'watch setup and claim cleanup both failed');\n }\n if (canceledByCaller) return;\n throw err;\n } finally {\n requestShutdown = undefined;\n }\n}\n"],"names":["runWatch","DEBOUNCE_MS","isCallerAbort","signal","reason","aborted","Object","is","errorMessage","Error","message","String","cfg","opts","onEvent","debounceMs","reconcileIntervalMs","claimIntervalMs","rootDir","configDir","claimFailure","requestShutdown","claim","claimCloseStarted","closeClaim","watcher","startup","startupNotification","scheduleReconcile","stopping","callerCanceled","startupEvents","initialStore","dbPath","initialWarnings","initialParsed","initialTotal","store","parsed","warnings","running","queuedAlways","tick","startCycle","requestCycle","debounceTimer","reconcileTimer","err","canceledByCaller","closeError","heartbeatIntervalMs","WATCH_HEARTBEAT_INTERVAL_MS","Number","isFinite","SenseError","Math","min","baseDir","startWatchClaim","force","close","throwIfAborted","fsWatch","recursive","_event","filename","shouldReconcileWatchNotification","on","openStore","length","docCount","push","total","alwaysEmit","type","then","again","clearTimeout","setTimeout","setInterval","guardedTick","Promise","resolveShutdown","rejectShutdown","shutdownReason","shutdown","shutdownTask","finalError","finalStore","process","off","stopNormally","removeEventListener","stopForCaller","clearInterval","AggregateError","undefined","once","addEventListener","event"],"mappings":";;;;+BAoCsBA;;;eAAAA;;;sBApCW;wBAEN;6BACC;mCACqB;uBACb;4BACyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE7D,4FAA4F;AAC5F,6DAA6D;AAC7D,IAAMC,cAAc;AAcpB,SAASC,cAAcC,MAA+B,EAAEC,MAAe;IACrE,OAAOD,CAAAA,mBAAAA,6BAAAA,OAAQE,OAAO,MAAK,QAAQC,OAAOC,EAAE,CAACH,QAAQD,OAAOC,MAAM;AACpE;AAEA,SAASI,aAAaJ,MAAe;IACnC,OAAOA,AAAM,YAANA,QAAkBK,SAAQL,OAAOM,OAAO,GAAGC,OAAOP;AAC3D;AAMO,SAAeJ;wCAASY,GAAmB;YAAEC,MAElCA,eACGA,kBACSA,2BAIZD,cACEA,gBAG6BC,aAX3CA,cACEC,SACAC,YACAC,qBAGAC,iBACAC,SACAC,WACFC,cACAC,iBACEC,OAIFC,mBACEC,YAIFC,SACAC,SACAC,qBACAC,mBACAC,UACAC,gBAEFjB,eAsBAA,eAiBiCA,eA1B3BkB,eACoF,MAA3EC,cAAcC,QAAkBC,iBAAyBC,eACpEC,oBAeFvB,eAOAA,eANoC,OAA5BwB,OAAOC,QAAQC,oBAarBC,SACAC,cAEEC,MAgBAC,YAWAC,cASFC,eAUEC,gBAmECC,KACDC,kBAKGC;;;;;oBAlMuCpC,OAAAA,oEAAqB,CAAC;oBACxE,KAAIA,eAAAA,KAAKV,MAAM,cAAXU,mCAAAA,aAAaR,OAAO,EAAE;;;oBACpBS,WAAUD,gBAAAA,KAAKC,OAAO,cAAZD,2BAAAA,gBAAiB,YAAO;oBAClCE,cAAaF,mBAAAA,KAAKE,UAAU,cAAfF,8BAAAA,mBAAmBZ;oBAChCe,uBAAsBH,4BAAAA,KAAKqC,mBAAmB,cAAxBrC,uCAAAA,4BAA4BsC,yCAA2B;oBACnF,IAAI,CAACC,OAAOC,QAAQ,CAACrC,wBAAwBA,uBAAuB,GAAG,MAAM,IAAIsC,oBAAU,CAAC,kBAAkB;oBAC9G,gGAAgG;oBAC1FrC,kBAAkBsC,KAAKC,GAAG,CAACxC,qBAAqBmC,yCAA2B;oBAC3EjC,WAAUN,eAAAA,IAAIM,OAAO,cAAXN,0BAAAA,eAAeA,IAAI6C,OAAO;oBACpCtC,aAAYP,iBAAAA,IAAIO,SAAS,cAAbP,4BAAAA,iBAAiBM;oBAC/BE,eAA6B;oBAEnB;;wBAAMsC,IAAAA,6BAAe,EAACvC,YAAWN,cAAAA,KAAK8C,KAAK,cAAV9C,yBAAAA,cAAc,OAAOI,iBAAiB,SAAC8B;4BACpF3B,yBAAAA,0BAAAA,eAAAA,eAAiB2B;4BACjB1B,4BAAAA,sCAAAA,gBAAkB0B;wBACpB;;;oBAHMzB,QAAQ;oBAIVC,oBAAoB;oBAClBC,aAAa;wBACjBD,oBAAoB;wBACpB,OAAOD,MAAMsC,KAAK;oBACpB;oBAEIlC,UAAU;oBACVC,sBAAsB;oBAEtBE,WAAW;oBACXC,iBAAiB;;;;;;;;;qBAEnBjB,gBAAAA,KAAKV,MAAM,cAAXU,oCAAAA,cAAagD,cAAc;oBAC3B,2FAA2F;oBAC3F,mEAAmE;oBACnEpC,UAAUqC,IAAAA,aAAO,EAAC5C,SAAS;wBAAE6C,WAAW;oBAAK,GAAG,SAACC,QAAQC;wBACvD,IAAI,CAACC,IAAAA,qDAAgC,EAACD,WAAW;wBACjD,IAAIvC,SAASC,sBAAsB;6BAC9BC,8BAAAA,wCAAAA;oBACP;oBACAH,QAAQ0C,EAAE,CAAC,SAAS,SAACpB;wBACnB3B,yBAAAA,0BAAAA,eAAAA,eAAiB2B;wBACjB1B,4BAAAA,sCAAAA,gBAAkB0B;oBACpB;oBAEMhB;oBACoF;;wBAAMqC,IAAAA,kBAAS,EAACxD,KAAK;4BAAET,QAAQU,KAAKV,MAAM;wBAAC;;;oBAA3C,OAAA,eAA3E6B,eAA2E,KAAlFK,OAAqBJ,SAA6D,KAA7DA,QAAkBC,kBAA2C,KAArDK,UAAmCJ,gBAAkB,KAA1BG;oBAC5DF,eAAe;;;;;;;;;yBAGFF,CAAAA,gBAAgBmC,MAAM,GAAG,KAAKlC,gBAAgB,CAAA,GAA9CD;;;;oBAAkD;;wBAAMoC,IAAAA,iBAAQ,EAACtC;;;2BAAf;;;;;;2BAA+B;;;oBADhG,mFAAmF;oBACnFI;;;;;;oBAEA;;wBAAMJ,aAAa4B,KAAK;;;oBAAxB;;;;;qBAEF/C,gBAAAA,KAAKV,MAAM,cAAXU,oCAAAA,cAAagD,cAAc;oBAC3B,IAAIzC,cAAc,MAAMA;oBAExBW,cAAcwC,IAAI,CAAC;wBAAEjC,QAAQH;wBAAeqC,OAAOpC;wBAAcG,UAAUL;oBAAgB;;;oBAIzFP,sBAAsB;qBACtBd,gBAAAA,KAAKV,MAAM,cAAXU,oCAAAA,cAAagD,cAAc;oBACS;;wBAAMO,IAAAA,kBAAS,EAACxD,KAAK;4BAAET,QAAQU,KAAKV,MAAM;wBAAC;;;oBAA3C,QAAA,eAA5BkC,QAA4B,MAA5BA,OAAOC,SAAqB,MAArBA,QAAQC,WAAa,MAAbA;;;;;;;;;yBAEjBD,CAAAA,SAAS,KAAKC,SAAS8B,MAAM,GAAG,CAAA,GAAhC/B;;;;wBAAmCP,cAAcwC,IAAI;;wBAAGjC,QAAAA;;oBAAe;;wBAAMgC,IAAAA,iBAAQ,EAACjC;;;oBAAnDN,QAAAA;+BAA6ByC,QAAO,qBAAuBjC,WAAAA;;;;;;;;;oBAElG;;wBAAMF,MAAMuB,KAAK;;;oBAAjB;;;;;qBAEF/C,gBAAAA,KAAKV,MAAM,cAAXU,oCAAAA,cAAagD,cAAc;oBAC3B,IAAIzC,cAAc,MAAMA;;;wBACjBO,uBAAuB,GAACd,gBAAAA,KAAKV,MAAM,cAAXU,oCAAAA,cAAaR,OAAO,GAA5CsB;;;;;;oBACTD,UAAU;oBAEV,6FAA6F;oBAC7F,qFAAqF;oBACjFc,UAAgC;oBAChCC,eAA+B;oBAE7BC,OAAO,cAAO+B;;gCAEoB,MAA5BpC,OAAOC,QAAQC,gBAQhBQ;;;;;;;;;;wCAR6B;;4CAAMqB,IAAAA,kBAAS,EAACxD,KAAK;gDAAET,QAAQU,KAAKV,MAAM;4CAAC;;;wCAA3C,OAAA,eAA5BkC,QAA4B,KAA5BA,OAAOC,SAAqB,KAArBA,QAAQC,WAAa,KAAbA;;;;;;;;;6CAEjBkC,CAAAA,cAAcnC,SAAS,KAAKC,SAAS8B,MAAM,GAAG,CAAA,GAA9CI;;;;;4CACQC,MAAM;4CAAcpC,QAAAA;;wCAAe;;4CAAMgC,IAAAA,iBAAQ,EAACjC;;;wCAA5DvB;kDAAsC0D,QAAO,oBAAuBjC,WAAAA;;;;;;;;;wCAGtE;;4CAAMF,MAAMuB,KAAK;;;wCAAjB;;;;;;;;;;wCAEKb;wCACP,IAAI7C,cAAcW,KAAKV,MAAM,EAAE4C,MAAM;;;wCACrCjC,QAAQ;4CAAE4D,MAAM;4CAAmBhE,SAASF,aAAauC;wCAAK;;;;;;;;;;;wBAElE;;oBAEMJ,aAAa,qBAAC8B;wBAClBjC,UAAUE,KAAK+B,YAAYE,IAAI,CAAC;4BAC9BnC,UAAU;4BACV,IAAIC,iBAAiB,QAAQ,CAACZ,UAAU;gCACtC,IAAM+C,QAAQnC;gCACdA,eAAe;gCACfE,WAAWiC;4BACb;wBACF;oBACF;oBAEMhC,eAAe,sBAAC6B;wBACpB,IAAI5C,UAAU;wBACd,IAAIW,SAAS;4BACXC,eAAeA,gBAAgBgC;4BAC/B;wBACF;wBACA9B,WAAW8B;oBACb;oBAEI5B,gBAAuC;oBAC3C,gGAAgG;oBAChG,mGAAmG;oBACnGjB,oBAAoB;wBAClB,IAAIiB,eAAegC,aAAahC;wBAChCA,gBAAgBiC,WAAW;4BACzBjC,gBAAgB;4BAChBD,aAAa;wBACf,GAAG7B;oBACL;oBACM+B,iBAAiBiC,YACrBC,IAAAA,0BAAW,EACT;;;;;oCAAYpC,aAAa;;;;uBACzB;+BAAMf;wBAERb;oBAGK;;wBAAM,IAAIiE,QAAc,SAACC,iBAAiBC;gCA2CtCtE;4BA1CT,IAAIuE,iBAA+B;4BACnC,IAAMC,WAAW,kBAACjF;oCAAgB4C,oFAAmB;gCACnDoC,2BAAAA,4BAAAA,iBAAAA,iBAAmBhF,mBAAAA,oBAAAA,SAAU;gCAC7B0B,mBAAAA,iBAAmBkB;gCACnB,IAAInB,UAAU;gCACdA,WAAW;gCACX,IAAMyD,eAAe,AAAC;;4CAGpBzE,cAKI0E,YAK8B,MAAfC,YAGVzC,KAKAA;;;;oDApBT0C,QAAQC,GAAG,CAAC,UAAUC;oDACtBF,QAAQC,GAAG,CAAC,WAAWC;qDACvB9E,eAAAA,KAAKV,MAAM,cAAXU,mCAAAA,aAAa+E,mBAAmB,CAAC,SAASC;oDAC1CC,cAAchD;oDACd,IAAID,eAAegC,aAAahC;oDAChCpB,oBAAAA,8BAAAA,QAASmC,KAAK;oDACd;;wDAAMpB;;;oDAAN;;;;;;;;;yDAKM,CAAA,CAAC4C,kBAAkB,CAACtD,cAAa,GAAjC;;;;oDAC4B;;wDAAMsC,IAAAA,kBAAS,EAACxD;;;oDAAhB,OAAA,eAAf4E,aAAe,KAAtBnD;oDACR;;wDAAMmD,WAAW5B,KAAK;;;oDAAtB;;;;;;;;oDAEKb;oDACPwC,aAAaxC;;;;;;;;;;;;oDAGb;;wDAAMvB;;;oDAAN;;;;;;oDACOuB;oDACP,IAAIwC,YAAY,MAAM,IAAIQ;wDAAgBR;wDAAYxC;uDAAM;oDAC5D,MAAMA;;oDAER,IAAIwC,YAAY,MAAMA;oDACtB,IAAIH,gBAAgB,MAAMA;;;;;;oCAC5B;;gCACAE,aAAaX,IAAI,CAACO,iBAAiBC;4BACrC;4BACA,IAAMQ,eAAe;uCAAMN;;4BAC3B,IAAMQ,gBAAgB;uCAAMR,SAASW,WAAW;;4BAChD3E,kBAAkBgE;4BAClBI,QAAQQ,IAAI,CAAC,UAAUN;4BACvBF,QAAQQ,IAAI,CAAC,WAAWN;4BACxB,IAAIvE,cAAciE,SAASjE;iCACtB,KAAIP,eAAAA,KAAKV,MAAM,cAAXU,mCAAAA,aAAaR,OAAO,EAAEwF;iCAC1B;oCACHhF;iCAAAA,gBAAAA,KAAKV,MAAM,cAAXU,oCAAAA,cAAaqF,gBAAgB,CAAC,SAASL,eAAe;oCAAEI,MAAM;gCAAK;gCACnE,IAAI;oCACFnF,QAAQ;wCAAE4D,MAAM;wCAAWxD,SAAAA;wCAASe,QAAAA;oCAAO;oCAC3C,IAAI,CAACJ,UAAU;4CACR,kCAAA,2BAAA;;4CAAL,QAAK,YAAeE,kCAAf,SAAA,6BAAA,QAAA,yBAAA,iCAA8B;gDAA9B,IAAMoE,QAAN;gDACH,IAAItE,UAAU;gDACd,IAAIsE,MAAM5D,QAAQ,CAAC8B,MAAM,GAAG,KAAK8B,MAAM7D,MAAM,GAAG,GAAGxB,QAAQ;oDAAE4D,MAAM;mDAAiByB;4CACtF;;4CAHK;4CAAA;;;qDAAA,6BAAA;oDAAA;;;oDAAA;0DAAA;;;;oCAIP;gCACF,EAAE,OAAOpD,KAAK;oCACZsC,SAAStC,AAAG,YAAHA,KAAetC,SAAQsC,MAAM,IAAItC,MAAME,OAAOoC;gCACzD;4BACF;wBACF;;;oBA1DA;;wBAAO;;;oBA2DAA;oBACDC,mBAAmB9C,cAAcW,KAAKV,MAAM,EAAE4C;oBACpDtB,oBAAAA,8BAAAA,QAASmC,KAAK;oBACd,IAAIrC,mBAAmB,MAAMwB;;;;;;;;;oBAE3B;;wBAAMvB;;;oBAAN;;;;;;oBACOyB;oBACP,MAAM,IAAI8C;wBAAgBhD;wBAAKE;uBAAa;;oBAE9C,IAAID,kBAAkB;;;oBACtB,MAAMD;;oBAEN1B,kBAAkB2E;;;;;;;;;;IAEtB"}
|
|
@@ -6,8 +6,8 @@ export interface ParseWorkerData {
|
|
|
6
6
|
cfg: Config;
|
|
7
7
|
featureNames: FeatureName[];
|
|
8
8
|
}
|
|
9
|
-
export type ParseTask = FileStat;
|
|
10
|
-
export type
|
|
9
|
+
export type ParseTask = FileStat[];
|
|
10
|
+
export type ParseFileResult = {
|
|
11
11
|
ok: true;
|
|
12
12
|
doc: ParsedDoc;
|
|
13
13
|
warnings: string[];
|
|
@@ -16,4 +16,5 @@ export type ParseTaskResult = {
|
|
|
16
16
|
ok: false;
|
|
17
17
|
error: WorkerErrorPayload;
|
|
18
18
|
};
|
|
19
|
-
export
|
|
19
|
+
export type ParseTaskResult = ParseFileResult[];
|
|
20
|
+
export default function parseTask(files: ParseTask): ParseTaskResult;
|
|
@@ -6,8 +6,8 @@ export interface ParseWorkerData {
|
|
|
6
6
|
cfg: Config;
|
|
7
7
|
featureNames: FeatureName[];
|
|
8
8
|
}
|
|
9
|
-
export type ParseTask = FileStat;
|
|
10
|
-
export type
|
|
9
|
+
export type ParseTask = FileStat[];
|
|
10
|
+
export type ParseFileResult = {
|
|
11
11
|
ok: true;
|
|
12
12
|
doc: ParsedDoc;
|
|
13
13
|
warnings: string[];
|
|
@@ -16,4 +16,5 @@ export type ParseTaskResult = {
|
|
|
16
16
|
ok: false;
|
|
17
17
|
error: WorkerErrorPayload;
|
|
18
18
|
};
|
|
19
|
-
export
|
|
19
|
+
export type ParseTaskResult = ParseFileResult[];
|
|
20
|
+
export default function parseTask(files: ParseTask): ParseTaskResult;
|
|
@@ -25,22 +25,24 @@ var _Tinypool_workerData = _tinypool.default.workerData, cfg = _Tinypool_workerD
|
|
|
25
25
|
var selected = _indexts.FEATURES.filter(function(feature) {
|
|
26
26
|
return featureNames.includes(feature.name);
|
|
27
27
|
});
|
|
28
|
-
function parseTask(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
28
|
+
function parseTask(files) {
|
|
29
|
+
return files.map(function(file) {
|
|
30
|
+
try {
|
|
31
|
+
var start = process.hrtime.bigint();
|
|
32
|
+
var _parseFile = (0, _indexts1.parseFile)(file, (0, _reparsets.featuresForFile)(selected, cfg, file), cfg), doc = _parseFile.doc, warnings = _parseFile.warnings;
|
|
33
|
+
var parseMs = Number(process.hrtime.bigint() - start) / 1e6;
|
|
34
|
+
return {
|
|
35
|
+
ok: true,
|
|
36
|
+
doc: doc,
|
|
37
|
+
warnings: warnings,
|
|
38
|
+
parseMs: parseMs
|
|
39
|
+
};
|
|
40
|
+
} catch (err) {
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
error: (0, _workererrorts.serializeError)(err)
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
});
|
|
45
47
|
}
|
|
46
48
|
/* 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; }
|