sensemaking 0.27.0 → 0.28.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/bin/cli.js +16 -7
- package/dist/cjs/chunk/extract.js.map +1 -1
- package/dist/cjs/chunk/group.js.map +1 -1
- package/dist/cjs/chunk/index.js.map +1 -1
- package/dist/cjs/chunk/parse.js.map +1 -1
- package/dist/cjs/chunk/parser.js.map +1 -1
- package/dist/cjs/chunk/tokens.js.map +1 -1
- package/dist/cjs/chunk/version.js.map +1 -1
- package/dist/cjs/cli/build.js.map +1 -1
- package/dist/cjs/cli/constants.d.cts +2 -0
- package/dist/cjs/cli/constants.d.ts +2 -0
- package/dist/cjs/cli/constants.js +21 -0
- package/dist/cjs/cli/constants.js.map +1 -0
- package/dist/cjs/cli/download.js.map +1 -1
- package/dist/cjs/cli/index.js.map +1 -1
- package/dist/cjs/cli/init.js.map +1 -1
- package/dist/cjs/cli/map.js.map +1 -1
- package/dist/cjs/cli/named.js +2 -1
- package/dist/cjs/cli/named.js.map +1 -1
- package/dist/cjs/cli/path.js.map +1 -1
- package/dist/cjs/cli/peek.js.map +1 -1
- package/dist/cjs/cli/related.js.map +1 -1
- package/dist/cjs/cli/search.js.map +1 -1
- package/dist/cjs/cli/shared.js +5 -4
- package/dist/cjs/cli/shared.js.map +1 -1
- package/dist/cjs/cli/sql.js.map +1 -1
- package/dist/cjs/cli/status.js.map +1 -1
- package/dist/cjs/cli/watch.js.map +1 -1
- package/dist/cjs/cli.js +10 -9
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/commands/index.js.map +1 -1
- package/dist/cjs/commands/map.js.map +1 -1
- package/dist/cjs/commands/path.js.map +1 -1
- package/dist/cjs/commands/peek.js.map +1 -1
- package/dist/cjs/commands/related.js.map +1 -1
- package/dist/cjs/commands/scope.js.map +1 -1
- package/dist/cjs/commands/search.js.map +1 -1
- package/dist/cjs/commands/signals.js.map +1 -1
- package/dist/cjs/commands/snapshot.js.map +1 -1
- package/dist/cjs/commands/status.js.map +1 -1
- package/dist/cjs/config/access.js.map +1 -1
- package/dist/cjs/config/index.js.map +1 -1
- package/dist/cjs/config/load.js.map +1 -1
- package/dist/cjs/config/resolve.js.map +1 -1
- package/dist/cjs/config/signals.js.map +1 -1
- package/dist/cjs/config/types.js.map +1 -1
- package/dist/cjs/config/validate.js.map +1 -1
- package/dist/cjs/embed/cohere.js.map +1 -1
- package/dist/cjs/embed/distribution.js.map +1 -1
- package/dist/cjs/embed/endpoint.js.map +1 -1
- package/dist/cjs/embed/handoff.js.map +1 -1
- package/dist/cjs/embed/http.js.map +1 -1
- package/dist/cjs/embed/identity.js.map +1 -1
- package/dist/cjs/embed/langfit.js.map +1 -1
- package/dist/cjs/embed/languages.js.map +1 -1
- package/dist/cjs/embed/openai.js.map +1 -1
- package/dist/cjs/embed/query.js.map +1 -1
- package/dist/cjs/embed/registry.js.map +1 -1
- package/dist/cjs/embed/static.js.map +1 -1
- package/dist/cjs/embed/store.js.map +1 -1
- package/dist/cjs/embed/types.js.map +1 -1
- package/dist/cjs/errors.js.map +1 -1
- package/dist/cjs/features/embed.js.map +1 -1
- package/dist/cjs/features/fences.js.map +1 -1
- package/dist/cjs/features/index.js.map +1 -1
- package/dist/cjs/features/links.js.map +1 -1
- package/dist/cjs/features/rank.js.map +1 -1
- package/dist/cjs/features/sections.js.map +1 -1
- package/dist/cjs/features/tags.js.map +1 -1
- package/dist/cjs/graph/graph.js.map +1 -1
- package/dist/cjs/graph/traverse.js.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/lib/atomic-write.js.map +1 -1
- package/dist/cjs/lib/guarded-tick.js.map +1 -1
- package/dist/cjs/lib/serial-query.js.map +1 -1
- package/dist/cjs/lib/watch-notification.js.map +1 -1
- package/dist/cjs/lib/worker-file.js.map +1 -1
- package/dist/cjs/output/column-hint.js.map +1 -1
- package/dist/cjs/output/output.js.map +1 -1
- package/dist/cjs/output/progress.js.map +1 -1
- package/dist/cjs/output/search-error.js.map +1 -1
- package/dist/cjs/scan/frontmatter.js.map +1 -1
- package/dist/cjs/scan/index.js.map +1 -1
- package/dist/cjs/scan/list.js.map +1 -1
- package/dist/cjs/scan/pool.js.map +1 -1
- package/dist/cjs/scan/reparse.js.map +1 -1
- package/dist/cjs/scan/worker-error.js.map +1 -1
- package/dist/cjs/store/batch.js.map +1 -1
- package/dist/cjs/store/builder.js.map +1 -1
- package/dist/cjs/store/cache.js.map +1 -1
- package/dist/cjs/store/duckdb/batch.js.map +1 -1
- package/dist/cjs/store/duckdb/connection.js.map +1 -1
- package/dist/cjs/store/duckdb/engine.d.cts +11 -0
- package/dist/cjs/store/duckdb/engine.d.ts +11 -0
- package/dist/cjs/store/duckdb/engine.js +193 -0
- package/dist/cjs/store/duckdb/engine.js.map +1 -0
- package/dist/cjs/store/duckdb/fieldStats.js.map +1 -1
- package/dist/cjs/store/duckdb/lexical.d.cts +1 -6
- package/dist/cjs/store/duckdb/lexical.d.ts +1 -6
- package/dist/cjs/store/duckdb/lexical.js +48 -45
- package/dist/cjs/store/duckdb/lexical.js.map +1 -1
- package/dist/cjs/store/duckdb/native.d.cts +5 -3
- package/dist/cjs/store/duckdb/native.d.ts +5 -3
- package/dist/cjs/store/duckdb/native.js +157 -18
- package/dist/cjs/store/duckdb/native.js.map +1 -1
- package/dist/cjs/store/duckdb/open.js +151 -3
- package/dist/cjs/store/duckdb/open.js.map +1 -1
- package/dist/cjs/store/duckdb/ordered-bm25.d.cts +3 -16
- package/dist/cjs/store/duckdb/ordered-bm25.d.ts +3 -16
- package/dist/cjs/store/duckdb/ordered-bm25.js +24 -80
- package/dist/cjs/store/duckdb/ordered-bm25.js.map +1 -1
- package/dist/cjs/store/duckdb/reconcile.js.map +1 -1
- package/dist/cjs/store/duckdb/sql-functions.js.map +1 -1
- package/dist/cjs/store/duckdb/store.js.map +1 -1
- package/dist/cjs/store/duckdb/vectors.js.map +1 -1
- package/dist/cjs/store/embed-scope.js.map +1 -1
- package/dist/cjs/store/engine.d.cts +28 -0
- package/dist/cjs/store/engine.d.ts +28 -0
- package/dist/cjs/store/engine.js +362 -0
- package/dist/cjs/store/engine.js.map +1 -0
- package/dist/cjs/store/feature-scope.js.map +1 -1
- package/dist/cjs/store/index.js.map +1 -1
- package/dist/cjs/store/lock-wait.js.map +1 -1
- package/dist/cjs/store/native.d.cts +8 -5
- package/dist/cjs/store/native.d.ts +8 -5
- package/dist/cjs/store/native.js +78 -73
- package/dist/cjs/store/native.js.map +1 -1
- package/dist/cjs/store/open.js +100 -40
- package/dist/cjs/store/open.js.map +1 -1
- package/dist/cjs/store/preset-scope.js.map +1 -1
- package/dist/cjs/store/readiness.js.map +1 -1
- package/dist/cjs/store/reconcile.js.map +1 -1
- package/dist/cjs/store/shared.js.map +1 -1
- package/dist/cjs/store/signature.js.map +1 -1
- package/dist/cjs/store/sql-functions.js.map +1 -1
- package/dist/cjs/store/sqlite/connection.js.map +1 -1
- package/dist/cjs/store/sqlite/engine.d.cts +12 -0
- package/dist/cjs/store/sqlite/engine.d.ts +12 -0
- package/dist/cjs/store/sqlite/engine.js +53 -0
- package/dist/cjs/store/sqlite/engine.js.map +1 -0
- package/dist/cjs/store/sqlite/fieldStats.js.map +1 -1
- package/dist/cjs/store/sqlite/lexical.js +3 -4
- package/dist/cjs/store/sqlite/lexical.js.map +1 -1
- package/dist/cjs/store/sqlite/open.js +119 -6
- package/dist/cjs/store/sqlite/open.js.map +1 -1
- package/dist/cjs/store/sqlite/reconcile.js.map +1 -1
- package/dist/cjs/store/sqlite/sql-functions.js.map +1 -1
- package/dist/cjs/store/sqlite/store.js.map +1 -1
- package/dist/cjs/store/sqlite/vectors.js.map +1 -1
- package/dist/cjs/store/stages.js.map +1 -1
- package/dist/cjs/store/transaction.js.map +1 -1
- package/dist/cjs/store/turso/connection.js.map +1 -1
- package/dist/cjs/store/turso/engine.d.cts +9 -0
- package/dist/cjs/store/turso/engine.d.ts +9 -0
- package/dist/cjs/store/turso/engine.js +189 -0
- package/dist/cjs/store/turso/engine.js.map +1 -0
- package/dist/cjs/store/turso/fieldStats.js.map +1 -1
- package/dist/cjs/store/turso/lexical-text.js.map +1 -1
- package/dist/cjs/store/turso/lexical.js +16 -11
- package/dist/cjs/store/turso/lexical.js.map +1 -1
- package/dist/cjs/store/turso/native.d.cts +5 -1
- package/dist/cjs/store/turso/native.d.ts +5 -1
- package/dist/cjs/store/turso/native.js +157 -8
- package/dist/cjs/store/turso/native.js.map +1 -1
- package/dist/cjs/store/turso/open.js +172 -27
- package/dist/cjs/store/turso/open.js.map +1 -1
- package/dist/cjs/store/turso/reconcile.d.cts +0 -1
- package/dist/cjs/store/turso/reconcile.d.ts +0 -1
- package/dist/cjs/store/turso/reconcile.js +22 -23
- package/dist/cjs/store/turso/reconcile.js.map +1 -1
- package/dist/cjs/store/turso/sql-functions.js.map +1 -1
- package/dist/cjs/store/turso/store.js.map +1 -1
- package/dist/cjs/store/turso/vectors.js.map +1 -1
- package/dist/cjs/store/types.d.cts +2 -0
- package/dist/cjs/store/types.d.ts +2 -0
- package/dist/cjs/store/types.js.map +1 -1
- package/dist/cjs/store/vectors.js.map +1 -1
- package/dist/cjs/text/segment.js.map +1 -1
- package/dist/cjs/text/strip.js.map +1 -1
- package/dist/cjs/watch-claim.js.map +1 -1
- package/dist/cjs/watch.js.map +1 -1
- package/dist/cjs/workers/parse.js.map +1 -1
- package/dist/cjs/workers/watch-heartbeat.js.map +1 -1
- package/dist/esm/chunk/extract.js.map +1 -1
- package/dist/esm/chunk/group.js.map +1 -1
- package/dist/esm/chunk/index.js.map +1 -1
- package/dist/esm/chunk/parse.js.map +1 -1
- package/dist/esm/chunk/parser.js.map +1 -1
- package/dist/esm/chunk/tokens.js.map +1 -1
- package/dist/esm/chunk/types.js.map +1 -1
- package/dist/esm/chunk/version.js.map +1 -1
- package/dist/esm/cli/build.js.map +1 -1
- package/dist/esm/cli/constants.d.ts +2 -0
- package/dist/esm/cli/constants.js +2 -0
- package/dist/esm/cli/constants.js.map +1 -0
- package/dist/esm/cli/download.js.map +1 -1
- package/dist/esm/cli/index.js.map +1 -1
- package/dist/esm/cli/init.js.map +1 -1
- package/dist/esm/cli/map.js.map +1 -1
- package/dist/esm/cli/named.js +2 -1
- package/dist/esm/cli/named.js.map +1 -1
- package/dist/esm/cli/path.js.map +1 -1
- package/dist/esm/cli/peek.js.map +1 -1
- package/dist/esm/cli/related.js.map +1 -1
- package/dist/esm/cli/search.js.map +1 -1
- package/dist/esm/cli/shared.js +6 -5
- package/dist/esm/cli/shared.js.map +1 -1
- package/dist/esm/cli/sql.js.map +1 -1
- package/dist/esm/cli/status.js.map +1 -1
- package/dist/esm/cli/types.js.map +1 -1
- package/dist/esm/cli/watch.js.map +1 -1
- package/dist/esm/cli.js +10 -9
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/commands/index.js.map +1 -1
- package/dist/esm/commands/map.js.map +1 -1
- package/dist/esm/commands/path.js.map +1 -1
- package/dist/esm/commands/peek.js.map +1 -1
- package/dist/esm/commands/related.js.map +1 -1
- package/dist/esm/commands/scope.js.map +1 -1
- package/dist/esm/commands/search.js.map +1 -1
- package/dist/esm/commands/signals.js.map +1 -1
- package/dist/esm/commands/snapshot.js.map +1 -1
- package/dist/esm/commands/status.js.map +1 -1
- package/dist/esm/config/access.js.map +1 -1
- package/dist/esm/config/index.js.map +1 -1
- package/dist/esm/config/load.js.map +1 -1
- package/dist/esm/config/resolve.js.map +1 -1
- package/dist/esm/config/signals.js.map +1 -1
- package/dist/esm/config/types.js.map +1 -1
- package/dist/esm/config/validate.js.map +1 -1
- package/dist/esm/embed/cohere.js.map +1 -1
- package/dist/esm/embed/distribution.js.map +1 -1
- package/dist/esm/embed/endpoint.js.map +1 -1
- package/dist/esm/embed/handoff.js.map +1 -1
- package/dist/esm/embed/http.js.map +1 -1
- package/dist/esm/embed/identity.js.map +1 -1
- package/dist/esm/embed/langfit.js.map +1 -1
- package/dist/esm/embed/languages.js.map +1 -1
- package/dist/esm/embed/openai.js.map +1 -1
- package/dist/esm/embed/query.js +1 -1
- package/dist/esm/embed/query.js.map +1 -1
- package/dist/esm/embed/registry.js.map +1 -1
- package/dist/esm/embed/static.js.map +1 -1
- package/dist/esm/embed/store.js.map +1 -1
- package/dist/esm/embed/types.js.map +1 -1
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/features/embed.js.map +1 -1
- package/dist/esm/features/fences.js.map +1 -1
- package/dist/esm/features/index.js.map +1 -1
- package/dist/esm/features/links.js.map +1 -1
- package/dist/esm/features/rank.js.map +1 -1
- package/dist/esm/features/sections.js.map +1 -1
- package/dist/esm/features/tags.js.map +1 -1
- package/dist/esm/features/types.js.map +1 -1
- package/dist/esm/graph/graph.js.map +1 -1
- package/dist/esm/graph/traverse.js.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/atomic-write.js.map +1 -1
- package/dist/esm/lib/guarded-tick.js.map +1 -1
- package/dist/esm/lib/serial-query.js.map +1 -1
- package/dist/esm/lib/watch-notification.js.map +1 -1
- package/dist/esm/lib/worker-file.js.map +1 -1
- package/dist/esm/output/column-hint.js.map +1 -1
- package/dist/esm/output/output.js.map +1 -1
- package/dist/esm/output/progress.js.map +1 -1
- package/dist/esm/output/search-error.js.map +1 -1
- package/dist/esm/scan/frontmatter.js.map +1 -1
- package/dist/esm/scan/index.js.map +1 -1
- package/dist/esm/scan/list.js.map +1 -1
- package/dist/esm/scan/pool.js.map +1 -1
- package/dist/esm/scan/reparse.js.map +1 -1
- package/dist/esm/scan/worker-error.js.map +1 -1
- package/dist/esm/store/batch.js.map +1 -1
- package/dist/esm/store/builder.js.map +1 -1
- package/dist/esm/store/cache.js.map +1 -1
- package/dist/esm/store/duckdb/batch.js.map +1 -1
- package/dist/esm/store/duckdb/connection.js.map +1 -1
- package/dist/esm/store/duckdb/engine.d.ts +11 -0
- package/dist/esm/store/duckdb/engine.js +18 -0
- package/dist/esm/store/duckdb/engine.js.map +1 -0
- package/dist/esm/store/duckdb/fieldStats.js.map +1 -1
- package/dist/esm/store/duckdb/lexical.d.ts +1 -6
- package/dist/esm/store/duckdb/lexical.js +16 -20
- package/dist/esm/store/duckdb/lexical.js.map +1 -1
- package/dist/esm/store/duckdb/native.d.ts +5 -3
- package/dist/esm/store/duckdb/native.js +16 -14
- package/dist/esm/store/duckdb/native.js.map +1 -1
- package/dist/esm/store/duckdb/open.js +40 -2
- package/dist/esm/store/duckdb/open.js.map +1 -1
- package/dist/esm/store/duckdb/ordered-bm25.d.ts +3 -16
- package/dist/esm/store/duckdb/ordered-bm25.js +14 -55
- package/dist/esm/store/duckdb/ordered-bm25.js.map +1 -1
- package/dist/esm/store/duckdb/reconcile.js.map +1 -1
- package/dist/esm/store/duckdb/sql-functions.js.map +1 -1
- package/dist/esm/store/duckdb/store.js.map +1 -1
- package/dist/esm/store/duckdb/vectors.js.map +1 -1
- package/dist/esm/store/embed-scope.js.map +1 -1
- package/dist/esm/store/engine.d.ts +28 -0
- package/dist/esm/store/engine.js +85 -0
- package/dist/esm/store/engine.js.map +1 -0
- package/dist/esm/store/feature-scope.js.map +1 -1
- package/dist/esm/store/index.js.map +1 -1
- package/dist/esm/store/lock-wait.js.map +1 -1
- package/dist/esm/store/native.d.ts +8 -5
- package/dist/esm/store/native.js +59 -57
- package/dist/esm/store/native.js.map +1 -1
- package/dist/esm/store/open.js +24 -7
- package/dist/esm/store/open.js.map +1 -1
- package/dist/esm/store/preset-scope.js.map +1 -1
- package/dist/esm/store/readiness.js.map +1 -1
- package/dist/esm/store/reconcile.js.map +1 -1
- package/dist/esm/store/shared.js.map +1 -1
- package/dist/esm/store/signature.js.map +1 -1
- package/dist/esm/store/sql-functions.js.map +1 -1
- package/dist/esm/store/sqlite/connection.js.map +1 -1
- package/dist/esm/store/sqlite/engine.d.ts +12 -0
- package/dist/esm/store/sqlite/engine.js +16 -0
- package/dist/esm/store/sqlite/engine.js.map +1 -0
- package/dist/esm/store/sqlite/fieldStats.js.map +1 -1
- package/dist/esm/store/sqlite/lexical.js +2 -3
- package/dist/esm/store/sqlite/lexical.js.map +1 -1
- package/dist/esm/store/sqlite/open.js +38 -7
- package/dist/esm/store/sqlite/open.js.map +1 -1
- package/dist/esm/store/sqlite/reconcile.js.map +1 -1
- package/dist/esm/store/sqlite/sql-functions.js.map +1 -1
- package/dist/esm/store/sqlite/store.js.map +1 -1
- package/dist/esm/store/sqlite/vectors.js.map +1 -1
- package/dist/esm/store/stages.js.map +1 -1
- package/dist/esm/store/transaction.js.map +1 -1
- package/dist/esm/store/turso/connection.js.map +1 -1
- package/dist/esm/store/turso/engine.d.ts +9 -0
- package/dist/esm/store/turso/engine.js +14 -0
- package/dist/esm/store/turso/engine.js.map +1 -0
- package/dist/esm/store/turso/fieldStats.js.map +1 -1
- package/dist/esm/store/turso/lexical-text.js.map +1 -1
- package/dist/esm/store/turso/lexical.js +9 -9
- package/dist/esm/store/turso/lexical.js.map +1 -1
- package/dist/esm/store/turso/native.d.ts +5 -1
- package/dist/esm/store/turso/native.js +16 -10
- package/dist/esm/store/turso/native.js.map +1 -1
- package/dist/esm/store/turso/open.js +44 -3
- package/dist/esm/store/turso/open.js.map +1 -1
- package/dist/esm/store/turso/reconcile.d.ts +0 -1
- package/dist/esm/store/turso/reconcile.js +3 -8
- package/dist/esm/store/turso/reconcile.js.map +1 -1
- package/dist/esm/store/turso/sql-functions.js.map +1 -1
- package/dist/esm/store/turso/store.js.map +1 -1
- package/dist/esm/store/turso/vectors.js.map +1 -1
- package/dist/esm/store/types.d.ts +2 -0
- package/dist/esm/store/types.js.map +1 -1
- package/dist/esm/store/vectors.js.map +1 -1
- package/dist/esm/text/segment.js.map +1 -1
- package/dist/esm/text/strip.js.map +1 -1
- package/dist/esm/watch-claim.js.map +1 -1
- package/dist/esm/watch.js.map +1 -1
- package/dist/esm/workers/parse.js.map +1 -1
- package/dist/esm/workers/watch-heartbeat.js.map +1 -1
- package/package.json +21 -6
- package/skills/sense/SKILL.md +1 -1
- package/skills/sense/references/stores/duckdb.md +1 -1
- package/skills/sense/references/stores/sqlite.md +1 -1
- package/skills/sense/references/stores/turso.md +1 -1
- package/skills/sense-setup/references/stores/duckdb.md +1 -1
- package/skills/sense-setup/references/stores/sqlite.md +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/features/links.ts"],"sourcesContent":["import posix from 'node:path/posix';\nimport type { FileStat } from '../scan/index.ts';\nimport { appendRows } from '../store/shared.ts';\nimport type { Connection } from '../store/types.ts';\nimport { maskRegions } from './fences.ts';\nimport type { ExtractedDoc, Feature, ReconcileDelta } from './types.ts';\n\n// links(src, target, target_base, dst, embed): target as written, target_base its indexed baseKey, dst the resolved path or NULL (a queryable dead link).\n// embed distinguishes `![[x]]`/`` from `[[x]]`/`[](x.md)` -- Obsidian's grain: a target both linked and embedded in one note is two rows.\n\n// Alias stripped after |; a leading # keeps the anchor as the target (self-link needs a\n// heading name), else the anchor splits off. Null = not a link.\nfunction parseWikilinkInner(inner: string): string | null {\n const beforeAlias = inner.split('|')[0].trim();\n if (beforeAlias.startsWith('#')) return beforeAlias.length > 1 ? beforeAlias : null;\n const target = beforeAlias.split('#')[0].trim();\n return target || null;\n}\n\n// A frontmatter value counts only when it is exactly a wikilink (\"[[X]]\") -- mid-string and\n// ![[...]] forms don't count there, per Obsidian's rule (probe-verified).\nfunction extract(_raw: string, rawBody: string, _search?: { title: string; summary: string }, data?: Record<string, unknown>): Array<{ target: string; embed: boolean }> {\n const body = /\\[\\[|\\]\\(/.test(rawBody) ? maskRegions(rawBody) : rawBody;\n const seen = new Set<string>();\n const results: Array<{ target: string; embed: boolean }> = [];\n const add = (target: string, embed: boolean) => {\n const key = `${target}\\0${embed ? '1' : '0'}`;\n if (seen.has(key)) return;\n seen.add(key);\n results.push({ target, embed });\n };\n // To the first ]], as Obsidian parses it, so a heading or alias holding a lone ] still\n // matches; anchor and alias split off in parseWikilinkInner.\n for (const m of body.matchAll(/\\[\\[(.*?)\\]\\]/g)) {\n const target = parseWikilinkInner(m[1]);\n if (target) add(target, body[(m.index ?? 0) - 1] === '!');\n }\n // Any internal destination, not only .md-suffixed: \\](Zektor) resolves like [[Zektor]] and\n // \\](#anchor) is a self-edge. External URLs and titled links (dest stops at whitespace) skip.\n for (const m of body.matchAll(/(!)?\\[[^\\]]*\\]\\(((?:[^()\\s]|\\([^()\\s]*\\))+)(?:\\s+(?:\"[^)]*\"|'[^)]*'))?\\)/g)) {\n const dest = m[2].trim();\n // External: a URI scheme prefix (mailto:, tel:, data:, https:...), protocol-relative\n // //host, a www. shorthand, or a scheme anywhere (the malformed double-paren case).\n if (!dest || dest.includes('://')) continue;\n if (/^([a-z][a-z0-9+.-]*:|\\/\\/|www\\.)/i.test(dest)) continue;\n const target = dest.startsWith('#') ? dest : dest.split('#')[0];\n if (target) add(target, m[1] === '!');\n }\n for (const value of Object.values(data ?? {})) {\n for (const item of Array.isArray(value) ? value : [value]) {\n if (typeof item !== 'string') continue;\n const m = /^\\[\\[(.*)\\]\\]$/.exec(item.trim());\n if (!m) continue;\n const target = parseWikilinkInner(m[1]);\n if (target) add(target, false);\n }\n }\n return results;\n}\n\nfunction cleanTarget(target: string): string {\n return target.replace(/\\\\/g, '/').replace(/^\\.\\//, '');\n}\n\nfunction baseKey(path: string): string {\n return posix.basename(path).replace(/\\.md$/i, '').toLowerCase();\n}\n\n// Obsidian-style: exact relative path (with/without .md), path relative to the linking note's\n// directory, then basename match (shortest path wins ties, verified against a cold-loaded vault).\nfunction resolveTarget(src: string, target: string, pathSet: Set<string>, byBase: Map<string, string[]>): string | null {\n // [[#Heading]]: a same-note anchor, always the note itself -- never depends on other files.\n if (target.startsWith('#')) return src;\n const clean = cleanTarget(target);\n const fromSrc = posix.normalize(posix.join(posix.dirname(src), clean));\n for (const candidate of [clean, `${clean}.md`, fromSrc, `${fromSrc}.md`]) {\n if (pathSet.has(candidate)) return candidate;\n }\n const candidates = byBase.get(baseKey(clean));\n if (!candidates) return null;\n // The linking note itself wins a basename collision (Obsidian resolves to self before the\n // shortest-path rule -- cold-load verified on the hub corpus).\n return candidates.includes(src) ? src : candidates[0];\n}\n\n// Shortest path wins a basename collision; equal lengths fall back to lexicographic, our own\n// deterministic tiebreak for a case Obsidian itself leaves registration-order-dependent.\nfunction buildByBase(files: FileStat[]): Map<string, string[]> {\n const byBase = new Map<string, string[]>();\n const paths = files.map((f) => f.relPath).sort((a, b) => a.length - b.length || (a < b ? -1 : a > b ? 1 : 0));\n for (const path of paths) {\n const key = baseKey(path);\n const list = byBase.get(key);\n if (list) list.push(path);\n else byBase.set(key, [path]);\n }\n return byBase;\n}\n\ninterface LinkRow {\n src: string;\n target: string;\n dst: string | null;\n embed: number;\n}\n\n// resolveTarget applied to `rows`, returning only the rows whose dst changed, so the caller\n// can write them in one runBatch call.\nfunction resolveRows(rows: LinkRow[], pathSet: Set<string>, byBase: Map<string, string[]>): LinkRow[] {\n const changed: LinkRow[] = [];\n for (const row of rows) {\n const dst = resolveTarget(row.src, row.target, pathSet, byBase);\n if (dst !== row.dst) changed.push({ ...row, dst });\n }\n return changed;\n}\n\nasync function writeResolved(db: Connection, rows: LinkRow[]): Promise<void> {\n if (rows.length === 0) return;\n await db.runBatch(\n 'UPDATE links SET dst = ? WHERE src = ? AND target = ?',\n rows.map((r) => [r.dst, r.src, r.target])\n );\n}\n\n// Chunked so a large-but-under-threshold delta never exceeds SQLite's bound-variable limit\n// (SQLITE_MAX_VARIABLE_NUMBER, 32766); harmless headroom on DuckDB, which has no such cap.\nasync function selectIn(db: Connection, column: string, keys: string[]): Promise<LinkRow[]> {\n const rows: LinkRow[] = [];\n for (let i = 0; i < keys.length; i += 500) {\n const chunk = keys.slice(i, i + 500);\n const stmt = await db.prepare(`SELECT src, target, dst, embed FROM links WHERE ${column} IN (${chunk.map(() => '?').join(', ')})`);\n rows.push(...((await stmt.all(...chunk)) as unknown as LinkRow[]));\n }\n return rows;\n}\n\n// Re-resolves only what this reconcile could have touched: re-stored sources, links whose\n// target basename matches an added/vanished file, and links whose dst vanished -- all indexed.\nasync function resolveIncremental(db: Connection, delta: ReconcileDelta): Promise<boolean> {\n const pathSet = new Set(delta.files.map((f) => f.relPath));\n const byBase = buildByBase(delta.files);\n\n const changedBasenames = new Set<string>();\n for (const p of delta.added) changedBasenames.add(baseKey(p));\n for (const p of delta.vanished) changedBasenames.add(baseKey(p));\n\n // \\0 can't appear in a path or target, so the key never collides; a space can.\n const candidates = new Map<string, LinkRow>();\n const collect = (rows: LinkRow[]) => {\n for (const row of rows) candidates.set(`${row.src}\\0${row.target}\\0${row.embed}`, row);\n };\n collect(await selectIn(db, 'src', delta.reparsed));\n collect(await selectIn(db, 'target_base', [...changedBasenames]));\n collect(await selectIn(db, 'dst', delta.vanished));\n\n const changed = resolveRows([...candidates.values()], pathSet, byBase);\n await writeResolved(db, changed);\n return changed.length > 0;\n}\n\n// One edge per (src, target); an embed row is excluded only when the same pair also exists as\n// a link. Self-edges are dropped so PageRank mass is not self-recycled.\nexport const LINK_EDGES_SQL = `SELECT src, dst FROM links WHERE dst IS NOT NULL AND embed = 0 AND src != dst\n UNION ALL\n SELECT src, dst FROM links l WHERE dst IS NOT NULL AND embed = 1 AND src != dst\n AND NOT EXISTS (SELECT 1 FROM links l0 WHERE l0.src = l.src AND l0.target = l.target AND l0.embed = 0)`;\n\nexport function toEdges(rows: Array<{ src: string; dst: string }>): [string, string][] {\n return rows.map((r) => [r.src, r.dst]);\n}\n\n// Resolved edges, for rank (inside reconcile's afterReconcile pass).\nexport async function linkEdges(db: Connection): Promise<[string, string][]> {\n const stmt = await db.prepare(LINK_EDGES_SQL);\n return toEdges((await stmt.all()) as Array<{ src: string; dst: string }>);\n}\n\n// Records whether remove()/store() deleted any link row, since afterReconcile runs after both\n// and dstChanged alone misses the reparsed-to-zero-links case. Keyed on delta so state dies with it.\nconst removedWithLinks = new WeakMap<ReconcileDelta, boolean>();\n\n// Cold build only: whether store() resolved at least one row to a non-null dst, so afterReconcile\n// can report linksChanged without re-reading the table it just wrote.\nconst coldResolved = new WeakMap<ReconcileDelta, boolean>();\n\n// dst stays NULL here on an incremental store (resolution runs afterward); a cold build resolves\n// it inline in store() instead, through the *_RESOLVED column list and SQL below.\nconst LINK_COLUMNS = ['src', 'target', 'target_base', 'embed'];\nconst UPSERT_LINK_SQL = 'INSERT INTO links (src, target, target_base, dst, embed) VALUES (?, ?, ?, NULL, ?) ON CONFLICT(src, target, embed) DO UPDATE SET target_base = excluded.target_base';\nconst LINK_COLUMNS_RESOLVED = ['src', 'target', 'target_base', 'dst', 'embed'];\nconst UPSERT_LINK_SQL_RESOLVED = 'INSERT INTO links (src, target, target_base, dst, embed) VALUES (?, ?, ?, ?, ?) ON CONFLICT(src, target, embed) DO UPDATE SET target_base = excluded.target_base';\n\nexport const links: Feature = {\n name: 'links',\n async schema(db) {\n await db.exec('CREATE TABLE IF NOT EXISTS links (src TEXT, target TEXT, target_base TEXT, dst TEXT, embed INTEGER, PRIMARY KEY (src, target, embed))');\n await db.exec('CREATE INDEX IF NOT EXISTS links_dst ON links(dst)');\n await db.exec('CREATE INDEX IF NOT EXISTS links_target_base ON links(target_base)');\n },\n extract,\n // Reparsed docs are diffed in store() instead of wiped here: delete-and-reinsert resets dst\n // to NULL, making every touch-only reparse look like an edge change and recompute PageRank.\n async remove(db, paths, delta) {\n const vanishedSet = new Set(delta.vanished);\n const vanished = paths.filter((p) => vanishedSet.has(p));\n if (vanished.length === 0) return;\n const existingRows = await selectIn(db, 'src', vanished);\n await db.runBatch(\n 'DELETE FROM links WHERE src = ?',\n vanished.map((p) => [p])\n );\n if (existingRows.length > 0) removedWithLinks.set(delta, true);\n },\n async store(db, docs: ExtractedDoc[], delta) {\n const byPath = new Map(docs.map((d) => [d.path, d.extracted as Array<{ target: string; embed: boolean }>]));\n const addedSet = new Set(delta.added);\n const reparsedExisting = docs.map((d) => d.path).filter((p) => !addedSet.has(p));\n\n // Stale rows (target/embed pairs missing from the new parse) are diffed in JS from one\n // bulk SELECT, so this pass costs one query plus one batched DELETE regardless of file count.\n const existingRows = await selectIn(db, 'src', reparsedExisting);\n const staleRows = existingRows.filter((row) => {\n const targets = byPath.get(row.src) ?? [];\n return !targets.some((t) => t.target === row.target && (t.embed ? 1 : 0) === row.embed);\n });\n if (staleRows.length > 0) {\n await db.runBatch(\n 'DELETE FROM links WHERE src = ? AND target = ? AND embed = ?',\n staleRows.map((r) => [r.src, r.target, r.embed])\n );\n removedWithLinks.set(delta, true);\n }\n\n // Cold build: every path is in `added`, so pathSet/byBase cover the same complete tree\n // afterReconcile's large branch would otherwise re-derive; resolve dst here instead.\n const cold = delta.files.length === 0 || delta.added.length === delta.files.length;\n let resolveNew: ((src: string, target: string) => string | null) | undefined;\n if (cold) {\n const pathSet = new Set(delta.files.map((f) => f.relPath));\n const byBase = buildByBase(delta.files);\n resolveNew = (src, target) => resolveTarget(src, target, pathSet, byBase);\n }\n let resolvedLink = false;\n\n // Upsert preserves dst on surviving rows; a cold build resolves new rows, else they start NULL.\n // A same-note anchor gets no target_base, so SQL's `IN` excludes it from resolveIncremental's lookup.\n // Split, unlike the other features: this hook has no remove() pass behind it (see above), so\n // only a path in `added` is guaranteed to have no row yet. The rest genuinely conflict and the\n // upsert is what preserves their `dst`.\n const appendable: unknown[][] = [];\n const upsertRows: unknown[][] = [];\n for (const [path, targets] of byPath) {\n for (const { target, embed } of targets) {\n const targetBase = target.startsWith('#') ? null : baseKey(cleanTarget(target));\n if (!addedSet.has(path)) {\n upsertRows.push([path, target, targetBase, embed ? 1 : 0]);\n continue;\n }\n if (!resolveNew) {\n appendable.push([path, target, targetBase, embed ? 1 : 0]);\n continue;\n }\n const dst = resolveNew(path, target);\n if (dst !== null) resolvedLink = true;\n appendable.push([path, target, targetBase, dst, embed ? 1 : 0]);\n }\n }\n await appendRows(db, 'links', resolveNew ? LINK_COLUMNS_RESOLVED : LINK_COLUMNS, resolveNew ? UPSERT_LINK_SQL_RESOLVED : UPSERT_LINK_SQL, appendable);\n if (upsertRows.length > 0) await db.runBatch(UPSERT_LINK_SQL, upsertRows);\n if (cold) coldResolved.set(delta, resolvedLink);\n },\n async afterReconcile(db, delta) {\n // Any deleted rows mean the edge set shrank -- whether the file vanished or was reparsed\n // down to fewer/no links.\n const removeHadLinks = removedWithLinks.get(delta) ?? false;\n\n // A cold build is the only case a full pass wins. Measured 2026-09-01 on 6,566 notes, resolve\n // time alone: full is flat near 90ms at any churn, incremental 7ms at 10 files and 30ms at 2,000.\n const large = delta.files.length === 0 || delta.added.length === delta.files.length;\n // store() already resolved dst inline on this cold build (same test), so nothing is left to update.\n if (large) {\n delta.linksChanged = (coldResolved.get(delta) ?? false) || removeHadLinks;\n return;\n }\n\n const dstChanged = await resolveIncremental(db, delta);\n delta.linksChanged = dstChanged || removeHadLinks;\n },\n};\n"],"names":["LINK_EDGES_SQL","linkEdges","links","toEdges","parseWikilinkInner","inner","beforeAlias","split","trim","startsWith","length","target","extract","_raw","rawBody","_search","data","body","test","maskRegions","seen","Set","results","add","embed","key","has","push","matchAll","m","index","dest","includes","Object","values","value","Array","isArray","item","exec","cleanTarget","replace","baseKey","path","posix","basename","toLowerCase","resolveTarget","src","pathSet","byBase","clean","fromSrc","normalize","join","dirname","candidate","candidates","get","buildByBase","files","Map","paths","map","f","relPath","sort","a","b","list","set","resolveRows","rows","changed","row","dst","writeResolved","db","runBatch","r","selectIn","column","keys","i","stmt","chunk","slice","prepare","all","resolveIncremental","delta","changedBasenames","p","collect","added","vanished","reparsed","removedWithLinks","WeakMap","coldResolved","LINK_COLUMNS","UPSERT_LINK_SQL","LINK_COLUMNS_RESOLVED","UPSERT_LINK_SQL_RESOLVED","name","schema","remove","vanishedSet","existingRows","filter","store","docs","byPath","addedSet","reparsedExisting","staleRows","cold","resolveNew","resolvedLink","appendable","upsertRows","targets","targetBase","d","extracted","some","t","appendRows","afterReconcile","removeHadLinks","large","dstChanged","linksChanged"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/features/links.ts"],"sourcesContent":["import posix from 'node:path/posix';\nimport type { FileStat } from '../scan/index.ts';\nimport { appendRows } from '../store/shared.ts';\nimport type { Connection } from '../store/types.ts';\nimport { maskRegions } from './fences.ts';\nimport type { ExtractedDoc, Feature, ReconcileDelta } from './types.ts';\n\n// links(src, target, target_base, dst, embed): target as written, target_base its indexed baseKey, dst the resolved path or NULL (a queryable dead link).\n// embed distinguishes `![[x]]`/`` from `[[x]]`/`[](x.md)` -- Obsidian's grain: a target both linked and embedded in one note is two rows.\n\n// Alias stripped after |; a leading # keeps the anchor as the target (self-link needs a\n// heading name), else the anchor splits off. Null = not a link.\nfunction parseWikilinkInner(inner: string): string | null {\n const beforeAlias = inner.split('|')[0].trim();\n if (beforeAlias.startsWith('#')) return beforeAlias.length > 1 ? beforeAlias : null;\n const target = beforeAlias.split('#')[0].trim();\n return target || null;\n}\n\n// A frontmatter value counts only when it is exactly a wikilink (\"[[X]]\") -- mid-string and\n// ![[...]] forms don't count there, per Obsidian's rule (probe-verified).\nfunction extract(_raw: string, rawBody: string, _search?: { title: string; summary: string }, data?: Record<string, unknown>): Array<{ target: string; embed: boolean }> {\n const body = /\\[\\[|\\]\\(/.test(rawBody) ? maskRegions(rawBody) : rawBody;\n const seen = new Set<string>();\n const results: Array<{ target: string; embed: boolean }> = [];\n const add = (target: string, embed: boolean) => {\n const key = `${target}\\0${embed ? '1' : '0'}`;\n if (seen.has(key)) return;\n seen.add(key);\n results.push({ target, embed });\n };\n // To the first ]], as Obsidian parses it, so a heading or alias holding a lone ] still\n // matches; anchor and alias split off in parseWikilinkInner.\n for (const m of body.matchAll(/\\[\\[(.*?)\\]\\]/g)) {\n const target = parseWikilinkInner(m[1]);\n if (target) add(target, body[(m.index ?? 0) - 1] === '!');\n }\n // Any internal destination, not only .md-suffixed: \\](Zektor) resolves like [[Zektor]] and\n // \\](#anchor) is a self-edge. External URLs and titled links (dest stops at whitespace) skip.\n for (const m of body.matchAll(/(!)?\\[[^\\]]*\\]\\(((?:[^()\\s]|\\([^()\\s]*\\))+)(?:\\s+(?:\"[^)]*\"|'[^)]*'))?\\)/g)) {\n const dest = m[2].trim();\n // External: a URI scheme prefix (mailto:, tel:, data:, https:...), protocol-relative\n // //host, a www. shorthand, or a scheme anywhere (the malformed double-paren case).\n if (!dest || dest.includes('://')) continue;\n if (/^([a-z][a-z0-9+.-]*:|\\/\\/|www\\.)/i.test(dest)) continue;\n const target = dest.startsWith('#') ? dest : dest.split('#')[0];\n if (target) add(target, m[1] === '!');\n }\n for (const value of Object.values(data ?? {})) {\n for (const item of Array.isArray(value) ? value : [value]) {\n if (typeof item !== 'string') continue;\n const m = /^\\[\\[(.*)\\]\\]$/.exec(item.trim());\n if (!m) continue;\n const target = parseWikilinkInner(m[1]);\n if (target) add(target, false);\n }\n }\n return results;\n}\n\nfunction cleanTarget(target: string): string {\n return target.replace(/\\\\/g, '/').replace(/^\\.\\//, '');\n}\n\nfunction baseKey(path: string): string {\n return posix.basename(path).replace(/\\.md$/i, '').toLowerCase();\n}\n\n// Obsidian-style: exact relative path (with/without .md), path relative to the linking note's\n// directory, then basename match (shortest path wins ties, verified against a cold-loaded vault).\nfunction resolveTarget(src: string, target: string, pathSet: Set<string>, byBase: Map<string, string[]>): string | null {\n // [[#Heading]]: a same-note anchor, always the note itself -- never depends on other files.\n if (target.startsWith('#')) return src;\n const clean = cleanTarget(target);\n const fromSrc = posix.normalize(posix.join(posix.dirname(src), clean));\n for (const candidate of [clean, `${clean}.md`, fromSrc, `${fromSrc}.md`]) {\n if (pathSet.has(candidate)) return candidate;\n }\n const candidates = byBase.get(baseKey(clean));\n if (!candidates) return null;\n // The linking note itself wins a basename collision (Obsidian resolves to self before the\n // shortest-path rule -- cold-load verified on the hub corpus).\n return candidates.includes(src) ? src : candidates[0];\n}\n\n// Shortest path wins a basename collision; equal lengths fall back to lexicographic, our own\n// deterministic tiebreak for a case Obsidian itself leaves registration-order-dependent.\nfunction buildByBase(files: FileStat[]): Map<string, string[]> {\n const byBase = new Map<string, string[]>();\n const paths = files.map((f) => f.relPath).sort((a, b) => a.length - b.length || (a < b ? -1 : a > b ? 1 : 0));\n for (const path of paths) {\n const key = baseKey(path);\n const list = byBase.get(key);\n if (list) list.push(path);\n else byBase.set(key, [path]);\n }\n return byBase;\n}\n\ninterface LinkRow {\n src: string;\n target: string;\n dst: string | null;\n embed: number;\n}\n\n// resolveTarget applied to `rows`, returning only the rows whose dst changed, so the caller\n// can write them in one runBatch call.\nfunction resolveRows(rows: LinkRow[], pathSet: Set<string>, byBase: Map<string, string[]>): LinkRow[] {\n const changed: LinkRow[] = [];\n for (const row of rows) {\n const dst = resolveTarget(row.src, row.target, pathSet, byBase);\n if (dst !== row.dst) changed.push({ ...row, dst });\n }\n return changed;\n}\n\nasync function writeResolved(db: Connection, rows: LinkRow[]): Promise<void> {\n if (rows.length === 0) return;\n await db.runBatch(\n 'UPDATE links SET dst = ? WHERE src = ? AND target = ?',\n rows.map((r) => [r.dst, r.src, r.target])\n );\n}\n\n// Chunked so a large-but-under-threshold delta never exceeds SQLite's bound-variable limit\n// (SQLITE_MAX_VARIABLE_NUMBER, 32766); harmless headroom on DuckDB, which has no such cap.\nasync function selectIn(db: Connection, column: string, keys: string[]): Promise<LinkRow[]> {\n const rows: LinkRow[] = [];\n for (let i = 0; i < keys.length; i += 500) {\n const chunk = keys.slice(i, i + 500);\n const stmt = await db.prepare(`SELECT src, target, dst, embed FROM links WHERE ${column} IN (${chunk.map(() => '?').join(', ')})`);\n rows.push(...((await stmt.all(...chunk)) as unknown as LinkRow[]));\n }\n return rows;\n}\n\n// Re-resolves only what this reconcile could have touched: re-stored sources, links whose\n// target basename matches an added/vanished file, and links whose dst vanished -- all indexed.\nasync function resolveIncremental(db: Connection, delta: ReconcileDelta): Promise<boolean> {\n const pathSet = new Set(delta.files.map((f) => f.relPath));\n const byBase = buildByBase(delta.files);\n\n const changedBasenames = new Set<string>();\n for (const p of delta.added) changedBasenames.add(baseKey(p));\n for (const p of delta.vanished) changedBasenames.add(baseKey(p));\n\n // \\0 can't appear in a path or target, so the key never collides; a space can.\n const candidates = new Map<string, LinkRow>();\n const collect = (rows: LinkRow[]) => {\n for (const row of rows) candidates.set(`${row.src}\\0${row.target}\\0${row.embed}`, row);\n };\n collect(await selectIn(db, 'src', delta.reparsed));\n collect(await selectIn(db, 'target_base', [...changedBasenames]));\n collect(await selectIn(db, 'dst', delta.vanished));\n\n const changed = resolveRows([...candidates.values()], pathSet, byBase);\n await writeResolved(db, changed);\n return changed.length > 0;\n}\n\n// One edge per (src, target); an embed row is excluded only when the same pair also exists as\n// a link. Self-edges are dropped so PageRank mass is not self-recycled.\nexport const LINK_EDGES_SQL = `SELECT src, dst FROM links WHERE dst IS NOT NULL AND embed = 0 AND src != dst\n UNION ALL\n SELECT src, dst FROM links l WHERE dst IS NOT NULL AND embed = 1 AND src != dst\n AND NOT EXISTS (SELECT 1 FROM links l0 WHERE l0.src = l.src AND l0.target = l.target AND l0.embed = 0)`;\n\nexport function toEdges(rows: Array<{ src: string; dst: string }>): [string, string][] {\n return rows.map((r) => [r.src, r.dst]);\n}\n\n// Resolved edges, for rank (inside reconcile's afterReconcile pass).\nexport async function linkEdges(db: Connection): Promise<[string, string][]> {\n const stmt = await db.prepare(LINK_EDGES_SQL);\n return toEdges((await stmt.all()) as Array<{ src: string; dst: string }>);\n}\n\n// Records whether remove()/store() deleted any link row, since afterReconcile runs after both\n// and dstChanged alone misses the reparsed-to-zero-links case. Keyed on delta so state dies with it.\nconst removedWithLinks = new WeakMap<ReconcileDelta, boolean>();\n\n// Cold build only: whether store() resolved at least one row to a non-null dst, so afterReconcile\n// can report linksChanged without re-reading the table it just wrote.\nconst coldResolved = new WeakMap<ReconcileDelta, boolean>();\n\n// dst stays NULL here on an incremental store (resolution runs afterward); a cold build resolves\n// it inline in store() instead, through the *_RESOLVED column list and SQL below.\nconst LINK_COLUMNS = ['src', 'target', 'target_base', 'embed'];\nconst UPSERT_LINK_SQL = 'INSERT INTO links (src, target, target_base, dst, embed) VALUES (?, ?, ?, NULL, ?) ON CONFLICT(src, target, embed) DO UPDATE SET target_base = excluded.target_base';\nconst LINK_COLUMNS_RESOLVED = ['src', 'target', 'target_base', 'dst', 'embed'];\nconst UPSERT_LINK_SQL_RESOLVED = 'INSERT INTO links (src, target, target_base, dst, embed) VALUES (?, ?, ?, ?, ?) ON CONFLICT(src, target, embed) DO UPDATE SET target_base = excluded.target_base';\n\nexport const links: Feature = {\n name: 'links',\n async schema(db) {\n await db.exec('CREATE TABLE IF NOT EXISTS links (src TEXT, target TEXT, target_base TEXT, dst TEXT, embed INTEGER, PRIMARY KEY (src, target, embed))');\n await db.exec('CREATE INDEX IF NOT EXISTS links_dst ON links(dst)');\n await db.exec('CREATE INDEX IF NOT EXISTS links_target_base ON links(target_base)');\n },\n extract,\n // Reparsed docs are diffed in store() instead of wiped here: delete-and-reinsert resets dst\n // to NULL, making every touch-only reparse look like an edge change and recompute PageRank.\n async remove(db, paths, delta) {\n const vanishedSet = new Set(delta.vanished);\n const vanished = paths.filter((p) => vanishedSet.has(p));\n if (vanished.length === 0) return;\n const existingRows = await selectIn(db, 'src', vanished);\n await db.runBatch(\n 'DELETE FROM links WHERE src = ?',\n vanished.map((p) => [p])\n );\n if (existingRows.length > 0) removedWithLinks.set(delta, true);\n },\n async store(db, docs: ExtractedDoc[], delta) {\n const byPath = new Map(docs.map((d) => [d.path, d.extracted as Array<{ target: string; embed: boolean }>]));\n const addedSet = new Set(delta.added);\n const reparsedExisting = docs.map((d) => d.path).filter((p) => !addedSet.has(p));\n\n // Stale rows (target/embed pairs missing from the new parse) are diffed in JS from one\n // bulk SELECT, so this pass costs one query plus one batched DELETE regardless of file count.\n const existingRows = await selectIn(db, 'src', reparsedExisting);\n const staleRows = existingRows.filter((row) => {\n const targets = byPath.get(row.src) ?? [];\n return !targets.some((t) => t.target === row.target && (t.embed ? 1 : 0) === row.embed);\n });\n if (staleRows.length > 0) {\n await db.runBatch(\n 'DELETE FROM links WHERE src = ? AND target = ? AND embed = ?',\n staleRows.map((r) => [r.src, r.target, r.embed])\n );\n removedWithLinks.set(delta, true);\n }\n\n // Cold build: every path is in `added`, so pathSet/byBase cover the same complete tree\n // afterReconcile's large branch would otherwise re-derive; resolve dst here instead.\n const cold = delta.files.length === 0 || delta.added.length === delta.files.length;\n let resolveNew: ((src: string, target: string) => string | null) | undefined;\n if (cold) {\n const pathSet = new Set(delta.files.map((f) => f.relPath));\n const byBase = buildByBase(delta.files);\n resolveNew = (src, target) => resolveTarget(src, target, pathSet, byBase);\n }\n let resolvedLink = false;\n\n // Upsert preserves dst on surviving rows; a cold build resolves new rows, else they start NULL.\n // A same-note anchor gets no target_base, so SQL's `IN` excludes it from resolveIncremental's lookup.\n // Split, unlike the other features: this hook has no remove() pass behind it (see above), so\n // only a path in `added` is guaranteed to have no row yet. The rest genuinely conflict and the\n // upsert is what preserves their `dst`.\n const appendable: unknown[][] = [];\n const upsertRows: unknown[][] = [];\n for (const [path, targets] of byPath) {\n for (const { target, embed } of targets) {\n const targetBase = target.startsWith('#') ? null : baseKey(cleanTarget(target));\n if (!addedSet.has(path)) {\n upsertRows.push([path, target, targetBase, embed ? 1 : 0]);\n continue;\n }\n if (!resolveNew) {\n appendable.push([path, target, targetBase, embed ? 1 : 0]);\n continue;\n }\n const dst = resolveNew(path, target);\n if (dst !== null) resolvedLink = true;\n appendable.push([path, target, targetBase, dst, embed ? 1 : 0]);\n }\n }\n await appendRows(db, 'links', resolveNew ? LINK_COLUMNS_RESOLVED : LINK_COLUMNS, resolveNew ? UPSERT_LINK_SQL_RESOLVED : UPSERT_LINK_SQL, appendable);\n if (upsertRows.length > 0) await db.runBatch(UPSERT_LINK_SQL, upsertRows);\n if (cold) coldResolved.set(delta, resolvedLink);\n },\n async afterReconcile(db, delta) {\n // Any deleted rows mean the edge set shrank -- whether the file vanished or was reparsed\n // down to fewer/no links.\n const removeHadLinks = removedWithLinks.get(delta) ?? false;\n\n // A cold build is the only case a full pass wins. Measured 2026-09-01 on 6,566 notes, resolve\n // time alone: full is flat near 90ms at any churn, incremental 7ms at 10 files and 30ms at 2,000.\n const large = delta.files.length === 0 || delta.added.length === delta.files.length;\n // store() already resolved dst inline on this cold build (same test), so nothing is left to update.\n if (large) {\n delta.linksChanged = (coldResolved.get(delta) ?? false) || removeHadLinks;\n return;\n }\n\n const dstChanged = await resolveIncremental(db, delta);\n delta.linksChanged = dstChanged || removeHadLinks;\n },\n};\n"],"names":["LINK_EDGES_SQL","linkEdges","links","toEdges","parseWikilinkInner","inner","beforeAlias","split","trim","startsWith","length","target","extract","_raw","rawBody","_search","data","body","test","maskRegions","seen","Set","results","add","embed","key","has","push","matchAll","m","index","dest","includes","Object","values","value","Array","isArray","item","exec","cleanTarget","replace","baseKey","path","posix","basename","toLowerCase","resolveTarget","src","pathSet","byBase","clean","fromSrc","normalize","join","dirname","candidate","candidates","get","buildByBase","files","Map","paths","map","f","relPath","sort","a","b","list","set","resolveRows","rows","changed","row","dst","writeResolved","db","runBatch","r","selectIn","column","keys","i","stmt","chunk","slice","prepare","all","resolveIncremental","delta","changedBasenames","p","collect","added","vanished","reparsed","removedWithLinks","WeakMap","coldResolved","LINK_COLUMNS","UPSERT_LINK_SQL","LINK_COLUMNS_RESOLVED","UPSERT_LINK_SQL_RESOLVED","name","schema","remove","vanishedSet","existingRows","filter","store","docs","byPath","addedSet","reparsedExisting","staleRows","cold","resolveNew","resolvedLink","appendable","upsertRows","targets","targetBase","d","extracted","some","t","appendRows","afterReconcile","removeHadLinks","large","dstChanged","linksChanged"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/features/rank.ts"],"sourcesContent":["import { pagerank } from '../graph/graph.ts';\nimport { linkEdges } from './links.ts';\nimport type { Feature } from './types.ts';\n\n// frontmatter._rank: PageRank over resolved links -- a static \"how load-bearing is this\n// note\" prior. Depends on links (enforced in config.featureEnabled).\n\nexport const rank: Feature = {\n name: 'rank',\n async schema(db) {\n const stmt = await db.prepare('PRAGMA table_info(frontmatter)');\n const columns = (await stmt.all()) as Array<{ name: string }>;\n if (!columns.some((c) => c.name === '_rank')) await db.exec('ALTER TABLE frontmatter ADD COLUMN \"_rank\" REAL');\n },\n async afterReconcile(db, delta) {\n // Only an explicit linksChanged:false skips. Rank also depends on the node set, so any\n // add or vanish recomputes -- otherwise a new linkless note keeps _rank NULL.\n if (delta.linksChanged === false && delta.added.length === 0 && delta.vanished.length === 0) return;\n const pathsStmt = await db.prepare('SELECT \"path\" FROM frontmatter');\n const nodes = ((await pathsStmt.all()) as Array<{ path: string }>).map((r) => r.path);\n const ranks = pagerank(nodes, await linkEdges(db));\n if (ranks.size === 0) return;\n await db.runBatch(\n 'UPDATE frontmatter SET \"_rank\" = ? WHERE \"path\" = ?',\n [...ranks].map(([path, value]) => [value, path])\n );\n },\n};\n"],"names":["rank","name","schema","db","stmt","columns","prepare","all","some","c","exec","afterReconcile","delta","pathsStmt","nodes","ranks","linksChanged","added","length","vanished","map","r","path","linkEdges","pagerank","size","runBatch","value"],"mappings":";;;;+BAOaA;;;eAAAA;;;uBAPY;uBACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMnB,IAAMA,OAAgB;IAC3BC,MAAM;IACAC,QAAN,SAAMA,OAAOC,EAAE;;gBACPC,MACAC;;;;wBADO;;4BAAMF,GAAGG,OAAO,CAAC;;;wBAAxBF,OAAO;wBACI;;4BAAMA,KAAKG,GAAG;;;wBAAzBF,UAAW;6BACb,CAACA,QAAQG,IAAI,CAAC,SAACC;mCAAMA,EAAER,IAAI,KAAK;4BAAhC;;;;wBAA0C;;4BAAME,GAAGO,IAAI,CAAC;;;wBAAd;;;;;;;;QAChD;;IACMC,gBAAN,SAAMA,eAAeR,EAAE,EAAES,KAAK;;gBAItBC,WACAC,OACAC;;;;wBALN,uFAAuF;wBACvF,8EAA8E;wBAC9E,IAAIH,MAAMI,YAAY,KAAK,SAASJ,MAAMK,KAAK,CAACC,MAAM,KAAK,KAAKN,MAAMO,QAAQ,CAACD,MAAM,KAAK,GAAG;;;wBAC3E;;4BAAMf,GAAGG,OAAO,CAAC;;;wBAA7BO,YAAY;wBACF;;4BAAMA,UAAUN,GAAG;;;wBAA7BO,QAAQ,AAAE,cAAmDM,GAAG,CAAC,SAACC;mCAAMA,EAAEC,IAAI;;;4BAC7DR;;wBAAO;;4BAAMS,IAAAA,kBAAS,EAACpB;;;wBAAxCY,QAAQS,iBAAQ;4BAAQ;;wBAC9B,IAAIT,MAAMU,IAAI,KAAK,GAAG;;;wBACtB;;4BAAMtB,GAAGuB,QAAQ,CACf,uDACA,AAAC,qBAAGX,OAAOK,GAAG,CAAC;yEAAEE,kBAAMK;uCAAW;oCAACA;oCAAOL;iCAAK;;;;wBAFjD;;;;;;QAIF;;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/features/sections.ts"],"sourcesContent":["import type { Block } from '../chunk/index.ts';\nimport { estimateTokens, parse } from '../chunk/index.ts';\nimport { countLines } from '../scan/frontmatter.ts';\nimport { appendRows } from '../store/shared.ts';\nimport type { Feature } from './types.ts';\n\n// sections(path, idx, level, heading, start_line, end_line, tokens): the heading outline,\n// 1-indexed over the raw file so a row is a direct Read range; tokens is estimateTokens (D5), CJK-aware.\n\nexport interface Section {\n level: number;\n heading: string;\n startLine: number;\n endLine: number;\n tokens: number;\n}\n\n// Heading blocks parse() already found (markdown-it/CommonMark fences), offset back onto the raw file;\n// a section runs to just before the next heading, or EOF.\nfunction sectionsFromBlocks(blocks: Block[], raw: string, body: string): Section[] {\n const rawLines = raw.split('\\n');\n const offset = rawLines.length - countLines(body);\n const found: Section[] = blocks.filter((b) => b.type === 'heading').map((b) => ({ level: b.depth ?? 1, heading: (b.text ?? '').trim(), startLine: b.startLine + offset, endLine: rawLines.length, tokens: 0 }));\n for (let s = 0; s < found.length; s++) {\n if (s + 1 < found.length) found[s].endLine = found[s + 1].startLine - 1;\n const text = rawLines.slice(found[s].startLine - 1, found[s].endLine).join('\\n');\n found[s].tokens = Math.ceil(estimateTokens(text));\n }\n return found;\n}\n\nconst SECTION_COLUMNS = ['path', 'idx', 'level', 'heading', 'start_line', 'end_line', 'tokens'];\n\nexport const sections: Feature = {\n name: 'sections',\n async schema(db) {\n await db.exec(`CREATE TABLE IF NOT EXISTS sections (\"path\" TEXT, idx INTEGER, level INTEGER, heading TEXT, start_line INTEGER, end_line INTEGER, tokens INTEGER, PRIMARY KEY (\"path\", idx))`);\n },\n extract(raw, body, _search, _data, _cfg, blocks) {\n return sectionsFromBlocks(blocks ?? parse(body), raw, body);\n },\n async remove(db, paths) {\n if (paths.length === 0) return;\n await db.runBatch(\n 'DELETE FROM sections WHERE \"path\" = ?',\n paths.map((p) => [p])\n );\n },\n async store(db, docs) {\n const rows: unknown[][] = [];\n for (const { path, extracted } of docs) (extracted as Section[]).forEach((s, idx) => rows.push([path, idx, s.level, s.heading, s.startLine, s.endLine, s.tokens]));\n // DO NOTHING, not a bare INSERT: reconcile's added/touched split is decided before this\n // write's lock, so a path called \"added\" here can already have this row from a concurrent\n // reconcile that committed first -- same file, same parse, same row. A store with an append\n // path has no second writer, and remove() cleared every touched path above, so it skips the guard.\n await appendRows(db, 'sections', SECTION_COLUMNS, 'INSERT INTO sections (\"path\", idx, level, heading, start_line, end_line, tokens) VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT(\"path\", idx) DO NOTHING', rows);\n },\n};\n"],"names":["sections","sectionsFromBlocks","blocks","raw","body","rawLines","split","offset","length","countLines","found","filter","b","type","map","level","depth","heading","text","trim","startLine","endLine","tokens","s","slice","join","Math","ceil","estimateTokens","SECTION_COLUMNS","name","schema","db","exec","extract","_search","_data","_cfg","parse","remove","paths","runBatch","p","store","docs","rows","path","extracted","forEach","idx","push","appendRows"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/features/tags.ts"],"sourcesContent":["import { appendRows } from '../store/shared.ts';\nimport { maskRegions } from './fences.ts';\nimport type { Feature } from './types.ts';\n\n// tags(path, tag): Obsidian's file.tags grain -- frontmatter list/string tags plus inline\n// #tags, deduplicated, source not distinguished. Nested tags store full (book/scifi); `tag = 'book' OR tag LIKE 'book/%'` matches the parent too.\n\n// Obsidian treats [[#Heading]] as a same-note link, not a tag.\nconst WIKILINK_RE = /\\[\\[.*?\\]\\]/g; // to the first ]], so a heading holding a lone ] still masks\n// Obsidian doesn't read tags inside HTML markup.\nconst HTML_TAG_RE = /<\\/?[a-zA-Z][^>]*>/g; // tag-shaped only: a comparison's `< 5` must not open a span\n// Anchors on start-of-line or a preceding whitespace/(/[ so `a#b` and URL fragments don't count.\nconst INLINE_TAG_RE = /(?:^|[\\s([])#([\\p{L}\\p{N}_/-]+)/gu;\n// A markdown link destination `](...)` -- `[text](#anchor)` is a same-page link, not a tag.\nconst LINK_DEST_RE = /\\]\\((?:[^()]|\\([^()]*\\))*\\)/g; // one paren-nesting level, as CommonMark destinations allow: (https://x/a_(b)#frag)\n\n// Strips a leading # (frontmatter entries may carry one) and a trailing /; rejects an\n// all-digit result -- a tag needs at least one non-digit character.\nfunction normalizeTag(raw: string): string | null {\n const stripped = raw.replace(/^#/, '').replace(/\\/+$/, '');\n if (!stripped || /^\\d+$/.test(stripped)) return null;\n return stripped;\n}\n\n// data.tags: a YAML list (Obsidian also accepts a bare string). Null members and non-string\n// members are skipped rather than throwing -- `tags:\\n -` parses to [null].\nfunction frontmatterTags(data?: Record<string, unknown>): string[] {\n const raw = data?.tags;\n const list = Array.isArray(raw) ? raw : typeof raw === 'string' ? [raw] : [];\n const found: string[] = [];\n for (const item of list) {\n if (typeof item !== 'string') continue;\n const tag = normalizeTag(item);\n if (tag) found.push(tag);\n }\n return found;\n}\n\n// #tag tokens outside the regions maskRegions() masks (fences, code spans, wikilinks, HTML,\n// comments, link destinations); this loop only does per-line tag extraction.\nfunction inlineTags(body: string): string[] {\n const found: string[] = [];\n for (const line of maskRegions(body).split('\\n')) {\n if (!line.includes('#')) continue; // most lines; skip the regex work\n let cleaned = line;\n if (cleaned.includes('[[')) cleaned = cleaned.replace(WIKILINK_RE, (m) => ' '.repeat(m.length));\n if (cleaned.includes('](')) cleaned = cleaned.replace(LINK_DEST_RE, (m) => ' '.repeat(m.length));\n if (cleaned.includes('<')) cleaned = cleaned.replace(HTML_TAG_RE, (m) => ' '.repeat(m.length));\n for (const m of cleaned.matchAll(INLINE_TAG_RE)) {\n const tag = normalizeTag(m[1]);\n if (tag) found.push(tag);\n }\n }\n return found;\n}\n\nfunction extract(_raw: string, body: string, _search?: { title: string; summary: string }, data?: Record<string, unknown>): string[] {\n return [...new Set([...frontmatterTags(data), ...inlineTags(body)])].sort();\n}\n\nexport const tags: Feature = {\n name: 'tags',\n async schema(db) {\n await db.exec('CREATE TABLE IF NOT EXISTS tags (\"path\" TEXT, tag TEXT, PRIMARY KEY (\"path\", tag))');\n await db.exec('CREATE INDEX IF NOT EXISTS tags_tag ON tags(tag)');\n },\n extract,\n // Blanket clear-then-reinsert (store() always writes the full found list back), so remove()\n // covers vanished and reparsed files without per-file NOT IN diffing, which cannot be one statement shared across files.\n async remove(db, paths) {\n if (paths.length === 0) return;\n await db.runBatch(\n 'DELETE FROM tags WHERE \"path\" = ?',\n paths.map((p) => [p])\n );\n },\n async store(db, docs) {\n const rows: unknown[][] = [];\n for (const { path, extracted } of docs) for (const tag of extracted as string[]) rows.push([path, tag]);\n // OR IGNORE guards the same concurrent-reconcile race sections.ts documents; remove() cleared\n // every touched path above, so a store with an append path needs no guard.\n await appendRows(db, 'tags', ['path', 'tag'], 'INSERT OR IGNORE INTO tags (\"path\", tag) VALUES (?, ?)', rows);\n },\n};\n"],"names":["tags","WIKILINK_RE","HTML_TAG_RE","INLINE_TAG_RE","LINK_DEST_RE","normalizeTag","raw","stripped","replace","test","frontmatterTags","data","list","Array","isArray","found","item","tag","push","inlineTags","body","maskRegions","split","line","includes","cleaned","m","repeat","length","matchAll","extract","_raw","_search","Set","sort","name","schema","db","exec","remove","paths","runBatch","map","p","store","docs","rows","path","extracted","appendRows"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/graph/graph.ts"],"sourcesContent":["// Link-graph math: PageRank at reconcile, personalized PageRank at query time. Pure JS, no deps.\n\nexport type Edge = [src: string, dst: string];\n\n// Power iteration. `personal` biases both teleport and dangling mass toward seed nodes;\n// without it this is plain PageRank (uniform base). Returns scores summing to ~1.\nexport function pagerank(nodes: string[], edges: Edge[], opts: { damping?: number; iterations?: number; personal?: Map<string, number> } = {}): Map<string, number> {\n const damping = opts.damping ?? 0.85;\n const iterations = opts.iterations ?? 30;\n const n = nodes.length;\n if (n === 0) return new Map();\n\n const index = new Map(nodes.map((node, i) => [node, i]));\n const out: number[][] = nodes.map(() => []);\n for (const [src, dst] of edges) {\n const si = index.get(src);\n const di = index.get(dst);\n if (si !== undefined && di !== undefined) out[si].push(di);\n }\n\n let base: number[];\n if (opts.personal) {\n base = nodes.map(() => 0);\n let total = 0;\n for (const [node, weight] of opts.personal) {\n const i = index.get(node);\n if (i !== undefined && weight > 0) {\n base[i] = weight;\n total += weight;\n }\n }\n if (total === 0) return new Map(nodes.map((node) => [node, 0]));\n base = base.map((b) => b / total);\n } else {\n base = nodes.map(() => 1 / n);\n }\n\n let rank = [...base];\n for (let iter = 0; iter < iterations; iter++) {\n const next = base.map((b) => (1 - damping) * b);\n let dangling = 0;\n for (let i = 0; i < n; i++) {\n if (out[i].length === 0) {\n dangling += rank[i];\n continue;\n }\n const share = (damping * rank[i]) / out[i].length;\n for (const j of out[i]) next[j] += share;\n }\n for (let i = 0; i < n; i++) next[i] += damping * dangling * base[i];\n rank = next;\n }\n return new Map(nodes.map((node, i) => [node, rank[i]]));\n}\n\n// Connective expansion: walk the graph (undirected -- backlinks relate as much as links)\n// from a seed result set. Answers \"what is linked to the notes that matched\".\nexport function personalizedRank(nodes: string[], edges: Edge[], seeds: Map<string, number>): Map<string, number> {\n const undirected: Edge[] = [];\n for (const [src, dst] of edges) {\n undirected.push([src, dst], [dst, src]);\n }\n return pagerank(nodes, undirected, { damping: 0.7, iterations: 15, personal: seeds });\n}\n"],"names":["pagerank","personalizedRank","nodes","edges","opts","damping","iterations","n","length","Map","index","map","node","i","out","src","dst","si","get","di","undefined","push","base","personal","total","weight","b","rank","iter","next","dangling","share","j","seeds","undirected"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/graph/traverse.ts"],"sourcesContent":["// Frontier-by-frontier BFS through a temp visited table, one indexed anti-join per ring: a\n// local question touches a neighborhood, never the whole edge list.\n\nimport { serialQuery } from '../lib/serial-query.ts';\nimport type { Store } from '../store/types.ts';\n\ntype Direction = 'forward' | 'reverse' | 'both';\n\nexport interface FindPathOptions {\n directed?: boolean;\n maxDepth?: number;\n allowed?: Set<string>;\n}\n\nasync function resetVisited(store: Store): Promise<void> {\n await store.exec('DROP TABLE IF EXISTS temp.visited');\n await store.exec('CREATE TEMP TABLE visited (path TEXT PRIMARY KEY, depth INTEGER NOT NULL, pred TEXT)');\n}\n\n// Materializes the caller-resolved scope Set into a temp table so it joins like any other\n// indexed column. `extra`, when given, is always in scope -- findPath's `to` endpoint.\nasync function setupAllowed(store: Store, allowed: Set<string>, extra?: string): Promise<void> {\n const all = new Set(allowed);\n if (extra !== undefined) all.add(extra);\n await store.exec('DROP TABLE IF EXISTS temp.allowed_nodes');\n await store.exec('CREATE TEMP TABLE allowed_nodes (path TEXT PRIMARY KEY)');\n await store.runBatch(\n 'INSERT INTO allowed_nodes (path) VALUES (?)',\n [...all].map((p) => [p])\n );\n}\n\n// Only resolved links (dst IS NOT NULL) are followed, in either direction.\nfunction candidateSelect(direction: Direction): string {\n const forward = 'SELECT l.dst AS path, l.src AS pred FROM links l JOIN visited v ON v.path = l.src AND v.depth = ?1 WHERE l.dst IS NOT NULL';\n const reverse = 'SELECT l.src AS path, l.dst AS pred FROM links l JOIN visited v ON v.path = l.dst AND v.depth = ?1 WHERE l.dst IS NOT NULL';\n if (direction === 'forward') return forward;\n if (direction === 'reverse') return reverse;\n return `${forward} UNION ALL ${reverse}`;\n}\n\n// One ring: candidates adjacent to the previous ring's frontier (?1), anti-joined against\n// everything already visited, optionally filtered to the allowed set, inserted at the new depth (?2); RETURNING gives what this ring newly reached.\nfunction ringSql(direction: Direction, hasAllowed: boolean): string {\n return `\nINSERT INTO visited (path, depth, pred)\nSELECT cand.path, ?2, MIN(cand.pred)\nFROM (${candidateSelect(direction)}) cand\nWHERE NOT EXISTS (SELECT 1 FROM visited v2 WHERE v2.path = cand.path)\n${hasAllowed ? 'AND EXISTS (SELECT 1 FROM allowed_nodes a WHERE a.path = cand.path)' : ''}\nGROUP BY cand.path\nORDER BY cand.path\nRETURNING path`;\n}\n\nasync function reconstructPath(store: Store, to: string): Promise<string[]> {\n const lookup = await store.prepare('SELECT pred FROM visited WHERE path = ?');\n const path: string[] = [];\n let cur: string | null = to;\n while (cur !== null) {\n path.push(cur);\n const row = (await lookup.get(cur)) as { pred: string | null } | undefined;\n cur = row ? row.pred : null;\n }\n return path.reverse();\n}\n\n// One BFS from `from`, tracking a predecessor per node. Undirected by default, matching\n// personalizedRank; null when `to` is unreached within `maxDepth`.\nexport function findPath(store: Store, from: string, to: string, opts: FindPathOptions = {}): Promise<string[] | null> {\n return serialQuery(store, () => store.transaction(() => findPathInSnapshot(store, from, to, opts)));\n}\n\n// Internal entry for the scoped command wrapper, whose transaction also owns endpoint resolution\n// and scope reads. Direct graph callers use findPath() above and receive the same snapshot rule.\nexport async function findPathInSnapshot(store: Store, from: string, to: string, opts: FindPathOptions): Promise<string[] | null> {\n if (from === to) return [from];\n\n const direction: Direction = opts.directed ? 'forward' : 'both';\n const maxDepth = opts.maxDepth ?? Infinity;\n if (maxDepth <= 0) return null;\n\n await resetVisited(store);\n const insertStart = await store.prepare('INSERT INTO visited (path, depth, pred) VALUES (?, 0, NULL)');\n await insertStart.run(from);\n if (opts.allowed) await setupAllowed(store, opts.allowed, to);\n\n const stmt = await store.prepare(ringSql(direction, !!opts.allowed));\n for (let ring = 1; ring <= maxDepth; ring++) {\n const rows = (await stmt.all(ring - 1, ring)) as Array<{ path: string }>;\n if (rows.length === 0) break;\n if (rows.some((row) => row.path === to)) return reconstructPath(store, to);\n }\n return null;\n}\n"],"names":["findPath","findPathInSnapshot","resetVisited","store","exec","setupAllowed","allowed","extra","all","Set","undefined","add","runBatch","map","p","candidateSelect","direction","forward","reverse","ringSql","hasAllowed","reconstructPath","to","lookup","path","cur","row","prepare","push","get","pred","from","opts","serialQuery","transaction","maxDepth","insertStart","stmt","ring","rows","directed","Infinity","run","length","some"],"mappings":"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"}
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/index.ts"],"sourcesContent":["// Public library API. Deliberately small: every export is a stability promise;\n// internals (feature registry, graph, scan, meta) stay module-private.\n\nexport type { PathOptions, Peek, PeekOptions, PeekSection, PresetCoverage, RelatedOptions, RelatedResult, SearchOptions, SearchResult, SearchResultVia, SearchSignalContribution, TreeMap, TreeMapField, TreeMapHub, TreeMapRecent } from './commands/index.ts';\nexport { findPath, mapTree, peek, presetCoverage, relatedNotes, search } from './commands/index.ts';\nexport type { Config, EmbedConfig, FeatureName, InitOverrides, LoadConfigOptions, Preset, ResolvedConfig, SavedQuery, SavedSearch, SearchOverrides, SignalName, SignalWeights, StoreName } from './config/index.ts';\nexport { CONFIG_FILENAME, initConfig, loadConfig, migrateConfig, SIGNAL_NAMES, STATE_DIR, STORE_NAMES, SUPPORTED_CONFIG_VERSION } from './config/index.ts';\nexport type { SenseErrorCode } from './errors.ts';\nexport { SenseError } from './errors.ts';\nexport type { Format, Row, RowFormat } from './output/output.ts';\nexport { printRows } from './output/output.ts';\nexport type { BuildOptions, BuildResult, OpenOptions, OpenResult, Stages } from './store/index.ts';\nexport { buildIndex as build, CAPABILITY_NAMES, clearCache, openStore as open } from './store/index.ts';\nexport type { Capability, DocumentStore, FieldStat, LexicalHit, LexicalIndex, LexicalQueryOptions, RawStatement, RunResult, SqlSession, Statement, Store, VectorCandidate, VectorSimilar, VectorStore, VectorWriteRow } from './store/types.ts';\n\nexport type { WatchEvent, WatchOptions } from './watch.ts';\nexport { runWatch } from './watch.ts';\n"],"names":["CAPABILITY_NAMES","CONFIG_FILENAME","SIGNAL_NAMES","STATE_DIR","STORE_NAMES","SUPPORTED_CONFIG_VERSION","SenseError","build","buildIndex","clearCache","findPath","initConfig","loadConfig","mapTree","migrateConfig","open","openStore","peek","presetCoverage","printRows","relatedNotes","runWatch","search"],"mappings":"AAAA,+EAA+E;AAC/E,uEAAuE;;;;;;;;;;;;QAWzCA;eAAAA,0BAAgB;;QANrCC;eAAAA,yBAAe;;QAAyCC;eAAAA,sBAAY;;QAAEC;eAAAA,mBAAS;;QAAEC;eAAAA,qBAAW;;QAAEC;eAAAA,kCAAwB;;QAEtHC;eAAAA,oBAAU;;QAIIC;eAAdC,oBAAU;;QAA6BC;eAAAA,oBAAU;;QARjDC;eAAAA,iBAAQ;;QAESC;eAAAA,oBAAU;;QAAEC;eAAAA,oBAAU;;QAF7BC;eAAAA,gBAAO;;QAEwBC;eAAAA,uBAAa;;QAMUC;eAAbC,mBAAS;;QARzCC;eAAAA,aAAI;;QAAEC;eAAAA,uBAAc;;QAMvCC;eAAAA,mBAAS;;QANgCC;eAAAA,qBAAY;;QAYrDC;eAAAA,iBAAQ;;QAZ+CC;eAAAA,eAAM;;;uBAAQ;wBAEyD;wBAE5G;wBAED;wBAE2D;uBAI5D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/lib/atomic-write.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { renameSync, unlinkSync, writeFileSync } from 'node:fs';\n\n// Stage-then-swap: write beside the target, then rename over it. A crash or full disk mid-write\n// leaves the target untouched instead of truncated. Matches embed/store.ts's model-download idiom.\nexport function writeFileAtomic(path: string, data: string | Buffer): void {\n const tmp = `${path}.${randomUUID()}.part`;\n let staged = false;\n try {\n writeFileSync(tmp, data, { flag: 'wx' });\n staged = true;\n renameSync(tmp, path);\n } catch (err) {\n // An exclusive-create collision belongs to another writer; never remove its staging file.\n if (staged || !(err instanceof Error && 'code' in err && err.code === 'EEXIST')) {\n try {\n unlinkSync(tmp);\n } catch {\n // best-effort cleanup; the original error below is what matters\n }\n }\n throw err;\n }\n}\n"],"names":["writeFileAtomic","path","data","tmp","randomUUID","staged","writeFileSync","flag","renameSync","err","Error","code","unlinkSync"],"mappings":";;;;+BAKgBA;;;eAAAA;;;0BALW;sBAC2B;;;;;;;AAI/C,SAASA,gBAAgBC,IAAY,EAAEC,IAAqB;IACjE,IAAMC,MAAM,AAAC,GAAUC,OAARH,MAAK,KAAgB,OAAbG,IAAAA,sBAAU,KAAG;IACpC,IAAIC,SAAS;IACb,IAAI;QACFC,IAAAA,qBAAa,EAACH,KAAKD,MAAM;YAAEK,MAAM;QAAK;QACtCF,SAAS;QACTG,IAAAA,kBAAU,EAACL,KAAKF;IAClB,EAAE,OAAOQ,KAAK;QACZ,0FAA0F;QAC1F,IAAIJ,UAAU,CAAEI,CAAAA,AAAG,YAAHA,KAAeC,UAAS,UAAUD,OAAOA,IAAIE,IAAI,KAAK,QAAO,GAAI;YAC/E,IAAI;gBACFC,IAAAA,kBAAU,EAACT;YACb,EAAE,eAAM;YACN,gEAAgE;YAClE;QACF;QACA,MAAMM;IACR;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/lib/guarded-tick.ts"],"sourcesContent":["// Wraps an async interval tick so a rejection (e.g. a store closed mid-await) never\n// escapes as an unhandled rejection, and so a skip() guard can suppress the call entirely.\nexport function guardedTick(fn: () => Promise<void>, skip: () => boolean): () => void {\n return () => {\n if (skip()) return;\n fn().catch(() => {});\n };\n}\n"],"names":["guardedTick","fn","skip","catch"],"mappings":"AAAA,oFAAoF;AACpF,2FAA2F;;;;;+BAC3EA;;;eAAAA;;;AAAT,SAASA,YAAYC,EAAuB,EAAEC,IAAmB;IACtE,OAAO;QACL,IAAIA,QAAQ;QACZD,KAAKE,KAAK,CAAC,YAAO;IACpB;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/lib/serial-query.ts"],"sourcesContent":["const pending = new WeakMap<object, Promise<void>>();\n\n// High-level queries share temporary tables and transaction state on a handle.\n// Raw SQL and handle closure remain caller-owned and must await these queries.\nexport function serialQuery<T>(handle: object, query: () => Promise<T>): Promise<T> {\n const result = (pending.get(handle) ?? Promise.resolve()).then(query);\n const settled = result.then(\n () => {},\n () => {}\n );\n pending.set(handle, settled);\n void settled.then(() => {\n if (pending.get(handle) === settled) pending.delete(handle);\n });\n return result;\n}\n"],"names":["serialQuery","pending","WeakMap","handle","query","result","get","Promise","resolve","then","settled","set","delete"],"mappings":";;;;+BAIgBA;;;eAAAA;;;AAJhB,IAAMC,UAAU,IAAIC;AAIb,SAASF,YAAeG,MAAc,EAAEC,KAAuB;QACpDH;IAAhB,IAAMI,SAAS,EAACJ,eAAAA,QAAQK,GAAG,CAACH,qBAAZF,0BAAAA,eAAuBM,QAAQC,OAAO,IAAIC,IAAI,CAACL;IAC/D,IAAMM,UAAUL,OAAOI,IAAI,CACzB,YAAO,GACP,YAAO;IAETR,QAAQU,GAAG,CAACR,QAAQO;IACpB,KAAKA,QAAQD,IAAI,CAAC;QAChB,IAAIR,QAAQK,GAAG,CAACH,YAAYO,SAAST,QAAQW,MAAM,CAACT;IACtD;IACA,OAAOE;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/lib/watch-notification.ts"],"sourcesContent":["import { STATE_DIR } from '../config/types.ts';\n\nexport function shouldReconcileWatchNotification(filename: string | Buffer | null): boolean {\n return typeof filename !== 'string' || !filename.startsWith(STATE_DIR);\n}\n"],"names":["shouldReconcileWatchNotification","filename","startsWith","STATE_DIR"],"mappings":";;;;+BAEgBA;;;eAAAA;;;uBAFU;AAEnB,SAASA,iCAAiCC,QAAgC;IAC/E,OAAO,OAAOA,aAAa,YAAY,CAACA,SAASC,UAAU,CAACC,kBAAS;AACvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/lib/worker-file.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\n\nlet packageRoot: string | undefined;\n\n// Workers load emitted CommonJS because a fresh worker thread does not inherit the source TS loader.\n// Resolve the package lazily so callers that never spawn a worker do no filesystem work here.\nexport function resolveWorkerFile(name: string): string {\n if (!packageRoot) {\n const load = createRequire(import.meta.url);\n for (const rel of ['..', '../..', '../../..']) {\n try {\n if ((load(`${rel}/package.json`) as { name?: string }).name === 'sensemaking') {\n packageRoot = dirname(load.resolve(`${rel}/package.json`));\n break;\n }\n } catch {}\n }\n }\n if (!packageRoot) throw new Error(`cannot locate the sensemaking package root, so the ${name} worker cannot be found; run npm run build`);\n return join(packageRoot, 'dist', 'cjs', 'workers', `${name}.js`);\n}\n"],"names":["resolveWorkerFile","packageRoot","name","load","createRequire","rel","dirname","resolve","Error","join"],"mappings":";;;;+BAOgBA;;;eAAAA;;;0BAPc;wBACA;AAE9B,IAAIC;AAIG,SAASD,kBAAkBE,IAAY;IAC5C,IAAI,CAACD,aAAa;QAChB,IAAME,OAAOC,IAAAA,yBAAa,EAAC;QAC3B,gBAAkB,QAAA;YAAC;YAAM;YAAS;SAAW,OAA3B,mBAA6B;gBAApCC,MAAO;YAChB,IAAI;gBACF,IAAI,AAACF,KAAK,AAAC,GAAM,OAAJE,KAAI,kBAAsCH,IAAI,KAAK,eAAe;oBAC7ED,cAAcK,IAAAA,iBAAO,EAACH,KAAKI,OAAO,CAAC,AAAC,GAAM,OAAJF,KAAI;oBAC1C;gBACF;YACF,EAAE,eAAM,CAAC;QACX;IACF;IACA,IAAI,CAACJ,aAAa,MAAM,IAAIO,MAAM,AAAC,sDAA0D,OAALN,MAAK;IAC7F,OAAOO,IAAAA,cAAI,EAACR,aAAa,QAAQ,OAAO,WAAW,AAAC,GAAO,OAALC,MAAK;AAC7D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/output/column-hint.ts"],"sourcesContent":["// A frontmatter key with punctuation (`plugin-id`, `a.b`) is a real column, but unquoted in SQL\n// it parses as an expression; this maps SQLite's/DuckDB's fragment error back to the real column.\n\nfunction startsWithBoundary(name: string, prefix: string): boolean {\n return name.length > prefix.length && name.startsWith(prefix) && /\\W/.test(name[prefix.length]);\n}\n\n// columns: the tree's frontmatter columns (store.docs.columns()), read by the caller so this\n// stays a pure function rather than a store dependency.\nexport function columnHint(columns: string[], err: Error): Error {\n const match = /no such column: (\\S+)|Referenced column \"([^\"]+)\" not found in FROM clause|Referenced table \"([^\"]+)\" not found/.exec(err.message);\n if (!match) return err;\n const token = match[1] ?? match[2] ?? match[3];\n // `f.plugin` -> `plugin`; left as-is when there's no leading alias segment, so a column\n // literally named `a.b` still matches via the full-token check below.\n const aliasStripped = token.replace(/^[A-Za-z_]\\w*\\./, '');\n const forms = new Set([token, aliasStripped]);\n const candidates = new Set<string>();\n for (const name of columns) {\n for (const form of forms) {\n if (name === form || startsWithBoundary(name, form)) candidates.add(name);\n }\n }\n if (candidates.size === 0) return err;\n const quoted = [...candidates].map((name) => `\"${name.split('\"').join('\"\"')}\"`).join(', ');\n return new Error(`${err.message} -- ${quoted} needs double quotes in SQL: unquoted, the engine parses the punctuation as an operator or a qualifier, not part of a column name.`);\n}\n"],"names":["columnHint","startsWithBoundary","name","prefix","length","startsWith","test","columns","err","match","exec","message","token","aliasStripped","replace","forms","Set","candidates","form","add","size","quoted","map","split","join","Error"],"mappings":";;;;+BASgBA;;;eAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAThB,gGAAgG;AAChG,kGAAkG;AAElG,SAASC,mBAAmBC,IAAY,EAAEC,MAAc;IACtD,OAAOD,KAAKE,MAAM,GAAGD,OAAOC,MAAM,IAAIF,KAAKG,UAAU,CAACF,WAAW,KAAKG,IAAI,CAACJ,IAAI,CAACC,OAAOC,MAAM,CAAC;AAChG;AAIO,SAASJ,WAAWO,OAAiB,EAAEC,GAAU;QAGxCC,MAAAA;IAFd,IAAMA,QAAQ,kHAAkHC,IAAI,CAACF,IAAIG,OAAO;IAChJ,IAAI,CAACF,OAAO,OAAOD;IACnB,IAAMI,SAAQH,QAAAA,UAAAA,KAAK,CAAC,EAAE,cAARA,qBAAAA,UAAYA,KAAK,CAAC,EAAE,cAApBA,kBAAAA,OAAwBA,KAAK,CAAC,EAAE;IAC9C,wFAAwF;IACxF,sEAAsE;IACtE,IAAMI,gBAAgBD,MAAME,OAAO,CAAC,mBAAmB;IACvD,IAAMC,QAAQ,IAAIC,IAAI;QAACJ;QAAOC;KAAc;IAC5C,IAAMI,aAAa,IAAID;QAClB,kCAAA,2BAAA;;QAAL,QAAK,YAAcT,4BAAd,SAAA,6BAAA,QAAA,yBAAA,iCAAuB;YAAvB,IAAML,OAAN;gBACE,mCAAA,4BAAA;;gBAAL,QAAK,aAAca,0BAAd,UAAA,8BAAA,SAAA,0BAAA,kCAAqB;oBAArB,IAAMG,OAAN;oBACH,IAAIhB,SAASgB,QAAQjB,mBAAmBC,MAAMgB,OAAOD,WAAWE,GAAG,CAACjB;gBACtE;;gBAFK;gBAAA;;;yBAAA,8BAAA;wBAAA;;;wBAAA;8BAAA;;;;QAGP;;QAJK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAKL,IAAIe,WAAWG,IAAI,KAAK,GAAG,OAAOZ;IAClC,IAAMa,SAAS,AAAC,qBAAGJ,YAAYK,GAAG,CAAC,SAACpB;eAAS,AAAC,IAA8B,OAA3BA,KAAKqB,KAAK,CAAC,KAAKC,IAAI,CAAC,OAAM;OAAIA,IAAI,CAAC;IACrF,OAAO,IAAIC,MAAM,AAAC,GAAoBJ,OAAlBb,IAAIG,OAAO,EAAC,QAAa,OAAPU,QAAO;AAC/C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/output/output.ts"],"sourcesContent":["import type { TreeMap } from '../commands/map.ts';\nimport type { Peek } from '../commands/peek.ts';\n\n// rows -> table (default) | json | csv\n\nexport type Row = Record<string, unknown>;\n\n// map/peek/status/path render structures rather than a row set, so csv has nothing to mean\n// there; the commands that emit rows take RowFormat.\nexport type Format = 'table' | 'json';\nexport type RowFormat = Format | 'csv';\n\n// Warned about on stderr (keeps --format json stdout machine-readable), never truncated.\nconst OVERSIZE_BYTES = 50_000;\n\n// Flatten embedded newlines so they can't break table column alignment; JSON output keeps them as-is.\nfunction cell(value: unknown): string {\n return String(value ?? '').replace(/\\s*\\n\\s*/g, ' ');\n}\n\n// RFC 4180, deliberately not cell(): csv is the redirect-to-file format, so it keeps every\n// character, newlines included; what it cannot carry (NULL vs empty, types) is what json is for.\n// An array (e.g. snippets) joins with the one delimiter our content provably cannot contain,\n// inside the quoted field newlines already trigger (DESIGN.md \"Rendering a list of snippets\").\nfunction csvField(value: unknown): string {\n const text = value === null || value === undefined ? '' : Array.isArray(value) ? value.join('\\n') : String(value);\n return /[\"\\r\\n,]/.test(text) ? `\"${text.replace(/\"/g, '\"\"')}\"` : text;\n}\n\nfunction csvLine(values: unknown[]): string {\n return values.map(csvField).join(',');\n}\n\nfunction warnOversize(bytes: number, rowCount: number): void {\n if (bytes <= OVERSIZE_BYTES) return;\n console.warn(`warning: result is ${Math.round(bytes / 1000)} KB across ${rowCount} row(s); consider a LIMIT, fewer columns, snippet() instead of whole values, or --format csv redirected to a file`);\n}\n\n// JSON.stringify throws on BigInt, and stores return int64 as BigInt (DuckDB does): a value\n// that fits a safe integer stays a number, a larger one becomes its decimal string.\nconst MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);\nconst bigintSafe = (_key: string, value: unknown): unknown => (typeof value === 'bigint' ? (value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value.toString()) : value);\n\nexport function stringifyJson(value: unknown, indent?: number): string {\n return JSON.stringify(value, bigintSafe, indent);\n}\n\nexport function printRows(rows: Row[], format: RowFormat, columns?: string[]): void {\n if (format === 'csv') {\n // Names from a row wherever there is one: the statement's column list keeps duplicates the\n // row collapsed. Nothing at all with no row and no columns -- a bare newline is an empty record.\n const names = rows.length > 0 ? Object.keys(rows[0]) : [...new Set(columns ?? [])];\n if (names.length === 0) return;\n const rendered = [csvLine(names), ...rows.map((row) => csvLine(names.map((name) => row[name])))].join('\\n');\n console.log(rendered);\n // Bytes, not code units -- CJK is 3 bytes per character.\n warnOversize(Buffer.byteLength(rendered), rows.length);\n return;\n }\n const rendered = renderRows(rows, format);\n console.log(rendered);\n warnOversize(Buffer.byteLength(rendered), rows.length);\n}\n\n// Streaming counterpart for the one unbounded caller, `sense sql`: the result is never held as\n// rows and again as a rendered string. Table buffers (column width depends on the last row); json/csv write row by row.\nexport async function printRowStream(rows: AsyncIterable<Row>, format: RowFormat, columns: string[]): Promise<void> {\n const iterator = rows[Symbol.asyncIterator]();\n // One step before any write. FTS5 parses a MATCH expression at step time rather than at\n // prepare time, so a bad search string throws here, with stdout still clean for the error.\n const first = await iterator.next();\n const rest: AsyncIterable<Row> = { [Symbol.asyncIterator]: () => iterator };\n\n if (format === 'table') {\n const collected: Row[] = first.done ? [] : [first.value];\n for await (const row of rest) collected.push(row);\n printRows(collected, format, columns);\n return;\n }\n\n let bytes = 0;\n let rowCount = 0;\n const write = (text: string): void => {\n // Bytes, not code units -- CJK is 3 bytes per character.\n bytes += Buffer.byteLength(text);\n process.stdout.write(text);\n };\n\n if (format === 'json') {\n // Byte-identical to JSON.stringify(rows, null, 2) + newline: each row re-indented one\n // level, comma-joined, inside the array brackets written here.\n const indent = (row: Row) =>\n stringifyJson(row, 2)\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n if (first.done) {\n write('[]\\n');\n } else {\n write('[\\n');\n write(indent(first.value));\n rowCount = 1;\n for await (const row of rest) {\n write(',\\n');\n write(indent(row));\n rowCount++;\n }\n write('\\n]\\n');\n }\n } else if (first.done) {\n const names = [...new Set(columns)];\n if (names.length > 0) write(`${csvLine(names)}\\n`);\n } else {\n const names = Object.keys(first.value);\n write(`${csvLine(names)}\\n`);\n write(`${csvLine(names.map((name) => first.value[name]))}\\n`);\n rowCount = 1;\n for await (const row of rest) {\n write(`${csvLine(names.map((name) => row[name]))}\\n`);\n rowCount++;\n }\n }\n warnOversize(bytes, rowCount);\n}\n\n// Tables are for reading, and a row wider than the terminal wraps unreadably: widest columns\n// give up space first, down to a floor. --format json is never truncated.\nconst MIN_COLUMN = 12;\nconst TRUNCATED = '…';\n\nfunction fitWidths(widths: number[], limit: number): number[] {\n const gaps = (widths.length - 1) * 2;\n const fitted = [...widths];\n for (;;) {\n const total = fitted.reduce((a, b) => a + b, 0) + gaps;\n if (total <= limit) return fitted;\n const widest = fitted.indexOf(Math.max(...fitted));\n if (fitted[widest] <= MIN_COLUMN) return fitted;\n fitted[widest] = Math.max(MIN_COLUMN, fitted[widest] - Math.max(1, total - limit));\n }\n}\n\n// An array cell (snippets) becomes one physical line per element; every other value stays the\n// single line cell() already produced. No cell in any other command holds one today, so a row\n// with no array-valued cell yields exactly one physical line, unchanged from before this existed.\nfunction cellLines(value: unknown): string[] {\n if (Array.isArray(value)) return value.length === 0 ? [''] : value.map((v) => cell(v));\n return [cell(value)];\n}\n\nfunction renderRows(rows: object[], format: Format, width = process.stdout.columns): string {\n if (format === 'json') return stringifyJson(rows, 2);\n if (rows.length === 0) return '(0 rows)';\n\n const columns = Object.keys(rows[0]);\n const linesByCell = rows.map((row) => columns.map((col) => cellLines(Reflect.get(row, col))));\n const heights = linesByCell.map((cellsInRow) => Math.max(1, ...cellsInRow.map((lines) => lines.length)));\n const natural = columns.map((col, i) => Math.max(col.length, ...linesByCell.flatMap((cellsInRow) => cellsInRow[i]).map((line) => line.length)));\n const widths = width && width > MIN_COLUMN ? fitWidths(natural, width) : natural;\n\n const clip = (value: string, w: number) => (value.length <= w ? value.padEnd(w) : `${value.slice(0, w - 1)}${TRUNCATED}`);\n const formatRow = (values: string[]) =>\n values\n .map((value, i) => clip(value, widths[i]))\n .join(' ')\n .trimEnd();\n\n // A row becomes as many physical lines as its tallest cell; other columns blank-pad on\n // continuation lines (DESIGN.md \"Rendering a list of snippets\").\n const body: string[] = [];\n for (let r = 0; r < rows.length; r++) {\n for (let li = 0; li < heights[r]; li++) body.push(formatRow(columns.map((_, c) => linesByCell[r][c][li] ?? '')));\n }\n\n return [formatRow(columns), widths.map((w) => '-'.repeat(w)).join(' '), ...body].join('\\n');\n}\n\n// Text renderers for the top-level commands; cli.ts prints what these return.\n\n// Names the config key that turns a feature back on. Only the three features-block toggles\n// reach here; `embed` has its own status line.\nexport function featureOffHint(name: string): string {\n return `features.${name}`;\n}\n\nexport function featuresLine(features: { on: string[]; off: string[] }): string {\n const off = features.off.length > 0 ? ` · off: ${features.off.map((name) => `${name} (${featureOffHint(name)})`).join(', ')}` : '';\n return `features: ${features.on.join(', ')}${off}`;\n}\n\n// name, or name:weight when the weight is not the default 1.\nfunction signalLabels(signals: Record<string, number>): string {\n return Object.entries(signals)\n .map(([name, weight]) => (weight === 1 ? name : `${name}:${weight}`))\n .join(', ');\n}\n\nexport function presetsLines(presets: Array<{ name: string; files: number; embedded: number; signals: Record<string, number> }>): string[] {\n // \"0 embedded\" is ambiguous between a scope that declined vectors and one that has not built\n // them yet, so a preset without the vectors signal says what it uses instead.\n return ['presets:', ...presets.map((p) => ` ${p.name}: ${p.files} file(s), ${p.embedded} embedded${p.signals.vectors !== undefined ? '' : ` (signals: ${signalLabels(p.signals)})`}`)];\n}\n\nexport function renderMap(result: TreeMap): string {\n const parts = [`docs: ${result.docs.count} (${Math.round(result.docs.bytes / 1024)} KB)`, featuresLine(result.features), '', ...presetsLines(result.presets), '', renderRows(result.fields, 'table')];\n if (result.fieldsTotal > result.fields.length) parts.push(`(+${result.fieldsTotal - result.fields.length} more fields)`);\n if (result.hubs.length > 0) parts.push('\\nhubs (by link rank):', renderRows(result.hubs, 'table'));\n else if (result.features.off.includes('rank')) parts.push(`\\nhubs: off (${featureOffHint('rank')})`);\n parts.push('\\nrecent:');\n if (result.recentCaveat) parts.push(result.recentCaveat);\n parts.push(renderRows(result.recent, 'table'));\n return parts.join('\\n');\n}\n\nexport function renderPeek(result: Peek): string {\n const lines = [`${result.path} (~${result.tokens} tokens)`];\n // Otherwise a refused parse is indistinguishable from a note that has no frontmatter, which\n // is the confusion the whole quarantine design exists to remove.\n if (result.parseError) lines.push(` frontmatter: did not parse, so none of it is indexed (${result.parseError})`);\n for (const [key, value] of Object.entries(result.frontmatter)) lines.push(` ${key}: ${value}`);\n if (result.sections.length > 0) {\n lines.push('', 'sections:');\n for (const s of result.sections) lines.push(` ${'#'.repeat(s.level)} ${s.heading} [L${s.start_line}-${s.end_line}, ~${s.tokens}t]`);\n if (result.sectionsTotal > result.sections.length) lines.push(` (+${result.sectionsTotal - result.sections.length} more sections -- sections table has all of them)`);\n } else if (result.off.includes('sections')) lines.push('', 'sections: off (features.sections)');\n if (result.off.includes('links')) {\n lines.push('', 'links: off (features.links)');\n } else {\n const linkLine = (label: string, shown: string[], total: number) => {\n if (total > 0) lines.push(`${label} (${total}): ${shown.join(', ')}${total > shown.length ? `, +${total - shown.length} more` : ''}`);\n };\n if (result.outboundTotal + result.unresolvedTotal + result.backlinksTotal > 0) lines.push('');\n linkLine('links out', result.outbound, result.outboundTotal);\n linkLine('unresolved', result.unresolved, result.unresolvedTotal);\n linkLine('backlinks', result.backlinks, result.backlinksTotal);\n }\n return lines.join('\\n');\n}\n"],"names":["featureOffHint","featuresLine","presetsLines","printRowStream","printRows","renderMap","renderPeek","stringifyJson","OVERSIZE_BYTES","cell","value","String","replace","csvField","text","undefined","Array","isArray","join","test","csvLine","values","map","warnOversize","bytes","rowCount","console","warn","Math","round","MAX_SAFE","BigInt","Number","MAX_SAFE_INTEGER","bigintSafe","_key","toString","indent","JSON","stringify","rows","format","columns","names","length","Object","keys","Set","rendered","row","name","log","Buffer","byteLength","renderRows","iterator","first","rest","collected","write","Symbol","asyncIterator","next","done","push","process","stdout","split","line","MIN_COLUMN","TRUNCATED","fitWidths","widths","limit","gaps","fitted","total","reduce","a","b","widest","indexOf","max","cellLines","v","body","formatRow","_","c","linesByCell","r","li","heights","width","col","Reflect","get","cellsInRow","lines","natural","i","flatMap","clip","w","padEnd","slice","trimEnd","repeat","features","off","on","signalLabels","signals","entries","weight","presets","p","files","embedded","vectors","result","parts","docs","count","fields","fieldsTotal","hubs","includes","recentCaveat","recent","path","tokens","parseError","frontmatter","key","sections","s","level","heading","start_line","end_line","sectionsTotal","linkLine","label","shown","outboundTotal","unresolvedTotal","backlinksTotal","outbound","unresolved","backlinks"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/output/output.ts"],"sourcesContent":["import type { TreeMap } from '../commands/map.ts';\nimport type { Peek } from '../commands/peek.ts';\n\n// rows -> table (default) | json | csv\n\nexport type Row = Record<string, unknown>;\n\n// map/peek/status/path render structures rather than a row set, so csv has nothing to mean\n// there; the commands that emit rows take RowFormat.\nexport type Format = 'table' | 'json';\nexport type RowFormat = Format | 'csv';\n\n// Warned about on stderr (keeps --format json stdout machine-readable), never truncated.\nconst OVERSIZE_BYTES = 50_000;\n\n// Flatten embedded newlines so they can't break table column alignment; JSON output keeps them as-is.\nfunction cell(value: unknown): string {\n return String(value ?? '').replace(/\\s*\\n\\s*/g, ' ');\n}\n\n// RFC 4180, deliberately not cell(): csv is the redirect-to-file format, so it keeps every\n// character, newlines included; what it cannot carry (NULL vs empty, types) is what json is for.\n// An array (e.g. snippets) joins with the one delimiter our content provably cannot contain,\n// inside the quoted field newlines already trigger (DESIGN.md \"Rendering a list of snippets\").\nfunction csvField(value: unknown): string {\n const text = value === null || value === undefined ? '' : Array.isArray(value) ? value.join('\\n') : String(value);\n return /[\"\\r\\n,]/.test(text) ? `\"${text.replace(/\"/g, '\"\"')}\"` : text;\n}\n\nfunction csvLine(values: unknown[]): string {\n return values.map(csvField).join(',');\n}\n\nfunction warnOversize(bytes: number, rowCount: number): void {\n if (bytes <= OVERSIZE_BYTES) return;\n console.warn(`warning: result is ${Math.round(bytes / 1000)} KB across ${rowCount} row(s); consider a LIMIT, fewer columns, snippet() instead of whole values, or --format csv redirected to a file`);\n}\n\n// JSON.stringify throws on BigInt, and stores return int64 as BigInt (DuckDB does): a value\n// that fits a safe integer stays a number, a larger one becomes its decimal string.\nconst MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);\nconst bigintSafe = (_key: string, value: unknown): unknown => (typeof value === 'bigint' ? (value >= -MAX_SAFE && value <= MAX_SAFE ? Number(value) : value.toString()) : value);\n\nexport function stringifyJson(value: unknown, indent?: number): string {\n return JSON.stringify(value, bigintSafe, indent);\n}\n\nexport function printRows(rows: Row[], format: RowFormat, columns?: string[]): void {\n if (format === 'csv') {\n // Names from a row wherever there is one: the statement's column list keeps duplicates the\n // row collapsed. Nothing at all with no row and no columns -- a bare newline is an empty record.\n const names = rows.length > 0 ? Object.keys(rows[0]) : [...new Set(columns ?? [])];\n if (names.length === 0) return;\n const rendered = [csvLine(names), ...rows.map((row) => csvLine(names.map((name) => row[name])))].join('\\n');\n console.log(rendered);\n // Bytes, not code units -- CJK is 3 bytes per character.\n warnOversize(Buffer.byteLength(rendered), rows.length);\n return;\n }\n const rendered = renderRows(rows, format);\n console.log(rendered);\n warnOversize(Buffer.byteLength(rendered), rows.length);\n}\n\n// Streaming counterpart for the one unbounded caller, `sense sql`: the result is never held as\n// rows and again as a rendered string. Table buffers (column width depends on the last row); json/csv write row by row.\nexport async function printRowStream(rows: AsyncIterable<Row>, format: RowFormat, columns: string[]): Promise<void> {\n const iterator = rows[Symbol.asyncIterator]();\n // One step before any write. FTS5 parses a MATCH expression at step time rather than at\n // prepare time, so a bad search string throws here, with stdout still clean for the error.\n const first = await iterator.next();\n const rest: AsyncIterable<Row> = { [Symbol.asyncIterator]: () => iterator };\n\n if (format === 'table') {\n const collected: Row[] = first.done ? [] : [first.value];\n for await (const row of rest) collected.push(row);\n printRows(collected, format, columns);\n return;\n }\n\n let bytes = 0;\n let rowCount = 0;\n const write = (text: string): void => {\n // Bytes, not code units -- CJK is 3 bytes per character.\n bytes += Buffer.byteLength(text);\n process.stdout.write(text);\n };\n\n if (format === 'json') {\n // Byte-identical to JSON.stringify(rows, null, 2) + newline: each row re-indented one\n // level, comma-joined, inside the array brackets written here.\n const indent = (row: Row) =>\n stringifyJson(row, 2)\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n if (first.done) {\n write('[]\\n');\n } else {\n write('[\\n');\n write(indent(first.value));\n rowCount = 1;\n for await (const row of rest) {\n write(',\\n');\n write(indent(row));\n rowCount++;\n }\n write('\\n]\\n');\n }\n } else if (first.done) {\n const names = [...new Set(columns)];\n if (names.length > 0) write(`${csvLine(names)}\\n`);\n } else {\n const names = Object.keys(first.value);\n write(`${csvLine(names)}\\n`);\n write(`${csvLine(names.map((name) => first.value[name]))}\\n`);\n rowCount = 1;\n for await (const row of rest) {\n write(`${csvLine(names.map((name) => row[name]))}\\n`);\n rowCount++;\n }\n }\n warnOversize(bytes, rowCount);\n}\n\n// Tables are for reading, and a row wider than the terminal wraps unreadably: widest columns\n// give up space first, down to a floor. --format json is never truncated.\nconst MIN_COLUMN = 12;\nconst TRUNCATED = '…';\n\nfunction fitWidths(widths: number[], limit: number): number[] {\n const gaps = (widths.length - 1) * 2;\n const fitted = [...widths];\n for (;;) {\n const total = fitted.reduce((a, b) => a + b, 0) + gaps;\n if (total <= limit) return fitted;\n const widest = fitted.indexOf(Math.max(...fitted));\n if (fitted[widest] <= MIN_COLUMN) return fitted;\n fitted[widest] = Math.max(MIN_COLUMN, fitted[widest] - Math.max(1, total - limit));\n }\n}\n\n// An array cell (snippets) becomes one physical line per element; every other value stays the\n// single line cell() already produced. No cell in any other command holds one today, so a row\n// with no array-valued cell yields exactly one physical line, unchanged from before this existed.\nfunction cellLines(value: unknown): string[] {\n if (Array.isArray(value)) return value.length === 0 ? [''] : value.map((v) => cell(v));\n return [cell(value)];\n}\n\nfunction renderRows(rows: object[], format: Format, width = process.stdout.columns): string {\n if (format === 'json') return stringifyJson(rows, 2);\n if (rows.length === 0) return '(0 rows)';\n\n const columns = Object.keys(rows[0]);\n const linesByCell = rows.map((row) => columns.map((col) => cellLines(Reflect.get(row, col))));\n const heights = linesByCell.map((cellsInRow) => Math.max(1, ...cellsInRow.map((lines) => lines.length)));\n const natural = columns.map((col, i) => Math.max(col.length, ...linesByCell.flatMap((cellsInRow) => cellsInRow[i]).map((line) => line.length)));\n const widths = width && width > MIN_COLUMN ? fitWidths(natural, width) : natural;\n\n const clip = (value: string, w: number) => (value.length <= w ? value.padEnd(w) : `${value.slice(0, w - 1)}${TRUNCATED}`);\n const formatRow = (values: string[]) =>\n values\n .map((value, i) => clip(value, widths[i]))\n .join(' ')\n .trimEnd();\n\n // A row becomes as many physical lines as its tallest cell; other columns blank-pad on\n // continuation lines (DESIGN.md \"Rendering a list of snippets\").\n const body: string[] = [];\n for (let r = 0; r < rows.length; r++) {\n for (let li = 0; li < heights[r]; li++) body.push(formatRow(columns.map((_, c) => linesByCell[r][c][li] ?? '')));\n }\n\n return [formatRow(columns), widths.map((w) => '-'.repeat(w)).join(' '), ...body].join('\\n');\n}\n\n// Text renderers for the top-level commands; cli.ts prints what these return.\n\n// Names the config key that turns a feature back on. Only the three features-block toggles\n// reach here; `embed` has its own status line.\nexport function featureOffHint(name: string): string {\n return `features.${name}`;\n}\n\nexport function featuresLine(features: { on: string[]; off: string[] }): string {\n const off = features.off.length > 0 ? ` · off: ${features.off.map((name) => `${name} (${featureOffHint(name)})`).join(', ')}` : '';\n return `features: ${features.on.join(', ')}${off}`;\n}\n\n// name, or name:weight when the weight is not the default 1.\nfunction signalLabels(signals: Record<string, number>): string {\n return Object.entries(signals)\n .map(([name, weight]) => (weight === 1 ? name : `${name}:${weight}`))\n .join(', ');\n}\n\nexport function presetsLines(presets: Array<{ name: string; files: number; embedded: number; signals: Record<string, number> }>): string[] {\n // \"0 embedded\" is ambiguous between a scope that declined vectors and one that has not built\n // them yet, so a preset without the vectors signal says what it uses instead.\n return ['presets:', ...presets.map((p) => ` ${p.name}: ${p.files} file(s), ${p.embedded} embedded${p.signals.vectors !== undefined ? '' : ` (signals: ${signalLabels(p.signals)})`}`)];\n}\n\nexport function renderMap(result: TreeMap): string {\n const parts = [`docs: ${result.docs.count} (${Math.round(result.docs.bytes / 1024)} KB)`, featuresLine(result.features), '', ...presetsLines(result.presets), '', renderRows(result.fields, 'table')];\n if (result.fieldsTotal > result.fields.length) parts.push(`(+${result.fieldsTotal - result.fields.length} more fields)`);\n if (result.hubs.length > 0) parts.push('\\nhubs (by link rank):', renderRows(result.hubs, 'table'));\n else if (result.features.off.includes('rank')) parts.push(`\\nhubs: off (${featureOffHint('rank')})`);\n parts.push('\\nrecent:');\n if (result.recentCaveat) parts.push(result.recentCaveat);\n parts.push(renderRows(result.recent, 'table'));\n return parts.join('\\n');\n}\n\nexport function renderPeek(result: Peek): string {\n const lines = [`${result.path} (~${result.tokens} tokens)`];\n // Otherwise a refused parse is indistinguishable from a note that has no frontmatter, which\n // is the confusion the whole quarantine design exists to remove.\n if (result.parseError) lines.push(` frontmatter: did not parse, so none of it is indexed (${result.parseError})`);\n for (const [key, value] of Object.entries(result.frontmatter)) lines.push(` ${key}: ${value}`);\n if (result.sections.length > 0) {\n lines.push('', 'sections:');\n for (const s of result.sections) lines.push(` ${'#'.repeat(s.level)} ${s.heading} [L${s.start_line}-${s.end_line}, ~${s.tokens}t]`);\n if (result.sectionsTotal > result.sections.length) lines.push(` (+${result.sectionsTotal - result.sections.length} more sections -- sections table has all of them)`);\n } else if (result.off.includes('sections')) lines.push('', 'sections: off (features.sections)');\n if (result.off.includes('links')) {\n lines.push('', 'links: off (features.links)');\n } else {\n const linkLine = (label: string, shown: string[], total: number) => {\n if (total > 0) lines.push(`${label} (${total}): ${shown.join(', ')}${total > shown.length ? `, +${total - shown.length} more` : ''}`);\n };\n if (result.outboundTotal + result.unresolvedTotal + result.backlinksTotal > 0) lines.push('');\n linkLine('links out', result.outbound, result.outboundTotal);\n linkLine('unresolved', result.unresolved, result.unresolvedTotal);\n linkLine('backlinks', result.backlinks, result.backlinksTotal);\n }\n return lines.join('\\n');\n}\n"],"names":["featureOffHint","featuresLine","presetsLines","printRowStream","printRows","renderMap","renderPeek","stringifyJson","OVERSIZE_BYTES","cell","value","String","replace","csvField","text","undefined","Array","isArray","join","test","csvLine","values","map","warnOversize","bytes","rowCount","console","warn","Math","round","MAX_SAFE","BigInt","Number","MAX_SAFE_INTEGER","bigintSafe","_key","toString","indent","JSON","stringify","rows","format","columns","names","length","Object","keys","Set","rendered","row","name","log","Buffer","byteLength","renderRows","iterator","first","rest","collected","write","Symbol","asyncIterator","next","done","push","process","stdout","split","line","MIN_COLUMN","TRUNCATED","fitWidths","widths","limit","gaps","fitted","total","reduce","a","b","widest","indexOf","max","cellLines","v","body","formatRow","_","c","linesByCell","r","li","heights","width","col","Reflect","get","cellsInRow","lines","natural","i","flatMap","clip","w","padEnd","slice","trimEnd","repeat","features","off","on","signalLabels","signals","entries","weight","presets","p","files","embedded","vectors","result","parts","docs","count","fields","fieldsTotal","hubs","includes","recentCaveat","recent","path","tokens","parseError","frontmatter","key","sections","s","level","heading","start_line","end_line","sectionsTotal","linkLine","label","shown","outboundTotal","unresolvedTotal","backlinksTotal","outbound","unresolved","backlinks"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/output/progress.ts"],"sourcesContent":["// Progress on stderr only, so it can never corrupt --format json. A TTY gets one\n// self-overwriting line; a pipe gets a few append-only ones, not redraw frames.\n\nconst NON_TTY_MILESTONES = 4;\n\nexport interface Progress {\n tick(done: number): void;\n finish(): void;\n}\n\n// `total` known upfront; `label` names the work (\"embedding notes\", \"reparsing files\").\n// Silent entirely below `threshold` -- short work needs no narration.\nexport function progress(label: string, total: number, threshold = 200): Progress {\n if (total < threshold) return { tick() {}, finish() {} };\n\n const started = Date.now();\n const isTTY = process.stderr.isTTY === true;\n let lastShown = 0;\n let wrote = false;\n\n const line = (done: number) => {\n const elapsed = (Date.now() - started) / 1000;\n // Estimate from observed rate, only once there is a rate to observe.\n const eta = done > 0 && done < total ? `, ~${Math.max(1, Math.round((elapsed / done) * (total - done)))}s left` : '';\n return `${label}: ${done}/${total}${eta}`;\n };\n\n return {\n tick(done: number) {\n if (isTTY) {\n process.stderr.write(`\\r${line(done)}`);\n wrote = true;\n return;\n }\n // Sparse milestones: first tick, then every 1/NON_TTY_MILESTONES of the total.\n if (done === lastShown) return;\n if (lastShown === 0 || done - lastShown >= total / NON_TTY_MILESTONES) {\n process.stderr.write(`${line(done)}\\n`);\n lastShown = done;\n wrote = true;\n }\n },\n finish() {\n if (!wrote) return;\n if (isTTY) process.stderr.write(`\\r${line(total)}\\n`);\n else if (lastShown < total) process.stderr.write(`${line(total)}\\n`);\n },\n };\n}\n"],"names":["progress","NON_TTY_MILESTONES","label","total","threshold","tick","finish","started","Date","now","isTTY","process","stderr","lastShown","wrote","line","done","elapsed","eta","Math","max","round","write"],"mappings":";;;;+BAYgBA;;;eAAAA;;;AAZhB,iFAAiF;AACjF,gFAAgF;AAEhF,IAAMC,qBAAqB;AASpB,SAASD,SAASE,KAAa,EAAEC,KAAa;QAAEC,YAAAA,iEAAY;IACjE,IAAID,QAAQC,WAAW,OAAO;QAAEC,MAAAA,SAAAA,QAAQ;QAAGC,QAAAA,SAAAA,UAAU;IAAE;IAEvD,IAAMC,UAAUC,KAAKC,GAAG;IACxB,IAAMC,QAAQC,QAAQC,MAAM,CAACF,KAAK,KAAK;IACvC,IAAIG,YAAY;IAChB,IAAIC,QAAQ;IAEZ,IAAMC,OAAO,cAACC;QACZ,IAAMC,UAAU,AAACT,CAAAA,KAAKC,GAAG,KAAKF,OAAM,IAAK;QACzC,qEAAqE;QACrE,IAAMW,MAAMF,OAAO,KAAKA,OAAOb,QAAQ,AAAC,MAAgE,OAA3DgB,KAAKC,GAAG,CAAC,GAAGD,KAAKE,KAAK,CAAC,AAACJ,UAAUD,OAASb,CAAAA,QAAQa,IAAG,KAAK,YAAU;QAClH,OAAO,AAAC,GAAYA,OAAVd,OAAM,MAAYC,OAARa,MAAK,KAAWE,OAARf,OAAY,OAAJe;IACtC;IAEA,OAAO;QACLb,MAAAA,SAAAA,KAAKW,IAAY;YACf,IAAIN,OAAO;gBACTC,QAAQC,MAAM,CAACU,KAAK,CAAC,AAAC,KAAe,OAAXP,KAAKC;gBAC/BF,QAAQ;gBACR;YACF;YACA,+EAA+E;YAC/E,IAAIE,SAASH,WAAW;YACxB,IAAIA,cAAc,KAAKG,OAAOH,aAAaV,QAAQF,oBAAoB;gBACrEU,QAAQC,MAAM,CAACU,KAAK,CAAC,AAAC,GAAa,OAAXP,KAAKC,OAAM;gBACnCH,YAAYG;gBACZF,QAAQ;YACV;QACF;QACAR,QAAAA,SAAAA;YACE,IAAI,CAACQ,OAAO;YACZ,IAAIJ,OAAOC,QAAQC,MAAM,CAACU,KAAK,CAAC,AAAC,KAAgB,OAAZP,KAAKZ,QAAO;iBAC5C,IAAIU,YAAYV,OAAOQ,QAAQC,MAAM,CAACU,KAAK,CAAC,AAAC,GAAc,OAAZP,KAAKZ,QAAO;QAClE;IACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/open-source/ai/sensemaking/src/output/search-error.ts"],"sourcesContent":["import { SenseError } from '../errors.ts';\nimport { hasUnspacedRun } from '../text/segment.ts';\n\n// FTS5 reads punctuation as syntax, so `end-to-end` parses as a filter on column `to` and\n// errors `no such column: to` -- true about the parse, misleading about the input.\nconst FTS5_PUNCTUATION = /[^\\p{L}\\p{M}\\p{N}_\\s]/u;\n\nfunction hasBalancedGrouping(text: string): boolean {\n let depth = 0;\n let grouped = false;\n for (const char of text) {\n if (char === '(') {\n depth++;\n grouped = true;\n } else if (char === ')') {\n depth--;\n if (depth < 0) return false;\n }\n }\n return grouped && depth === 0;\n}\n\n// Detects routing intent only. SQLite parses the complete expression, while other stores name\n// the unsupported operator; neither path silently interprets its punctuation as literal text.\nfunction hasExplicitFts5Syntax(terms: string): boolean {\n const text = terms.replace(/\"[^\"]*\"/g, 'phrase');\n return /[\\p{L}\\p{N}_]+\\*(?=\\s|$)/u.test(text) || /(?:^|[\\s(])(?:AND|OR|NOT)(?=\\s|\\)|$)/u.test(text) || /(?:^|[\\s(])NEAR\\b/u.test(text) || /(?:^|[\\s(])\\^\\S+/u.test(text) || /(?:^|[\\s(])[\\p{L}_]\\w*\\s*:/u.test(text) || hasBalancedGrouping(text);\n}\n\n// SQLite treats punctuation in an unquoted spaced-script token as MATCH syntax. Validate that\n// boundary before dispatch so DuckDB and Tantivy do not silently interpret the same input as text.\nexport function bareTermSyntaxError(terms: string): Error | null {\n if (hasExplicitFts5Syntax(terms)) return null;\n const outsideQuotes = terms.replace(/\"[^\"]*\"/g, ' ');\n const suspects = (outsideQuotes.match(/\\S+/g) ?? []).filter((token) => {\n if (!FTS5_PUNCTUATION.test(token) || hasUnspacedRun(token)) return false;\n if (/^[\\p{L}_]\\w*\\s*:/u.test(token)) return false;\n if (/^[\\p{L}\\p{N}_]+\\*(?:\\s|$)/u.test(token)) return false;\n if (/^(?:AND|OR|NOT)$/u.test(token)) return false;\n return true;\n });\n if (suspects.length === 0) return null;\n return new SenseError('SEARCH_SYNTAX', `the punctuation in ${suspects.map((term) => `\\`${term}\\``).join(', ')} is FTS5 syntax, not literal text; search for it literally by double-quoting: '\"${suspects[0]}\"'. Searchable columns are title, summary, text.`);\n}\n\nexport function searchError(err: Error, terms: string, scope?: string): Error {\n const message = err.message;\n if (!/no such column|fts5: syntax error|malformed MATCH/.test(message)) return err;\n const suspects = (terms.match(/\\S+/g) ?? []).filter((t) => !t.startsWith('\"') && FTS5_PUNCTUATION.test(t));\n // Blame the terms only when the failing token actually came from one -- a typo'd column\n // in --where can raise \"no such column\" through this same statement.\n const col = /no such column: (\\S+)/.exec(message)?.[1];\n const fromTerms = col === undefined ? suspects.length > 0 : suspects.some((t) => t.split(/[^\\p{L}\\p{N}]+/u).includes(col));\n if (fromTerms && suspects.length > 0) {\n return new SenseError('SEARCH_SYNTAX', `${message} -- the punctuation in ${suspects.map((t) => `\\`${t}\\``).join(', ')} is FTS5 syntax, not literal text; search for it literally by double-quoting: '\"${suspects[0]}\"'. Searchable columns are title, summary, text.`);\n }\n if (col !== undefined && scope !== undefined) {\n return new SenseError('SEARCH_SYNTAX', `${message} -- the where condition (${scope}) references it; frontmatter columns are listed by sense sql \"SELECT name FROM pragma_table_info('frontmatter')\".`);\n }\n return new SenseError('SEARCH_SYNTAX', `${message} -- searchable columns are title, summary, text; frontmatter fields are queried with --where or sense sql (list them with pragma_table_info('frontmatter')).`);\n}\n"],"names":["bareTermSyntaxError","searchError","FTS5_PUNCTUATION","hasBalancedGrouping","text","depth","grouped","char","hasExplicitFts5Syntax","terms","replace","test","outsideQuotes","suspects","match","filter","token","hasUnspacedRun","length","SenseError","map","term","join","err","scope","message","t","startsWith","col","exec","fromTerms","undefined","some","split","includes"],"mappings":"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"}
|